import type { ComputedRef, Ref } from 'vue'; import type { FormProps, FormSchema, FormActionType } from '../types/form'; import type { NamePath } from 'ant-design-vue/lib/form/interface'; import { unref, toRaw, nextTick } from 'vue'; import { isArray, isFunction, isObject, isString, isDef, isNullOrUnDef } from '/@/utils/is'; import { deepMerge } from '/@/utils'; import { dateItemType, handleInputNumberValue, defaultValueComponents } from '../helper'; import { dateUtil } from '/@/utils/dateUtil'; import { cloneDeep, uniqBy } from 'lodash-es'; import { error } from '/@/utils/log'; interface UseFormActionContext { emit: EmitType; getProps: ComputedRef; getSchema: ComputedRef; formModel: Recordable; defaultValueRef: Ref; formElRef: Ref; schemaRef: Ref; handleFormValues: Fn; } export function useFormEvents({ emit, getProps, formModel, getSchema, defaultValueRef, formElRef, schemaRef, handleFormValues, }: UseFormActionContext) { async function resetFields(): Promise { const { resetFunc, submitOnReset } = unref(getProps); resetFunc && isFunction(resetFunc) && (await resetFunc()); const formEl = unref(formElRef); if (!formEl) return; Object.keys(formModel).forEach((key) => { const schema = unref(getSchema).find((item) => item.field === key); const isInput = schema?.component && defaultValueComponents.includes(schema.component); const defaultValue = cloneDeep(defaultValueRef.value[key]); formModel[key] = isInput ? defaultValue || '' : defaultValue; }); nextTick(() => clearValidate()); emit('reset', toRaw(formModel)); submitOnReset && handleSubmit(); } /** * @description: 设置表单值 */ async function setFieldsValue(values: Recordable): Promise { const fields = unref(getSchema) .map((item) => item.field) .filter(Boolean); // key 支持 a.b.c 的嵌套写法 const delimiter = '.'; const nestKeyArray = fields.filter((item) => item.indexOf(delimiter) >= 0); const validKeys: string[] = []; Object.keys(values).forEach((key) => { const schema = unref(getSchema).find((item) => item.field === key); let value = values[key]; const hasKey = Reflect.has(values, key); value = handleInputNumberValue(schema?.component, value); const { componentProps } = schema || {}; let _props = componentProps as any; if (typeof componentProps === 'function') { _props = _props({ formModel: unref(formModel) }); } // 0| '' is allow if (hasKey && fields.includes(key)) { // time type if (itemIsDateType(key)) { if (Array.isArray(value)) { const arr: any[] = []; for (const ele of value) { arr.push(ele ? dateUtil(ele) : null); } unref(formModel)[key] = arr; } else { unref(formModel)[key] = value ? (_props?.valueFormat ? value : dateUtil(value)) : null; } } else { unref(formModel)[key] = value; } if (_props?.onChange) { _props?.onChange(value); } validKeys.push(key); } else { nestKeyArray.forEach((nestKey: string) => { try { const value = eval('values' + delimiter + nestKey); if (isDef(value)) { unref(formModel)[nestKey] = unref(value); validKeys.push(nestKey); } } catch (e) { // key not exist if (isDef(defaultValueRef.value[nestKey])) { unref(formModel)[nestKey] = cloneDeep(unref(defaultValueRef.value[nestKey])); } } }); } }); validateFields(validKeys).catch((_) => {}); } /** * @description: 根据字段名删除 */ async function removeSchemaByFiled(fields: string | string[]): Promise { const schemaList: FormSchema[] = cloneDeep(unref(getSchema)); if (!fields) { return; } let fieldList: string[] = isString(fields) ? [fields] : fields; if (isString(fields)) { fieldList = [fields]; } for (const field of fieldList) { _removeSchemaByFiled(field, schemaList); } schemaRef.value = schemaList; } /** * @description: 根据字段名删除 */ function _removeSchemaByFiled(field: string, schemaList: FormSchema[]): void { if (isString(field)) { const index = schemaList.findIndex((schema) => schema.field === field); if (index !== -1) { delete formModel[field]; schemaList.splice(index, 1); } } } /** * @description: 在某个字段之后插入,如果不插入最后一个 */ async function appendSchemaByField( schema: FormSchema | FormSchema[], prefixField?: string, first = false, ) { const schemaList: FormSchema[] = cloneDeep(unref(getSchema)); const index = schemaList.findIndex((schema) => schema.field === prefixField); const _schemaList = isObject(schema) ? [schema as FormSchema] : (schema as FormSchema[]); if (!prefixField || index === -1 || first) { first ? schemaList.unshift(..._schemaList) : schemaList.push(..._schemaList); schemaRef.value = schemaList; _setDefaultValue(schema); return; } if (index !== -1) { schemaList.splice(index + 1, 0, ..._schemaList); } _setDefaultValue(schema); schemaRef.value = schemaList; } async function resetSchema(data: Partial | Partial[]) { let updateData: Partial[] = []; if (isObject(data)) { updateData.push(data as FormSchema); } if (isArray(data)) { updateData = [...data]; } const hasField = updateData.every( (item) => item.component === 'Divider' || (Reflect.has(item, 'field') && item.field), ); if (!hasField) { error('所有需要更新的 Schema 数组的子表单必须包含 `field` 字段'); return; } schemaRef.value = updateData as FormSchema[]; } async function updateSchema(data: Partial | Partial[]) { let updateData: Partial[] = []; if (isObject(data)) { updateData.push(data as FormSchema); } if (isArray(data)) { updateData = [...data]; } const hasField = updateData.every( (item) => item.component === 'Divider' || (Reflect.has(item, 'field') && item.field), ); if (!hasField) { error('所有需要更新的 Schema 数组的子表单必须包含 `field` 字段'); return; } const schema: FormSchema[] = []; unref(getSchema).forEach((val) => { let _val; updateData.forEach((item) => { if (val.field === item.field) { _val = item; } }); if (_val !== undefined && val.field === _val.field) { const newSchema = deepMerge(val, _val); schema.push(newSchema as FormSchema); } else { schema.push(val); } }); _setDefaultValue(schema); schemaRef.value = uniqBy(schema, 'field'); } function _setDefaultValue(data: FormSchema | FormSchema[]) { let schemas: FormSchema[] = []; if (isObject(data)) { schemas.push(data as FormSchema); } if (isArray(data)) { schemas = [...data]; } const obj: Recordable = {}; const currentFieldsValue = getFieldsValue(); schemas.forEach((item) => { if ( item.component != 'Divider' && Reflect.has(item, 'field') && item.field && !isNullOrUnDef(item.defaultValue) && !(item.field in currentFieldsValue) ) { obj[item.field] = item.defaultValue; } }); setFieldsValue(obj); } function getFieldsValue(): Recordable { const formEl = unref(formElRef); if (!formEl) return {}; return handleFormValues(toRaw(unref(formModel))); } /** * @description: Is it time */ function itemIsDateType(key: string) { return unref(getSchema).some((item) => { return item.field === key ? dateItemType.includes(item.component) : false; }); } async function validateFields(nameList?: NamePath[] | undefined) { return unref(formElRef)?.validateFields(nameList); } async function validate(nameList?: NamePath[] | undefined) { return await unref(formElRef)?.validate(nameList); } async function clearValidate(name?: string | string[]) { await unref(formElRef)?.clearValidate(name); } async function scrollToField(name: NamePath, options?: ScrollOptions | undefined) { await unref(formElRef)?.scrollToField(name, options); } /** * @description: 表单提交 */ async function handleSubmit(e?: Event): Promise { e && e.preventDefault(); const { submitFunc } = unref(getProps); if (submitFunc && isFunction(submitFunc)) { await submitFunc(); return; } const formEl = unref(formElRef); if (!formEl) return; try { const values = await validate(); const res = handleFormValues(values); emit('submit', res); } catch (error: any) { throw new Error(error); } } return { handleSubmit, clearValidate, validate, validateFields, getFieldsValue, updateSchema, resetSchema, appendSchemaByField, removeSchemaByFiled, resetFields, setFieldsValue, scrollToField, }; }