web/src/components/AnForm/components/Form.tsx

103 lines
2.8 KiB
TypeScript

import { Form, FormInstance } from '@arco-design/web-vue';
import { useVModel } from '@vueuse/core';
import { PropType } from 'vue';
import { FormContextKey } from './useFormContext';
import { useFormItems } from './useFormItems';
import { useFormModel } from './useFormModel';
import { useFormRef } from './useFormRef';
import { useFormSubmit } from './useFormSubmit';
import { AnFormItem, AnFormItemProps } from './FormItem';
/**
* 表单组件
*/
export const AnForm = defineComponent({
name: 'AnForm',
props: {
/**
* 表单数据
* @example
* ```ts
* {
* id: undefined
* }
* ```
*/
model: {
type: Object as PropType<Recordable>,
default: () => ({}),
},
/**
* 表单项
* @example
* ```ts
* [{
* field: 'name',
* label: '昵称',
* setter: 'input'
* }]
* ```
*/
items: {
type: Array as PropType<AnFormItemProps[]>,
default: () => [],
},
/**
* 提交表单
* @example
* ```ts
* (model) => api.user.addUser(model)
* ```
*/
submit: {
type: [String, Function, Object] as PropType<AnFormSubmit>,
},
/**
* 传给Form组件的参数
* @exmaple
* ```ts
* {
* layout: 'vertical'
* }
* ```
*/
formProps: {
type: Object as PropType<Omit<FormInstance['$props'], 'model' | 'ref'>>,
},
},
emits: ['update:model'],
setup(props, { slots, emit }) {
const model = useVModel(props, 'model', emit);
const items = computed(() => props.items);
const formRefes = useFormRef();
const formModel = useFormModel(model, formRefes.clearValidate);
const formItems = useFormItems(items, model);
const formSubmit = useFormSubmit(props, formRefes.validate, formModel.getModel);
const context = { slots, ...formModel, ...formItems, ...formRefes, ...formSubmit };
provide(FormContextKey, context);
return context;
},
render() {
return (
<Form layout="vertical" {...this.$attrs} {...this.formProps} class="an-form" ref="formRef" model={this.model}>
{this.items.map(item => (
<AnFormItem key={item.field} item={item} items={this.items} model={this.model}></AnFormItem>
))}
{this.$slots.submit?.(this.model, this.validate) ||
(this.submit && this.submitItem && (
<AnFormItem item={this.submitItem} items={this.items} model={this.model}></AnFormItem>
))}
</Form>
);
},
});
export type AnFormInstance = InstanceType<typeof AnForm>;
export type AnFormProps = Pick<AnFormInstance['$props'], 'model' | 'items' | 'submit' | 'formProps'>;
export type AnFormSubmitFn = (model: Recordable, items: AnFormItemProps[]) => any;
export type AnFormSubmit = string | AnFormSubmitFn;