feat: 临时提交

master
luoer 2023-11-14 17:41:22 +08:00
parent 51e287c747
commit 72fd7eba25
51 changed files with 1517 additions and 241 deletions

View File

@ -0,0 +1,77 @@
import { Form, FormInstance } from "@arco-design/web-vue";
import { PropType } from "vue";
import { FormContextKey } from "../core/useFormContext";
import { useFormItems } from "../core/useFormItems";
import { useFormModel } from "../core/useFormModel";
import { useFormRef } from "../core/useFormRef";
import { useFormSubmit } from "../core/useFormSubmit";
import { AnFormItem, IAnFormItem } from "./FormItem";
import { useVModel } from "@vueuse/core";
/**
*
*/
export const AnForm = defineComponent({
name: "AnForm",
props: {
/**
*
*/
model: {
type: Object as PropType<Recordable>,
required: true,
},
/**
*
*/
items: {
type: Array as PropType<IAnFormItem[]>,
default: () => [],
},
/**
*
*/
submit: {
type: Function as PropType<IAnFormSubmit>,
},
/**
* Form
*/
formProps: {
type: Object as IAnFormProps,
},
},
emits: ["update:model"],
setup(props, { slots, emit }) {
const model = useVModel(props, "model", emit);
const items = computed(() => props.items);
const submit = computed(() => props.submit);
const formRefes = useFormRef();
const formModel = useFormModel(model, formRefes.clearValidate);
const formItems = useFormItems(items, model);
const formSubmit = useFormSubmit({ items, model, validate: formRefes.validate, submit }, formModel.getModel);
const context = { slots, ...formModel, ...formItems, ...formRefes, ...formSubmit };
provide(FormContextKey, context);
return context;
},
render() {
return (
<Form layout="vertical" {...this.$attrs} {...this.formProps} ref="formRef" model={this.model}>
{this.items.map((item) => (
<AnFormItem key={item.field} item={item} items={this.items} model={this.model}></AnFormItem>
))}
</Form>
);
},
});
export type AnFormInstance = InstanceType<typeof AnForm>;
export type AnFormProps = AnFormInstance["$props"];
export type IAnFormProps = PropType<Omit<FormInstance["$props"], "model">>;
export type IAnForm = Pick<AnFormProps, "model" | "items" | "submit" | "formProps">;
export type IAnFormSubmit = (model: Recordable, items: IAnFormItem) => any;

View File

@ -0,0 +1,136 @@
import { FormItem as BaseFormItem, FieldRule, FormItemInstance } from "@arco-design/web-vue";
import { isFunction } from "lodash-es";
import { PropType } from "vue";
import { SetterItem, SetterType, setterMap } from "./FormSetter";
/**
*
*/
export const AnFormItem = defineComponent({
name: "AnFormItem",
props: {
/**
*
*/
item: {
type: Object as PropType<IAnFormItem>,
required: true,
},
/**
*
*/
items: {
type: Array as PropType<IAnFormItem[]>,
required: true,
},
/**
*
*/
model: {
type: Object as PropType<Recordable>,
required: true,
},
},
setup(props) {
const rules = computed(() => props.item.rules?.filter((i) => !i.disable?.(props.model, props.item, props.items)));
const disabled = computed(() => Boolean(props.item.disable?.(props.model, props.item, props.items)));
const label = strOrFnRender(props.item.label, props);
const help = strOrFnRender(props.item.help, props);
const extra = strOrFnRender(props.item.extra, props);
const render = () => {
let render = props.item.setter as any;
if (!render) {
return null;
}
if (typeof render === "string") {
render = setterMap[render as SetterType]?.render;
if (!render) {
return null;
}
return <render {...props.item.nodeProps} v-model={props.model[props.item.field]} />;
}
if (isFunction(render)) {
return <render {...props.item.nodeProps} items={props.items} model={props.model} item={props.item} />;
}
};
return () => {
if (props.item.visible && !props.item.visible(props.model, props.item, props.items)) {
return null;
}
return (
<BaseFormItem {...props.item.itemProps} rules={rules.value} disabled={disabled.value} field={props.item.field}>
{{ default: render, label, help, extra }}
</BaseFormItem>
);
};
},
});
export function strOrFnRender(fn: any, ...args: any[]) {
if (typeof fn === "string") {
return () => fn;
}
if (typeof fn === "function") {
return fn(...args);
}
return null;
}
export type IAnFormItemBoolFn = (model: Recordable, item: IAnFormItem, items: IAnFormItem[]) => boolean;
export type IAnFormItemElemFn = (model: Recordable, item: IAnFormItem, items: IAnFormItem[]) => any;
export type IAnFormItemRule = FieldRule & { disable?: IAnFormItemBoolFn };
export type IAnFormItemBase = {
/**
*
* @description
* @required
*/
field: string;
/**
*
* @default null
*/
itemProps?: Partial<Omit<FormItemInstance["$props"], "field" | "label" | "required" | "rules" | "disabled">>;
/**
*
*/
rules?: IAnFormItemRule[];
/**
*
*/
visible?: IAnFormItemBoolFn;
/**
*
*/
disable?: IAnFormItemBoolFn;
/**
*
*/
label?: string | IAnFormItemElemFn;
/**
*
*/
help?: string | IAnFormItemElemFn;
/**
*
*/
extra?: string | IAnFormItemElemFn;
options?: any;
init?: any;
};
export type IAnFormItem = IAnFormItemBase & SetterItem;

View File

@ -0,0 +1,141 @@
import { Button, ButtonInstance, Form, FormInstance, Modal } from "@arco-design/web-vue";
import { PropType } from "vue";
import { FormContextKey } from "../core/useFormContext";
import { useFormItems } from "../core/useFormItems";
import { useFormModel } from "../core/useFormModel";
import { useFormRef } from "../core/useFormRef";
import { useFormSubmit } from "../core/useFormSubmit";
import { AnFormItem, IAnFormItem } from "./FormItem";
import { useVModel } from "@vueuse/core";
import { AnForm, IAnFormProps, IAnFormSubmit } from "./Form";
/**
*
*/
export const AnFormModal = defineComponent({
name: "AnFormModal",
props: {
/**
*
* @default '添加'
*/
title: {
type: [String, Function] as PropType<ModalType>,
default: "添加",
},
/**
*
*/
trigger: {
type: [Boolean, Function, Object] as PropType<ModalTrigger>,
default: true,
},
/**
* Modalprops
*/
modalProps: {
type: Object as PropType<ModalProps>,
},
/**
*
*/
model: {
type: Object as PropType<Recordable>,
required: true,
},
/**
*
*/
items: {
type: Array as PropType<IAnFormItem[]>,
default: () => [],
},
/**
*
*/
submit: {
type: Function as PropType<IAnFormSubmit>,
},
/**
* Form
*/
formProps: {
type: Object as IAnFormProps,
},
},
emits: ["update:model"],
setup(props, { slots, emit }) {
const visible = ref(false);
const formRef = ref<InstanceType<typeof AnForm> | null>(null);
const modalTitle = () => {
if (typeof props.title === "string") {
return props.title;
}
return <props.title model={props.model} items={props.items}></props.title>;
};
const modalTrigger = () => {
if (!props.trigger) {
return null;
}
if (typeof props.trigger === "boolean") {
return <Button onClick={() => (visible.value = true)}></Button>;
}
if (typeof props.trigger === "object") {
return (
<Button {...props.trigger} onClick={() => (visible.value = true)}>
</Button>
);
}
return <props.trigger model={props.model} items={props.items}></props.trigger>;
};
return {
visible,
formRef,
modalTitle,
modalTrigger,
};
},
render() {
return (
<>
<this.modalTrigger></this.modalTrigger>
<Modal titleAlign="start" closable={false} {...this.$attrs} {...this.modalProps} v-model:visible={this.visible}>
{{
title: this.modalTitle,
default: () => (
<AnForm
model={this.model}
onUpdate:model={(v) => this.$emit("update:model", v)}
items={this.items}
submit={this.submit}
formProps={this.formProps}
></AnForm>
),
...this.$slots,
}}
</Modal>
</>
);
},
});
type ModalProps = Omit<InstanceType<typeof Modal>["$props"], "visible" | "title" | "onBeforeOk">;
type ModalType = string | ((model: Recordable, items: IAnFormItem[]) => any);
type ModalTrigger =
| boolean
| ((model: Recordable, items: IAnFormItem[]) => any)
| {
text?: string;
buttonProps?: ButtonInstance["$props"];
};
export type FormModalProps = Pick<
InstanceType<typeof AnFormModal>["$props"],
"title" | "trigger" | "modalProps" | "model" | "items" | "submit" | "formProps"
>;

View File

@ -0,0 +1,18 @@
import setterMap from "../setters";
export type SetterMap = typeof setterMap;
export type SetterType = keyof SetterMap;
export type SetterItem = {
[key in SetterType]: Partial<
Omit<SetterMap[key], "setter"> & {
/**
*
*/
setter: key;
}
>;
}[SetterType];
export { setterMap };

View File

@ -0,0 +1,14 @@
import { InjectionKey } from "vue";
import { FormItems } from "./useFormItems";
import { FormModel } from "./useFormModel";
import { FormRef } from "./useFormRef";
import { FormSubmit } from "./useFormSubmit";
export type FormContextInterface = FormModel &
FormItems &
FormRef &
FormSubmit & {
slots: Recordable;
};
export const FormContextKey = Symbol("FormContextKey") as InjectionKey<FormContextInterface>;

View File

@ -0,0 +1,46 @@
import { Ref } from "vue";
import { IAnFormItem } from "../components/FormItem";
export function useFormItems(items: Ref<IAnFormItem[]>, model: Ref<Recordable>) {
const getItem = (field: string) => {
return items.value.find((i) => i.field === field);
};
const getItemOptions = (field: string) => {
const item = getItem(field);
if (item) {
return (item.nodeProps as any)?.options;
}
};
const initItemOptions = (field: string) => {
const item = getItem(field);
item && item.init?.();
};
const initItems = () => {
for (const item of items.value) {
item.init?.({ item, model: model.value });
}
};
const initItem = (field: string) => {
const item = getItem(field);
item && item.init?.({ item, model: model.value });
};
onMounted(() => {
initItems();
});
return {
items,
getItem,
initItem,
initItems,
getItemOptions,
initItemOptions,
};
}
export type FormItems = ReturnType<typeof useFormItems>;

View File

@ -0,0 +1,112 @@
import { cloneDeep } from "lodash-es";
import { Ref } from "vue";
/**
*
* @param initial
* @returns
*/
export function useFormModel(model: Ref<Recordable>, clearValidate: any) {
const initial = cloneDeep(model.value);
const resetModel = () => {
model.value = cloneDeep(initial);
clearValidate();
};
const getInitialModel = () => {
return initial;
};
const setModel = (data: Recordable) => {
for (const key of Object.keys(model.value)) {
model.value[key] = data[key];
}
};
const getModel = () => {
return formatModel(model.value);
};
return {
model,
getInitialModel,
resetModel,
setModel,
getModel,
};
}
export type FormModel = ReturnType<typeof useFormModel>;
export function formatModel(model: Recordable) {
const data: Recordable = {};
for (const [key, value] of Object.entries(model)) {
if (/^\[.+\]$/.test(key)) {
formatModelArray(key, value, data);
continue;
}
if (/^\{.+\}$/.test(key)) {
formatModelObject(key, value, data);
continue;
}
data[key] = value;
}
return data;
}
function formatModelArray(key: string, value: any, data: Recordable) {
let field = key.replaceAll(/\s/g, "");
field = field.match(/^\[(.+)\]$/)?.[1] ?? "";
if (!field) {
data[key] = value;
return;
}
const keys = field.split(",");
keys.forEach((k, i) => {
if (/(.+)?:number$/.test(k)) {
k = k.replace(/:number$/, "");
data[k] = value?.[i] && Number(value[i]);
return;
}
if (/(.+)?:boolean$/.test(k)) {
k = k.replace(/:boolean$/, "");
data[k] = value?.[i] && Boolean(value[i]);
return;
}
data[k] = value?.[i];
});
return data;
}
function formatModelObject(key: string, value: any, data: Recordable) {
let field = key.replaceAll(/\s/g, "");
field = field.match(/^\{(.+)\}$/)?.[1] ?? "";
if (!field) {
data[key] = value;
return;
}
const keys = field.split(",");
keys.forEach((k, i) => {
if (/(.+)?:number$/.test(k)) {
k = k.replace(/:number$/, "");
data[k] = value?.[i] && Number(value[i]);
return;
}
if (/(.+)?:boolean$/.test(k)) {
k = k.replace(/:boolean$/, "");
data[k] = value?.[i] && Boolean(value[i]);
return;
}
data[k] = value?.[i];
});
return data;
}

View File

@ -0,0 +1,34 @@
import { FormInstance } from "@arco-design/web-vue";
export function useFormRef() {
/**
*
*/
const formRef = ref<FormInstance | null>(null);
type Validate = FormInstance["validate"];
type ValidateField = FormInstance["validateField"];
type ResetFields = FormInstance["resetFields"];
type ClearValidate = FormInstance["clearValidate"];
type SetFields = FormInstance["setFields"];
type ScrollToField = FormInstance["scrollToField"];
const validate: Validate = async (...args) => formRef.value?.validate(...args);
const validateField: ValidateField = async (...args) => formRef.value?.validateField(...args);
const resetFields: ResetFields = (...args) => formRef.value?.resetFields(...args);
const clearValidate: ClearValidate = (...args) => formRef.value?.clearValidate(...args);
const setFields: SetFields = (...args) => formRef.value?.setFields(...args);
const scrollToField: ScrollToField = (...args) => formRef.value?.scrollToField(...args);
return {
formRef,
validate,
validateField,
resetFields,
clearValidate,
setFields,
scrollToField,
};
}
export type FormRef = ReturnType<typeof useFormRef>;

View File

@ -0,0 +1,57 @@
import { FormInstance, Message } from "@arco-design/web-vue";
import { Ref } from "vue";
import { IAnFormItem } from "../components/FormItem";
interface Options {
items: Ref<IAnFormItem[]>;
model: Ref<Recordable>;
submit: Ref<Function | undefined>;
validate: FormInstance["validate"];
}
export function useFormSubmit(options: Options, getModel: any) {
const { items, submit, validate } = options;
const loading = ref(false);
/**
* loading
* @param value
*/
const setLoading = (value: boolean) => {
loading.value = value;
};
/**
*
*/
const submitForm = async () => {
if (await validate()) {
return;
}
try {
loading.value = true;
const data = getModel();
const res = await submit.value?.(data, items.value);
const msg = res?.data?.message;
msg && Message.success(`提示: ${msg}`);
} catch {
console.log();
} finally {
loading.value = false;
}
};
/**
*
*/
const cancelForm = () => {};
return {
loading,
setLoading,
submitForm,
cancelForm,
};
}
export type FormSubmit = ReturnType<typeof useFormSubmit>;

View File

@ -0,0 +1,45 @@
import { FormItem, useItems } from "./useItems";
import { AnForm, IAnForm } from "../components/Form";
export type UseForm = Partial<Omit<IAnForm, "items">> & {
/**
*
*/
items?: FormItem[];
};
/**
*
*/
export const useForm = (options: UseForm) => {
const { items: _items = [], model: _model = {}, submit, formProps: _props = {} } = options;
const items = useItems(_items, _model, Boolean(options.submit));
const model = ref(_model);
const formProps = ref(_props);
const instance = ref<InstanceType<typeof AnForm> | null>(null);
const component = () => {
const onUpdateModel = (value: Recordable) => {
model.value = value;
};
return (
<AnForm
ref={(el: any) => (instance.value = el)}
model={model.value}
onUpdate:model={onUpdateModel}
items={items.value}
submit={submit}
formProps={formProps.value}
></AnForm>
);
};
return {
component,
instance,
model,
items,
formProps,
submit,
};
};

View File

@ -0,0 +1,39 @@
import { AnFormModal, FormModalProps } from "../components/FormModal";
import { UseForm, useForm } from "./useForm";
import { FormItem } from "./useItems";
type FormModalUseOptions = Partial<Omit<FormModalProps, "items">> & {
items: FormItem[];
};
export function useFormModal(options: FormModalUseOptions) {
const { model, items, formProps } = useForm({ ...options, submit: undefined });
const trigger = ref(options.trigger);
const title = ref(options.title);
const modalProps = ref(options.modalProps);
const modalRef = ref<InstanceType<typeof AnFormModal> | null>(null);
const formRef = computed(() => modalRef.value?.formRef);
const component = () => {
return (
<AnFormModal
ref={(el: any) => (modalRef.value = el)}
title={title.value}
trigger={trigger.value}
modalProps={modalProps.value}
model={model.value}
items={items.value}
formProps={formProps.value}
></AnFormModal>
);
};
return {
model,
items,
formProps,
component,
modalRef,
formRef,
};
}

View File

@ -0,0 +1,77 @@
import { defaultsDeep, merge, omit } from "lodash-es";
import { Rule, useRules } from "./useRules";
import { IAnFormItem } from "../components/FormItem";
import { setterMap } from "../components/FormSetter";
/**
*
*/
export type FormItem = Omit<IAnFormItem, "rules"> & {
/**
*
* @default undefined
*/
value?: any;
/**
*
* @default false
*/
required?: boolean;
/**
*
* @default undefined
*/
rules?: Rule[];
};
const ITEM: Partial<FormItem> = {
setter: "input",
itemProps: {},
};
const SUBMIT_ITEM: FormItem = {
field: "id",
setter: "submit",
itemProps: {
hideLabel: true,
},
};
export function useItems(list: FormItem[], model: Recordable, submit: boolean) {
const items = ref<IAnFormItem[]>([]);
let hasSubmit = false;
for (const item of list) {
let target: any = defaultsDeep({}, ITEM);
if (!item.setter || typeof item.setter === "string") {
const defaults = setterMap[item.setter ?? "input"];
if (defaults) {
defaultsDeep(target, defaults);
}
}
if (item.setter === "submit") {
target = merge(target, SUBMIT_ITEM);
hasSubmit = true;
}
target = merge(target, omit(item, ["required", "rules"]));
const rules = useRules(item);
if (rules) {
target.rules = rules;
}
model[item.field] = model[item.field] ?? item.value;
items.value.push(target);
}
if (submit && !hasSubmit) {
items.value.push(defaultsDeep({}, SUBMIT_ITEM, setterMap.submit));
}
return items;
}

View File

@ -0,0 +1,96 @@
import { FieldRule } from "@arco-design/web-vue";
import { has, isString } from "lodash-es";
import { IAnFormItemRule } from "../components/FormItem";
/**
*
*/
export const FieldRuleMap = defineRuleMap({
required: {
required: true,
message: "该项不能为空",
},
string: {
type: "string",
message: "请输入字符串",
},
number: {
type: "number",
message: "请输入数字",
},
email: {
type: "email",
message: "邮箱格式错误,示例: xx@abc.com",
},
url: {
type: "url",
message: "URL格式错误, 示例: www.abc.com",
},
ip: {
type: "ip",
message: "IP格式错误, 示例: 101.10.10.30",
},
phone: {
match: /^(?:(?:\+|00)86)?1\d{10}$/,
message: "手机格式错误, 示例(11位): 15912345678",
},
idcard: {
match: /^[1-9]\d{5}(?:18|19|20)\d{2}(?:0[1-9]|10|11|12)(?:0[1-9]|[1-2]\d|30|31)\d{3}[\dXx]$/,
message: "身份证格式错误, 长度为15或18位",
},
alphabet: {
match: /^[a-zA-Z]\w{4,15}$/,
message: "请输入英文字母, 长度为4~15位",
},
password: {
match: /^\S*(?=\S{6,})(?=\S*\d)(?=\S*[A-Z])(?=\S*[a-z])(?=\S*[!@#$%^&*? ])\S*$/,
message: "至少包含大写字母、小写字母、数字和特殊字符",
},
});
/**
* ()
*/
export type FieldStringRule = keyof typeof FieldRuleMap;
/**
*
*/
export type Rule = FieldStringRule | IAnFormItemRule;
/**
* (TS)
*/
function defineRuleMap<T extends Record<string, FieldRule>>(ruleMap: T) {
return ruleMap;
}
/**
*
* @param item
* @returns
*/
export const useRules = <T extends { required?: boolean; rules?: Rule[] }>(item: T) => {
const data: IAnFormItemRule[] = [];
const { required, rules } = item;
if (!has(item, "required") && !has(item, "rules")) {
return null;
}
if (required) {
data.push(FieldRuleMap.required);
}
for (const rule of rules ?? []) {
if (isString(rule)) {
if (FieldRuleMap[rule]) {
data.push(FieldRuleMap[rule]);
}
} else {
data.push(rule);
}
}
return data;
};

View File

@ -0,0 +1,3 @@
export * from "./components/Form";
export * from "./hooks/useForm";
export * from "./core/useFormContext";

View File

@ -0,0 +1,14 @@
import { Cascader, CascaderInstance } from "@arco-design/web-vue";
import { initOptions } from "../utils/initOptions";
type Props = CascaderInstance["$props"];
export default {
render: Cascader,
init: initOptions,
nodeProps: {
placeholder: "请选择",
allowClear: true,
expandTrigger: "hover",
} as Props,
};

View File

@ -0,0 +1,6 @@
export default {
render: () => {
return "1";
},
nodeProps: {},
};

View File

@ -0,0 +1,11 @@
import { DatePicker, DatePickerInstance } from "@arco-design/web-vue";
type Props = DatePickerInstance["$props"];
export default {
render: DatePicker,
nodeProps: {
placeholder: "请选择",
allowClear: true,
} as Props,
};

View File

@ -0,0 +1,10 @@
import { RangePicker, RangePickerInstance } from "@arco-design/web-vue";
type Props = RangePickerInstance["$props"];
export default {
render: RangePicker,
nodeProps: {
allowClear: true,
} as Props,
};

View File

@ -0,0 +1,11 @@
import { Input, InputInstance } from "@arco-design/web-vue";
type Props = InputInstance["$props"];
export default {
render: Input,
nodeProps: {
placeholder: "请输入",
allowClear: true,
} as Props,
};

View File

@ -0,0 +1,12 @@
import { InputInstance, InputNumber, InputNumberInstance } from "@arco-design/web-vue";
type Props = InputInstance["$props"] & InputNumberInstance["$props"];
export default {
render: InputNumber,
nodeProps: {
placeholder: "请输入",
defaultValue: 0,
allowClear: true,
} as Props,
};

View File

@ -0,0 +1,10 @@
import { InputInstance, InputPassword, InputPasswordInstance } from "@arco-design/web-vue";
type Props = InputInstance["$props"] & InputPasswordInstance["$props"];
export default {
render: InputPassword,
nodeProps: {
placeholder: "请输入",
} as Props,
};

View File

@ -0,0 +1,11 @@
import { InputInstance, InputSearch, InputSearchInstance } from "@arco-design/web-vue";
type Props = InputInstance["$props"] & InputSearchInstance["$props"];
export default {
render: InputSearch,
nodeProps: {
placeholder: "请输入",
allowClear: true,
} as Props,
};

View File

@ -0,0 +1,14 @@
import { Select, SelectInstance, SelectOptionData } from "@arco-design/web-vue";
import { initOptions } from "../utils/initOptions";
export default {
render: Select,
init: initOptions,
nodeProps: {
placeholder: "请选择",
allowClear: true,
allowSearch: true,
options: [],
} as SelectInstance["$props"],
options: [] as SelectOptionData[] | ((arg: any) => Recordable[] | Promise<Recordable[]>) | undefined,
};

View File

@ -0,0 +1,19 @@
import { Button } from "@arco-design/web-vue";
import { FormContextKey } from "../core/useFormContext";
export default {
render() {
const { loading, submitForm, resetModel } = inject(FormContextKey)!;
return (
<>
<Button type="primary" loading={loading.value} onClick={submitForm} class="mr-3">
</Button>
<Button disabled={loading.value} onClick={resetModel}>
</Button>
</>
);
},
nodeProps: {},
};

View File

@ -0,0 +1,11 @@
import { InputInstance, Textarea, TextareaInstance } from "@arco-design/web-vue";
type Props = InputInstance["$props"] & TextareaInstance["$props"];
export default {
render: Textarea,
nodeProps: {
placeholder: "请输入",
allowClear: true,
} as Props,
};

View File

@ -0,0 +1,10 @@
import { TimePicker, TimePickerInstance } from "@arco-design/web-vue";
type Props = TimePickerInstance["$props"];
export default {
render: TimePicker,
nodeProps: {
allowClear: true,
} as Props,
};

View File

@ -0,0 +1,15 @@
import { TreeSelect, TreeSelectInstance } from "@arco-design/web-vue";
import { initOptions } from "../utils/initOptions";
type Props = TreeSelectInstance["$props"];
export default {
render: TreeSelect,
init: (arg: any) => initOptions(arg, "data"),
nodeProps: {
placeholder: "请选择",
allowClear: true,
allowSearch: true,
options: [],
} as Props,
};

View File

@ -0,0 +1,29 @@
import cascader from "./Cascader";
import custom from "./Custom";
import date from "./Date";
import input from "./Input";
import number from "./Number";
import password from "./Password";
import search from "./Search";
import select from "./Select";
import submit from "./Submit";
import textarea from "./Textarea";
import time from "./Time";
import treeSelect from "./TreeSelect";
import dateRange from "./DateRange";
export default {
input,
number,
search,
textarea,
select,
treeSelect,
time,
password,
cascader,
date,
submit,
custom,
dateRange,
};

View File

@ -0,0 +1,27 @@
import { Component } from "vue";
import { IAnFormItem, IAnFormItemBase } from "../components/FormItem";
interface Setter<T extends Component, P = T extends new (...args: any) => any ? InstanceType<T>["$props"] : any> {
/**
*
*/
component: T;
/**
*
*/
componentProps?: P;
/**
*
* @param model
* @param item
* @param items
* @returns
*/
onSetup?: (model: Recordable, item: IAnFormItemBase, items: IAnFormItemBase[]) => void;
}
export function defineSetter<T extends Component>(options: Setter<T>): Setter<T> {
return options;
}

View File

@ -0,0 +1,30 @@
export function initOptions({ item, model }: any, key = "options") {
if (Array.isArray(item.options)) {
item.nodeProps[key] = item.options;
return;
}
if (item.options && typeof item.options === "object") {
const { value, source } = item.options;
item._updateOptions = async () => {};
return;
}
if (typeof item.options === "function") {
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)) {
item.nodeProps[key].splice(0);
item.nodeProps[key].push(...data);
}
};
item._updateOptions();
}
}

View File

@ -0,0 +1,9 @@
export function strOrFnRender(fn: any, options: any) {
if (typeof fn === "string") {
return () => fn;
}
if (typeof fn === "function") {
return fn(options);
}
return null;
}

View File

@ -7,6 +7,7 @@ import { useFormRef } from "../core/useFormRef";
import { useFormSubmit } from "../core/useFormSubmit";
import { AnFormItem, IAnFormItem } from "./FormItem";
import { SubmitFn } from "./types/Form";
import { useVModel } from "@vueuse/core";
/**
*
@ -32,7 +33,7 @@ export const AnForm = defineComponent({
*
*/
submit: {
type: Function as PropType<SubmitFn>,
type: Function as PropType<IAnFormSubmit>,
},
/**
* Form
@ -41,22 +42,16 @@ export const AnForm = defineComponent({
type: Object as PropType<Omit<BaseFormInstance["$props"], "model">>,
},
},
setup(props, { slots }) {
const model = computed(() => props.model);
emits: ["update:model"],
setup(props, { slots, emit }) {
const model = useVModel(props, "model", emit);
const items = computed(() => props.items);
const submit = computed(() => props.submit);
const formRefes = useFormRef();
const formModel = useFormModel(model);
const formModel = useFormModel(model, formRefes.clearValidate);
const formItems = useFormItems(items, model);
const formSubmit = useFormSubmit({ items, model, validate: formRefes.validate, submit });
const context = {
slots,
...formModel,
...formItems,
...formRefes,
...formSubmit,
};
const formSubmit = useFormSubmit({ items, model, validate: formRefes.validate, submit }, formModel.getModel);
const context = { slots, ...formModel, ...formItems, ...formRefes, ...formSubmit };
provide(FormContextKey, context);
return context;
@ -65,7 +60,7 @@ export const AnForm = defineComponent({
return (
<BaseForm layout="vertical" {...this.$attrs} {...this.formProps} ref="formRef" model={this.model}>
{this.items.map((item) => (
<AnFormItem item={item} items={this.items} model={this.model}></AnFormItem>
<AnFormItem key={item.field} item={item} items={this.items} model={this.model}></AnFormItem>
))}
</BaseForm>
);
@ -77,3 +72,5 @@ export type AnFormInstance = InstanceType<typeof AnForm>;
export type AnFormProps = AnFormInstance["$props"];
export type IAnForm = Pick<AnFormProps, "model" | "items" | "submit" | "formProps">;
export type IAnFormSubmit = (model: Recordable, items: IAnFormItem) => any;

View File

@ -1,9 +1,7 @@
import { FormItem as BaseFormItem, FormItemInstance } from "@arco-design/web-vue";
import { FormItem as BaseFormItem, FieldRule, FormItemInstance } from "@arco-design/web-vue";
import { isFunction } from "lodash-es";
import { PropType } from "vue";
import { FieldObjectRule } from "../hooks/useRules";
import { NodeType, NodeUnion, nodeMap } from "../nodes";
import { strOrFnRender } from "../utils/strOrFnRender";
/**
*
@ -34,19 +32,12 @@ export const AnFormItem = defineComponent({
},
},
setup(props) {
/**
*
*/
const rules = computed(() => props.item.rules?.filter((i) => !i.disable?.(props)));
const rules = computed(() => props.item.rules?.filter((i) => !i.disable?.(props.model, props.item, props.items)));
const disabled = computed(() => Boolean(props.item.disable?.(props.model, props.item, props.items)));
const label = strOrFnRender(props.item.label, props);
const help = strOrFnRender(props.item.help, props);
const extra = strOrFnRender(props.item.extra, props);
/**
*
*/
const disabled = computed(() => Boolean(props.item.disable?.(props)));
/**
*
*/
const render = () => {
let render = (props.item as any).render;
if (!render) {
@ -64,23 +55,8 @@ export const AnFormItem = defineComponent({
}
};
/**
*
*/
const label = strOrFnRender(props.item.label, props);
/**
*
*/
const help = strOrFnRender(props.item.help, props);
/**
*
*/
const extra = strOrFnRender(props.item.extra, props);
return () => {
if (props.item.visible && !props.item.visible(props)) {
if (props.item.visible && !props.item.visible(props.model, props.item, props.items)) {
return null;
}
return (
@ -92,13 +68,23 @@ export const AnFormItem = defineComponent({
},
});
type FormItemFnArg<T = IAnFormItem> = {
item: T;
items: T[];
model: Record<string, any>;
};
export function strOrFnRender(fn: any, ...args: any[]) {
if (typeof fn === "string") {
return () => fn;
}
if (typeof fn === "function") {
return fn(...args);
}
return null;
}
type FormItemBase = {
export type IAnFormItemBoolFn = (model: Recordable, item: IAnFormItem, items: IAnFormItem[]) => boolean;
export type IAnFormItemElemFn = (model: Recordable, item: IAnFormItem, items: IAnFormItem[]) => any;
export type IAnFormItemRule = FieldRule & { disable?: IAnFormItemBoolFn };
export type IAnFormItemBase = {
/**
*
*/
@ -112,32 +98,34 @@ type FormItemBase = {
/**
*
*/
rules?: FieldObjectRule<IAnFormItem>[];
rules?: IAnFormItemRule[];
/**
*
*/
visible?: (arg: FormItemFnArg) => boolean;
visible?: IAnFormItemBoolFn;
/**
*
*/
disable?: (arg: FormItemFnArg) => boolean;
disable?: IAnFormItemBoolFn;
/**
*
*/
label?: string | ((args: FormItemFnArg) => any);
label?: string | IAnFormItemElemFn;
/**
*
*/
help?: string | ((args: FormItemFnArg) => any);
help?: string | IAnFormItemElemFn;
/**
*
*/
extra?: string | ((args: FormItemFnArg) => any);
extra?: string | IAnFormItemElemFn;
init?: any;
};
export type IAnFormItem = FormItemBase & NodeUnion;
export type IAnFormItem = IAnFormItemBase & NodeUnion;

View File

@ -0,0 +1,22 @@
import { InjectionKey } from "vue";
import { FormItems } from "./useFormItems";
import { FormModel } from "./useFormModel";
import { FormRef } from "./useFormRef";
import { FormSubmit } from "./useFormSubmit";
export type FormContextInterface = FormModel &
FormItems &
FormRef &
FormSubmit & {
slots: Recordable;
};
export const FormContextKey = Symbol("FormContextKey") as InjectionKey<FormContextInterface>;
export function useFormContext() {
const context = inject(FormContextKey);
if (!context) {
throw Error("useFormContext musb be used in AnForm children!");
}
return context;
}

View File

@ -15,18 +15,18 @@ export function useFormItems(items: Ref<IAnFormItem[]>, model: Ref<Recordable>)
const initItemOptions = (field: string) => {
const item = getItem(field);
item && item.initial?.();
item && item.init?.();
};
const initItems = () => {
for (const item of items.value) {
item.initial?.(item, model);
item.init?.({ item, model: model.value });
}
};
const initItem = (field: string) => {
const item = getItem(field);
item && item.initial(item, model);
item && item.init?.({ item, model: model.value });
};
onMounted(() => {

View File

@ -6,11 +6,12 @@ import { Ref } from "vue";
* @param initial
* @returns
*/
export function useFormModel(model: Ref<Recordable>) {
export function useFormModel(model: Ref<Recordable>, clearValidate: any) {
const initial = cloneDeep(model.value);
const resetModel = () => {
model.value = cloneDeep(initial);
clearValidate();
};
const getInitialModel = () => {
@ -38,7 +39,7 @@ export function useFormModel(model: Ref<Recordable>) {
export type FormModel = ReturnType<typeof useFormModel>;
function formatModel(model: Recordable) {
export function formatModel(model: Recordable) {
const data: Recordable = {};
for (const [key, value] of Object.entries(model)) {

View File

@ -1,16 +1,16 @@
import { FormInstance, Message } from "@arco-design/web-vue";
import { Ref } from "vue";
import { IFormItem } from "../components/FormItem";
import { IAnFormItem } from "../components/FormItem";
interface Options {
items: Ref<IFormItem[]>;
items: Ref<IAnFormItem[]>;
model: Ref<Recordable>;
submit: Ref<Function | undefined>;
validate: FormInstance["validate"];
}
export function useFormSubmit(options: Options) {
const { model, items, submit, validate } = options;
export function useFormSubmit(options: Options, getModel: any) {
const { items, submit, validate } = options;
const loading = ref(false);
/**
@ -30,7 +30,8 @@ export function useFormSubmit(options: Options) {
}
try {
loading.value = true;
const res = await submit.value?.(model.value, items.value);
const data = getModel();
const res = await submit.value?.(data, items.value);
const msg = res?.data?.message;
msg && Message.success(`提示: ${msg}`);
} catch {

View File

@ -1,4 +1,9 @@
export const config = {
item: {
defaults: {
type: "input",
},
},
/**
* API
*/
@ -79,10 +84,12 @@ export const config = {
export function initOptions({ item, model }: any, key = "options") {
if (Array.isArray(item.options)) {
item.nodeProps[key] = item.options;
return;
}
if (item.options && typeof item.options === "object") {
const { value, source } = item.options;
item._updateOptions = async () => {};
return;
}
if (typeof item.options === "function") {
const loadData = item.options;

View File

@ -1,21 +1,25 @@
import { FormInstance } from "@arco-design/web-vue";
import { FormItem, FormItemFnArg } from "./FormItem";
type FormInstanceProps = Partial<Omit<FormInstance["$props"], "model">>;
export type UseForm = {
/**
*
*
*/
model?: Recordable;
/**
*
*
*/
items?: FormItem[];
/**
*
* @description
*/
submit?: (arg: Omit<FormItemFnArg, "item">) => PromiseLike<any>;
submit?: string | ((arg: any) => PromiseLike<any>);
/**
*
*
* @description
*/
formProps?: Partial<FormInstance["$props"]>;
formProps?: FormInstanceProps;
};

View File

@ -1,6 +1,7 @@
import { FormItemInstance, SelectOptionData } from "@arco-design/web-vue";
import { FormItemInstance } from "@arco-design/web-vue";
import { NodeType, NodeUnion } from "../../nodes";
import { Rule } from "../useRules";
import { IAnFormItem, IAnFormItemBoolFn, IAnFormItemElemFn } from "../../components/FormItem";
/**
*
@ -12,9 +13,60 @@ export type FormItemFnArg<T = FormItem> = {
};
/**
*
*
*/
type BaseFormItem = {
/**
*
* @example
* ```typescript
* '[v1, v2]' => { v1, v2 }
* ```
*/
field: string;
/**
*
* @description model
*/
value?: any;
/**
*
* @description
*/
render?: NodeType | IAnFormItemElemFn;
/**
*
* @description FormItemlabel
*/
label?: string | IAnFormItemElemFn;
/**
*
* @description FormItemhelp
*/
help?: string | IAnFormItemElemFn;
/**
*
* @description FormItemextra
*/
extra?: string | IAnFormItemElemFn;
/**
*
* @description false
*/
required?: boolean;
/**
*
* @description ()
*/
rules?: Rule[];
/**
* `FormItem`
* @description fieldlabelrequiredrulesdisabled
@ -25,91 +77,16 @@ type BaseFormItem = {
*
* @description
*/
visible?: (arg: FormItemFnArg) => boolean;
visible?: IAnFormItemBoolFn;
/**
*
* @description
*/
disable?: (arg: FormItemFnArg) => boolean;
/**
*
* @description ,
*/
options?: SelectOptionData[] | ((arg: FormItemFnArg) => PromiseLike<Recordable[]>);
};
/**
*
*/
type BaseFormItemSlots = {
/**
*
* @description
*/
render?: NodeType | ((args: FormItemFnArg) => any);
/**
*
* @description FormItemlabel
*/
label?: string | ((args: FormItemFnArg) => any);
/**
*
* @description FormItemhelp
* @see https://arco.design/vue/component/form#form-item%20Slots
*/
help?: string | ((args: FormItemFnArg) => any);
/**
*
* @description FormItemextra
* @see https://arco.design/vue/component/form#form-item%20Slots
*/
extra?: string | ((args: FormItemFnArg) => any);
};
/**
*
*/
type BaseFormItemRules = {
/**
*
* @description false
*/
required?: boolean;
/**
*
* @description ()
* @see https://arco.design/vue/component/form#FieldRule
*/
rules?: Rule<FormItem>[];
};
/**
*
*/
type BaseFormItemModel = {
/**
*
* @example
* ```typescript
* '[v1,v2]' => { v1: 1, v2: 2 }
* ```
*/
field: string;
/**
*
* @description model
*/
initial?: any;
disable?: IAnFormItemBoolFn;
};
/**
*
*/
export type FormItem = BaseFormItem & BaseFormItemModel & BaseFormItemRules & BaseFormItemSlots & NodeUnion;
export type FormItem = BaseFormItem & NodeUnion;

View File

@ -1,19 +1,44 @@
import { UseForm } from "./types/Form";
import { useItems } from "./useItems";
import { FormInstance } from "@arco-design/web-vue";
import { FormItem } from "./types/FormItem";
import { IAnForm, IAnFormSubmit } from "../components/Form";
type FormInstanceProps = Partial<Omit<FormInstance["$props"], "model">>;
export type UseForm = {
/**
*
*/
model?: Recordable;
/**
*
*/
items?: FormItem[];
/**
*
* @description
*/
submit?: IAnFormSubmit;
/**
*
* @description
*/
formProps?: FormInstanceProps;
};
/**
*
*/
export const useForm = (options: UseForm) => {
const { model: _model = {}, items: _items = [], submit, formProps: _formProps } = options;
const items = ref(useItems(_items, _model, Boolean(options.submit)))
const { items: _items = [], model: _model = {}, submit, formProps: _props = {} } = options;
const items = useItems(_items, _model, Boolean(options.submit));
const model = ref(_model);
const formProps = ref(_formProps);
const formProps = ref(_props);
return {
model,
items,
submit,
formProps,
submit,
};
};

View File

@ -1,10 +1,12 @@
import { merge } from "lodash-es";
import { nodeMap } from "../nodes";
import { defaultsDeep, merge, omit } from "lodash-es";
import { NodeType, nodeMap } from "../nodes";
import { FormItem } from "./types/FormItem";
import { useRules } from "./useRules";
import { IAnFormItem } from "../components/FormItem";
const ITEM: Partial<FormItem> = {
render: "input",
itemProps: {},
};
const SUBMIT_ITEM: FormItem = {
@ -16,26 +18,37 @@ const SUBMIT_ITEM: FormItem = {
};
export function useItems(list: FormItem[], model: Recordable, submit: boolean) {
const items = [];
const items = ref<IAnFormItem[]>([]);
let hasSubmit = false;
for (const item of list) {
let target: Recordable = merge({}, nodeMap[typeof item.render === "string" ? item.render : "input"]);
let target: any = defaultsDeep({}, ITEM);
if (!item.render || typeof item.render === "string") {
const defaults = nodeMap[item.render ?? "input"];
if (defaults) {
defaultsDeep(target, defaults);
}
}
if (item.render === "submit") {
target = merge(item, SUBMIT_ITEM);
target = merge(target, SUBMIT_ITEM);
hasSubmit = true;
}
target = merge(item, item);
target.rules = useRules(item);
target = merge(target, omit(item, ["required", "rules"]));
model[item.field] = model[item.field] ?? item.initial;
items.push(target as any);
const rules = useRules(item);
if (rules) {
target.rules = rules;
}
model[item.field] = model[item.field] ?? item.value;
items.value.push(target);
}
if (submit && !hasSubmit) {
items.push(merge({}, SUBMIT_ITEM));
items.value.push(defaultsDeep({}, SUBMIT_ITEM, nodeMap.submit));
}
return items;

View File

@ -1,5 +1,6 @@
import { FieldRule } from "@arco-design/web-vue";
import { isString } from "lodash-es";
import { has, isString } from "lodash-es";
import { IAnFormItemBoolFn, IAnFormItemRule } from "../components/FormItem";
/**
*
@ -52,17 +53,10 @@ export const FieldRuleMap = defineRuleMap({
*/
export type FieldStringRule = keyof typeof FieldRuleMap;
/**
*
*/
export type FieldObjectRule<T> = FieldRule & {
disable?: (arg: { item: T; model: Record<string, any> }) => boolean;
};
/**
*
*/
export type Rule<T> = FieldStringRule | FieldObjectRule<T>;
export type Rule = FieldStringRule | IAnFormItemRule;
/**
* (TS)
@ -76,19 +70,26 @@ function defineRuleMap<T extends Record<string, FieldRule>>(ruleMap: T) {
* @param item
* @returns
*/
export const useRules = <T extends { required?: boolean; rules?: Rule<any>[] }>(item: T) => {
const rules: FieldObjectRule<T>[] = [];
if (item.required) {
rules.push(FieldRuleMap.required);
export const useRules = <T extends { required?: boolean; rules?: Rule[] }>(item: T) => {
const { required, rules } = item;
if (!has(item, "required") && !has(item, "rules")) {
return null;
}
for (const rule of item.rules ?? []) {
const data: IAnFormItemRule[] = [];
if (required) {
data.push(FieldRuleMap.required);
}
for (const rule of rules ?? []) {
if (isString(rule)) {
if (FieldRuleMap[rule]) {
rules.push(FieldRuleMap[rule]);
data.push(FieldRuleMap[rule]);
}
} else {
rules.push(rule);
data.push(rule);
}
}
return rules;
return data;
};

View File

@ -5,7 +5,7 @@ type Props = DatePickerInstance["$props"];
export default {
render: DatePicker,
nodeProps: {
placeholder: "请输入",
placeholder: "请选择",
allowClear: true,
} as Props,
};

View File

@ -0,0 +1,10 @@
import { RangePicker, RangePickerInstance } from "@arco-design/web-vue";
type Props = RangePickerInstance["$props"];
export default {
render: RangePicker,
nodeProps: {
allowClear: true,
} as Props,
};

View File

@ -1,9 +1,19 @@
import { Select, SelectInstance } from "@arco-design/web-vue";
import { Select, SelectInstance, SelectOptionData } from "@arco-design/web-vue";
import { initOptions } from "../form-config";
import { Component } from "vue";
import { defineSetter } from "../utils/defineSetter";
type Props = SelectInstance["$props"];
interface Interface {
init: any;
render: Component;
nodeProps: SelectInstance["$props"];
/**
*
*/
options?: SelectOptionData[] | ((arg: any) => Recordable[] | Promise<Recordable[]>);
}
export default {
const select: Interface = {
render: Select,
init: initOptions,
nodeProps: {
@ -11,5 +21,18 @@ export default {
allowClear: true,
allowSearch: true,
options: [],
} as Props,
},
options: [],
};
export default select;
// export default defineSetter({
// setter: Select,
// setterProps: {
// placeholder: "请选择",
// allowClear: true,
// allowSearch: true,
// options: [],
// },
// });

View File

@ -1,15 +1,17 @@
import { Button } from "@arco-design/web-vue";
import { FormContextKey } from "../core/interface";
export default {
render: (props: any, { emit }: any) => {
render() {
const { loading, submitForm, resetModel } = inject(FormContextKey)!;
return (
<>
<Button type="primary" loading={props.loading} onClick={() => emit("submit")} class="mr-3">
<Button type="primary" loading={loading.value} onClick={submitForm} class="mr-3">
</Button>
<Button disabled={loading.value} onClick={resetModel}>
</Button>
{/* <Button loading={props.loading} onClick={() => emit("cancel")}>
</Button> */}
</>
);
},

View File

@ -10,6 +10,7 @@ import submit from "./Submit";
import textarea from "./Textarea";
import time from "./Time";
import treeSelect from "./TreeSelect";
import dateRange from "./DateRange";
export const nodeMap = {
input,
@ -24,6 +25,7 @@ export const nodeMap = {
date,
submit,
custom,
dateRange,
};
export type NodeMap = typeof nodeMap;

View File

@ -0,0 +1,27 @@
import { Component } from "vue";
import { FormItem } from "../hooks/types/FormItem";
interface Setter<T extends Component, P = T extends new (...args: any) => any ? InstanceType<T>["$props"] : any> {
/**
*
*/
setter: T;
/**
*
*/
setterProps?: P;
/**
*
* @param model
* @param item
* @param items
* @returns
*/
onSetup?: (model: Recordable, item: FormItem, items: FormItem[]) => void;
}
export function defineSetter<T extends Component>(options: Setter<T>): Setter<T> {
return options;
}

View File

@ -1,32 +1,94 @@
<template>
<div class="m-4">
<div class="border-2 border-green-500 px-2 w-40 text-3xl text-green-500">AR K056</div>
<AnForm :model="model" :items="items" :submit="submit" :form-props="formProps"></AnForm>
<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>
<TestForm></TestForm>
<div>{{ formatModel(model) }}</div>
</div>
</template>
<script setup lang="tsx">
import { AnForm } from "@/components/form/components/Form";
import { useForm } from "@/components/form/hooks/useForm";
import { useFormModal } from "@/components/AnForm/hooks/useFormModal";
import { formatModel } from "@/components/form/core/useFormModel";
import { sleep } from "@/utils";
const { model, items, submit, formProps } = useForm({
model: {},
const { component: TestForm, model } = useFormModal({
trigger: true,
modalProps: {
width: 880
},
formProps: {
class: 'grid! grid-cols-2 gap-x-4'
},
items: [
{
field: "id",
render: "input",
label: "输入组件",
setter: "input",
},
{
field: 'tod',
render: 'select',
field: "xsa",
label: "动态渲染",
setter: "input",
visible: (model) => model.id,
},
{
field: "fsa",
label: "动态禁止",
setter: "input",
disable: (model) => model.id,
},
{
field: "sgs",
label: "校验规则",
setter: "input",
required: true,
rules: ["email"],
},
{
field: "sgss",
label: "动态规则",
setter: "input",
rules: [
{
required: true,
message: "必须项",
disable: (model) => !model.id,
},
],
},
{
field: "num",
value: 20,
label: "数字组件",
setter: "number",
},
{
field: "date",
label: "日期组件",
setter: "date",
},
{
field: "[startDate, endDate]",
label: "字段语法",
setter: "dateRange",
},
{
field: "tod",
value: 1,
label: "下拉组件",
setter: "select",
options: [
{
label: '测试',
value: 1
}
]
}
label: "测试",
value: 1,
},
],
},
],
async submit(model) {
await sleep(3000);
return { message: "操作成功" };
},
});
</script>

View File

@ -7,58 +7,28 @@ export {}
declare module '@vue/runtime-core' {
export interface GlobalComponents {
AAlert: typeof import('@arco-design/web-vue')['Alert']
AAutoComplete: typeof import('@arco-design/web-vue')['AutoComplete']
AAvatar: typeof import('@arco-design/web-vue')['Avatar']
ABreadcrumb: typeof import('@arco-design/web-vue')['Breadcrumb']
ABreadcrumbItem: typeof import('@arco-design/web-vue')['BreadcrumbItem']
AButton: typeof import('@arco-design/web-vue')['Button']
ACard: typeof import('@arco-design/web-vue')['Card']
ACheckbox: typeof import('@arco-design/web-vue')['Checkbox']
ACheckboxGroup: typeof import('@arco-design/web-vue')['CheckboxGroup']
AConfigProvider: typeof import('@arco-design/web-vue')['ConfigProvider']
ADatePicker: typeof import('@arco-design/web-vue')['DatePicker']
ADivider: typeof import('@arco-design/web-vue')['Divider']
ADoption: typeof import('@arco-design/web-vue')['Doption']
ADrawer: typeof import('@arco-design/web-vue')['Drawer']
ADropdown: typeof import('@arco-design/web-vue')['Dropdown']
ADropdownButton: typeof import('@arco-design/web-vue')['DropdownButton']
AEmpty: typeof import('@arco-design/web-vue')['Empty']
AForm: typeof import('@arco-design/web-vue')['Form']
AFormItem: typeof import('@arco-design/web-vue')['FormItem']
AImage: typeof import('@arco-design/web-vue')['Image']
AImagePreview: typeof import('@arco-design/web-vue')['ImagePreview']
AInput: typeof import('@arco-design/web-vue')['Input']
AInputNumber: typeof import('@arco-design/web-vue')['InputNumber']
AInputSearch: typeof import('@arco-design/web-vue')['InputSearch']
ALayout: typeof import('@arco-design/web-vue')['Layout']
ALayoutContent: typeof import('@arco-design/web-vue')['LayoutContent']
ALayoutHeader: typeof import('@arco-design/web-vue')['LayoutHeader']
ALayoutSider: typeof import('@arco-design/web-vue')['LayoutSider']
ALink: typeof import('@arco-design/web-vue')['Link']
AList: typeof import('@arco-design/web-vue')['List']
AListItem: typeof import('@arco-design/web-vue')['ListItem']
AListItemMeta: typeof import('@arco-design/web-vue')['ListItemMeta']
AMenu: typeof import('@arco-design/web-vue')['Menu']
AMenuItem: typeof import('@arco-design/web-vue')['MenuItem']
AModal: typeof import('@arco-design/web-vue')['Modal']
AniEmpty: typeof import('./../components/empty/AniEmpty.vue')['default']
APagination: typeof import('@arco-design/web-vue')['Pagination']
APopover: typeof import('@arco-design/web-vue')['Popover']
AProgress: typeof import('@arco-design/web-vue')['Progress']
ARadio: typeof import('@arco-design/web-vue')['Radio']
ARadioGroup: typeof import('@arco-design/web-vue')['RadioGroup']
AScrollbar: typeof import('@arco-design/web-vue')['Scrollbar']
ASelect: typeof import('@arco-design/web-vue')['Select']
ASpin: typeof import('@arco-design/web-vue')['Spin']
ASwitch: typeof import('@arco-design/web-vue')['Switch']
ATabPane: typeof import('@arco-design/web-vue')['TabPane']
ATabs: typeof import('@arco-design/web-vue')['Tabs']
ATag: typeof import('@arco-design/web-vue')['Tag']
ATextarea: typeof import('@arco-design/web-vue')['Textarea']
ATooltip: typeof import('@arco-design/web-vue')['Tooltip']
ATree: typeof import('@arco-design/web-vue')['Tree']
AUpload: typeof import('@arco-design/web-vue')['Upload']
BaseOption: typeof import('./../components/editor/components/BaseOption.vue')['default']
BreadCrumb: typeof import('./../components/breadcrumb/bread-crumb.vue')['default']
BreadPage: typeof import('./../components/breadcrumb/bread-page.vue')['default']