feat: 添加表格列设置组件
parent
17c695d065
commit
85b781d946
2
.env
2
.env
|
|
@ -8,7 +8,7 @@ VITE_SUBTITLE = 快速开发web应用的模板工具
|
||||||
# 部署路径: 当为 ./ 时路由模式需为 hash
|
# 部署路径: 当为 ./ 时路由模式需为 hash
|
||||||
VITE_BASE = /
|
VITE_BASE = /
|
||||||
# 接口前缀:参见 axios 的 baseURL
|
# 接口前缀:参见 axios 的 baseURL
|
||||||
VITE_API = /
|
VITE_API = https://appnify.app.juetan.cn/
|
||||||
# 首页路径
|
# 首页路径
|
||||||
VITE_HOME_PATH = /home/home
|
VITE_HOME_PATH = /home/home
|
||||||
# 路由模式:web(路径) hash(锚点)
|
# 路由模式:web(路径) hash(锚点)
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,11 @@ declare module "axios" {
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
closeToast?: () => void;
|
closeToast?: () => void;
|
||||||
|
/**
|
||||||
|
* 是否在请求成功后提示
|
||||||
|
* @default false
|
||||||
|
*/
|
||||||
|
msg?: boolean | string;
|
||||||
/**
|
/**
|
||||||
* 响应异常提示
|
* 响应异常提示
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import { IToastOptions, toast } from "@/components";
|
import { IToastOptions, toast } from '@/components';
|
||||||
import { AxiosInstance } from "axios";
|
import { Message } from '@arco-design/web-vue';
|
||||||
|
import { AxiosInstance } from 'axios';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 提示拦截器
|
* 提示拦截器
|
||||||
|
|
@ -7,31 +8,35 @@ import { AxiosInstance } from "axios";
|
||||||
*/
|
*/
|
||||||
export function addToastInterceptor(axios: AxiosInstance) {
|
export function addToastInterceptor(axios: AxiosInstance) {
|
||||||
axios.interceptors.request.use(
|
axios.interceptors.request.use(
|
||||||
(config) => {
|
config => {
|
||||||
if (config.toast) {
|
if (config.toast) {
|
||||||
let options: IToastOptions = {};
|
let options: IToastOptions = {};
|
||||||
if (typeof config.toast === "string") {
|
if (typeof config.toast === 'string') {
|
||||||
options = { message: config.toast };
|
options = { message: config.toast };
|
||||||
}
|
}
|
||||||
if (typeof config.toast === "object") {
|
if (typeof config.toast === 'object') {
|
||||||
options = config.toast;
|
options = config.toast;
|
||||||
}
|
}
|
||||||
config.closeToast = toast(options);
|
config.closeToast = toast(options);
|
||||||
}
|
}
|
||||||
return config;
|
return config;
|
||||||
},
|
},
|
||||||
(error) => {
|
error => {
|
||||||
error.config.closeToast?.();
|
error.config.closeToast?.();
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
axios.interceptors.response.use(
|
axios.interceptors.response.use(
|
||||||
(response) => {
|
response => {
|
||||||
response.config.closeToast?.();
|
const { closeToast, msg } = response.config;
|
||||||
|
closeToast?.();
|
||||||
|
if (msg) {
|
||||||
|
Message.success(`提示: ${typeof msg === 'string' ? msg : response.data?.message}`);
|
||||||
|
}
|
||||||
return response;
|
return response;
|
||||||
},
|
},
|
||||||
(error) => {
|
error => {
|
||||||
error.config.closeToast?.();
|
error.config.closeToast?.();
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,18 @@
|
||||||
import { Form, FormInstance } from "@arco-design/web-vue";
|
import { Form, FormInstance } from '@arco-design/web-vue';
|
||||||
import { useVModel } from "@vueuse/core";
|
import { useVModel } from '@vueuse/core';
|
||||||
import { PropType } from "vue";
|
import { PropType } from 'vue';
|
||||||
import { FormContextKey } from "../core/useFormContext";
|
import { FormContextKey } from './useFormContext';
|
||||||
import { useFormItems } from "../core/useFormItems";
|
import { useFormItems } from './useFormItems';
|
||||||
import { useFormModel } from "../core/useFormModel";
|
import { useFormModel } from './useFormModel';
|
||||||
import { useFormRef } from "../core/useFormRef";
|
import { useFormRef } from './useFormRef';
|
||||||
import { useFormSubmit } from "../core/useFormSubmit";
|
import { useFormSubmit } from './useFormSubmit';
|
||||||
import { AnFormItem, IAnFormItem } from "./FormItem";
|
import { AnFormItem, IAnFormItem } from './FormItem';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 表单组件
|
* 表单组件
|
||||||
*/
|
*/
|
||||||
export const AnForm = defineComponent({
|
export const AnForm = defineComponent({
|
||||||
name: "AnForm",
|
name: 'AnForm',
|
||||||
props: {
|
props: {
|
||||||
/**
|
/**
|
||||||
* 表单数据
|
* 表单数据
|
||||||
|
|
@ -38,9 +38,7 @@ export const AnForm = defineComponent({
|
||||||
* 提交表单
|
* 提交表单
|
||||||
* @example
|
* @example
|
||||||
* ```ts
|
* ```ts
|
||||||
* (model) => {
|
* (model) => api.user.addUser(model)
|
||||||
* return api.user.addUser(model)
|
|
||||||
* }
|
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
submit: {
|
submit: {
|
||||||
|
|
@ -59,9 +57,9 @@ export const AnForm = defineComponent({
|
||||||
type: Object as IAnFormProps,
|
type: Object as IAnFormProps,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
emits: ["update:model"],
|
emits: ['update:model'],
|
||||||
setup(props, { slots, emit }) {
|
setup(props, { slots, emit }) {
|
||||||
const model = useVModel(props, "model", emit);
|
const model = useVModel(props, 'model', emit);
|
||||||
const items = computed(() => props.items);
|
const items = computed(() => props.items);
|
||||||
const formRefes = useFormRef();
|
const formRefes = useFormRef();
|
||||||
const formModel = useFormModel(model, formRefes.clearValidate);
|
const formModel = useFormModel(model, formRefes.clearValidate);
|
||||||
|
|
@ -75,9 +73,12 @@ export const AnForm = defineComponent({
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<Form layout="vertical" {...this.$attrs} {...this.formProps} ref="formRef" model={this.model}>
|
<Form layout="vertical" {...this.$attrs} {...this.formProps} ref="formRef" model={this.model}>
|
||||||
{this.items.map((item) => (
|
{this.items.map(item => (
|
||||||
<AnFormItem key={item.field} item={item} items={this.items} model={this.model}></AnFormItem>
|
<AnFormItem key={item.field} item={item} items={this.items} model={this.model}></AnFormItem>
|
||||||
))}
|
))}
|
||||||
|
{this.submit && this.submitItem && (
|
||||||
|
<AnFormItem item={this.submitItem} items={this.items} model={this.model}></AnFormItem>
|
||||||
|
)}
|
||||||
</Form>
|
</Form>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -85,11 +86,11 @@ export const AnForm = defineComponent({
|
||||||
|
|
||||||
export type AnFormInstance = InstanceType<typeof AnForm>;
|
export type AnFormInstance = InstanceType<typeof AnForm>;
|
||||||
|
|
||||||
export type AnFormProps = AnFormInstance["$props"];
|
export type AnFormProps = AnFormInstance['$props'];
|
||||||
|
|
||||||
export type IAnFormProps = PropType<Omit<FormInstance["$props"], "model">>;
|
export type IAnFormProps = PropType<Omit<FormInstance['$props'], 'model'>>;
|
||||||
|
|
||||||
export type IAnForm = Pick<AnFormProps, "model" | "items" | "submit" | "formProps">;
|
export type IAnForm = Pick<AnFormProps, 'model' | 'items' | 'submit' | 'formProps'>;
|
||||||
|
|
||||||
export type IAnFormSubmitFn = (model: Recordable, items: IAnFormItem[]) => any;
|
export type IAnFormSubmitFn = (model: Recordable, items: IAnFormItem[]) => any;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ import {
|
||||||
import { InjectionKey, PropType, provide } from 'vue';
|
import { InjectionKey, PropType, provide } from 'vue';
|
||||||
import { SetterItem, SetterType, setterMap } from './FormSetter';
|
import { SetterItem, SetterType, setterMap } from './FormSetter';
|
||||||
|
|
||||||
export const FormItemContextKey = Symbol('FormItemContextKey') as InjectionKey<any>;
|
export const FormItemContextKey = Symbol('FormItemContextKey') as InjectionKey<IAnFormItemFnProps>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 表单项
|
* 表单项
|
||||||
|
|
@ -42,44 +42,43 @@ export const AnFormItem = defineComponent({
|
||||||
const rules = computed(() => props.item.rules?.filter(i => !i.disable?.(props)));
|
const rules = computed(() => props.item.rules?.filter(i => !i.disable?.(props)));
|
||||||
const disabled = computed(() => Boolean(props.item.disable?.(props)));
|
const disabled = computed(() => Boolean(props.item.disable?.(props)));
|
||||||
|
|
||||||
const setterSlots = computed(() => {
|
const setterSlots = (() => {
|
||||||
const slots = props.item.setterSlots;
|
const slots = props.item.setterSlots;
|
||||||
if (!slots) {
|
if (!slots) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const items: Recordable = {};
|
const items: Recordable = {};
|
||||||
for (const [name, Slot] of Object.entries(slots)) {
|
for (const [name, Slot] of Object.entries(slots)) {
|
||||||
items[name] = () => <Slot {...props} />;
|
items[name] = (p: Recordable) => <Slot {...p} {...props} />;
|
||||||
}
|
}
|
||||||
return items;
|
return items;
|
||||||
});
|
})();
|
||||||
|
|
||||||
const contentRender = () => {
|
const itemSlots = (() => {
|
||||||
const Slot = props.item.itemSlots?.default;
|
|
||||||
if (Slot) {
|
|
||||||
return <Slot {...props} />;
|
|
||||||
}
|
|
||||||
const Setter = setterMap[props.item.setter as SetterType]?.setter as any;
|
const Setter = setterMap[props.item.setter as SetterType]?.setter as any;
|
||||||
if (!Setter) {
|
const slots = props.item.itemSlots;
|
||||||
|
if (!slots && !Setter) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return (
|
const SetterRender = () => (
|
||||||
<Setter {...props.item.setterProps} v-model={props.model[props.item.field]}>
|
<Setter {...props.item.setterProps} v-model={props.model[props.item.field]}>
|
||||||
{setterSlots.value}
|
{setterSlots}
|
||||||
</Setter>
|
</Setter>
|
||||||
);
|
);
|
||||||
|
if (!slots) {
|
||||||
|
return {
|
||||||
|
default: SetterRender,
|
||||||
};
|
};
|
||||||
|
}
|
||||||
const makeSlot = (name: 'help' | 'extra' | 'label' | 'default') => {
|
const items: Recordable = {};
|
||||||
return () => {
|
for (const [name, Slot] of Object.entries(slots)) {
|
||||||
const Slot = props.item.itemSlots?.[name];
|
items[name] = (p: Recordable) => <Slot {...p} {...props}></Slot>;
|
||||||
return Slot ? () => <Slot {...props} /> : null;
|
}
|
||||||
};
|
if (Setter) {
|
||||||
};
|
items.default = SetterRender;
|
||||||
|
}
|
||||||
const help = computed(makeSlot('help'));
|
return items;
|
||||||
const extra = computed(makeSlot('extra'));
|
})();
|
||||||
const label = computed(makeSlot('label'));
|
|
||||||
|
|
||||||
provide(FormItemContextKey, props);
|
provide(FormItemContextKey, props);
|
||||||
|
|
||||||
|
|
@ -95,12 +94,7 @@ export const AnFormItem = defineComponent({
|
||||||
disabled={disabled.value}
|
disabled={disabled.value}
|
||||||
field={props.item.field}
|
field={props.item.field}
|
||||||
>
|
>
|
||||||
{{
|
{itemSlots}
|
||||||
default: contentRender,
|
|
||||||
help: help.value,
|
|
||||||
extra: extra.value,
|
|
||||||
label: label.value,
|
|
||||||
}}
|
|
||||||
</BaseFormItem>
|
</BaseFormItem>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
@ -211,6 +205,12 @@ export type IAnFormItemBase = {
|
||||||
* @see 1
|
* @see 1
|
||||||
*/
|
*/
|
||||||
itemSlots?: IAnFormItemSlots;
|
itemSlots?: IAnFormItemSlots;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 内置
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
$init?: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type IAnFormItem = IAnFormItemBase & SetterItem;
|
export type IAnFormItem = IAnFormItemBase & SetterItem;
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import { useVisible } from "@/hooks/useVisible";
|
import { useVisible } from "@/hooks/useVisible";
|
||||||
import { Button, ButtonInstance, Modal } from "@arco-design/web-vue";
|
import { Button, ButtonInstance, Modal } from "@arco-design/web-vue";
|
||||||
import { PropType } from "vue";
|
import { PropType } from "vue";
|
||||||
import { useModalSubmit } from "../core/useModalSubmit";
|
import { useModalSubmit } from "./useModalSubmit";
|
||||||
import { useModalTrigger } from "../core/useModalTrigger";
|
import { useModalTrigger } from "./useModalTrigger";
|
||||||
import { AnForm, IAnFormProps, IAnFormSubmit } from "./Form";
|
import { AnForm, IAnFormProps, IAnFormSubmit } from "./Form";
|
||||||
import { IAnFormItem } from "./FormItem";
|
import { IAnFormItem } from "./FormItem";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ export type SetterItemMap = {
|
||||||
* 'input'
|
* 'input'
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
setter?: key;
|
setter: key;
|
||||||
/**
|
/**
|
||||||
* 控件参数
|
* 控件参数
|
||||||
* @example
|
* @example
|
||||||
|
|
@ -26,20 +26,13 @@ export type SetterItemMap = {
|
||||||
* 控件插槽
|
* 控件插槽
|
||||||
* @example
|
* @example
|
||||||
* ```tsx
|
* ```tsx
|
||||||
* {
|
* label: (props) => <span>{props.item.label}</span>
|
||||||
* help: (props) => {
|
|
||||||
* return <span>
|
|
||||||
* {props.item.label}
|
|
||||||
* </span>
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
setterSlots?: SetterMap[key]['setterSlots'];
|
setterSlots?: SetterMap[key]['setterSlots'];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export type SetterItem = SetterItemMap[SetterType];
|
export type SetterItem = SetterItemMap[SetterType] | { setter?: undefined; setterProps?: undefined; setterSlots?: undefined };
|
||||||
|
|
||||||
export { setterMap };
|
export { setterMap };
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
import { Ref } from "vue";
|
import { Ref } from 'vue';
|
||||||
import { IAnFormItem } from "../components/FormItem";
|
import { IAnFormItem } from './FormItem';
|
||||||
|
import { setterMap } from './FormSetter';
|
||||||
|
|
||||||
export function useFormItems(items: Ref<IAnFormItem[]>, model: Ref<Recordable>) {
|
export function useFormItems(items: Ref<IAnFormItem[]>, model: Ref<Recordable>) {
|
||||||
const getItem = (field: string) => {
|
const getItem = (field: string) => {
|
||||||
return items.value.find((i) => i.field === field);
|
return items.value.find(i => i.field === field);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getItemOptions = (field: string) => {
|
const getItemOptions = (field: string) => {
|
||||||
|
|
@ -15,18 +16,30 @@ export function useFormItems(items: Ref<IAnFormItem[]>, model: Ref<Recordable>)
|
||||||
|
|
||||||
const initItemOptions = (field: string) => {
|
const initItemOptions = (field: string) => {
|
||||||
const item = getItem(field);
|
const item = getItem(field);
|
||||||
item && item.init?.();
|
if (!item) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const setter = setterMap[item.setter!];
|
||||||
|
if (!setter) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setter.onSetup?.({ item, items: items.value, model: model.value });
|
||||||
};
|
};
|
||||||
|
|
||||||
const initItems = () => {
|
const initItems = () => {
|
||||||
for (const item of items.value) {
|
for (const item of items.value) {
|
||||||
item.init?.({ item, model: model.value });
|
const setter = setterMap[item?.setter!];
|
||||||
|
setter.onSetup?.({ item, items: items.value, model: model.value });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const initItem = (field: string) => {
|
const initItem = (field: string) => {
|
||||||
const item = getItem(field);
|
const item = getItem(field);
|
||||||
item && item.init?.({ item, model: model.value });
|
if (!item) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const setter = setterMap[item?.setter!];
|
||||||
|
setter.onSetup?.({ item, items: items.value, model: model.value });
|
||||||
};
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
|
@ -43,6 +43,9 @@ export function formatModel(model: Recordable) {
|
||||||
const data: Recordable = {};
|
const data: Recordable = {};
|
||||||
|
|
||||||
for (const [key, value] of Object.entries(model)) {
|
for (const [key, value] of Object.entries(model)) {
|
||||||
|
if (value === '') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (/^\[.+\]$/.test(key)) {
|
if (/^\[.+\]$/.test(key)) {
|
||||||
formatModelArray(key, value, data);
|
formatModelArray(key, value, data);
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -1,8 +1,23 @@
|
||||||
import { Message } from "@arco-design/web-vue";
|
import { Message } from '@arco-design/web-vue';
|
||||||
import { IAnForm } from "../components/Form";
|
import { IAnForm } from './Form';
|
||||||
|
import { IAnFormItem } from './FormItem';
|
||||||
|
import { cloneDeep } from 'lodash-es';
|
||||||
|
|
||||||
|
const SUBMIT_ITEM = {
|
||||||
|
field: 'id',
|
||||||
|
setter: 'submit' as const,
|
||||||
|
itemProps: {
|
||||||
|
hideLabel: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
export function useFormSubmit(props: IAnForm, validate: any, getModel: any) {
|
export function useFormSubmit(props: IAnForm, validate: any, getModel: any) {
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
|
const submitItem = ref<IAnFormItem | null>(null);
|
||||||
|
|
||||||
|
if (props.submit) {
|
||||||
|
submitItem.value = cloneDeep(SUBMIT_ITEM);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置loading
|
* 设置loading
|
||||||
|
|
@ -19,7 +34,7 @@ export function useFormSubmit(props: IAnForm, validate: any, getModel: any) {
|
||||||
if (await validate()) {
|
if (await validate()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const submit = typeof props.submit === "string" ? () => null : props.submit;
|
const submit = typeof props.submit === 'string' ? () => null : props.submit;
|
||||||
try {
|
try {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
const data = getModel();
|
const data = getModel();
|
||||||
|
|
@ -40,6 +55,7 @@ export function useFormSubmit(props: IAnForm, validate: any, getModel: any) {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
loading,
|
loading,
|
||||||
|
submitItem,
|
||||||
setLoading,
|
setLoading,
|
||||||
submitForm,
|
submitForm,
|
||||||
cancelForm,
|
cancelForm,
|
||||||
|
|
@ -1,16 +1,18 @@
|
||||||
import { AnForm, IAnForm } from "../components/Form";
|
import { AnForm, IAnForm } from '../components/Form';
|
||||||
import { FormItem, useItems } from "./useItems";
|
import { FormItem, useItems } from './useItems';
|
||||||
|
|
||||||
export type FormUseOptions = Partial<Omit<IAnForm, "items">> & {
|
export type FormUseOptions = Partial<Omit<IAnForm, 'items'>> & {
|
||||||
/**
|
/**
|
||||||
* 表单项
|
* 表单项
|
||||||
* @example
|
* @example
|
||||||
* ```ts
|
* ```ts
|
||||||
* [{
|
* [
|
||||||
|
* {
|
||||||
* field: 'name',
|
* field: 'name',
|
||||||
* label: '昵称',
|
* label: '昵称',
|
||||||
* setter: 'input'
|
* setter: 'input'
|
||||||
* }]
|
* }
|
||||||
|
* ]
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
items?: FormItem[];
|
items?: FormItem[];
|
||||||
|
|
@ -21,33 +23,27 @@ export type FormUseOptions = Partial<Omit<IAnForm, "items">> & {
|
||||||
*/
|
*/
|
||||||
export const useForm = (options: FormUseOptions) => {
|
export const useForm = (options: FormUseOptions) => {
|
||||||
const { items: _items = [], model: _model = {}, submit, formProps: _props = {} } = options;
|
const { items: _items = [], model: _model = {}, submit, formProps: _props = {} } = options;
|
||||||
const items = useItems(_items, _model, Boolean(options.submit));
|
const items = useItems(_items, _model);
|
||||||
const model = ref(_model);
|
const model = ref(_model);
|
||||||
const formProps = ref(_props);
|
const formProps = ref(_props);
|
||||||
const instance = ref<InstanceType<typeof AnForm> | null>(null);
|
const formRef = ref<InstanceType<typeof AnForm> | null>(null);
|
||||||
|
|
||||||
const component = () => {
|
const AnFormer = () => (
|
||||||
const onUpdateModel = (value: Recordable) => {
|
|
||||||
model.value = value;
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
<AnForm
|
<AnForm
|
||||||
ref={(el: any) => (instance.value = el)}
|
ref={(el: any) => (formRef.value = el)}
|
||||||
model={model.value}
|
v-model:model={model.value}
|
||||||
onUpdate:model={onUpdateModel}
|
|
||||||
items={items.value}
|
items={items.value}
|
||||||
submit={submit}
|
submit={submit}
|
||||||
formProps={formProps.value}
|
formProps={formProps.value}
|
||||||
></AnForm>
|
></AnForm>
|
||||||
);
|
);
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
component,
|
component: AnFormer,
|
||||||
instance,
|
|
||||||
model,
|
model,
|
||||||
items,
|
items,
|
||||||
formProps,
|
|
||||||
submit,
|
submit,
|
||||||
|
formProps,
|
||||||
|
formRef,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -38,37 +38,22 @@ export type FormItem = Omit<IAnFormItemBase, 'rules'> &
|
||||||
|
|
||||||
const ITEM: Partial<FormItem> = {
|
const ITEM: Partial<FormItem> = {
|
||||||
setter: 'input',
|
setter: 'input',
|
||||||
itemProps: {},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const SUBMIT_ITEM: FormItem = {
|
export function useItems(list: FormItem[], model: Recordable) {
|
||||||
field: 'id',
|
|
||||||
setter: 'submit',
|
|
||||||
itemProps: {
|
|
||||||
hideLabel: true,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export function useItems(list: FormItem[], model: Recordable, submit: boolean) {
|
|
||||||
const items = ref<IAnFormItem[]>([]);
|
const items = ref<IAnFormItem[]>([]);
|
||||||
let hasSubmit = false;
|
|
||||||
|
|
||||||
for (const item of list) {
|
for (const item of list) {
|
||||||
let target: any = defaultsDeep({}, ITEM);
|
let target: any = defaultsDeep({}, ITEM);
|
||||||
|
|
||||||
if (!item.setter || typeof item.setter === 'string') {
|
if (!item.setter || typeof item.setter === 'string') {
|
||||||
const defaults = setterMap[item.setter ?? 'input'];
|
const setter = setterMap[item.setter ?? 'input'];
|
||||||
if (defaults) {
|
if (setter) {
|
||||||
defaultsDeep(target, defaults);
|
defaultsDeep(target, { setterProps: setter.setterProps ?? {} });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item.setter === 'submit') {
|
target = merge(target, omit(item, ['required', 'rules', 'value']));
|
||||||
target = merge(target, SUBMIT_ITEM);
|
|
||||||
hasSubmit = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
target = merge(target, omit(item, ['required', 'rules']));
|
|
||||||
|
|
||||||
const rules = useRules(item);
|
const rules = useRules(item);
|
||||||
if (rules) {
|
if (rules) {
|
||||||
|
|
@ -79,9 +64,5 @@ export function useItems(list: FormItem[], model: Recordable, submit: boolean) {
|
||||||
items.value.push(target);
|
items.value.push(target);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (submit && !hasSubmit) {
|
|
||||||
items.value.push(defaultsDeep({}, SUBMIT_ITEM, setterMap.submit));
|
|
||||||
}
|
|
||||||
|
|
||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
export * from "./components/Form";
|
export * from './components/Form';
|
||||||
export * from "./hooks/useForm";
|
export * from './hooks/useForm';
|
||||||
export * from "./core/useFormContext";
|
export * from './components/useFormContext';
|
||||||
export * from "./components/FormItem";
|
export * from './components/FormItem';
|
||||||
|
export * from './components/useFormModel';
|
||||||
|
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
import { defineSetter } from './util';
|
|
||||||
|
|
||||||
export default defineSetter<{ a: number }, '11'>({
|
|
||||||
setter: () => '1',
|
|
||||||
});
|
|
||||||
|
|
@ -1,14 +1,23 @@
|
||||||
import { DatePicker, DatePickerInstance } from '@arco-design/web-vue';
|
import { DatePicker, DatePickerInstance } from '@arco-design/web-vue';
|
||||||
import { defineSetter } from './util';
|
import { defineSetter } from './util';
|
||||||
|
import { PickerProps } from '@arco-design/web-vue/es/date-picker/interface';
|
||||||
|
|
||||||
type DateProps = DatePickerInstance['$props'];
|
type DateProps = DatePickerInstance['$props'] & Partial<PickerProps>;
|
||||||
|
|
||||||
type DateSlots = 'prefix' | 'suffixIcon' | 'iconNextDouble' | 'iconPrevDouble' | 'iconNext' | 'iconPrev' | 'cell' | 'extra';
|
type DateSlots =
|
||||||
|
| 'prefix'
|
||||||
|
| 'suffixIcon'
|
||||||
|
| 'iconNextDouble'
|
||||||
|
| 'iconPrevDouble'
|
||||||
|
| 'iconNext'
|
||||||
|
| 'iconPrev'
|
||||||
|
| 'cell'
|
||||||
|
| 'extra';
|
||||||
|
|
||||||
export default defineSetter<DateProps, DateSlots>({
|
export default defineSetter<DateProps, DateSlots>({
|
||||||
setter: DatePicker,
|
setter: DatePicker,
|
||||||
setterProps: {
|
setterProps: {
|
||||||
placeholder: '请选择',
|
placeholder: '请选择',
|
||||||
allowClear: true,
|
allowClear: true,
|
||||||
} as any,
|
},
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import { defineSetter } from './util';
|
||||||
|
|
||||||
type RangeProps = RangePickerInstance['$props'];
|
type RangeProps = RangePickerInstance['$props'];
|
||||||
|
|
||||||
type RangeSlots = "1";
|
type RangeSlots = "none";
|
||||||
|
|
||||||
export default defineSetter<RangeProps, RangeSlots>({
|
export default defineSetter<RangeProps, RangeSlots>({
|
||||||
setter: RangePicker,
|
setter: RangePicker,
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import { defineSetter } from './util';
|
||||||
|
|
||||||
type InputProps = InputInstance['$props'];
|
type InputProps = InputInstance['$props'];
|
||||||
|
|
||||||
type InputSlots = "2";
|
type InputSlots = 'prepend' | 'append' | 'suffix' | 'prefix';
|
||||||
|
|
||||||
export default defineSetter<InputProps, InputSlots>({
|
export default defineSetter<InputProps, InputSlots>({
|
||||||
setter: Input,
|
setter: Input,
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import { defineSetter } from './util';
|
||||||
|
|
||||||
type NumberProps = InputInstance['$props'] | InputNumberInstance['$props'];
|
type NumberProps = InputInstance['$props'] | InputNumberInstance['$props'];
|
||||||
|
|
||||||
type NumberSlots = "3";
|
type NumberSlots = 'minus' | 'plus' | 'append' | 'prepend' | 'suffix' | 'prefix';
|
||||||
|
|
||||||
export default defineSetter<NumberProps, NumberSlots>({
|
export default defineSetter<NumberProps, NumberSlots>({
|
||||||
setter: InputNumber,
|
setter: InputNumber,
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import { defineSetter } from './util';
|
||||||
|
|
||||||
type PasswordProps = InputInstance['$props'] & InputPasswordInstance['$props'];
|
type PasswordProps = InputInstance['$props'] & InputPasswordInstance['$props'];
|
||||||
|
|
||||||
type PasswordSlots = "4";
|
type PasswordSlots = 'none';
|
||||||
|
|
||||||
export default defineSetter<PasswordProps, PasswordSlots>({
|
export default defineSetter<PasswordProps, PasswordSlots>({
|
||||||
setter: InputPassword,
|
setter: InputPassword,
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import { defineSetter } from './util';
|
||||||
|
|
||||||
type SearchProps = InputInstance['$props'] & InputSearchInstance['$props'];
|
type SearchProps = InputInstance['$props'] & InputSearchInstance['$props'];
|
||||||
|
|
||||||
type SearchSlots = "5";
|
type SearchSlots = "none";
|
||||||
|
|
||||||
export default defineSetter<SearchProps, SearchSlots>({
|
export default defineSetter<SearchProps, SearchSlots>({
|
||||||
setter: InputSearch,
|
setter: InputSearch,
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,17 @@ import { defineSetter } from './util';
|
||||||
|
|
||||||
type SelectProps = SelectInstance['$props'];
|
type SelectProps = SelectInstance['$props'];
|
||||||
|
|
||||||
type SelectSlots = "6";
|
type SelectSlots =
|
||||||
|
| 'trigger'
|
||||||
|
| 'prefix'
|
||||||
|
| 'searchIcon'
|
||||||
|
| 'loadingIcon'
|
||||||
|
| 'arrowIcon'
|
||||||
|
| 'footer'
|
||||||
|
| 'header'
|
||||||
|
| 'label'
|
||||||
|
| 'option'
|
||||||
|
| 'empty';
|
||||||
|
|
||||||
export default defineSetter<SelectProps, SelectSlots>({
|
export default defineSetter<SelectProps, SelectSlots>({
|
||||||
setter: Select,
|
setter: Select,
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import { Button } from "@arco-design/web-vue";
|
import { Button } from '@arco-design/web-vue';
|
||||||
import { FormContextKey } from "../core/useFormContext";
|
import { FormContextKey } from '../components/useFormContext';
|
||||||
import { defineSetter } from "./util";
|
import { defineSetter } from './util';
|
||||||
|
|
||||||
export default defineSetter<{ a1?: number }, "10">({
|
export default defineSetter<{}, 'none'>({
|
||||||
setter() {
|
setter() {
|
||||||
const { loading, submitForm, resetModel } = inject(FormContextKey)!;
|
const { loading, submitForm, resetModel } = inject(FormContextKey)!;
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import { defineSetter } from './util';
|
||||||
|
|
||||||
type TextareaProps = InputInstance['$props'] & TextareaInstance['$props'];
|
type TextareaProps = InputInstance['$props'] & TextareaInstance['$props'];
|
||||||
|
|
||||||
type TextareaSlots = "7";
|
type TextareaSlots = "none";
|
||||||
|
|
||||||
export default defineSetter<TextareaProps, TextareaSlots>({
|
export default defineSetter<TextareaProps, TextareaSlots>({
|
||||||
setter: Textarea,
|
setter: Textarea,
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import { defineSetter } from './util';
|
||||||
|
|
||||||
type TimeProps = TimePickerInstance['$props'];
|
type TimeProps = TimePickerInstance['$props'];
|
||||||
|
|
||||||
type TimeSlots = "8";
|
type TimeSlots = 'prefix' | 'suffixIcon' | 'extra';
|
||||||
|
|
||||||
export default defineSetter<TimeProps, TimeSlots>({
|
export default defineSetter<TimeProps, TimeSlots>({
|
||||||
setter: TimePicker,
|
setter: TimePicker,
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,18 @@ import { defineSetter } from './util';
|
||||||
|
|
||||||
type TreeSelectProps = TreeSelectInstance['$props'];
|
type TreeSelectProps = TreeSelectInstance['$props'];
|
||||||
|
|
||||||
type TreeSelectSlots = "9";
|
type TreeSelectSlots =
|
||||||
|
| 'trigger'
|
||||||
|
| 'prefix'
|
||||||
|
| 'label'
|
||||||
|
| 'header'
|
||||||
|
| 'loader'
|
||||||
|
| 'empty'
|
||||||
|
| 'footer'
|
||||||
|
| 'treeSlotExtra'
|
||||||
|
| 'treeSlotTitle'
|
||||||
|
| 'treeSlotIcon'
|
||||||
|
| 'treeSlotSwitcherIcon';
|
||||||
|
|
||||||
export default defineSetter<TreeSelectProps, TreeSelectSlots>({
|
export default defineSetter<TreeSelectProps, TreeSelectSlots>({
|
||||||
setter: TreeSelect,
|
setter: TreeSelect,
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import cascader from './Cascader';
|
import cascader from './Cascader';
|
||||||
import custom from './Custom';
|
|
||||||
import date from './Date';
|
import date from './Date';
|
||||||
import dateRange from './DateRange';
|
import dateRange from './DateRange';
|
||||||
import input from './Input';
|
import input from './Input';
|
||||||
|
|
@ -24,6 +23,5 @@ export default {
|
||||||
cascader,
|
cascader,
|
||||||
date,
|
date,
|
||||||
submit,
|
submit,
|
||||||
custom,
|
|
||||||
dateRange,
|
dateRange,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ export interface ItemSetter<P extends object, S extends string> {
|
||||||
/**
|
/**
|
||||||
* 初始化钩子
|
* 初始化钩子
|
||||||
*/
|
*/
|
||||||
onSetup?: (model: Recordable, item: IAnFormItemBase, items: IAnFormItemBase[]) => void;
|
onSetup?: (args: { model: Recordable; item: IAnFormItemBase; items: IAnFormItemBase[] }) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function defineSetter<P extends object, S extends string>(setter: ItemSetter<P, S>) {
|
export function defineSetter<P extends object, S extends string>(setter: ItemSetter<P, S>) {
|
||||||
|
|
|
||||||
|
|
@ -1,30 +1,28 @@
|
||||||
export function initOptions({ item, model }: any, key = "options") {
|
import { IAnFormItemFnProps } from '../components/FormItem';
|
||||||
if (Array.isArray(item.options)) {
|
|
||||||
item.nodeProps[key] = item.options;
|
export function initOptions({ item, model }: IAnFormItemFnProps, key: string = 'options') {
|
||||||
|
const setterProps: Recordable = item.setterProps!;
|
||||||
|
if (Array.isArray(item.options) && item.setterProps) {
|
||||||
|
setterProps[key] = item.options;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (item.options && typeof item.options === "object") {
|
if (typeof item.options === 'function') {
|
||||||
const { value, source } = item.options;
|
setterProps[key] = reactive([]);
|
||||||
item._updateOptions = async () => {};
|
item.$init = async () => {
|
||||||
|
const res = await (item as any).options({ item, model });
|
||||||
|
if (Array.isArray(res)) {
|
||||||
|
setterProps[key].splice(0);
|
||||||
|
setterProps[key].push(...res);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (typeof item.options === "function") {
|
const data = res?.data?.data;
|
||||||
const loadData = item.options;
|
|
||||||
item.nodeProps[key] = reactive([]);
|
|
||||||
item._updateOptions = async () => {
|
|
||||||
let data = await loadData({ item, model });
|
|
||||||
if (Array.isArray(data?.data?.data)) {
|
|
||||||
data = data.data.data.map((i: any) => ({
|
|
||||||
...i,
|
|
||||||
label: i.name,
|
|
||||||
value: i.id,
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
if (Array.isArray(data)) {
|
if (Array.isArray(data)) {
|
||||||
item.nodeProps[key].splice(0);
|
const maped = data.map((i: any) => ({ ...i, value: i.id, label: i.name }));
|
||||||
item.nodeProps[key].push(...data);
|
setterProps[key].splice(0);
|
||||||
|
setterProps[key].push(...maped);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
item._updateOptions();
|
item.$init();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,59 +1,58 @@
|
||||||
import { AnForm, IAnForm, IAnFormProps } from "@/components/AnForm";
|
import { IAnForm } from '@/components/AnForm';
|
||||||
import { AnFormModal } from "@/components/AnForm/components/FormModal";
|
import AniEmpty from '@/components/empty/AniEmpty.vue';
|
||||||
import AniEmpty from "@/components/empty/AniEmpty.vue";
|
import { FormModalProps } from '@/components/form';
|
||||||
import { FormModalProps } from "@/components/form";
|
|
||||||
import {
|
import {
|
||||||
TableColumnData as BaseColumn,
|
TableColumnData as BaseColumn,
|
||||||
TableData as BaseData,
|
TableData as BaseData,
|
||||||
Table as BaseTable,
|
Table as BaseTable,
|
||||||
|
Button,
|
||||||
PaginationProps,
|
PaginationProps,
|
||||||
} from "@arco-design/web-vue";
|
} from '@arco-design/web-vue';
|
||||||
import { isObject, merge } from "lodash-es";
|
import { isObject, merge } from 'lodash-es';
|
||||||
import { PropType, computed, defineComponent, ref } from "vue";
|
import { PropType, defineComponent, ref } from 'vue';
|
||||||
|
|
||||||
type DataFn = (search: Record<string, any>, paging: { page: number; size: number }) => Promise<any>;
|
type DataFn = (filter: { page: number; size: number; [key: string]: any }) => any | Promise<any>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 表格组件
|
* 表格组件
|
||||||
* @see src/components/table/table.tsx
|
|
||||||
*/
|
*/
|
||||||
export const AnTable = defineComponent({
|
export const AnTable = defineComponent({
|
||||||
name: "AnTable",
|
name: 'AnTable',
|
||||||
props: {
|
props: {
|
||||||
/**
|
/**
|
||||||
* 表格数据
|
* 表格数据
|
||||||
* @description 可以是数组或者函数
|
* @description 数组或者函数
|
||||||
*/
|
*/
|
||||||
data: {
|
data: {
|
||||||
type: [Array, Function] as PropType<BaseData[] | DataFn>,
|
type: [Array, Function] as PropType<BaseData[] | DataFn>,
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* 表格列设置
|
* 表格列
|
||||||
*/
|
*/
|
||||||
columns: {
|
columns: {
|
||||||
type: Array as PropType<BaseColumn[]>,
|
type: Array as PropType<BaseColumn[]>,
|
||||||
default: () => [],
|
default: () => [],
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* 分页参数配置
|
* 分页配置
|
||||||
*/
|
*/
|
||||||
pagination: {
|
pagination: {
|
||||||
type: Object as PropType<boolean | PaginationProps>,
|
type: Object as PropType<PaginationProps & { hide?: boolean }>,
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* 搜索表单配置
|
* 搜索表单
|
||||||
*/
|
*/
|
||||||
search: {
|
search: {
|
||||||
type: Object as PropType<IAnForm>,
|
type: Object as PropType<IAnForm>,
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* 新建弹窗配置
|
* 新建弹窗
|
||||||
*/
|
*/
|
||||||
create: {
|
create: {
|
||||||
type: Object as PropType<FormModalProps>,
|
type: Object as PropType<FormModalProps>,
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* 修改弹窗配置
|
* 修改弹窗
|
||||||
*/
|
*/
|
||||||
modify: {
|
modify: {
|
||||||
type: Object as PropType<FormModalProps>,
|
type: Object as PropType<FormModalProps>,
|
||||||
|
|
@ -62,33 +61,25 @@ export const AnTable = defineComponent({
|
||||||
* 传递给 Table 组件的属性
|
* 传递给 Table 组件的属性
|
||||||
*/
|
*/
|
||||||
tableProps: {
|
tableProps: {
|
||||||
type: Object as PropType<InstanceType<typeof BaseTable>["$props"]>,
|
type: Object as PropType<InstanceType<typeof BaseTable>['$props']>,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
setup(props) {
|
setup(props) {
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
const tableRef = ref<InstanceType<typeof BaseTable>>();
|
const tableRef = ref<InstanceType<typeof BaseTable>>();
|
||||||
const searchRef = ref<FormInstance>();
|
|
||||||
const createRef = ref<FormModalInstance>();
|
|
||||||
const modifyRef = ref<FormModalInstance>();
|
|
||||||
const renderData = ref<BaseData[]>([]);
|
const renderData = ref<BaseData[]>([]);
|
||||||
const inlined = computed(() => (props.search?.items?.length ?? 0) <= config.searchInlineCount);
|
const reloadData = () => loadData();
|
||||||
const reloadData = () => loadData({ current: 1, pageSize: 10 });
|
|
||||||
const openModifyModal = (data: any) => modifyRef.value?.open(data);
|
|
||||||
|
|
||||||
const useTablePaging = () => {
|
const useTablePaging = () => {
|
||||||
const getPaging = () => {
|
const getPaging = () => {
|
||||||
if (isObject(props.pagination)) {
|
|
||||||
return {
|
return {
|
||||||
page: props.pagination.current,
|
page: props.pagination?.current ?? 1,
|
||||||
size: props.pagination.pageSize,
|
size: props.pagination?.pageSize ?? 10,
|
||||||
};
|
};
|
||||||
}
|
|
||||||
return {};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const setPaging = (paging: PaginationProps) => {
|
const setPaging = (paging: PaginationProps) => {
|
||||||
if (isObject(props.pagination)) {
|
if (props.pagination) {
|
||||||
merge(props.pagination, paging);
|
merge(props.pagination, paging);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -112,28 +103,10 @@ export const AnTable = defineComponent({
|
||||||
*/
|
*/
|
||||||
const loadData = async () => {
|
const loadData = async () => {
|
||||||
const paging = getPaging();
|
const paging = getPaging();
|
||||||
const model = searchRef.value?.getModel() ?? {};
|
if (typeof props.data === 'function') {
|
||||||
|
|
||||||
// 本地加载
|
|
||||||
if (Array.isArray(props.data)) {
|
|
||||||
const filters = Object.entries(model);
|
|
||||||
const data = props.data.filter((item) => {
|
|
||||||
return filters.every(([key, value]) => {
|
|
||||||
if (typeof value === "string") {
|
|
||||||
return item[key].includes(value);
|
|
||||||
}
|
|
||||||
return item[key] === value;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
renderData.value = data;
|
|
||||||
setPaging({ total: renderData.value.length, current: 1 });
|
|
||||||
}
|
|
||||||
|
|
||||||
// 远程加载
|
|
||||||
if (typeof props.data === "function") {
|
|
||||||
try {
|
try {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
const resData = await props.data(model, paging);
|
const resData = await props.data({ ...paging });
|
||||||
const { data = [], total = 0 } = resData?.data || {};
|
const { data = [], total = 0 } = resData?.data || {};
|
||||||
renderData.value = data;
|
renderData.value = data;
|
||||||
setPaging({ total });
|
setPaging({ total });
|
||||||
|
|
@ -156,24 +129,27 @@ export const AnTable = defineComponent({
|
||||||
loadData();
|
loadData();
|
||||||
});
|
});
|
||||||
|
|
||||||
if (props.search) {
|
const onPageChange = (page: number) => {
|
||||||
merge(props.search, { formProps: { layout: "inline" } });
|
setPaging({ current: page });
|
||||||
}
|
loadData();
|
||||||
|
};
|
||||||
|
|
||||||
|
const onPageSizeChange = (size: number) => {
|
||||||
|
setPaging({ current: 1, pageSize: size });
|
||||||
|
loadData();
|
||||||
|
};
|
||||||
|
|
||||||
const state = {
|
const state = {
|
||||||
loading,
|
loading,
|
||||||
inlined,
|
|
||||||
tableRef,
|
tableRef,
|
||||||
searchRef,
|
|
||||||
createRef,
|
|
||||||
modifyRef,
|
|
||||||
renderData,
|
renderData,
|
||||||
loadData,
|
loadData,
|
||||||
reloadData,
|
reloadData,
|
||||||
openModifyModal,
|
onPageChange,
|
||||||
|
onPageSizeChange,
|
||||||
};
|
};
|
||||||
|
|
||||||
provide("ref:table", { ...state, ...props });
|
provide('ref:table', { ...state, ...props });
|
||||||
|
|
||||||
return state;
|
return state;
|
||||||
},
|
},
|
||||||
|
|
@ -181,53 +157,30 @@ export const AnTable = defineComponent({
|
||||||
(this.columns as any).instance = this;
|
(this.columns as any).instance = this;
|
||||||
return (
|
return (
|
||||||
<div class="table w-full">
|
<div class="table w-full">
|
||||||
{!this.inlined && this.search && (
|
<div class={`mb-3 flex toolbar justify-between`}>
|
||||||
<div class="border-b pb-0 border-slate-200 mb-3">
|
<div class={`flex-1 flex gap-2 `}>TODO</div>
|
||||||
<AnForm
|
<div>
|
||||||
ref="searchRef"
|
<div class="flex gap-1">
|
||||||
class="!grid grid-cols-4 gap-x-6"
|
<Button disabled={this.loading} onClick={this.loadData}>
|
||||||
v-model:model={this.search.model}
|
{{ icon: () => <span class="icon-park-outline-redo"></span> }}
|
||||||
items={this.search.items}
|
</Button>
|
||||||
submit={this.search.submit}
|
<Button>{{ icon: () => <span class="icon-park-outline-config"></span> }}</Button>
|
||||||
formProps={this.search.formProps}
|
|
||||||
></AnForm>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
|
||||||
|
|
||||||
<div class={`mb-3 flex toolbar justify-between ${!this.inlined && "mt-2"}`}>
|
|
||||||
<div class={`${this.create || this.$slots.action ? null : "!hidden"} flex-1 flex gap-2 `}>
|
|
||||||
{this.create && (
|
|
||||||
<AnFormModal
|
|
||||||
ref="createRef"
|
|
||||||
{...this.create}
|
|
||||||
v-model:model={this.create.model}
|
|
||||||
onSubmited={this.reloadData}
|
|
||||||
></AnFormModal>
|
|
||||||
)}
|
|
||||||
{this.modify && (
|
|
||||||
<FormModal
|
|
||||||
{...(this.modify as any)}
|
|
||||||
ref="modifyRef"
|
|
||||||
onSubmited={this.reloadData}
|
|
||||||
trigger={false}
|
|
||||||
></FormModal>
|
|
||||||
)}
|
|
||||||
{this.$slots.action?.()}
|
|
||||||
</div>
|
</div>
|
||||||
<div>{this.inlined && <Form ref="searchRef" {...this.search}></Form>}</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<BaseTable
|
<BaseTable
|
||||||
ref="tableRef"
|
|
||||||
row-key="id"
|
row-key="id"
|
||||||
bordered={false}
|
bordered={false}
|
||||||
{...this.$attrs}
|
{...this.$attrs}
|
||||||
{...this.tableProps}
|
{...this.tableProps}
|
||||||
|
ref="tableRef"
|
||||||
loading={this.loading}
|
loading={this.loading}
|
||||||
pagination={this.pagination}
|
pagination={this.pagination?.hide ? false : this.pagination}
|
||||||
data={this.renderData}
|
data={this.renderData}
|
||||||
columns={this.columns}
|
columns={this.columns}
|
||||||
onPageChange={(current: number) => this.loadData({ current })}
|
onPageChange={this.onPageChange}
|
||||||
|
onPageSizeChange={this.onPageSizeChange}
|
||||||
>
|
>
|
||||||
{{
|
{{
|
||||||
empty: () => <AniEmpty />,
|
empty: () => <AniEmpty />,
|
||||||
|
|
@ -242,9 +195,9 @@ export const AnTable = defineComponent({
|
||||||
/**
|
/**
|
||||||
* 表格组件实例
|
* 表格组件实例
|
||||||
*/
|
*/
|
||||||
export type TableInstance = InstanceType<typeof Table>;
|
export type TableInstance = InstanceType<typeof AnTable>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 表格组件参数
|
* 表格组件参数
|
||||||
*/
|
*/
|
||||||
export type TableProps = TableInstance["$props"];
|
export type TableProps = TableInstance['$props'];
|
||||||
|
|
|
||||||
|
|
@ -1,44 +0,0 @@
|
||||||
import { FormModalUseOptions } from "../../AnForm/hooks/useFormModal";
|
|
||||||
import { ModifyForm } from "./useModiyForm";
|
|
||||||
import { SearchForm } from "./useSearchForm";
|
|
||||||
import { TableColumn } from "./useTableColumn";
|
|
||||||
|
|
||||||
export interface TableUseOptions {
|
|
||||||
/**
|
|
||||||
* 表格列
|
|
||||||
*/
|
|
||||||
columns?: TableColumn[];
|
|
||||||
/**
|
|
||||||
* 搜索表单
|
|
||||||
*/
|
|
||||||
search?: SearchForm;
|
|
||||||
/**
|
|
||||||
* 新建弹窗
|
|
||||||
*/
|
|
||||||
create?: FormModalUseOptions;
|
|
||||||
/**
|
|
||||||
* 新建弹窗
|
|
||||||
*/
|
|
||||||
modify?: ModifyForm;
|
|
||||||
/**
|
|
||||||
* 详情弹窗
|
|
||||||
*/
|
|
||||||
detail?: any;
|
|
||||||
/**
|
|
||||||
* 批量删除
|
|
||||||
*/
|
|
||||||
delete?: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useTable(options: TableUseOptions) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
useTable({
|
|
||||||
columns: [
|
|
||||||
{
|
|
||||||
title: '测试',
|
|
||||||
type: 'index'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
})
|
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
import { FormModalUseOptions } from '../../AnForm/hooks/useFormModal';
|
||||||
|
import { AnTable, TableProps } from '../components/Table';
|
||||||
|
import { ModifyForm } from './useModiyForm';
|
||||||
|
import { SearchForm } from './useSearchForm';
|
||||||
|
import { TableColumn, useTableColumns } from './useTableColumn';
|
||||||
|
|
||||||
|
export interface TableUseOptions extends Pick<TableProps, 'data' | 'tableProps' | 'pagination'> {
|
||||||
|
/**
|
||||||
|
* 表格列
|
||||||
|
*/
|
||||||
|
columns?: TableColumn[];
|
||||||
|
/**
|
||||||
|
* 搜索表单
|
||||||
|
*/
|
||||||
|
search?: SearchForm;
|
||||||
|
/**
|
||||||
|
* 新建弹窗
|
||||||
|
*/
|
||||||
|
create?: FormModalUseOptions;
|
||||||
|
/**
|
||||||
|
* 新建弹窗
|
||||||
|
*/
|
||||||
|
modify?: ModifyForm;
|
||||||
|
/**
|
||||||
|
* 详情弹窗
|
||||||
|
*/
|
||||||
|
detail?: any;
|
||||||
|
/**
|
||||||
|
* 批量删除
|
||||||
|
*/
|
||||||
|
delete?: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useTable(options: TableUseOptions) {
|
||||||
|
const { columns } = useTableColumns(options.columns ?? []);
|
||||||
|
const data = ref(options.data);
|
||||||
|
const pagination = ref({ hide: false, showTotal: true, showPageSize: true, ...(options.pagination ?? {}) });
|
||||||
|
const tableProps = ref(options.tableProps ?? {});
|
||||||
|
const tableRef = ref<InstanceType<typeof AnTable> | null>(null);
|
||||||
|
|
||||||
|
const AnTabler = () => (
|
||||||
|
<AnTable
|
||||||
|
ref={(el: any) => (tableRef.value = el)}
|
||||||
|
columns={columns.value}
|
||||||
|
data={data.value}
|
||||||
|
pagination={pagination.value}
|
||||||
|
tableProps={tableProps.value}
|
||||||
|
></AnTable>
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
component: AnTabler,
|
||||||
|
columns,
|
||||||
|
tableRef,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -1,80 +0,0 @@
|
||||||
import { TableColumnData } from "@arco-design/web-vue";
|
|
||||||
|
|
||||||
interface TableBaseColumn {
|
|
||||||
/**
|
|
||||||
* 类型
|
|
||||||
*/
|
|
||||||
type?: undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface TableIndexColumn {
|
|
||||||
/**
|
|
||||||
* 类型
|
|
||||||
*/
|
|
||||||
type: "index";
|
|
||||||
}
|
|
||||||
|
|
||||||
interface TableButtonColumn {
|
|
||||||
/**
|
|
||||||
* 类型
|
|
||||||
*/
|
|
||||||
type: "button";
|
|
||||||
/**
|
|
||||||
* 按钮列表
|
|
||||||
*/
|
|
||||||
buttons: any[];
|
|
||||||
}
|
|
||||||
|
|
||||||
interface TableDropdownColumn {
|
|
||||||
/**
|
|
||||||
* 类型
|
|
||||||
*/
|
|
||||||
type: "dropdown";
|
|
||||||
/**
|
|
||||||
* 下拉列表
|
|
||||||
*/
|
|
||||||
dropdowns: any[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export type TableColumn = TableColumnData &
|
|
||||||
(TableIndexColumn | TableBaseColumn | TableButtonColumn | TableDropdownColumn);
|
|
||||||
|
|
||||||
export function useTableColumns(data: TableColumn[]) {
|
|
||||||
const columns = ref<any>([]);
|
|
||||||
|
|
||||||
// for (let column of data) {
|
|
||||||
// if (column.type === "index") {
|
|
||||||
// column = useTableIndexColumn(column);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (column.type === "button") {
|
|
||||||
// column = useTableButtonColumn(column);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (column.type === "dropdown") {
|
|
||||||
// column = useTableDropdownColumn(column);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// columns.push({ ...config.columnBase, ...column });
|
|
||||||
// }
|
|
||||||
|
|
||||||
return {
|
|
||||||
columns,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
useTableColumns([
|
|
||||||
{
|
|
||||||
type: "button",
|
|
||||||
buttons: [{}],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "11",
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
|
|
||||||
function useTableIndexColumn() {}
|
|
||||||
|
|
||||||
function useTableButtonColumn() {}
|
|
||||||
|
|
||||||
function useTableDropdownColumn() {}
|
|
||||||
|
|
@ -0,0 +1,143 @@
|
||||||
|
import { Divider, Link, TableColumnData } from '@arco-design/web-vue';
|
||||||
|
|
||||||
|
interface TableBaseColumn {
|
||||||
|
/**
|
||||||
|
* 类型
|
||||||
|
*/
|
||||||
|
type?: undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TableIndexColumn {
|
||||||
|
/**
|
||||||
|
* 类型
|
||||||
|
*/
|
||||||
|
type: 'index';
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TableColumnButton {
|
||||||
|
/**
|
||||||
|
* 特殊类型
|
||||||
|
* @example
|
||||||
|
* ```ts
|
||||||
|
* 'delete'
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
type?: 'modify' | 'delete';
|
||||||
|
/**
|
||||||
|
* 按钮文本
|
||||||
|
* @example
|
||||||
|
* ```ts
|
||||||
|
* '修改'
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
text?: string;
|
||||||
|
/**
|
||||||
|
* 按钮参数
|
||||||
|
* @see ALink
|
||||||
|
*/
|
||||||
|
buttonProps?: Recordable;
|
||||||
|
/**
|
||||||
|
* 是否可见
|
||||||
|
* @example
|
||||||
|
* ```ts
|
||||||
|
* (props) => props.record.status === 1
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
visible?: (args: Recordable) => boolean;
|
||||||
|
/**
|
||||||
|
* 是否禁用
|
||||||
|
* @example
|
||||||
|
* ```ts
|
||||||
|
* (props) => props.record.status === 1
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
disable?: (args: Recordable) => boolean;
|
||||||
|
/**
|
||||||
|
* 处理函数
|
||||||
|
* @example
|
||||||
|
* ```ts
|
||||||
|
* (props) => api.user.rmUser(props.record.id)
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
onClick?: (props: any) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TableButtonColumn {
|
||||||
|
/**
|
||||||
|
* 类型
|
||||||
|
*/
|
||||||
|
type: 'button';
|
||||||
|
/**
|
||||||
|
* 按钮列表
|
||||||
|
*/
|
||||||
|
buttons: TableColumnButton[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TableDropdownColumn {
|
||||||
|
/**
|
||||||
|
* 类型
|
||||||
|
*/
|
||||||
|
type: 'dropdown';
|
||||||
|
/**
|
||||||
|
* 下拉列表
|
||||||
|
*/
|
||||||
|
dropdowns: any[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export type TableColumn = TableColumnData &
|
||||||
|
(TableIndexColumn | TableBaseColumn | TableButtonColumn | TableDropdownColumn);
|
||||||
|
|
||||||
|
export function useTableColumns(data: TableColumn[]) {
|
||||||
|
const columns = ref<TableColumnData[]>([]);
|
||||||
|
|
||||||
|
// for (let column of data) {
|
||||||
|
// if (column.type === "index") {
|
||||||
|
// column = useTableIndexColumn(column);
|
||||||
|
// }
|
||||||
|
|
||||||
|
for (let column of data) {
|
||||||
|
if (column.type === 'button') {
|
||||||
|
column = useTableButtonColumn(column);
|
||||||
|
}
|
||||||
|
columns.value.push(column);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (column.type === "dropdown") {
|
||||||
|
// column = useTableDropdownColumn(column);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// columns.push({ ...config.columnBase, ...column });
|
||||||
|
// }
|
||||||
|
|
||||||
|
return {
|
||||||
|
columns,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function useTableIndexColumn() {}
|
||||||
|
|
||||||
|
function useTableButtonColumn(column: TableButtonColumn & TableColumnData) {
|
||||||
|
const { type, buttons } = column;
|
||||||
|
const items: TableColumnButton[] = [];
|
||||||
|
for (const button of buttons) {
|
||||||
|
items.push(button);
|
||||||
|
}
|
||||||
|
column.render = props => {
|
||||||
|
return items.map((item, index) => {
|
||||||
|
if (item.visible && !item.visible(props)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{index !== 0 && <Divider direction="vertical" margin={4} />}
|
||||||
|
<Link {...item.buttonProps} disabled={item.disable?.(props)} onClick={() => item.onClick?.(props)}>
|
||||||
|
{item.text}
|
||||||
|
</Link>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
return column;
|
||||||
|
}
|
||||||
|
|
||||||
|
function useTableDropdownColumn() {}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
export * from './hooks/useTable';
|
||||||
|
|
@ -0,0 +1,119 @@
|
||||||
|
<template>
|
||||||
|
<a-popover position="br" trigger="click">
|
||||||
|
<a-button class="float-right">设置</a-button>
|
||||||
|
<template #content>
|
||||||
|
<div class="mb-1 leading-none border-b border-gray-100 pb-3">设置表格列</div>
|
||||||
|
<a-scrollbar outer-class="h-96 overflow-hidden" class="h-full overflow-auto">
|
||||||
|
<ul class="grid m-0 p-0 divide-y divide-gray-100 w-[700px] overflow-auto overscroll-contain">
|
||||||
|
<li
|
||||||
|
v-for="(item, index) in items"
|
||||||
|
:key="item.dataIndex"
|
||||||
|
class="group flex items-center justify-between py-2 pr-8 select-none"
|
||||||
|
>
|
||||||
|
<div class="flex gap-2">
|
||||||
|
<a-checkbox v-model="item.enable" :disabled="item.disable" size="large" @change="onItemChange">
|
||||||
|
{{ item.dataIndex }}
|
||||||
|
</a-checkbox>
|
||||||
|
<span class="hidden group-hover:inline-block ml-4">
|
||||||
|
<i v-show="!item.disable" class="icon-park-outline-drag cursor-move"></i>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex gap-2 items-center">
|
||||||
|
<a-checkbox v-model="item.autoWidth" :disabled="item.disable">
|
||||||
|
<template #checkbox="{ checked }">
|
||||||
|
<a-tag :checked="checked" :checkable="!item.disable" color="blue">自适应</a-tag>
|
||||||
|
</template>
|
||||||
|
</a-checkbox>
|
||||||
|
<a-divider direction="vertical" :margin="8"></a-divider>
|
||||||
|
<a-input-number
|
||||||
|
size="small"
|
||||||
|
v-model="item.width"
|
||||||
|
:disabled="item.autoWidth || item.disable"
|
||||||
|
:min="60"
|
||||||
|
:step="10"
|
||||||
|
class="!w-20"
|
||||||
|
/>
|
||||||
|
<span class="text-gray-400">像素</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</a-scrollbar>
|
||||||
|
<div class="mt-4 flex gap-2 items-center justify-between">
|
||||||
|
<div class="flex items-center">
|
||||||
|
<a-checkbox
|
||||||
|
:indeterminate="indeterminate"
|
||||||
|
v-model="checkAll"
|
||||||
|
@change="(v: any) => items.forEach(i => i.enable = v)"
|
||||||
|
>
|
||||||
|
全选
|
||||||
|
</a-checkbox>
|
||||||
|
<span class="text-xs text-gray-400 ml-1">
|
||||||
|
({{ items.filter(i => i.enable).length }}/{{ items.length }})
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="space-x-2">
|
||||||
|
<a-button>重置</a-button>
|
||||||
|
<a-button type="primary">确定</a-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</a-popover>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { computed, ref } from 'vue';
|
||||||
|
|
||||||
|
const items = ref(
|
||||||
|
Array(10)
|
||||||
|
.fill(0)
|
||||||
|
.map((v, i) => {
|
||||||
|
return {
|
||||||
|
dataIndex: `测试${i}`,
|
||||||
|
enable: true,
|
||||||
|
autoWidth: false,
|
||||||
|
width: 80,
|
||||||
|
disable: false,
|
||||||
|
};
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
items.value.unshift({
|
||||||
|
dataIndex: '顺序',
|
||||||
|
enable: true,
|
||||||
|
autoWidth: false,
|
||||||
|
width: 80,
|
||||||
|
disable: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
items.value.push({
|
||||||
|
dataIndex: '操作',
|
||||||
|
enable: true,
|
||||||
|
autoWidth: false,
|
||||||
|
width: 80,
|
||||||
|
disable: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const checkAll = ref(false);
|
||||||
|
|
||||||
|
const indeterminate = computed(() => {
|
||||||
|
const check = checked.value.length;
|
||||||
|
const total = items.value.length;
|
||||||
|
return 0 < check && check < total;
|
||||||
|
});
|
||||||
|
|
||||||
|
const checked = computed(() => {
|
||||||
|
return items.value.filter(i => i.enable);
|
||||||
|
});
|
||||||
|
|
||||||
|
const onItemChange = () => {
|
||||||
|
if (checked.value.length === 0) {
|
||||||
|
checkAll.value = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (checked.value.length === items.value.length) {
|
||||||
|
checkAll.value = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
|
|
@ -1,14 +1,56 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="m-4 bg-white p-4">
|
<div class="m-4 bg-white p-4">
|
||||||
<div class="border-2 border-green-500 px-2 w-40 text-3xl text-green-500 mb-4">AR K056</div>
|
<div class="border-2 border-green-500 px-2 w-40 text-3xl text-green-500 mb-4">AR K056</div>
|
||||||
|
<column-configer></column-configer>
|
||||||
|
<user-table></user-table>
|
||||||
<div>{{ formatModel(emodel) }}</div>
|
<div>{{ formatModel(emodel) }}</div>
|
||||||
<UpForm />
|
<UpForm />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="tsx">
|
<script setup lang="tsx">
|
||||||
|
import { api } from '@/api';
|
||||||
import { useForm } from '@/components/AnForm';
|
import { useForm } from '@/components/AnForm';
|
||||||
import { formatModel } from '@/components/AnForm/core/useFormModel';
|
import { formatModel } from '@/components/AnForm';
|
||||||
|
import { useTable } from '@/components/AnTable';
|
||||||
|
import ColumnConfiger from './components/ColumnConfiger.vue';
|
||||||
|
|
||||||
|
const { component: UserTable } = useTable({
|
||||||
|
data(search) {
|
||||||
|
return api.user.getUsers(search);
|
||||||
|
},
|
||||||
|
pagination: {
|
||||||
|
hide: false,
|
||||||
|
},
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
dataIndex: 'id',
|
||||||
|
title: 'ID',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dataIndex: 'nickname',
|
||||||
|
title: '用户名称',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '操作',
|
||||||
|
type: 'button',
|
||||||
|
width: 140,
|
||||||
|
buttons: [
|
||||||
|
{
|
||||||
|
text: '修改',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: '修改',
|
||||||
|
visible: () => false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: '修改',
|
||||||
|
disable: () => true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
const { component: UpForm, model: emodel } = useForm({
|
const { component: UpForm, model: emodel } = useForm({
|
||||||
formProps: {
|
formProps: {
|
||||||
|
|
@ -19,16 +61,22 @@ const { component: UpForm, model: emodel } = useForm({
|
||||||
field: 'id',
|
field: 'id',
|
||||||
label: '输入组件',
|
label: '输入组件',
|
||||||
setter: 'input',
|
setter: 'input',
|
||||||
|
setterSlots: {
|
||||||
|
prefix: () => <span>123</span>,
|
||||||
|
},
|
||||||
itemSlots: {
|
itemSlots: {
|
||||||
help(props) {
|
help: props => props.item.label,
|
||||||
return props.item.label;
|
extra: () => 'extra',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
field: 'todo',
|
||||||
|
label: '测试',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'xsa',
|
field: 'xsa',
|
||||||
label: '动态渲染',
|
label: '动态渲染',
|
||||||
setter: 'cascader',
|
setter: 'input',
|
||||||
visible: props => props.model.id,
|
visible: props => props.model.id,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -42,7 +90,7 @@ const { component: UpForm, model: emodel } = useForm({
|
||||||
label: '校验规则',
|
label: '校验规则',
|
||||||
setter: 'input',
|
setter: 'input',
|
||||||
// required: true,
|
// required: true,
|
||||||
// rules: ["email"],
|
rules: ['email'],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'sgss',
|
field: 'sgss',
|
||||||
|
|
@ -115,3 +163,4 @@ const { component: UpForm, model: emodel } = useForm({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</route>
|
</route>
|
||||||
|
@/components/AnForm/components/useFormModel
|
||||||
|
|
|
||||||
|
|
@ -4,13 +4,14 @@ import { useProgressGard } from "../guards/progress";
|
||||||
import { useTitleGuard } from "../guards/title";
|
import { useTitleGuard } from "../guards/title";
|
||||||
import { baseRoutes } from "../routes/base";
|
import { baseRoutes } from "../routes/base";
|
||||||
import { historyMode } from "./util";
|
import { historyMode } from "./util";
|
||||||
|
import { routes } from "../routes/page";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 路由实例
|
* 路由实例
|
||||||
*/
|
*/
|
||||||
export const router = createRouter({
|
export const router = createRouter({
|
||||||
history: historyMode(),
|
history: historyMode(),
|
||||||
routes: [...baseRoutes],
|
routes: [...baseRoutes, ...routes],
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -37,8 +37,8 @@ body {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
.arco-modal-header {
|
.arco-modal-header {
|
||||||
background: var(--color-fill-3);
|
// background: var(--color-fill-3);
|
||||||
border-bottom: none;
|
// border-bottom: none;
|
||||||
}
|
}
|
||||||
.arco-modal-footer {
|
.arco-modal-footer {
|
||||||
padding-top: 0;
|
padding-top: 0;
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ declare module '@vue/runtime-core' {
|
||||||
AImagePreview: typeof import('@arco-design/web-vue')['ImagePreview']
|
AImagePreview: typeof import('@arco-design/web-vue')['ImagePreview']
|
||||||
AInput: typeof import('@arco-design/web-vue')['Input']
|
AInput: typeof import('@arco-design/web-vue')['Input']
|
||||||
AInputNumber: typeof import('@arco-design/web-vue')['InputNumber']
|
AInputNumber: typeof import('@arco-design/web-vue')['InputNumber']
|
||||||
|
AInputPassword: typeof import('@arco-design/web-vue')['InputPassword']
|
||||||
AInputSearch: typeof import('@arco-design/web-vue')['InputSearch']
|
AInputSearch: typeof import('@arco-design/web-vue')['InputSearch']
|
||||||
ALayout: typeof import('@arco-design/web-vue')['Layout']
|
ALayout: typeof import('@arco-design/web-vue')['Layout']
|
||||||
ALayoutContent: typeof import('@arco-design/web-vue')['LayoutContent']
|
ALayoutContent: typeof import('@arco-design/web-vue')['LayoutContent']
|
||||||
|
|
@ -50,8 +51,11 @@ declare module '@vue/runtime-core' {
|
||||||
ARadioGroup: typeof import('@arco-design/web-vue')['RadioGroup']
|
ARadioGroup: typeof import('@arco-design/web-vue')['RadioGroup']
|
||||||
AScrollbar: typeof import('@arco-design/web-vue')['Scrollbar']
|
AScrollbar: typeof import('@arco-design/web-vue')['Scrollbar']
|
||||||
ASelect: typeof import('@arco-design/web-vue')['Select']
|
ASelect: typeof import('@arco-design/web-vue')['Select']
|
||||||
|
ASpace: typeof import('@arco-design/web-vue')['Space']
|
||||||
ASpin: typeof import('@arco-design/web-vue')['Spin']
|
ASpin: typeof import('@arco-design/web-vue')['Spin']
|
||||||
ASwitch: typeof import('@arco-design/web-vue')['Switch']
|
ASwitch: typeof import('@arco-design/web-vue')['Switch']
|
||||||
|
ATable: typeof import('@arco-design/web-vue')['Table']
|
||||||
|
ATableColumn: typeof import('@arco-design/web-vue')['TableColumn']
|
||||||
ATabPane: typeof import('@arco-design/web-vue')['TabPane']
|
ATabPane: typeof import('@arco-design/web-vue')['TabPane']
|
||||||
ATabs: typeof import('@arco-design/web-vue')['Tabs']
|
ATabs: typeof import('@arco-design/web-vue')['Tabs']
|
||||||
ATag: typeof import('@arco-design/web-vue')['Tag']
|
ATag: typeof import('@arco-design/web-vue')['Tag']
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue