Cyrus Zhou
2023-01-18 16574395697669052b000df857a886c0a3121a11
提交 | 用户 | age
84c9d7 1 import type { ComputedRef, Ref } from 'vue';
2407b3 2 import type { FormProps, FormSchema, FormActionType } from '../types/form';
V 3 import type { NamePath } from 'ant-design-vue/lib/form/interface';
6b594a 4 import { unref, toRaw, nextTick } from 'vue';
0bb3b7 5 import {
V 6   isArray,
7   isFunction,
8   isObject,
9   isString,
10   isDef,
11   isNullOrUnDef,
12   isEmpty,
13 } from '/@/utils/is';
be3a3e 14 import { deepMerge } from '/@/utils';
2423ae 15 import { dateItemType, handleInputNumberValue, defaultValueComponents } from '../helper';
3509eb 16 import { dateUtil } from '/@/utils/dateUtil';
be3a3e 17 import { cloneDeep, uniqBy } from 'lodash-es';
4ff1c4 18 import { error } from '/@/utils/log';
84c9d7 19
V 20 interface UseFormActionContext {
21   emit: EmitType;
22   getProps: ComputedRef<FormProps>;
23   getSchema: ComputedRef<FormSchema[]>;
4ff1c4 24   formModel: Recordable;
V 25   defaultValueRef: Ref<Recordable>;
2407b3 26   formElRef: Ref<FormActionType>;
84c9d7 27   schemaRef: Ref<FormSchema[]>;
V 28   handleFormValues: Fn;
29 }
4ff1c4 30 export function useFormEvents({
84c9d7 31   emit,
V 32   getProps,
33   formModel,
34   getSchema,
35   defaultValueRef,
36   formElRef,
37   schemaRef,
38   handleFormValues,
39 }: UseFormActionContext) {
4ff1c4 40   async function resetFields(): Promise<void> {
84c9d7 41     const { resetFunc, submitOnReset } = unref(getProps);
V 42     resetFunc && isFunction(resetFunc) && (await resetFunc());
4ff1c4 43
84c9d7 44     const formEl = unref(formElRef);
V 45     if (!formEl) return;
4ff1c4 46
84c9d7 47     Object.keys(formModel).forEach((key) => {
2423ae 48       const schema = unref(getSchema).find((item) => item.field === key);
W 49       const isInput = schema?.component && defaultValueComponents.includes(schema.component);
d21578 50       const defaultValue = cloneDeep(defaultValueRef.value[key]);
A 51       formModel[key] = isInput ? defaultValue || '' : defaultValue;
84c9d7 52     });
6b594a 53     nextTick(() => clearValidate());
L 54
84c9d7 55     emit('reset', toRaw(formModel));
V 56     submitOnReset && handleSubmit();
57   }
58
59   /**
4ff1c4 60    * @description: Set form value
84c9d7 61    */
ac1a36 62   async function setFieldsValue(values: Recordable): Promise<void> {
84c9d7 63     const fields = unref(getSchema)
V 64       .map((item) => item.field)
65       .filter(Boolean);
1db72c 66
d09e99 67     // key 支持 a.b.c 的嵌套写法
J 68     const delimiter = '.';
69     const nestKeyArray = fields.filter((item) => item.indexOf(delimiter) >= 0);
70
1db72c 71     const validKeys: string[] = [];
84c9d7 72     Object.keys(values).forEach((key) => {
ac1a36 73       const schema = unref(getSchema).find((item) => item.field === key);
V 74       let value = values[key];
75
8f76ef 76       const hasKey = Reflect.has(values, key);
V 77
ac1a36 78       value = handleInputNumberValue(schema?.component, value);
4c67d8 79       const { componentProps } = schema || {};
V 80       let _props = componentProps as any;
81       if (typeof componentProps === 'function') {
82         _props = _props({ formModel: unref(formModel) });
83       }
4ff1c4 84       // 0| '' is allow
8f76ef 85       if (hasKey && fields.includes(key)) {
46e087 86         // time type
84c9d7 87         if (itemIsDateType(key)) {
ac1a36 88           if (Array.isArray(value)) {
e689ee 89             const arr: any[] = [];
ac1a36 90             for (const ele of value) {
e689ee 91               arr.push(ele ? dateUtil(ele) : null);
84c9d7 92             }
4c67d8 93             unref(formModel)[key] = arr;
84c9d7 94           } else {
4c67d8 95             unref(formModel)[key] = value ? (_props?.valueFormat ? value : dateUtil(value)) : null;
84c9d7 96           }
V 97         } else {
4c67d8 98           unref(formModel)[key] = value;
V 99         }
100         if (_props?.onChange) {
101           _props?.onChange(value);
84c9d7 102         }
1db72c 103         validKeys.push(key);
d09e99 104       } else {
J 105         nestKeyArray.forEach((nestKey: string) => {
106           try {
87ee7c 107             const value = nestKey.split('.').reduce((out, item) => out[item], values);
d09e99 108             if (isDef(value)) {
4c67d8 109               unref(formModel)[nestKey] = unref(value);
d09e99 110               validKeys.push(nestKey);
J 111             }
112           } catch (e) {
113             // key not exist
114             if (isDef(defaultValueRef.value[nestKey])) {
4c67d8 115               unref(formModel)[nestKey] = cloneDeep(unref(defaultValueRef.value[nestKey]));
d09e99 116             }
J 117           }
118         });
84c9d7 119       }
V 120     });
8d185b 121     validateFields(validKeys).catch((_) => {});
84c9d7 122   }
V 123   /**
46e087 124    * @description: Delete based on field name
84c9d7 125    */
768fad 126   async function removeSchemaByField(fields: string | string[]): Promise<void> {
84c9d7 127     const schemaList: FormSchema[] = cloneDeep(unref(getSchema));
38f507 128     if (!fields) {
V 129       return;
130     }
4ff1c4 131
V 132     let fieldList: string[] = isString(fields) ? [fields] : fields;
84c9d7 133     if (isString(fields)) {
V 134       fieldList = [fields];
135     }
136     for (const field of fieldList) {
9aa2cf 137       _removeSchemaByFeild(field, schemaList);
84c9d7 138     }
4ff1c4 139     schemaRef.value = schemaList;
84c9d7 140   }
V 141
142   /**
46e087 143    * @description: Delete based on field name
84c9d7 144    */
9aa2cf 145   function _removeSchemaByFeild(field: string, schemaList: FormSchema[]): void {
84c9d7 146     if (isString(field)) {
V 147       const index = schemaList.findIndex((schema) => schema.field === field);
148       if (index !== -1) {
38f507 149         delete formModel[field];
84c9d7 150         schemaList.splice(index, 1);
V 151       }
152     }
153   }
154
155   /**
46e087 156    * @description: Insert after a certain field, if not insert the last
84c9d7 157    */
098621 158   async function appendSchemaByField(
V 159     schema: FormSchema | FormSchema[],
160     prefixField?: string,
161     first = false,
162   ) {
84c9d7 163     const schemaList: FormSchema[] = cloneDeep(unref(getSchema));
V 164
165     const index = schemaList.findIndex((schema) => schema.field === prefixField);
098621 166     const _schemaList = isObject(schema) ? [schema as FormSchema] : (schema as FormSchema[]);
4ff1c4 167     if (!prefixField || index === -1 || first) {
098621 168       first ? schemaList.unshift(..._schemaList) : schemaList.push(..._schemaList);
4ff1c4 169       schemaRef.value = schemaList;
aaa30f 170       _setDefaultValue(schema);
84c9d7 171       return;
V 172     }
173     if (index !== -1) {
098621 174       schemaList.splice(index + 1, 0, ..._schemaList);
84c9d7 175     }
aaa30f 176     _setDefaultValue(schema);
L 177
4ff1c4 178     schemaRef.value = schemaList;
84c9d7 179   }
V 180
c639e4 181   async function resetSchema(data: Partial<FormSchema> | Partial<FormSchema>[]) {
Z 182     let updateData: Partial<FormSchema>[] = [];
183     if (isObject(data)) {
184       updateData.push(data as FormSchema);
185     }
186     if (isArray(data)) {
187       updateData = [...data];
188     }
189
47a448 190     const hasField = updateData.every(
56a966 191       (item) => item.component === 'Divider' || (Reflect.has(item, 'field') && item.field),
47a448 192     );
c639e4 193
Z 194     if (!hasField) {
195       error(
56a966 196         'All children of the form Schema array that need to be updated must contain the `field` field',
c639e4 197       );
Z 198       return;
199     }
200     schemaRef.value = updateData as FormSchema[];
201   }
202
4ff1c4 203   async function updateSchema(data: Partial<FormSchema> | Partial<FormSchema>[]) {
84c9d7 204     let updateData: Partial<FormSchema>[] = [];
V 205     if (isObject(data)) {
206       updateData.push(data as FormSchema);
207     }
208     if (isArray(data)) {
209       updateData = [...data];
210     }
4ff1c4 211
47a448 212     const hasField = updateData.every(
56a966 213       (item) => item.component === 'Divider' || (Reflect.has(item, 'field') && item.field),
47a448 214     );
4ff1c4 215
84c9d7 216     if (!hasField) {
4ff1c4 217       error(
56a966 218         'All children of the form Schema array that need to be updated must contain the `field` field',
4ff1c4 219       );
116a1f 220       return;
84c9d7 221     }
V 222     const schema: FormSchema[] = [];
165743 223     unref(getSchema).forEach((val) => {
CZ 224       let _val;
225       updateData.forEach((item) => {
84c9d7 226         if (val.field === item.field) {
165743 227           _val = item;
84c9d7 228         }
V 229       });
165743 230       if (_val !== undefined && val.field === _val.field) {
CZ 231         const newSchema = deepMerge(val, _val);
232         schema.push(newSchema as FormSchema);
233       } else {
234         schema.push(val);
235       }
84c9d7 236     });
aaa30f 237     _setDefaultValue(schema);
L 238
be3a3e 239     schemaRef.value = uniqBy(schema, 'field');
84c9d7 240   }
V 241
aaa30f 242   function _setDefaultValue(data: FormSchema | FormSchema[]) {
L 243     let schemas: FormSchema[] = [];
244     if (isObject(data)) {
245       schemas.push(data as FormSchema);
246     }
247     if (isArray(data)) {
248       schemas = [...data];
249     }
250
251     const obj: Recordable = {};
3cc72d 252     const currentFieldsValue = getFieldsValue();
aaa30f 253     schemas.forEach((item) => {
L 254       if (
255         item.component != 'Divider' &&
256         Reflect.has(item, 'field') &&
257         item.field &&
3cc72d 258         !isNullOrUnDef(item.defaultValue) &&
0bb3b7 259         (!(item.field in currentFieldsValue) ||
V 260           isNullOrUnDef(currentFieldsValue[item.field]) ||
261           isEmpty(currentFieldsValue[item.field]))
aaa30f 262       ) {
L 263         obj[item.field] = item.defaultValue;
264       }
265     });
266     setFieldsValue(obj);
267   }
268
4ff1c4 269   function getFieldsValue(): Recordable {
84c9d7 270     const formEl = unref(formElRef);
4ff1c4 271     if (!formEl) return {};
84c9d7 272     return handleFormValues(toRaw(unref(formModel)));
V 273   }
274
275   /**
46e087 276    * @description: Is it time
84c9d7 277    */
V 278   function itemIsDateType(key: string) {
279     return unref(getSchema).some((item) => {
4ff1c4 280       return item.field === key ? dateItemType.includes(item.component) : false;
84c9d7 281     });
V 282   }
283
4ff1c4 284   async function validateFields(nameList?: NamePath[] | undefined) {
a305e5 285     return unref(formElRef)?.validateFields(nameList);
84c9d7 286   }
43a45b 287
4ff1c4 288   async function validate(nameList?: NamePath[] | undefined) {
a305e5 289     return await unref(formElRef)?.validate(nameList);
84c9d7 290   }
V 291
4ff1c4 292   async function clearValidate(name?: string | string[]) {
V 293     await unref(formElRef)?.clearValidate(name);
294   }
295
296   async function scrollToField(name: NamePath, options?: ScrollOptions | undefined) {
297     await unref(formElRef)?.scrollToField(name, options);
84c9d7 298   }
V 299
300   /**
46e087 301    * @description: Form submission
84c9d7 302    */
V 303   async function handleSubmit(e?: Event): Promise<void> {
304     e && e.preventDefault();
305     const { submitFunc } = unref(getProps);
306     if (submitFunc && isFunction(submitFunc)) {
307       await submitFunc();
308       return;
309     }
310     const formEl = unref(formElRef);
311     if (!formEl) return;
312     try {
94bf85 313       const values = await validate();
84c9d7 314       const res = handleFormValues(values);
V 315       emit('submit', res);
a248e2 316     } catch (error: any) {
9a21b8 317       throw new Error(error);
LY 318     }
84c9d7 319   }
V 320
321   return {
322     handleSubmit,
323     clearValidate,
324     validate,
325     validateFields,
326     getFieldsValue,
327     updateSchema,
c639e4 328     resetSchema,
84c9d7 329     appendSchemaByField,
768fad 330     removeSchemaByField,
84c9d7 331     resetFields,
V 332     setFieldsValue,
4ff1c4 333     scrollToField,
84c9d7 334   };
V 335 }