refactor(form): code optimization and reconstruction
This commit is contained in:
parent
e2333642c4
commit
84c9d78fa7
|
|
@ -1,5 +1,17 @@
|
||||||
## Wip
|
## Wip
|
||||||
|
|
||||||
|
### ✨ Features
|
||||||
|
|
||||||
|
- 表单组件现在支持直接传入 model 直接进行 set 操作,参考**组件->弹窗扩展->打开弹窗并传递数据**
|
||||||
|
|
||||||
|
- modal 的 useModalInner 现在支持传入回调函数,用于接收外部`transferModalData`传进来的值,
|
||||||
|
- 用于处理打开弹窗对表单等组件的设置值。参考**组件->弹窗扩展->打开弹窗并传递数据**
|
||||||
|
- `receiveModalDataRef`这个值暂时保留。尽量少用。后续可能会删除。
|
||||||
|
|
||||||
|
### ✨ Refactor
|
||||||
|
|
||||||
|
- 表单代码优化重构
|
||||||
|
|
||||||
### 🎫 Chores
|
### 🎫 Chores
|
||||||
|
|
||||||
- 添加部分注释
|
- 添加部分注释
|
||||||
|
|
@ -10,6 +22,7 @@
|
||||||
|
|
||||||
- 修复本地代理 post 接口到 https 地址超时错误
|
- 修复本地代理 post 接口到 https 地址超时错误
|
||||||
- 修复 modal 在不显示 footer 的时候全屏高度计算问题
|
- 修复 modal 在不显示 footer 的时候全屏高度计算问题
|
||||||
|
- 修复表单重置未删除校验信息错误
|
||||||
|
|
||||||
## 2.0.0-rc.6 (2020-10-28)
|
## 2.0.0-rc.6 (2020-10-28)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,8 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { FormActionType, FormProps, FormSchema } from './types/form';
|
import type { FormActionType, FormProps, FormSchema } from './types/form';
|
||||||
import type { Form as FormType, ValidateFields } from 'ant-design-vue/types/form/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 {
|
import {
|
||||||
defineComponent,
|
defineComponent,
|
||||||
|
|
@ -32,27 +34,22 @@
|
||||||
ref,
|
ref,
|
||||||
computed,
|
computed,
|
||||||
unref,
|
unref,
|
||||||
toRaw,
|
|
||||||
watch,
|
|
||||||
toRef,
|
toRef,
|
||||||
onMounted,
|
onMounted,
|
||||||
|
watchEffect,
|
||||||
} from 'vue';
|
} from 'vue';
|
||||||
import { Form, Row } from 'ant-design-vue';
|
import { Form, Row } from 'ant-design-vue';
|
||||||
import FormItem from './FormItem';
|
import FormItem from './FormItem';
|
||||||
import { basicProps } from './props';
|
import { basicProps } from './props';
|
||||||
import { deepMerge, unique } from '/@/utils';
|
import { deepMerge } from '/@/utils';
|
||||||
import FormAction from './FormAction';
|
import FormAction from './FormAction';
|
||||||
|
|
||||||
import { dateItemType } from './helper';
|
import { dateItemType } from './helper';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import { isArray, isBoolean, isFunction, isNumber, isObject, isString } from '/@/utils/is';
|
|
||||||
import { cloneDeep } from 'lodash-es';
|
import { cloneDeep } from 'lodash-es';
|
||||||
import { useBreakpoint } from '/@/hooks/event/useBreakpoint';
|
|
||||||
// import { useThrottle } from '/@/hooks/core/useThrottle';
|
|
||||||
import { useFormValues } from './hooks/useFormValues';
|
import { useFormValues } from './hooks/useFormValues';
|
||||||
import type { ColEx } from './types';
|
import useAdvanced from './hooks/useAdvanced';
|
||||||
import { NamePath } from 'ant-design-vue/types/form/form-item';
|
import { useFormAction } from './hooks/useFormAction';
|
||||||
const BASIC_COL_LEN = 24;
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'BasicForm',
|
name: 'BasicForm',
|
||||||
|
|
@ -61,13 +58,20 @@
|
||||||
props: basicProps,
|
props: basicProps,
|
||||||
emits: ['advanced-change', 'reset', 'submit', 'register'],
|
emits: ['advanced-change', 'reset', 'submit', 'register'],
|
||||||
setup(props, { emit }) {
|
setup(props, { emit }) {
|
||||||
let formModel = reactive({});
|
const formModel = reactive({});
|
||||||
const advanceState = reactive({
|
|
||||||
|
const actionState = reactive({
|
||||||
|
resetAction: {},
|
||||||
|
submitAction: {},
|
||||||
|
});
|
||||||
|
|
||||||
|
const advanceState = reactive<AdvanceState>({
|
||||||
isAdvanced: true,
|
isAdvanced: true,
|
||||||
hideAdvanceBtn: false,
|
hideAdvanceBtn: false,
|
||||||
isLoad: false,
|
isLoad: false,
|
||||||
actionSpan: 6,
|
actionSpan: 6,
|
||||||
});
|
});
|
||||||
|
|
||||||
const defaultValueRef = ref<any>({});
|
const defaultValueRef = ref<any>({});
|
||||||
const propsRef = ref<Partial<FormProps>>({});
|
const propsRef = ref<Partial<FormProps>>({});
|
||||||
const schemaRef = ref<FormSchema[] | null>(null);
|
const schemaRef = ref<FormSchema[] | null>(null);
|
||||||
|
|
@ -78,50 +82,24 @@
|
||||||
return deepMerge(cloneDeep(props), unref(propsRef));
|
return deepMerge(cloneDeep(props), unref(propsRef));
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// 获取表单基本配置
|
// 获取表单基本配置
|
||||||
const getProps = computed(
|
const getProps = computed(
|
||||||
(): FormProps => {
|
(): FormProps => {
|
||||||
const resetAction = {
|
|
||||||
onClick: resetFields,
|
|
||||||
};
|
|
||||||
const submitAction = {
|
|
||||||
onClick: handleSubmit,
|
|
||||||
};
|
|
||||||
return {
|
return {
|
||||||
...unref(getMergePropsRef),
|
...unref(getMergePropsRef),
|
||||||
resetButtonOptions: deepMerge(
|
resetButtonOptions: deepMerge(
|
||||||
resetAction,
|
actionState.resetAction,
|
||||||
unref(getMergePropsRef).resetButtonOptions || {}
|
unref(getMergePropsRef).resetButtonOptions || {}
|
||||||
) as any,
|
),
|
||||||
submitButtonOptions: deepMerge(
|
submitButtonOptions: deepMerge(
|
||||||
submitAction,
|
actionState.submitAction,
|
||||||
unref(getMergePropsRef).submitButtonOptions || {}
|
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 getSchema = computed((): FormSchema[] => {
|
||||||
const schemas: FormSchema[] = unref(schemaRef) || (unref(getProps).schemas as any);
|
const schemas: FormSchema[] = unref(schemaRef) || (unref(getProps).schemas as any);
|
||||||
for (const schema of schemas) {
|
for (const schema of schemas) {
|
||||||
|
|
@ -133,305 +111,51 @@
|
||||||
return schemas as FormSchema[];
|
return schemas as FormSchema[];
|
||||||
});
|
});
|
||||||
|
|
||||||
const getEmptySpanRef = computed((): number => {
|
const { getActionPropsRef, handleToggleAdvanced } = useAdvanced({
|
||||||
if (!advanceState.isAdvanced) {
|
advanceState,
|
||||||
return 0;
|
emit,
|
||||||
}
|
getMergePropsRef,
|
||||||
const emptySpan = unref(getMergePropsRef).emptySpan || 0;
|
getProps,
|
||||||
|
getSchema,
|
||||||
if (isNumber(emptySpan)) {
|
formModel,
|
||||||
return emptySpan;
|
defaultValueRef,
|
||||||
}
|
|
||||||
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 { realWidthRef, screenEnum, screenRef } = useBreakpoint();
|
const { handleFormValues, initDefault } = useFormValues({
|
||||||
// const [throttleUpdateAdvanced] = useThrottle(updateAdvanced, 30, { immediate: true });
|
transformDateFuncRef: toRef(props, 'transformDateFunc') as Ref<Fn<any>>,
|
||||||
watch(
|
fieldMapToTimeRef: toRef(props, 'fieldMapToTime'),
|
||||||
[() => unref(getSchema), () => advanceState.isAdvanced, () => unref(realWidthRef)],
|
defaultValueRef,
|
||||||
() => {
|
getSchema,
|
||||||
const { showAdvancedButton } = unref(getProps);
|
formModel,
|
||||||
if (showAdvancedButton) {
|
});
|
||||||
updateAdvanced();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{ immediate: true }
|
|
||||||
);
|
|
||||||
|
|
||||||
function initDefault() {
|
const {
|
||||||
const schemas = unref(getSchema);
|
// handleSubmit,
|
||||||
const obj: any = {};
|
setFieldsValue,
|
||||||
schemas.forEach((item) => {
|
clearValidate,
|
||||||
if (item.defaultValue) {
|
validate,
|
||||||
obj[item.field] = item.defaultValue;
|
validateFields,
|
||||||
(formModel as any)[item.field] = item.defaultValue;
|
getFieldsValue,
|
||||||
}
|
updateSchema,
|
||||||
});
|
appendSchemaByField,
|
||||||
defaultValueRef.value = obj;
|
removeSchemaByFiled,
|
||||||
}
|
resetFields,
|
||||||
|
} = useFormAction({
|
||||||
|
emit,
|
||||||
|
getProps,
|
||||||
|
formModel,
|
||||||
|
getSchema,
|
||||||
|
defaultValueRef,
|
||||||
|
formElRef: formElRef as any,
|
||||||
|
schemaRef: schemaRef as any,
|
||||||
|
handleFormValues,
|
||||||
|
actionState,
|
||||||
|
});
|
||||||
|
|
||||||
function updateAdvanced() {
|
watchEffect(() => {
|
||||||
let itemColSum = 0;
|
if (!unref(getMergePropsRef).model) return;
|
||||||
let realItemColSum = 0;
|
setFieldsValue(unref(getMergePropsRef).model);
|
||||||
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')
|
|
||||||
);
|
|
||||||
|
|
||||||
function getFieldsValue(): any {
|
|
||||||
const formEl = unref(formElRef);
|
|
||||||
if (!formEl) return;
|
|
||||||
return handleFormValues(toRaw(unref(formModel)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description: 是否是时间
|
|
||||||
*/
|
|
||||||
function itemIsDateType(key: string) {
|
|
||||||
return unref(getSchema).some((item) => {
|
|
||||||
return item.field === key ? dateItemType.includes(item.component!) : false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description:设置表单
|
* @description:设置表单
|
||||||
|
|
@ -441,21 +165,6 @@
|
||||||
propsRef.value = mergeProps;
|
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> = {
|
const methods: Partial<FormActionType> = {
|
||||||
getFieldsValue,
|
getFieldsValue,
|
||||||
setFieldsValue,
|
setFieldsValue,
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,7 @@ export default defineComponent({
|
||||||
...props.resetButtonOptions,
|
...props.resetButtonOptions,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
const getSubmitBtnOptionsRef = computed(() => {
|
const getSubmitBtnOptionsRef = computed(() => {
|
||||||
return {
|
return {
|
||||||
text: '查询',
|
text: '查询',
|
||||||
|
|
@ -80,10 +81,12 @@ export default defineComponent({
|
||||||
function toggleAdvanced() {
|
function toggleAdvanced() {
|
||||||
emit('toggle-advanced');
|
emit('toggle-advanced');
|
||||||
}
|
}
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
if (!props.show) {
|
if (!props.show) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const {
|
const {
|
||||||
showAdvancedButton,
|
showAdvancedButton,
|
||||||
hideAdvanceBtn,
|
hideAdvanceBtn,
|
||||||
|
|
@ -91,50 +94,49 @@ export default defineComponent({
|
||||||
showResetButton,
|
showResetButton,
|
||||||
showSubmitButton,
|
showSubmitButton,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<Col {...unref(actionColOpt)} style={{ textAlign: 'right' }}>
|
||||||
<Col {...unref(actionColOpt)} style={{ textAlign: 'right' }}>
|
{() => (
|
||||||
{() => (
|
<Form.Item>
|
||||||
<Form.Item>
|
{() => (
|
||||||
{() => (
|
<>
|
||||||
<>
|
{getSlot(slots, 'advanceBefore')}
|
||||||
{getSlot(slots, 'advanceBefore')}
|
{showAdvancedButton && !hideAdvanceBtn && (
|
||||||
{showAdvancedButton && !hideAdvanceBtn && (
|
<Button type="default" class="mr-2" onClick={toggleAdvanced}>
|
||||||
<Button type="default" class="mr-2" onClick={toggleAdvanced}>
|
{() => (
|
||||||
{() => (
|
<>
|
||||||
<>
|
{isAdvanced ? '收起' : '展开'}
|
||||||
{isAdvanced ? '收起' : '展开'}
|
{isAdvanced ? (
|
||||||
{isAdvanced ? (
|
<UpOutlined class="advanced-icon" />
|
||||||
<UpOutlined class="advanced-icon" />
|
) : (
|
||||||
) : (
|
<DownOutlined class="advanced-icon" />
|
||||||
<DownOutlined class="advanced-icon" />
|
)}
|
||||||
)}
|
</>
|
||||||
</>
|
)}
|
||||||
)}
|
</Button>
|
||||||
</Button>
|
)}
|
||||||
)}
|
|
||||||
|
|
||||||
{getSlot(slots, 'resetBefore')}
|
{getSlot(slots, 'resetBefore')}
|
||||||
{showResetButton && (
|
{showResetButton && (
|
||||||
<Button type="default" class="mr-2" {...unref(getResetBtnOptionsRef)}>
|
<Button type="default" class="mr-2" {...unref(getResetBtnOptionsRef)}>
|
||||||
{() => unref(getResetBtnOptionsRef).text}
|
{() => unref(getResetBtnOptionsRef).text}
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{getSlot(slots, 'submitBefore')}
|
{getSlot(slots, 'submitBefore')}
|
||||||
{showSubmitButton && (
|
{showSubmitButton && (
|
||||||
<Button type="primary" {...unref(getSubmitBtnOptionsRef)}>
|
<Button type="primary" {...unref(getSubmitBtnOptionsRef)}>
|
||||||
{() => unref(getSubmitBtnOptionsRef).text}
|
{() => unref(getSubmitBtnOptionsRef).text}
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{getSlot(slots, 'submitAfter')}
|
{getSlot(slots, 'submitAfter')}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
)}
|
)}
|
||||||
</Col>
|
</Col>
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,20 @@
|
||||||
import { defineComponent, computed, unref, toRef } from 'vue';
|
import type { ValidationRule } from 'ant-design-vue/types/form/form';
|
||||||
import { Form, Col } from 'ant-design-vue';
|
|
||||||
import { componentMap } from './componentMap';
|
|
||||||
|
|
||||||
import type { PropType } from 'vue';
|
import type { PropType } from 'vue';
|
||||||
import type { FormProps } from './types/form';
|
import type { FormProps } from './types/form';
|
||||||
import type { FormSchema } from './types/form';
|
import type { FormSchema } from './types/form';
|
||||||
import { isBoolean, isFunction } from '/@/utils/is';
|
|
||||||
import { useItemLabelWidth } from './hooks/useLabelWidth';
|
import { defineComponent, computed, unref, toRef } from 'vue';
|
||||||
import { getSlot } from '/@/utils/helper/tsxHelper';
|
import { Form, Col } from 'ant-design-vue';
|
||||||
|
import { componentMap } from './componentMap';
|
||||||
import { BasicHelp } from '/@/components/Basic';
|
import { BasicHelp } from '/@/components/Basic';
|
||||||
|
|
||||||
|
import { isBoolean, isFunction } from '/@/utils/is';
|
||||||
|
import { getSlot } from '/@/utils/helper/tsxHelper';
|
||||||
import { createPlaceholderMessage } from './helper';
|
import { createPlaceholderMessage } from './helper';
|
||||||
import { upperFirst, cloneDeep } from 'lodash-es';
|
import { upperFirst, cloneDeep } from 'lodash-es';
|
||||||
import { ValidationRule } from 'ant-design-vue/types/form/form';
|
|
||||||
|
import { useItemLabelWidth } from './hooks/useLabelWidth';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'BasicFormItem',
|
name: 'BasicFormItem',
|
||||||
inheritAttrs: false,
|
inheritAttrs: false,
|
||||||
|
|
@ -50,6 +53,7 @@ export default defineComponent({
|
||||||
schema: schema,
|
schema: schema,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
const getShowRef = computed(() => {
|
const getShowRef = computed(() => {
|
||||||
const { show, ifShow, isAdvanced } = props.schema;
|
const { show, ifShow, isAdvanced } = props.schema;
|
||||||
const { showAdvancedButton } = props.formProps;
|
const { showAdvancedButton } = props.formProps;
|
||||||
|
|
@ -226,6 +230,7 @@ export default defineComponent({
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderItem() {
|
function renderItem() {
|
||||||
const { itemProps, slot, render, field } = props.schema;
|
const { itemProps, slot, render, field } = props.schema;
|
||||||
const { labelCol, wrapperCol } = unref(itemLabelWidthRef);
|
const { labelCol, wrapperCol } = unref(itemLabelWidthRef);
|
||||||
|
|
@ -255,11 +260,8 @@ export default defineComponent({
|
||||||
const { colProps = {}, colSlot, renderColContent, component } = props.schema;
|
const { colProps = {}, colSlot, renderColContent, component } = props.schema;
|
||||||
if (!componentMap.has(component)) return null;
|
if (!componentMap.has(component)) return null;
|
||||||
const { baseColProps = {} } = props.formProps;
|
const { baseColProps = {} } = props.formProps;
|
||||||
|
|
||||||
const realColProps = { ...baseColProps, ...colProps };
|
const realColProps = { ...baseColProps, ...colProps };
|
||||||
|
|
||||||
const { isIfShow, isShow } = unref(getShowRef);
|
const { isIfShow, isShow } = unref(getShowRef);
|
||||||
|
|
||||||
const getContent = () => {
|
const getContent = () => {
|
||||||
return colSlot
|
return colSlot
|
||||||
? getSlot(slots, colSlot)
|
? getSlot(slots, colSlot)
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import { ComponentType } from './types/index';
|
import type { ComponentType } from './types/index';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description: 生成placeholder
|
* @description: 生成placeholder
|
||||||
*/
|
*/
|
||||||
|
|
@ -21,9 +22,11 @@ export function createPlaceholderMessage(component: ComponentType) {
|
||||||
}
|
}
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
function genType() {
|
function genType() {
|
||||||
return ['DatePicker', 'MonthPicker', 'RangePicker', 'WeekPicker', 'TimePicker'];
|
return ['DatePicker', 'MonthPicker', 'RangePicker', 'WeekPicker', 'TimePicker'];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 时间字段
|
* 时间字段
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,179 @@
|
||||||
|
import type { ColEx } from '../types';
|
||||||
|
import type { AdvanceState } from '../types/hooks';
|
||||||
|
import type { ComputedRef, Ref } from 'vue';
|
||||||
|
import type { FormProps, FormSchema } from '../types/form';
|
||||||
|
|
||||||
|
import { computed, unref, watch } from 'vue';
|
||||||
|
import { isBoolean, isFunction, isNumber, isObject } from '/@/utils/is';
|
||||||
|
|
||||||
|
import { useBreakpoint } from '/@/hooks/event/useBreakpoint';
|
||||||
|
|
||||||
|
const BASIC_COL_LEN = 24;
|
||||||
|
|
||||||
|
interface UseAdvancedContext {
|
||||||
|
advanceState: AdvanceState;
|
||||||
|
emit: EmitType;
|
||||||
|
getMergePropsRef: ComputedRef<FormProps>;
|
||||||
|
getProps: ComputedRef<FormProps>;
|
||||||
|
getSchema: ComputedRef<FormSchema[]>;
|
||||||
|
formModel: any;
|
||||||
|
defaultValueRef: Ref<any>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function ({
|
||||||
|
advanceState,
|
||||||
|
emit,
|
||||||
|
getMergePropsRef,
|
||||||
|
getProps,
|
||||||
|
getSchema,
|
||||||
|
formModel,
|
||||||
|
defaultValueRef,
|
||||||
|
}: UseAdvancedContext) {
|
||||||
|
const { realWidthRef, screenEnum, screenRef } = useBreakpoint();
|
||||||
|
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 = computed(() => {
|
||||||
|
const {
|
||||||
|
resetButtonOptions,
|
||||||
|
submitButtonOptions,
|
||||||
|
showActionButtonGroup,
|
||||||
|
showResetButton,
|
||||||
|
showSubmitButton,
|
||||||
|
showAdvancedButton,
|
||||||
|
actionColOptions,
|
||||||
|
} = unref(getProps);
|
||||||
|
return {
|
||||||
|
resetButtonOptions,
|
||||||
|
submitButtonOptions,
|
||||||
|
show: showActionButtonGroup,
|
||||||
|
showResetButton,
|
||||||
|
showSubmitButton,
|
||||||
|
showAdvancedButton,
|
||||||
|
actionColOptions,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
watch(
|
||||||
|
[() => unref(getSchema), () => advanceState.isAdvanced, () => unref(realWidthRef)],
|
||||||
|
() => {
|
||||||
|
const { showAdvancedButton } = unref(getProps);
|
||||||
|
if (showAdvancedButton) {
|
||||||
|
updateAdvanced();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ immediate: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
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 * (unref(getMergePropsRef).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 };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 handleToggleAdvanced() {
|
||||||
|
advanceState.isAdvanced = !advanceState.isAdvanced;
|
||||||
|
}
|
||||||
|
return { getActionPropsRef, handleToggleAdvanced };
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
|
import type { ComponentType } from '../types/index';
|
||||||
import { tryOnUnmounted } from '/@/utils/helper/vueHelper';
|
import { tryOnUnmounted } from '/@/utils/helper/vueHelper';
|
||||||
import { add, del } from '../componentMap';
|
import { add, del } from '../componentMap';
|
||||||
|
|
||||||
import { ComponentType } from '../types/index';
|
|
||||||
export function useComponentRegister(compName: ComponentType, comp: any) {
|
export function useComponentRegister(compName: ComponentType, comp: any) {
|
||||||
add(compName, comp);
|
add(compName, comp);
|
||||||
tryOnUnmounted(() => {
|
tryOnUnmounted(() => {
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
import { ref, onUnmounted, unref } from 'vue';
|
import { ref, onUnmounted, unref } from 'vue';
|
||||||
|
|
||||||
import { isInSetup } from '/@/utils/helper/vueHelper';
|
import { isInSetup } from '/@/utils/helper/vueHelper';
|
||||||
|
import { isProdMode } from '/@/utils/env';
|
||||||
|
|
||||||
import type { FormProps, FormActionType, UseFormReturnType, FormSchema } from '../types/form';
|
import type { FormProps, FormActionType, UseFormReturnType, FormSchema } from '../types/form';
|
||||||
import { isProdMode } from '/@/utils/env';
|
|
||||||
import type { NamePath } from 'ant-design-vue/types/form/form-item';
|
import type { NamePath } from 'ant-design-vue/types/form/form-item';
|
||||||
import type { ValidateFields } from 'ant-design-vue/types/form/form';
|
import type { ValidateFields } from 'ant-design-vue/types/form/form';
|
||||||
|
|
||||||
|
|
@ -11,6 +11,7 @@ export function useForm(props?: Partial<FormProps>): UseFormReturnType {
|
||||||
isInSetup();
|
isInSetup();
|
||||||
const formRef = ref<FormActionType | null>(null);
|
const formRef = ref<FormActionType | null>(null);
|
||||||
const loadedRef = ref<boolean | null>(false);
|
const loadedRef = ref<boolean | null>(false);
|
||||||
|
|
||||||
function getForm() {
|
function getForm() {
|
||||||
const form = unref(formRef);
|
const form = unref(formRef);
|
||||||
if (!form) {
|
if (!form) {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,233 @@
|
||||||
|
import type { ComputedRef, Ref } from 'vue';
|
||||||
|
import type { FormProps, FormSchema } from '../types/form';
|
||||||
|
import type { Form as FormType } from 'ant-design-vue/types/form/form';
|
||||||
|
import type { NamePath } from 'ant-design-vue/types/form/form-item';
|
||||||
|
|
||||||
|
import { unref, toRaw } from 'vue';
|
||||||
|
|
||||||
|
import { isArray, isFunction, isObject, isString } from '/@/utils/is';
|
||||||
|
import { deepMerge, unique } from '/@/utils';
|
||||||
|
import { dateItemType } from '../helper';
|
||||||
|
import moment from 'moment';
|
||||||
|
import { cloneDeep } from 'lodash-es';
|
||||||
|
|
||||||
|
interface UseFormActionContext {
|
||||||
|
emit: EmitType;
|
||||||
|
getProps: ComputedRef<FormProps>;
|
||||||
|
getSchema: ComputedRef<FormSchema[]>;
|
||||||
|
formModel: any;
|
||||||
|
defaultValueRef: Ref<any>;
|
||||||
|
formElRef: Ref<FormType>;
|
||||||
|
schemaRef: Ref<FormSchema[]>;
|
||||||
|
handleFormValues: Fn;
|
||||||
|
actionState: {
|
||||||
|
resetAction: any;
|
||||||
|
submitAction: any;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
export function useFormAction({
|
||||||
|
emit,
|
||||||
|
getProps,
|
||||||
|
formModel,
|
||||||
|
getSchema,
|
||||||
|
defaultValueRef,
|
||||||
|
formElRef,
|
||||||
|
schemaRef,
|
||||||
|
handleFormValues,
|
||||||
|
actionState,
|
||||||
|
}: UseFormActionContext) {
|
||||||
|
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];
|
||||||
|
});
|
||||||
|
// @ts-ignore
|
||||||
|
// TODO 官方组件库类型定义错误,可以不传参数
|
||||||
|
formEl.clearValidate();
|
||||||
|
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: 根据字段名删除
|
||||||
|
*/
|
||||||
|
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 getFieldsValue(): any {
|
||||||
|
const formEl = unref(formElRef);
|
||||||
|
if (!formEl) return;
|
||||||
|
return handleFormValues(toRaw(unref(formModel)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: 是否是时间
|
||||||
|
*/
|
||||||
|
function itemIsDateType(key: string) {
|
||||||
|
return unref(getSchema).some((item) => {
|
||||||
|
return item.field === key ? dateItemType.includes(item.component!) : false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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) {}
|
||||||
|
}
|
||||||
|
actionState.resetAction = {
|
||||||
|
onClick: resetFields,
|
||||||
|
};
|
||||||
|
|
||||||
|
actionState.submitAction = {
|
||||||
|
onClick: handleSubmit,
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
handleSubmit,
|
||||||
|
clearValidate,
|
||||||
|
validate,
|
||||||
|
validateFields,
|
||||||
|
getFieldsValue,
|
||||||
|
updateSchema,
|
||||||
|
appendSchemaByField,
|
||||||
|
removeSchemaByFiled,
|
||||||
|
resetFields,
|
||||||
|
setFieldsValue,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -1,13 +1,23 @@
|
||||||
import { isArray, isFunction, isObject, isString } from '/@/utils/is';
|
import { isArray, isFunction, isObject, isString } from '/@/utils/is';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import { unref } from 'vue';
|
import { unref } from 'vue';
|
||||||
import type { Ref } from 'vue';
|
import type { Ref, ComputedRef } from 'vue';
|
||||||
import type { FieldMapToTime } from '../types/form';
|
import type { FieldMapToTime, FormSchema } from '../types/form';
|
||||||
|
|
||||||
export function useFormValues(
|
interface UseFormValuesContext {
|
||||||
transformDateFuncRef: Ref<Fn>,
|
transformDateFuncRef: Ref<Fn>;
|
||||||
fieldMapToTimeRef: Ref<FieldMapToTime>
|
fieldMapToTimeRef: Ref<FieldMapToTime>;
|
||||||
) {
|
defaultValueRef: Ref<any>;
|
||||||
|
getSchema: ComputedRef<FormSchema[]>;
|
||||||
|
formModel: any;
|
||||||
|
}
|
||||||
|
export function useFormValues({
|
||||||
|
transformDateFuncRef,
|
||||||
|
fieldMapToTimeRef,
|
||||||
|
defaultValueRef,
|
||||||
|
getSchema,
|
||||||
|
formModel,
|
||||||
|
}: UseFormValuesContext) {
|
||||||
// 处理表单值
|
// 处理表单值
|
||||||
function handleFormValues(values: any) {
|
function handleFormValues(values: any) {
|
||||||
if (!isObject(values)) {
|
if (!isObject(values)) {
|
||||||
|
|
@ -35,6 +45,7 @@ export function useFormValues(
|
||||||
}
|
}
|
||||||
return handleRangeTimeValue(resMap);
|
return handleRangeTimeValue(resMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description: 处理时间区间参数
|
* @description: 处理时间区间参数
|
||||||
*/
|
*/
|
||||||
|
|
@ -58,5 +69,18 @@ export function useFormValues(
|
||||||
|
|
||||||
return values;
|
return values;
|
||||||
}
|
}
|
||||||
return handleFormValues;
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
return { handleFormValues, initDefault };
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,10 @@ import type { PropType } from 'vue';
|
||||||
import type { ColEx } from './types';
|
import type { ColEx } from './types';
|
||||||
|
|
||||||
export const basicProps = {
|
export const basicProps = {
|
||||||
|
model: {
|
||||||
|
type: Object as PropType<any>,
|
||||||
|
default: {},
|
||||||
|
},
|
||||||
// 标签宽度 固定宽度
|
// 标签宽度 固定宽度
|
||||||
labelWidth: {
|
labelWidth: {
|
||||||
type: [Number, String] as PropType<number | string>,
|
type: [Number, String] as PropType<number | string>,
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,8 @@ export type RegisterFn = (formInstance: FormActionType) => void;
|
||||||
export type UseFormReturnType = [RegisterFn, FormActionType];
|
export type UseFormReturnType = [RegisterFn, FormActionType];
|
||||||
|
|
||||||
export interface FormProps {
|
export interface FormProps {
|
||||||
|
// 表单值
|
||||||
|
model?: any;
|
||||||
// 整个表单所有项宽度
|
// 整个表单所有项宽度
|
||||||
labelWidth?: number | string;
|
labelWidth?: number | string;
|
||||||
// 重置时提交
|
// 重置时提交
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
export interface AdvanceState {
|
||||||
|
isAdvanced: boolean;
|
||||||
|
hideAdvanceBtn: boolean;
|
||||||
|
isLoad: boolean;
|
||||||
|
actionSpan: number;
|
||||||
|
}
|
||||||
|
|
@ -15,13 +15,12 @@ import {
|
||||||
import { Spin } from 'ant-design-vue';
|
import { Spin } from 'ant-design-vue';
|
||||||
|
|
||||||
import { useWindowSizeFn } from '/@/hooks/event/useWindowSize';
|
import { useWindowSizeFn } from '/@/hooks/event/useWindowSize';
|
||||||
// import { useTimeout } from '/@/hooks/core/useTimeout';
|
import { useTimeout } from '/@/hooks/core/useTimeout';
|
||||||
|
|
||||||
import { getSlot } from '/@/utils/helper/tsxHelper';
|
import { getSlot } from '/@/utils/helper/tsxHelper';
|
||||||
import { useElResize } from '/@/hooks/event/useElResize';
|
import { useElResize } from '/@/hooks/event/useElResize';
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'ModalWrapper',
|
name: 'ModalWrapper',
|
||||||
emits: ['heightChange', 'getExtHeight'],
|
|
||||||
props: {
|
props: {
|
||||||
loading: {
|
loading: {
|
||||||
type: Boolean as PropType<boolean>,
|
type: Boolean as PropType<boolean>,
|
||||||
|
|
@ -52,6 +51,7 @@ export default defineComponent({
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
emits: ['heightChange', 'getExtHeight'],
|
||||||
setup(props: ModalWrapperProps, { slots, emit }) {
|
setup(props: ModalWrapperProps, { slots, emit }) {
|
||||||
const wrapperRef = ref<HTMLElement | null>(null);
|
const wrapperRef = ref<HTMLElement | null>(null);
|
||||||
const spinRef = ref<any>(null);
|
const spinRef = ref<any>(null);
|
||||||
|
|
@ -66,7 +66,7 @@ export default defineComponent({
|
||||||
});
|
});
|
||||||
|
|
||||||
// 重试次数
|
// 重试次数
|
||||||
// let tryCount = 0;
|
let tryCount = 0;
|
||||||
let stopElResizeFn: Fn = () => {};
|
let stopElResizeFn: Fn = () => {};
|
||||||
|
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
|
|
@ -123,17 +123,17 @@ export default defineComponent({
|
||||||
}
|
}
|
||||||
await nextTick();
|
await nextTick();
|
||||||
const spinEl = unref(spinRef);
|
const spinEl = unref(spinRef);
|
||||||
// if (!spinEl) {
|
if (!spinEl) {
|
||||||
// useTimeout(() => {
|
useTimeout(() => {
|
||||||
// // retry
|
// retry
|
||||||
// if (tryCount < 3) {
|
if (tryCount < 3) {
|
||||||
// setModalHeight();
|
setModalHeight();
|
||||||
// }
|
}
|
||||||
// tryCount++;
|
tryCount++;
|
||||||
// }, 10);
|
}, 10);
|
||||||
// return;
|
return;
|
||||||
// }
|
}
|
||||||
// tryCount = 0;
|
tryCount = 0;
|
||||||
|
|
||||||
const spinContainerEl = spinEl.$el.querySelector('.ant-spin-container') as HTMLElement;
|
const spinContainerEl = spinEl.$el.querySelector('.ant-spin-container') as HTMLElement;
|
||||||
if (!spinContainerEl) return;
|
if (!spinContainerEl) return;
|
||||||
|
|
@ -142,7 +142,7 @@ export default defineComponent({
|
||||||
|
|
||||||
if (props.fullScreen) {
|
if (props.fullScreen) {
|
||||||
realHeightRef.value =
|
realHeightRef.value =
|
||||||
window.innerHeight - props.modalFooterHeight - props.modalHeaderHeight - 26;
|
window.innerHeight - props.modalFooterHeight - props.modalHeaderHeight - 6;
|
||||||
} else {
|
} else {
|
||||||
realHeightRef.value = realHeight > maxHeight ? maxHeight : realHeight + 16 + 30;
|
realHeightRef.value = realHeight > maxHeight ? maxHeight : realHeight + 16 + 30;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,9 @@ import type {
|
||||||
ReturnMethods,
|
ReturnMethods,
|
||||||
UseModalInnerReturnType,
|
UseModalInnerReturnType,
|
||||||
} from './types';
|
} from './types';
|
||||||
import { ref, onUnmounted, unref, getCurrentInstance, reactive, computed } from 'vue';
|
import { ref, onUnmounted, unref, getCurrentInstance, reactive, computed, watchEffect } from 'vue';
|
||||||
import { isProdMode } from '/@/utils/env';
|
import { isProdMode } from '/@/utils/env';
|
||||||
|
import { isFunction } from '/@/utils/is';
|
||||||
const dataTransferRef = reactive<any>({});
|
const dataTransferRef = reactive<any>({});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -58,7 +59,7 @@ export function useModal(): UseModalReturnType {
|
||||||
return [register, methods];
|
return [register, methods];
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useModalInner = (): UseModalInnerReturnType => {
|
export const useModalInner = (callbackFn?: Fn): UseModalInnerReturnType => {
|
||||||
const modalInstanceRef = ref<ModalMethods | null>(null);
|
const modalInstanceRef = ref<ModalMethods | null>(null);
|
||||||
const currentInstall = getCurrentInstance();
|
const currentInstall = getCurrentInstance();
|
||||||
const uidRef = ref<string>('');
|
const uidRef = ref<string>('');
|
||||||
|
|
@ -81,6 +82,13 @@ export const useModalInner = (): UseModalInnerReturnType => {
|
||||||
currentInstall.emit('register', modalInstance);
|
currentInstall.emit('register', modalInstance);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
watchEffect(() => {
|
||||||
|
const data = dataTransferRef[unref(uidRef)];
|
||||||
|
if (!data) return;
|
||||||
|
if (!callbackFn || !isFunction(callbackFn)) return;
|
||||||
|
callbackFn(data);
|
||||||
|
});
|
||||||
|
|
||||||
return [
|
return [
|
||||||
register,
|
register,
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,68 @@
|
||||||
<template>
|
<template>
|
||||||
<BasicModal v-bind="$attrs" @register="register" title="Modal Title">
|
<BasicModal v-bind="$attrs" @register="register" title="Modal Title">
|
||||||
<p class="h-20">外部传递数据: {{ receiveModalDataRef }}</p>
|
<p class="h-20">外部传递数据: {{ receiveModalDataRef }}</p>
|
||||||
|
<BasicForm @register="registerForm" :model="model" />
|
||||||
</BasicModal>
|
</BasicModal>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent, nextTick, ref } from 'vue';
|
||||||
import { BasicModal, useModalInner } from '/@/components/Modal';
|
import { BasicModal, useModalInner } from '/@/components/Modal';
|
||||||
|
import { BasicForm, FormSchema, useForm } from '/@/components/Form/index';
|
||||||
|
const schemas: FormSchema[] = [
|
||||||
|
{
|
||||||
|
field: 'field1',
|
||||||
|
component: 'Input',
|
||||||
|
label: '字段1',
|
||||||
|
colProps: {
|
||||||
|
span: 12,
|
||||||
|
},
|
||||||
|
defaultValue: '111',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'field2',
|
||||||
|
component: 'Input',
|
||||||
|
label: '字段2',
|
||||||
|
colProps: {
|
||||||
|
span: 12,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: { BasicModal },
|
components: { BasicModal, BasicForm },
|
||||||
setup() {
|
setup() {
|
||||||
const [register, { receiveModalDataRef }] = useModalInner();
|
const modelRef = ref({});
|
||||||
return { register, receiveModalDataRef };
|
const [
|
||||||
|
registerForm,
|
||||||
|
{
|
||||||
|
// setFieldsValue,
|
||||||
|
// setProps
|
||||||
|
},
|
||||||
|
] = useForm({
|
||||||
|
labelWidth: 120,
|
||||||
|
schemas,
|
||||||
|
showActionButtonGroup: false,
|
||||||
|
actionColOptions: {
|
||||||
|
span: 24,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const [register, { receiveModalDataRef }] = useModalInner((data) => {
|
||||||
|
nextTick(() => {
|
||||||
|
// 方式1
|
||||||
|
// setFieldsValue({
|
||||||
|
// field2: data.data,
|
||||||
|
// field1: data.info,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// 方式2
|
||||||
|
modelRef.value = { field2: data.data, field1: data.info };
|
||||||
|
|
||||||
|
// setProps({
|
||||||
|
// model:{ field2: data.data, field1: data.info }
|
||||||
|
// })
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return { register, receiveModalDataRef, schemas, registerForm, model: modelRef };
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,12 @@
|
||||||
data: 'content',
|
data: 'content',
|
||||||
info: 'Info',
|
info: 'Info',
|
||||||
});
|
});
|
||||||
|
// setTimeout(() => {
|
||||||
|
// transferModalData({
|
||||||
|
// data: 'content1',
|
||||||
|
// info: 'Info1',
|
||||||
|
// });
|
||||||
|
// }, 3000);
|
||||||
openModal4(true);
|
openModal4(true);
|
||||||
}
|
}
|
||||||
function openModalLoading() {
|
function openModalLoading() {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue