|
@@ -25,6 +25,8 @@
|
|
|
<script lang="ts">
|
|
|
import type { FormActionType, FormProps, FormSchema } from './types/form';
|
|
|
import type { Form as FormType, ValidateFields } from 'ant-design-vue/types/form/form';
|
|
|
+ import type { AdvanceState } from './types/hooks';
|
|
|
+ import type { Ref } from 'vue';
|
|
|
|
|
|
import {
|
|
|
defineComponent,
|
|
@@ -32,27 +34,22 @@
|
|
|
ref,
|
|
|
computed,
|
|
|
unref,
|
|
|
- toRaw,
|
|
|
- watch,
|
|
|
toRef,
|
|
|
onMounted,
|
|
|
+ watchEffect,
|
|
|
} from 'vue';
|
|
|
import { Form, Row } from 'ant-design-vue';
|
|
|
import FormItem from './FormItem';
|
|
|
import { basicProps } from './props';
|
|
|
- import { deepMerge, unique } from '/@/utils';
|
|
|
+ import { deepMerge } from '/@/utils';
|
|
|
import FormAction from './FormAction';
|
|
|
|
|
|
import { dateItemType } from './helper';
|
|
|
import moment from 'moment';
|
|
|
- import { isArray, isBoolean, isFunction, isNumber, isObject, isString } from '/@/utils/is';
|
|
|
import { cloneDeep } from 'lodash-es';
|
|
|
- import { useBreakpoint } from '/@/hooks/event/useBreakpoint';
|
|
|
- // import { useThrottle } from '/@/hooks/core/useThrottle';
|
|
|
import { useFormValues } from './hooks/useFormValues';
|
|
|
- import type { ColEx } from './types';
|
|
|
- import { NamePath } from 'ant-design-vue/types/form/form-item';
|
|
|
- const BASIC_COL_LEN = 24;
|
|
|
+ import useAdvanced from './hooks/useAdvanced';
|
|
|
+ import { useFormAction } from './hooks/useFormAction';
|
|
|
|
|
|
export default defineComponent({
|
|
|
name: 'BasicForm',
|
|
@@ -61,13 +58,20 @@
|
|
|
props: basicProps,
|
|
|
emits: ['advanced-change', 'reset', 'submit', 'register'],
|
|
|
setup(props, { emit }) {
|
|
|
- let formModel = reactive({});
|
|
|
- const advanceState = reactive({
|
|
|
+ const formModel = reactive({});
|
|
|
+
|
|
|
+ const actionState = reactive({
|
|
|
+ resetAction: {},
|
|
|
+ submitAction: {},
|
|
|
+ });
|
|
|
+
|
|
|
+ const advanceState = reactive<AdvanceState>({
|
|
|
isAdvanced: true,
|
|
|
hideAdvanceBtn: false,
|
|
|
isLoad: false,
|
|
|
actionSpan: 6,
|
|
|
});
|
|
|
+
|
|
|
const defaultValueRef = ref<any>({});
|
|
|
const propsRef = ref<Partial<FormProps>>({});
|
|
|
const schemaRef = ref<FormSchema[] | null>(null);
|
|
@@ -78,50 +82,24 @@
|
|
|
return deepMerge(cloneDeep(props), unref(propsRef));
|
|
|
}
|
|
|
);
|
|
|
+
|
|
|
// 获取表单基本配置
|
|
|
const getProps = computed(
|
|
|
(): FormProps => {
|
|
|
- const resetAction = {
|
|
|
- onClick: resetFields,
|
|
|
- };
|
|
|
- const submitAction = {
|
|
|
- onClick: handleSubmit,
|
|
|
- };
|
|
|
return {
|
|
|
...unref(getMergePropsRef),
|
|
|
resetButtonOptions: deepMerge(
|
|
|
- resetAction,
|
|
|
+ actionState.resetAction,
|
|
|
unref(getMergePropsRef).resetButtonOptions || {}
|
|
|
- ) as any,
|
|
|
+ ),
|
|
|
submitButtonOptions: deepMerge(
|
|
|
- submitAction,
|
|
|
+ actionState.submitAction,
|
|
|
unref(getMergePropsRef).submitButtonOptions || {}
|
|
|
- ) as any,
|
|
|
+ ),
|
|
|
};
|
|
|
}
|
|
|
);
|
|
|
|
|
|
- const getActionPropsRef = computed(() => {
|
|
|
- const {
|
|
|
- resetButtonOptions,
|
|
|
- submitButtonOptions,
|
|
|
- showActionButtonGroup,
|
|
|
- showResetButton,
|
|
|
- showSubmitButton,
|
|
|
- showAdvancedButton,
|
|
|
- actionColOptions,
|
|
|
- } = unref(getProps);
|
|
|
- return {
|
|
|
- resetButtonOptions,
|
|
|
- submitButtonOptions,
|
|
|
- show: showActionButtonGroup,
|
|
|
- showResetButton,
|
|
|
- showSubmitButton,
|
|
|
- showAdvancedButton,
|
|
|
- actionColOptions,
|
|
|
- };
|
|
|
- });
|
|
|
-
|
|
|
const getSchema = computed((): FormSchema[] => {
|
|
|
const schemas: FormSchema[] = unref(schemaRef) || (unref(getProps).schemas as any);
|
|
|
for (const schema of schemas) {
|
|
@@ -133,305 +111,51 @@
|
|
|
return schemas as FormSchema[];
|
|
|
});
|
|
|
|
|
|
- const getEmptySpanRef = computed((): number => {
|
|
|
- if (!advanceState.isAdvanced) {
|
|
|
- return 0;
|
|
|
- }
|
|
|
- const emptySpan = unref(getMergePropsRef).emptySpan || 0;
|
|
|
-
|
|
|
- if (isNumber(emptySpan)) {
|
|
|
- return emptySpan;
|
|
|
- }
|
|
|
- if (isObject(emptySpan)) {
|
|
|
- const { span = 0 } = emptySpan;
|
|
|
- const screen = unref(screenRef) as string;
|
|
|
-
|
|
|
- const screenSpan = (emptySpan as any)[screen.toLowerCase()];
|
|
|
- return screenSpan || span || 0;
|
|
|
- }
|
|
|
- return 0;
|
|
|
+ const { getActionPropsRef, handleToggleAdvanced } = useAdvanced({
|
|
|
+ advanceState,
|
|
|
+ emit,
|
|
|
+ getMergePropsRef,
|
|
|
+ getProps,
|
|
|
+ getSchema,
|
|
|
+ formModel,
|
|
|
+ defaultValueRef,
|
|
|
});
|
|
|
|
|
|
- const { realWidthRef, screenEnum, screenRef } = useBreakpoint();
|
|
|
- // const [throttleUpdateAdvanced] = useThrottle(updateAdvanced, 30, { immediate: true });
|
|
|
- watch(
|
|
|
- [() => unref(getSchema), () => advanceState.isAdvanced, () => unref(realWidthRef)],
|
|
|
- () => {
|
|
|
- const { showAdvancedButton } = unref(getProps);
|
|
|
- if (showAdvancedButton) {
|
|
|
- updateAdvanced();
|
|
|
- }
|
|
|
- },
|
|
|
- { immediate: true }
|
|
|
- );
|
|
|
-
|
|
|
- function initDefault() {
|
|
|
- const schemas = unref(getSchema);
|
|
|
- const obj: any = {};
|
|
|
- schemas.forEach((item) => {
|
|
|
- if (item.defaultValue) {
|
|
|
- obj[item.field] = item.defaultValue;
|
|
|
- (formModel as any)[item.field] = item.defaultValue;
|
|
|
- }
|
|
|
- });
|
|
|
- defaultValueRef.value = obj;
|
|
|
- }
|
|
|
-
|
|
|
- function updateAdvanced() {
|
|
|
- let itemColSum = 0;
|
|
|
- let realItemColSum = 0;
|
|
|
- for (const schema of unref(getSchema)) {
|
|
|
- const { show, colProps } = schema;
|
|
|
- let isShow = true;
|
|
|
-
|
|
|
- if (isBoolean(show)) {
|
|
|
- isShow = show;
|
|
|
- }
|
|
|
-
|
|
|
- if (isFunction(show)) {
|
|
|
- isShow = show({
|
|
|
- schema: schema,
|
|
|
- model: formModel,
|
|
|
- field: schema.field,
|
|
|
- values: {
|
|
|
- ...unref(defaultValueRef),
|
|
|
- ...formModel,
|
|
|
- },
|
|
|
- });
|
|
|
- }
|
|
|
- if (isShow && colProps) {
|
|
|
- const { itemColSum: sum, isAdvanced } = getAdvanced(colProps, itemColSum);
|
|
|
-
|
|
|
- itemColSum = sum || 0;
|
|
|
- if (isAdvanced) {
|
|
|
- realItemColSum = itemColSum;
|
|
|
- }
|
|
|
- schema.isAdvanced = isAdvanced;
|
|
|
- }
|
|
|
- }
|
|
|
- advanceState.actionSpan = (realItemColSum % BASIC_COL_LEN) + unref(getEmptySpanRef);
|
|
|
- getAdvanced(
|
|
|
- unref(getActionPropsRef).actionColOptions || { span: BASIC_COL_LEN },
|
|
|
- itemColSum,
|
|
|
- true
|
|
|
- );
|
|
|
- emit('advanced-change');
|
|
|
- }
|
|
|
- function getAdvanced(itemCol: Partial<ColEx>, itemColSum = 0, isLastAction = false) {
|
|
|
- const width = unref(realWidthRef);
|
|
|
-
|
|
|
- const mdWidth =
|
|
|
- parseInt(itemCol.md as string) ||
|
|
|
- parseInt(itemCol.xs as string) ||
|
|
|
- parseInt(itemCol.sm as string) ||
|
|
|
- (itemCol.span as number) ||
|
|
|
- BASIC_COL_LEN;
|
|
|
- const lgWidth = parseInt(itemCol.lg as string) || mdWidth;
|
|
|
- const xlWidth = parseInt(itemCol.xl as string) || lgWidth;
|
|
|
- const xxlWidth = parseInt(itemCol.xxl as string) || xlWidth;
|
|
|
- if (width <= screenEnum.LG) {
|
|
|
- itemColSum += mdWidth;
|
|
|
- } else if (width < screenEnum.XL) {
|
|
|
- itemColSum += lgWidth;
|
|
|
- } else if (width < screenEnum.XXL) {
|
|
|
- itemColSum += xlWidth;
|
|
|
- } else {
|
|
|
- itemColSum += xxlWidth;
|
|
|
- }
|
|
|
- if (isLastAction) {
|
|
|
- advanceState.hideAdvanceBtn = false;
|
|
|
- if (itemColSum <= BASIC_COL_LEN * 2) {
|
|
|
- // 小于等于2行时,不显示收起展开按钮
|
|
|
- advanceState.hideAdvanceBtn = true;
|
|
|
- advanceState.isAdvanced = true;
|
|
|
- } else if (
|
|
|
- itemColSum > BASIC_COL_LEN * 2 &&
|
|
|
- itemColSum <= BASIC_COL_LEN * (props.autoAdvancedLine || 3)
|
|
|
- ) {
|
|
|
- advanceState.hideAdvanceBtn = false;
|
|
|
-
|
|
|
- // 大于3行默认收起
|
|
|
- } else if (!advanceState.isLoad) {
|
|
|
- advanceState.isLoad = true;
|
|
|
- advanceState.isAdvanced = !advanceState.isAdvanced;
|
|
|
- }
|
|
|
- return { isAdvanced: advanceState.isAdvanced, itemColSum };
|
|
|
- }
|
|
|
- if (itemColSum > BASIC_COL_LEN) {
|
|
|
- return { isAdvanced: advanceState.isAdvanced, itemColSum };
|
|
|
- } else {
|
|
|
- // 第一行始终显示
|
|
|
- return { isAdvanced: true, itemColSum };
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- async function resetFields(): Promise<any> {
|
|
|
- const { resetFunc, submitOnReset } = unref(getProps);
|
|
|
- resetFunc && isFunction(resetFunc) && (await resetFunc());
|
|
|
- const formEl = unref(formElRef);
|
|
|
- if (!formEl) return;
|
|
|
- Object.keys(formModel).forEach((key) => {
|
|
|
- (formModel as any)[key] = defaultValueRef.value[key];
|
|
|
- });
|
|
|
- // const values = formEl.resetFields();
|
|
|
- emit('reset', toRaw(formModel));
|
|
|
- // return values;
|
|
|
- submitOnReset && handleSubmit();
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * @description: 设置表单值
|
|
|
- */
|
|
|
- async function setFieldsValue(values: any): Promise<void> {
|
|
|
- const fields = unref(getSchema)
|
|
|
- .map((item) => item.field)
|
|
|
- .filter(Boolean);
|
|
|
- const formEl = unref(formElRef);
|
|
|
- Object.keys(values).forEach((key) => {
|
|
|
- const element = values[key];
|
|
|
- if (fields.includes(key) && element !== undefined && element !== null) {
|
|
|
- // 时间
|
|
|
- if (itemIsDateType(key)) {
|
|
|
- if (Array.isArray(element)) {
|
|
|
- const arr: any[] = [];
|
|
|
- for (const ele of element) {
|
|
|
- arr.push(moment(ele));
|
|
|
- }
|
|
|
- (formModel as any)[key] = arr;
|
|
|
- } else {
|
|
|
- (formModel as any)[key] = moment(element);
|
|
|
- }
|
|
|
- } else {
|
|
|
- (formModel as any)[key] = element;
|
|
|
- }
|
|
|
- if (formEl) {
|
|
|
- formEl.validateFields([key]);
|
|
|
- }
|
|
|
- }
|
|
|
- });
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * @description: 表单提交
|
|
|
- */
|
|
|
- async function handleSubmit(e?: Event): Promise<void> {
|
|
|
- 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 formEl.validate();
|
|
|
- const res = handleFormValues(values);
|
|
|
- emit('submit', res);
|
|
|
- } catch (error) {}
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * @description: 根据字段名删除
|
|
|
- */
|
|
|
- function removeSchemaByFiled(fields: string | string[]): void {
|
|
|
- const schemaList: FormSchema[] = cloneDeep(unref(getSchema));
|
|
|
- if (!fields) {
|
|
|
- return;
|
|
|
- }
|
|
|
- let fieldList: string[] = fields as string[];
|
|
|
- if (isString(fields)) {
|
|
|
- fieldList = [fields];
|
|
|
- }
|
|
|
- for (const field of fieldList) {
|
|
|
- _removeSchemaByFiled(field, schemaList);
|
|
|
- }
|
|
|
- schemaRef.value = schemaList as any;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * @description: 根据字段名删除
|
|
|
- */
|
|
|
- function _removeSchemaByFiled(field: string, schemaList: FormSchema[]): void {
|
|
|
- if (isString(field)) {
|
|
|
- const index = schemaList.findIndex((schema) => schema.field === field);
|
|
|
- if (index !== -1) {
|
|
|
- schemaList.splice(index, 1);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * @description: 往某个字段后面插入,如果没有插入最后一个
|
|
|
- */
|
|
|
- function appendSchemaByField(schema: FormSchema, prefixField?: string) {
|
|
|
- const schemaList: FormSchema[] = cloneDeep(unref(getSchema));
|
|
|
-
|
|
|
- const index = schemaList.findIndex((schema) => schema.field === prefixField);
|
|
|
- const hasInList = schemaList.find((item) => item.field === schema.field);
|
|
|
-
|
|
|
- if (hasInList) {
|
|
|
- return;
|
|
|
- }
|
|
|
- if (!prefixField || index === -1) {
|
|
|
- schemaList.push(schema);
|
|
|
- schemaRef.value = schemaList as any;
|
|
|
- return;
|
|
|
- }
|
|
|
- if (index !== -1) {
|
|
|
- schemaList.splice(index + 1, 0, schema);
|
|
|
- }
|
|
|
- schemaRef.value = schemaList as any;
|
|
|
- }
|
|
|
-
|
|
|
- function updateSchema(data: Partial<FormSchema> | Partial<FormSchema>[]) {
|
|
|
- let updateData: Partial<FormSchema>[] = [];
|
|
|
- if (isObject(data)) {
|
|
|
- updateData.push(data as FormSchema);
|
|
|
- }
|
|
|
- if (isArray(data)) {
|
|
|
- updateData = [...data];
|
|
|
- }
|
|
|
- const hasField = updateData.every((item) => Reflect.has(item, 'field') && item.field);
|
|
|
- if (!hasField) {
|
|
|
- throw new Error('Must pass in the `field` field!');
|
|
|
- }
|
|
|
- const schema: FormSchema[] = [];
|
|
|
- updateData.forEach((item) => {
|
|
|
- unref(getSchema).forEach((val) => {
|
|
|
- if (val.field === item.field) {
|
|
|
- const newScheam = deepMerge(val, item);
|
|
|
- schema.push(newScheam as FormSchema);
|
|
|
- } else {
|
|
|
- schema.push(val);
|
|
|
- }
|
|
|
- });
|
|
|
- });
|
|
|
- schemaRef.value = unique(schema, 'field') as any;
|
|
|
- }
|
|
|
-
|
|
|
- function handleToggleAdvanced() {
|
|
|
- advanceState.isAdvanced = !advanceState.isAdvanced;
|
|
|
- }
|
|
|
-
|
|
|
- const handleFormValues = useFormValues(
|
|
|
- toRef(props, 'transformDateFunc'),
|
|
|
- toRef(props, 'fieldMapToTime')
|
|
|
- );
|
|
|
+ const { handleFormValues, initDefault } = useFormValues({
|
|
|
+ transformDateFuncRef: toRef(props, 'transformDateFunc') as Ref<Fn<any>>,
|
|
|
+ fieldMapToTimeRef: toRef(props, 'fieldMapToTime'),
|
|
|
+ defaultValueRef,
|
|
|
+ getSchema,
|
|
|
+ formModel,
|
|
|
+ });
|
|
|
|
|
|
- function getFieldsValue(): any {
|
|
|
- const formEl = unref(formElRef);
|
|
|
- if (!formEl) return;
|
|
|
- return handleFormValues(toRaw(unref(formModel)));
|
|
|
- }
|
|
|
+ const {
|
|
|
+ // handleSubmit,
|
|
|
+ setFieldsValue,
|
|
|
+ clearValidate,
|
|
|
+ validate,
|
|
|
+ validateFields,
|
|
|
+ getFieldsValue,
|
|
|
+ updateSchema,
|
|
|
+ appendSchemaByField,
|
|
|
+ removeSchemaByFiled,
|
|
|
+ resetFields,
|
|
|
+ } = useFormAction({
|
|
|
+ emit,
|
|
|
+ getProps,
|
|
|
+ formModel,
|
|
|
+ getSchema,
|
|
|
+ defaultValueRef,
|
|
|
+ formElRef: formElRef as any,
|
|
|
+ schemaRef: schemaRef as any,
|
|
|
+ handleFormValues,
|
|
|
+ actionState,
|
|
|
+ });
|
|
|
|
|
|
- /**
|
|
|
- * @description: 是否是时间
|
|
|
- */
|
|
|
- function itemIsDateType(key: string) {
|
|
|
- return unref(getSchema).some((item) => {
|
|
|
- return item.field === key ? dateItemType.includes(item.component!) : false;
|
|
|
- });
|
|
|
- }
|
|
|
+ watchEffect(() => {
|
|
|
+ if (!unref(getMergePropsRef).model) return;
|
|
|
+ setFieldsValue(unref(getMergePropsRef).model);
|
|
|
+ });
|
|
|
|
|
|
/**
|
|
|
* @description:设置表单
|
|
@@ -441,21 +165,6 @@
|
|
|
propsRef.value = mergeProps;
|
|
|
}
|
|
|
|
|
|
- function validateFields(nameList?: NamePath[] | undefined) {
|
|
|
- if (!formElRef.value) return;
|
|
|
- return formElRef.value.validateFields(nameList);
|
|
|
- }
|
|
|
-
|
|
|
- function validate(nameList?: NamePath[] | undefined) {
|
|
|
- if (!formElRef.value) return;
|
|
|
- return formElRef.value.validate(nameList);
|
|
|
- }
|
|
|
-
|
|
|
- function clearValidate(name: string | string[]) {
|
|
|
- if (!formElRef.value) return;
|
|
|
- formElRef.value.clearValidate(name);
|
|
|
- }
|
|
|
-
|
|
|
const methods: Partial<FormActionType> = {
|
|
|
getFieldsValue,
|
|
|
setFieldsValue,
|