Commit 84c9d78fa7feffe3430b7c85dc97383cd7193ba1

Authored by vben
1 parent e2333642

refactor(form): code optimization and reconstruction

CHANGELOG.zh_CN.md
1 ## Wip 1 ## Wip
2 2
  3 +### ✨ Features
  4 +
  5 +- 表单组件现在支持直接传入 model 直接进行 set 操作,参考**组件->弹窗扩展->打开弹窗并传递数据**
  6 +
  7 +- modal 的 useModalInner 现在支持传入回调函数,用于接收外部`transferModalData`传进来的值,
  8 + - 用于处理打开弹窗对表单等组件的设置值。参考**组件->弹窗扩展->打开弹窗并传递数据**
  9 + - `receiveModalDataRef`这个值暂时保留。尽量少用。后续可能会删除。
  10 +
  11 +### ✨ Refactor
  12 +
  13 +- 表单代码优化重构
  14 +
3 ### 🎫 Chores 15 ### 🎫 Chores
4 16
5 - 添加部分注释 17 - 添加部分注释
@@ -10,6 +22,7 @@ @@ -10,6 +22,7 @@
10 22
11 - 修复本地代理 post 接口到 https 地址超时错误 23 - 修复本地代理 post 接口到 https 地址超时错误
12 - 修复 modal 在不显示 footer 的时候全屏高度计算问题 24 - 修复 modal 在不显示 footer 的时候全屏高度计算问题
  25 +- 修复表单重置未删除校验信息错误
13 26
14 ## 2.0.0-rc.6 (2020-10-28) 27 ## 2.0.0-rc.6 (2020-10-28)
15 28
src/components/Form/src/BasicForm.vue
@@ -25,6 +25,8 @@ @@ -25,6 +25,8 @@
25 <script lang="ts"> 25 <script lang="ts">
26 import type { FormActionType, FormProps, FormSchema } from './types/form'; 26 import type { FormActionType, FormProps, FormSchema } from './types/form';
27 import type { Form as FormType, ValidateFields } from 'ant-design-vue/types/form/form'; 27 import type { Form as FormType, ValidateFields } from 'ant-design-vue/types/form/form';
  28 + import type { AdvanceState } from './types/hooks';
  29 + import type { Ref } from 'vue';
28 30
29 import { 31 import {
30 defineComponent, 32 defineComponent,
@@ -32,27 +34,22 @@ @@ -32,27 +34,22 @@
32 ref, 34 ref,
33 computed, 35 computed,
34 unref, 36 unref,
35 - toRaw,  
36 - watch,  
37 toRef, 37 toRef,
38 onMounted, 38 onMounted,
  39 + watchEffect,
39 } from 'vue'; 40 } from 'vue';
40 import { Form, Row } from 'ant-design-vue'; 41 import { Form, Row } from 'ant-design-vue';
41 import FormItem from './FormItem'; 42 import FormItem from './FormItem';
42 import { basicProps } from './props'; 43 import { basicProps } from './props';
43 - import { deepMerge, unique } from '/@/utils'; 44 + import { deepMerge } from '/@/utils';
44 import FormAction from './FormAction'; 45 import FormAction from './FormAction';
45 46
46 import { dateItemType } from './helper'; 47 import { dateItemType } from './helper';
47 import moment from 'moment'; 48 import moment from 'moment';
48 - import { isArray, isBoolean, isFunction, isNumber, isObject, isString } from '/@/utils/is';  
49 import { cloneDeep } from 'lodash-es'; 49 import { cloneDeep } from 'lodash-es';
50 - import { useBreakpoint } from '/@/hooks/event/useBreakpoint';  
51 - // import { useThrottle } from '/@/hooks/core/useThrottle';  
52 import { useFormValues } from './hooks/useFormValues'; 50 import { useFormValues } from './hooks/useFormValues';
53 - import type { ColEx } from './types';  
54 - import { NamePath } from 'ant-design-vue/types/form/form-item';  
55 - const BASIC_COL_LEN = 24; 51 + import useAdvanced from './hooks/useAdvanced';
  52 + import { useFormAction } from './hooks/useFormAction';
56 53
57 export default defineComponent({ 54 export default defineComponent({
58 name: 'BasicForm', 55 name: 'BasicForm',
@@ -61,13 +58,20 @@ @@ -61,13 +58,20 @@
61 props: basicProps, 58 props: basicProps,
62 emits: ['advanced-change', 'reset', 'submit', 'register'], 59 emits: ['advanced-change', 'reset', 'submit', 'register'],
63 setup(props, { emit }) { 60 setup(props, { emit }) {
64 - let formModel = reactive({});  
65 - const advanceState = reactive({ 61 + const formModel = reactive({});
  62 +
  63 + const actionState = reactive({
  64 + resetAction: {},
  65 + submitAction: {},
  66 + });
  67 +
  68 + const advanceState = reactive<AdvanceState>({
66 isAdvanced: true, 69 isAdvanced: true,
67 hideAdvanceBtn: false, 70 hideAdvanceBtn: false,
68 isLoad: false, 71 isLoad: false,
69 actionSpan: 6, 72 actionSpan: 6,
70 }); 73 });
  74 +
71 const defaultValueRef = ref<any>({}); 75 const defaultValueRef = ref<any>({});
72 const propsRef = ref<Partial<FormProps>>({}); 76 const propsRef = ref<Partial<FormProps>>({});
73 const schemaRef = ref<FormSchema[] | null>(null); 77 const schemaRef = ref<FormSchema[] | null>(null);
@@ -78,50 +82,24 @@ @@ -78,50 +82,24 @@
78 return deepMerge(cloneDeep(props), unref(propsRef)); 82 return deepMerge(cloneDeep(props), unref(propsRef));
79 } 83 }
80 ); 84 );
  85 +
81 // 获取表单基本配置 86 // 获取表单基本配置
82 const getProps = computed( 87 const getProps = computed(
83 (): FormProps => { 88 (): FormProps => {
84 - const resetAction = {  
85 - onClick: resetFields,  
86 - };  
87 - const submitAction = {  
88 - onClick: handleSubmit,  
89 - };  
90 return { 89 return {
91 ...unref(getMergePropsRef), 90 ...unref(getMergePropsRef),
92 resetButtonOptions: deepMerge( 91 resetButtonOptions: deepMerge(
93 - resetAction, 92 + actionState.resetAction,
94 unref(getMergePropsRef).resetButtonOptions || {} 93 unref(getMergePropsRef).resetButtonOptions || {}
95 - ) as any, 94 + ),
96 submitButtonOptions: deepMerge( 95 submitButtonOptions: deepMerge(
97 - submitAction, 96 + actionState.submitAction,
98 unref(getMergePropsRef).submitButtonOptions || {} 97 unref(getMergePropsRef).submitButtonOptions || {}
99 - ) as any, 98 + ),
100 }; 99 };
101 } 100 }
102 ); 101 );
103 102
104 - const getActionPropsRef = computed(() => {  
105 - const {  
106 - resetButtonOptions,  
107 - submitButtonOptions,  
108 - showActionButtonGroup,  
109 - showResetButton,  
110 - showSubmitButton,  
111 - showAdvancedButton,  
112 - actionColOptions,  
113 - } = unref(getProps);  
114 - return {  
115 - resetButtonOptions,  
116 - submitButtonOptions,  
117 - show: showActionButtonGroup,  
118 - showResetButton,  
119 - showSubmitButton,  
120 - showAdvancedButton,  
121 - actionColOptions,  
122 - };  
123 - });  
124 -  
125 const getSchema = computed((): FormSchema[] => { 103 const getSchema = computed((): FormSchema[] => {
126 const schemas: FormSchema[] = unref(schemaRef) || (unref(getProps).schemas as any); 104 const schemas: FormSchema[] = unref(schemaRef) || (unref(getProps).schemas as any);
127 for (const schema of schemas) { 105 for (const schema of schemas) {
@@ -133,305 +111,51 @@ @@ -133,305 +111,51 @@
133 return schemas as FormSchema[]; 111 return schemas as FormSchema[];
134 }); 112 });
135 113
136 - const getEmptySpanRef = computed((): number => {  
137 - if (!advanceState.isAdvanced) {  
138 - return 0;  
139 - }  
140 - const emptySpan = unref(getMergePropsRef).emptySpan || 0;  
141 -  
142 - if (isNumber(emptySpan)) {  
143 - return emptySpan;  
144 - }  
145 - if (isObject(emptySpan)) {  
146 - const { span = 0 } = emptySpan;  
147 - const screen = unref(screenRef) as string;  
148 -  
149 - const screenSpan = (emptySpan as any)[screen.toLowerCase()];  
150 - return screenSpan || span || 0;  
151 - }  
152 - return 0; 114 + const { getActionPropsRef, handleToggleAdvanced } = useAdvanced({
  115 + advanceState,
  116 + emit,
  117 + getMergePropsRef,
  118 + getProps,
  119 + getSchema,
  120 + formModel,
  121 + defaultValueRef,
153 }); 122 });
154 123
155 - const { realWidthRef, screenEnum, screenRef } = useBreakpoint();  
156 - // const [throttleUpdateAdvanced] = useThrottle(updateAdvanced, 30, { immediate: true });  
157 - watch(  
158 - [() => unref(getSchema), () => advanceState.isAdvanced, () => unref(realWidthRef)],  
159 - () => {  
160 - const { showAdvancedButton } = unref(getProps);  
161 - if (showAdvancedButton) {  
162 - updateAdvanced();  
163 - }  
164 - },  
165 - { immediate: true }  
166 - );  
167 -  
168 - function initDefault() {  
169 - const schemas = unref(getSchema);  
170 - const obj: any = {};  
171 - schemas.forEach((item) => {  
172 - if (item.defaultValue) {  
173 - obj[item.field] = item.defaultValue;  
174 - (formModel as any)[item.field] = item.defaultValue;  
175 - }  
176 - });  
177 - defaultValueRef.value = obj;  
178 - }  
179 -  
180 - function updateAdvanced() {  
181 - let itemColSum = 0;  
182 - let realItemColSum = 0;  
183 - for (const schema of unref(getSchema)) {  
184 - const { show, colProps } = schema;  
185 - let isShow = true;  
186 -  
187 - if (isBoolean(show)) {  
188 - isShow = show;  
189 - }  
190 -  
191 - if (isFunction(show)) {  
192 - isShow = show({  
193 - schema: schema,  
194 - model: formModel,  
195 - field: schema.field,  
196 - values: {  
197 - ...unref(defaultValueRef),  
198 - ...formModel,  
199 - },  
200 - });  
201 - }  
202 - if (isShow && colProps) {  
203 - const { itemColSum: sum, isAdvanced } = getAdvanced(colProps, itemColSum);  
204 -  
205 - itemColSum = sum || 0;  
206 - if (isAdvanced) {  
207 - realItemColSum = itemColSum;  
208 - }  
209 - schema.isAdvanced = isAdvanced;  
210 - }  
211 - }  
212 - advanceState.actionSpan = (realItemColSum % BASIC_COL_LEN) + unref(getEmptySpanRef);  
213 - getAdvanced(  
214 - unref(getActionPropsRef).actionColOptions || { span: BASIC_COL_LEN },  
215 - itemColSum,  
216 - true  
217 - );  
218 - emit('advanced-change');  
219 - }  
220 - function getAdvanced(itemCol: Partial<ColEx>, itemColSum = 0, isLastAction = false) {  
221 - const width = unref(realWidthRef);  
222 -  
223 - const mdWidth =  
224 - parseInt(itemCol.md as string) ||  
225 - parseInt(itemCol.xs as string) ||  
226 - parseInt(itemCol.sm as string) ||  
227 - (itemCol.span as number) ||  
228 - BASIC_COL_LEN;  
229 - const lgWidth = parseInt(itemCol.lg as string) || mdWidth;  
230 - const xlWidth = parseInt(itemCol.xl as string) || lgWidth;  
231 - const xxlWidth = parseInt(itemCol.xxl as string) || xlWidth;  
232 - if (width <= screenEnum.LG) {  
233 - itemColSum += mdWidth;  
234 - } else if (width < screenEnum.XL) {  
235 - itemColSum += lgWidth;  
236 - } else if (width < screenEnum.XXL) {  
237 - itemColSum += xlWidth;  
238 - } else {  
239 - itemColSum += xxlWidth;  
240 - }  
241 - if (isLastAction) {  
242 - advanceState.hideAdvanceBtn = false;  
243 - if (itemColSum <= BASIC_COL_LEN * 2) {  
244 - // 小于等于2行时,不显示收起展开按钮  
245 - advanceState.hideAdvanceBtn = true;  
246 - advanceState.isAdvanced = true;  
247 - } else if (  
248 - itemColSum > BASIC_COL_LEN * 2 &&  
249 - itemColSum <= BASIC_COL_LEN * (props.autoAdvancedLine || 3)  
250 - ) {  
251 - advanceState.hideAdvanceBtn = false;  
252 -  
253 - // 大于3行默认收起  
254 - } else if (!advanceState.isLoad) {  
255 - advanceState.isLoad = true;  
256 - advanceState.isAdvanced = !advanceState.isAdvanced;  
257 - }  
258 - return { isAdvanced: advanceState.isAdvanced, itemColSum };  
259 - }  
260 - if (itemColSum > BASIC_COL_LEN) {  
261 - return { isAdvanced: advanceState.isAdvanced, itemColSum };  
262 - } else {  
263 - // 第一行始终显示  
264 - return { isAdvanced: true, itemColSum };  
265 - }  
266 - }  
267 -  
268 - async function resetFields(): Promise<any> {  
269 - const { resetFunc, submitOnReset } = unref(getProps);  
270 - resetFunc && isFunction(resetFunc) && (await resetFunc());  
271 - const formEl = unref(formElRef);  
272 - if (!formEl) return;  
273 - Object.keys(formModel).forEach((key) => {  
274 - (formModel as any)[key] = defaultValueRef.value[key];  
275 - });  
276 - // const values = formEl.resetFields();  
277 - emit('reset', toRaw(formModel));  
278 - // return values;  
279 - submitOnReset && handleSubmit();  
280 - }  
281 -  
282 - /**  
283 - * @description: 设置表单值  
284 - */  
285 - async function setFieldsValue(values: any): Promise<void> {  
286 - const fields = unref(getSchema)  
287 - .map((item) => item.field)  
288 - .filter(Boolean);  
289 - const formEl = unref(formElRef);  
290 - Object.keys(values).forEach((key) => {  
291 - const element = values[key];  
292 - if (fields.includes(key) && element !== undefined && element !== null) {  
293 - // 时间  
294 - if (itemIsDateType(key)) {  
295 - if (Array.isArray(element)) {  
296 - const arr: any[] = [];  
297 - for (const ele of element) {  
298 - arr.push(moment(ele));  
299 - }  
300 - (formModel as any)[key] = arr;  
301 - } else {  
302 - (formModel as any)[key] = moment(element);  
303 - }  
304 - } else {  
305 - (formModel as any)[key] = element;  
306 - }  
307 - if (formEl) {  
308 - formEl.validateFields([key]);  
309 - }  
310 - }  
311 - });  
312 - }  
313 -  
314 - /**  
315 - * @description: 表单提交  
316 - */  
317 - async function handleSubmit(e?: Event): Promise<void> {  
318 - e && e.preventDefault();  
319 - const { submitFunc } = unref(getProps);  
320 - if (submitFunc && isFunction(submitFunc)) {  
321 - await submitFunc();  
322 - return;  
323 - }  
324 - const formEl = unref(formElRef);  
325 - if (!formEl) return;  
326 - try {  
327 - const values = await formEl.validate();  
328 - const res = handleFormValues(values);  
329 - emit('submit', res);  
330 - } catch (error) {}  
331 - }  
332 -  
333 - /**  
334 - * @description: 根据字段名删除  
335 - */  
336 - function removeSchemaByFiled(fields: string | string[]): void {  
337 - const schemaList: FormSchema[] = cloneDeep(unref(getSchema));  
338 - if (!fields) {  
339 - return;  
340 - }  
341 - let fieldList: string[] = fields as string[];  
342 - if (isString(fields)) {  
343 - fieldList = [fields];  
344 - }  
345 - for (const field of fieldList) {  
346 - _removeSchemaByFiled(field, schemaList);  
347 - }  
348 - schemaRef.value = schemaList as any;  
349 - }  
350 -  
351 - /**  
352 - * @description: 根据字段名删除  
353 - */  
354 - function _removeSchemaByFiled(field: string, schemaList: FormSchema[]): void {  
355 - if (isString(field)) {  
356 - const index = schemaList.findIndex((schema) => schema.field === field);  
357 - if (index !== -1) {  
358 - schemaList.splice(index, 1);  
359 - }  
360 - }  
361 - }  
362 -  
363 - /**  
364 - * @description: 往某个字段后面插入,如果没有插入最后一个  
365 - */  
366 - function appendSchemaByField(schema: FormSchema, prefixField?: string) {  
367 - const schemaList: FormSchema[] = cloneDeep(unref(getSchema));  
368 -  
369 - const index = schemaList.findIndex((schema) => schema.field === prefixField);  
370 - const hasInList = schemaList.find((item) => item.field === schema.field);  
371 -  
372 - if (hasInList) {  
373 - return;  
374 - }  
375 - if (!prefixField || index === -1) {  
376 - schemaList.push(schema);  
377 - schemaRef.value = schemaList as any;  
378 - return;  
379 - }  
380 - if (index !== -1) {  
381 - schemaList.splice(index + 1, 0, schema);  
382 - }  
383 - schemaRef.value = schemaList as any;  
384 - }  
385 -  
386 - function updateSchema(data: Partial<FormSchema> | Partial<FormSchema>[]) {  
387 - let updateData: Partial<FormSchema>[] = [];  
388 - if (isObject(data)) {  
389 - updateData.push(data as FormSchema);  
390 - }  
391 - if (isArray(data)) {  
392 - updateData = [...data];  
393 - }  
394 - const hasField = updateData.every((item) => Reflect.has(item, 'field') && item.field);  
395 - if (!hasField) {  
396 - throw new Error('Must pass in the `field` field!');  
397 - }  
398 - const schema: FormSchema[] = [];  
399 - updateData.forEach((item) => {  
400 - unref(getSchema).forEach((val) => {  
401 - if (val.field === item.field) {  
402 - const newScheam = deepMerge(val, item);  
403 - schema.push(newScheam as FormSchema);  
404 - } else {  
405 - schema.push(val);  
406 - }  
407 - });  
408 - });  
409 - schemaRef.value = unique(schema, 'field') as any;  
410 - }  
411 -  
412 - function handleToggleAdvanced() {  
413 - advanceState.isAdvanced = !advanceState.isAdvanced;  
414 - }  
415 -  
416 - const handleFormValues = useFormValues(  
417 - toRef(props, 'transformDateFunc'),  
418 - toRef(props, 'fieldMapToTime')  
419 - ); 124 + const { handleFormValues, initDefault } = useFormValues({
  125 + transformDateFuncRef: toRef(props, 'transformDateFunc') as Ref<Fn<any>>,
  126 + fieldMapToTimeRef: toRef(props, 'fieldMapToTime'),
  127 + defaultValueRef,
  128 + getSchema,
  129 + formModel,
  130 + });
420 131
421 - function getFieldsValue(): any {  
422 - const formEl = unref(formElRef);  
423 - if (!formEl) return;  
424 - return handleFormValues(toRaw(unref(formModel)));  
425 - } 132 + const {
  133 + // handleSubmit,
  134 + setFieldsValue,
  135 + clearValidate,
  136 + validate,
  137 + validateFields,
  138 + getFieldsValue,
  139 + updateSchema,
  140 + appendSchemaByField,
  141 + removeSchemaByFiled,
  142 + resetFields,
  143 + } = useFormAction({
  144 + emit,
  145 + getProps,
  146 + formModel,
  147 + getSchema,
  148 + defaultValueRef,
  149 + formElRef: formElRef as any,
  150 + schemaRef: schemaRef as any,
  151 + handleFormValues,
  152 + actionState,
  153 + });
426 154
427 - /**  
428 - * @description: 是否是时间  
429 - */  
430 - function itemIsDateType(key: string) {  
431 - return unref(getSchema).some((item) => {  
432 - return item.field === key ? dateItemType.includes(item.component!) : false;  
433 - });  
434 - } 155 + watchEffect(() => {
  156 + if (!unref(getMergePropsRef).model) return;
  157 + setFieldsValue(unref(getMergePropsRef).model);
  158 + });
435 159
436 /** 160 /**
437 * @description:设置表单 161 * @description:设置表单
@@ -441,21 +165,6 @@ @@ -441,21 +165,6 @@
441 propsRef.value = mergeProps; 165 propsRef.value = mergeProps;
442 } 166 }
443 167
444 - function validateFields(nameList?: NamePath[] | undefined) {  
445 - if (!formElRef.value) return;  
446 - return formElRef.value.validateFields(nameList);  
447 - }  
448 -  
449 - function validate(nameList?: NamePath[] | undefined) {  
450 - if (!formElRef.value) return;  
451 - return formElRef.value.validate(nameList);  
452 - }  
453 -  
454 - function clearValidate(name: string | string[]) {  
455 - if (!formElRef.value) return;  
456 - formElRef.value.clearValidate(name);  
457 - }  
458 -  
459 const methods: Partial<FormActionType> = { 168 const methods: Partial<FormActionType> = {
460 getFieldsValue, 169 getFieldsValue,
461 setFieldsValue, 170 setFieldsValue,
src/components/Form/src/FormAction.tsx
@@ -57,6 +57,7 @@ export default defineComponent({ @@ -57,6 +57,7 @@ export default defineComponent({
57 ...props.resetButtonOptions, 57 ...props.resetButtonOptions,
58 }; 58 };
59 }); 59 });
  60 +
60 const getSubmitBtnOptionsRef = computed(() => { 61 const getSubmitBtnOptionsRef = computed(() => {
61 return { 62 return {
62 text: '查询', 63 text: '查询',
@@ -80,10 +81,12 @@ export default defineComponent({ @@ -80,10 +81,12 @@ export default defineComponent({
80 function toggleAdvanced() { 81 function toggleAdvanced() {
81 emit('toggle-advanced'); 82 emit('toggle-advanced');
82 } 83 }
  84 +
83 return () => { 85 return () => {
84 if (!props.show) { 86 if (!props.show) {
85 return; 87 return;
86 } 88 }
  89 +
87 const { 90 const {
88 showAdvancedButton, 91 showAdvancedButton,
89 hideAdvanceBtn, 92 hideAdvanceBtn,
@@ -91,50 +94,49 @@ export default defineComponent({ @@ -91,50 +94,49 @@ export default defineComponent({
91 showResetButton, 94 showResetButton,
92 showSubmitButton, 95 showSubmitButton,
93 } = props; 96 } = props;
  97 +
94 return ( 98 return (
95 - <>  
96 - <Col {...unref(actionColOpt)} style={{ textAlign: 'right' }}>  
97 - {() => (  
98 - <Form.Item>  
99 - {() => (  
100 - <>  
101 - {getSlot(slots, 'advanceBefore')}  
102 - {showAdvancedButton && !hideAdvanceBtn && (  
103 - <Button type="default" class="mr-2" onClick={toggleAdvanced}>  
104 - {() => (  
105 - <>  
106 - {isAdvanced ? '收起' : '展开'}  
107 - {isAdvanced ? (  
108 - <UpOutlined class="advanced-icon" />  
109 - ) : (  
110 - <DownOutlined class="advanced-icon" />  
111 - )}  
112 - </>  
113 - )}  
114 - </Button>  
115 - )} 99 + <Col {...unref(actionColOpt)} style={{ textAlign: 'right' }}>
  100 + {() => (
  101 + <Form.Item>
  102 + {() => (
  103 + <>
  104 + {getSlot(slots, 'advanceBefore')}
  105 + {showAdvancedButton && !hideAdvanceBtn && (
  106 + <Button type="default" class="mr-2" onClick={toggleAdvanced}>
  107 + {() => (
  108 + <>
  109 + {isAdvanced ? '收起' : '展开'}
  110 + {isAdvanced ? (
  111 + <UpOutlined class="advanced-icon" />
  112 + ) : (
  113 + <DownOutlined class="advanced-icon" />
  114 + )}
  115 + </>
  116 + )}
  117 + </Button>
  118 + )}
116 119
117 - {getSlot(slots, 'resetBefore')}  
118 - {showResetButton && (  
119 - <Button type="default" class="mr-2" {...unref(getResetBtnOptionsRef)}>  
120 - {() => unref(getResetBtnOptionsRef).text}  
121 - </Button>  
122 - )} 120 + {getSlot(slots, 'resetBefore')}
  121 + {showResetButton && (
  122 + <Button type="default" class="mr-2" {...unref(getResetBtnOptionsRef)}>
  123 + {() => unref(getResetBtnOptionsRef).text}
  124 + </Button>
  125 + )}
123 126
124 - {getSlot(slots, 'submitBefore')}  
125 - {showSubmitButton && (  
126 - <Button type="primary" {...unref(getSubmitBtnOptionsRef)}>  
127 - {() => unref(getSubmitBtnOptionsRef).text}  
128 - </Button>  
129 - )} 127 + {getSlot(slots, 'submitBefore')}
  128 + {showSubmitButton && (
  129 + <Button type="primary" {...unref(getSubmitBtnOptionsRef)}>
  130 + {() => unref(getSubmitBtnOptionsRef).text}
  131 + </Button>
  132 + )}
130 133
131 - {getSlot(slots, 'submitAfter')}  
132 - </>  
133 - )}  
134 - </Form.Item>  
135 - )}  
136 - </Col>  
137 - </> 134 + {getSlot(slots, 'submitAfter')}
  135 + </>
  136 + )}
  137 + </Form.Item>
  138 + )}
  139 + </Col>
138 ); 140 );
139 }; 141 };
140 }, 142 },
src/components/Form/src/FormItem.tsx
  1 +import type { ValidationRule } from 'ant-design-vue/types/form/form';
  2 +import type { PropType } from 'vue';
  3 +import type { FormProps } from './types/form';
  4 +import type { FormSchema } from './types/form';
  5 +
1 import { defineComponent, computed, unref, toRef } from 'vue'; 6 import { defineComponent, computed, unref, toRef } from 'vue';
2 import { Form, Col } from 'ant-design-vue'; 7 import { Form, Col } from 'ant-design-vue';
3 import { componentMap } from './componentMap'; 8 import { componentMap } from './componentMap';
  9 +import { BasicHelp } from '/@/components/Basic';
4 10
5 -import type { PropType } from 'vue';  
6 -import type { FormProps } from './types/form';  
7 -import type { FormSchema } from './types/form';  
8 import { isBoolean, isFunction } from '/@/utils/is'; 11 import { isBoolean, isFunction } from '/@/utils/is';
9 -import { useItemLabelWidth } from './hooks/useLabelWidth';  
10 import { getSlot } from '/@/utils/helper/tsxHelper'; 12 import { getSlot } from '/@/utils/helper/tsxHelper';
11 -import { BasicHelp } from '/@/components/Basic';  
12 import { createPlaceholderMessage } from './helper'; 13 import { createPlaceholderMessage } from './helper';
13 import { upperFirst, cloneDeep } from 'lodash-es'; 14 import { upperFirst, cloneDeep } from 'lodash-es';
14 -import { ValidationRule } from 'ant-design-vue/types/form/form'; 15 +
  16 +import { useItemLabelWidth } from './hooks/useLabelWidth';
  17 +
15 export default defineComponent({ 18 export default defineComponent({
16 name: 'BasicFormItem', 19 name: 'BasicFormItem',
17 inheritAttrs: false, 20 inheritAttrs: false,
@@ -50,6 +53,7 @@ export default defineComponent({ @@ -50,6 +53,7 @@ export default defineComponent({
50 schema: schema, 53 schema: schema,
51 }; 54 };
52 }); 55 });
  56 +
53 const getShowRef = computed(() => { 57 const getShowRef = computed(() => {
54 const { show, ifShow, isAdvanced } = props.schema; 58 const { show, ifShow, isAdvanced } = props.schema;
55 const { showAdvancedButton } = props.formProps; 59 const { showAdvancedButton } = props.formProps;
@@ -226,6 +230,7 @@ export default defineComponent({ @@ -226,6 +230,7 @@ export default defineComponent({
226 </span> 230 </span>
227 ); 231 );
228 } 232 }
  233 +
229 function renderItem() { 234 function renderItem() {
230 const { itemProps, slot, render, field } = props.schema; 235 const { itemProps, slot, render, field } = props.schema;
231 const { labelCol, wrapperCol } = unref(itemLabelWidthRef); 236 const { labelCol, wrapperCol } = unref(itemLabelWidthRef);
@@ -255,11 +260,8 @@ export default defineComponent({ @@ -255,11 +260,8 @@ export default defineComponent({
255 const { colProps = {}, colSlot, renderColContent, component } = props.schema; 260 const { colProps = {}, colSlot, renderColContent, component } = props.schema;
256 if (!componentMap.has(component)) return null; 261 if (!componentMap.has(component)) return null;
257 const { baseColProps = {} } = props.formProps; 262 const { baseColProps = {} } = props.formProps;
258 -  
259 const realColProps = { ...baseColProps, ...colProps }; 263 const realColProps = { ...baseColProps, ...colProps };
260 -  
261 const { isIfShow, isShow } = unref(getShowRef); 264 const { isIfShow, isShow } = unref(getShowRef);
262 -  
263 const getContent = () => { 265 const getContent = () => {
264 return colSlot 266 return colSlot
265 ? getSlot(slots, colSlot) 267 ? getSlot(slots, colSlot)
src/components/Form/src/helper.ts
1 -import { ComponentType } from './types/index'; 1 +import type { ComponentType } from './types/index';
  2 +
2 /** 3 /**
3 * @description: 生成placeholder 4 * @description: 生成placeholder
4 */ 5 */
@@ -21,9 +22,11 @@ export function createPlaceholderMessage(component: ComponentType) { @@ -21,9 +22,11 @@ export function createPlaceholderMessage(component: ComponentType) {
21 } 22 }
22 return ''; 23 return '';
23 } 24 }
  25 +
24 function genType() { 26 function genType() {
25 return ['DatePicker', 'MonthPicker', 'RangePicker', 'WeekPicker', 'TimePicker']; 27 return ['DatePicker', 'MonthPicker', 'RangePicker', 'WeekPicker', 'TimePicker'];
26 } 28 }
  29 +
27 /** 30 /**
28 * 时间字段 31 * 时间字段
29 */ 32 */
src/components/Form/src/hooks/useAdvanced.ts 0 → 100644
  1 +import type { ColEx } from '../types';
  2 +import type { AdvanceState } from '../types/hooks';
  3 +import type { ComputedRef, Ref } from 'vue';
  4 +import type { FormProps, FormSchema } from '../types/form';
  5 +
  6 +import { computed, unref, watch } from 'vue';
  7 +import { isBoolean, isFunction, isNumber, isObject } from '/@/utils/is';
  8 +
  9 +import { useBreakpoint } from '/@/hooks/event/useBreakpoint';
  10 +
  11 +const BASIC_COL_LEN = 24;
  12 +
  13 +interface UseAdvancedContext {
  14 + advanceState: AdvanceState;
  15 + emit: EmitType;
  16 + getMergePropsRef: ComputedRef<FormProps>;
  17 + getProps: ComputedRef<FormProps>;
  18 + getSchema: ComputedRef<FormSchema[]>;
  19 + formModel: any;
  20 + defaultValueRef: Ref<any>;
  21 +}
  22 +
  23 +export default function ({
  24 + advanceState,
  25 + emit,
  26 + getMergePropsRef,
  27 + getProps,
  28 + getSchema,
  29 + formModel,
  30 + defaultValueRef,
  31 +}: UseAdvancedContext) {
  32 + const { realWidthRef, screenEnum, screenRef } = useBreakpoint();
  33 + const getEmptySpanRef = computed((): number => {
  34 + if (!advanceState.isAdvanced) {
  35 + return 0;
  36 + }
  37 + const emptySpan = unref(getMergePropsRef).emptySpan || 0;
  38 +
  39 + if (isNumber(emptySpan)) {
  40 + return emptySpan;
  41 + }
  42 + if (isObject(emptySpan)) {
  43 + const { span = 0 } = emptySpan;
  44 + const screen = unref(screenRef) as string;
  45 +
  46 + const screenSpan = (emptySpan as any)[screen.toLowerCase()];
  47 + return screenSpan || span || 0;
  48 + }
  49 + return 0;
  50 + });
  51 +
  52 + const getActionPropsRef = computed(() => {
  53 + const {
  54 + resetButtonOptions,
  55 + submitButtonOptions,
  56 + showActionButtonGroup,
  57 + showResetButton,
  58 + showSubmitButton,
  59 + showAdvancedButton,
  60 + actionColOptions,
  61 + } = unref(getProps);
  62 + return {
  63 + resetButtonOptions,
  64 + submitButtonOptions,
  65 + show: showActionButtonGroup,
  66 + showResetButton,
  67 + showSubmitButton,
  68 + showAdvancedButton,
  69 + actionColOptions,
  70 + };
  71 + });
  72 + watch(
  73 + [() => unref(getSchema), () => advanceState.isAdvanced, () => unref(realWidthRef)],
  74 + () => {
  75 + const { showAdvancedButton } = unref(getProps);
  76 + if (showAdvancedButton) {
  77 + updateAdvanced();
  78 + }
  79 + },
  80 + { immediate: true }
  81 + );
  82 +
  83 + function getAdvanced(itemCol: Partial<ColEx>, itemColSum = 0, isLastAction = false) {
  84 + const width = unref(realWidthRef);
  85 +
  86 + const mdWidth =
  87 + parseInt(itemCol.md as string) ||
  88 + parseInt(itemCol.xs as string) ||
  89 + parseInt(itemCol.sm as string) ||
  90 + (itemCol.span as number) ||
  91 + BASIC_COL_LEN;
  92 + const lgWidth = parseInt(itemCol.lg as string) || mdWidth;
  93 + const xlWidth = parseInt(itemCol.xl as string) || lgWidth;
  94 + const xxlWidth = parseInt(itemCol.xxl as string) || xlWidth;
  95 + if (width <= screenEnum.LG) {
  96 + itemColSum += mdWidth;
  97 + } else if (width < screenEnum.XL) {
  98 + itemColSum += lgWidth;
  99 + } else if (width < screenEnum.XXL) {
  100 + itemColSum += xlWidth;
  101 + } else {
  102 + itemColSum += xxlWidth;
  103 + }
  104 + if (isLastAction) {
  105 + advanceState.hideAdvanceBtn = false;
  106 + if (itemColSum <= BASIC_COL_LEN * 2) {
  107 + // 小于等于2行时,不显示收起展开按钮
  108 + advanceState.hideAdvanceBtn = true;
  109 + advanceState.isAdvanced = true;
  110 + } else if (
  111 + itemColSum > BASIC_COL_LEN * 2 &&
  112 + itemColSum <= BASIC_COL_LEN * (unref(getMergePropsRef).autoAdvancedLine || 3)
  113 + ) {
  114 + advanceState.hideAdvanceBtn = false;
  115 +
  116 + // 大于3行默认收起
  117 + } else if (!advanceState.isLoad) {
  118 + advanceState.isLoad = true;
  119 + advanceState.isAdvanced = !advanceState.isAdvanced;
  120 + }
  121 + return { isAdvanced: advanceState.isAdvanced, itemColSum };
  122 + }
  123 + if (itemColSum > BASIC_COL_LEN) {
  124 + return { isAdvanced: advanceState.isAdvanced, itemColSum };
  125 + } else {
  126 + // 第一行始终显示
  127 + return { isAdvanced: true, itemColSum };
  128 + }
  129 + }
  130 +
  131 + function updateAdvanced() {
  132 + let itemColSum = 0;
  133 + let realItemColSum = 0;
  134 + for (const schema of unref(getSchema)) {
  135 + const { show, colProps } = schema;
  136 + let isShow = true;
  137 +
  138 + if (isBoolean(show)) {
  139 + isShow = show;
  140 + }
  141 +
  142 + if (isFunction(show)) {
  143 + isShow = show({
  144 + schema: schema,
  145 + model: formModel,
  146 + field: schema.field,
  147 + values: {
  148 + ...unref(defaultValueRef),
  149 + ...formModel,
  150 + },
  151 + });
  152 + }
  153 +
  154 + if (isShow && colProps) {
  155 + const { itemColSum: sum, isAdvanced } = getAdvanced(colProps, itemColSum);
  156 +
  157 + itemColSum = sum || 0;
  158 + if (isAdvanced) {
  159 + realItemColSum = itemColSum;
  160 + }
  161 + schema.isAdvanced = isAdvanced;
  162 + }
  163 + }
  164 +
  165 + advanceState.actionSpan = (realItemColSum % BASIC_COL_LEN) + unref(getEmptySpanRef);
  166 +
  167 + getAdvanced(
  168 + unref(getActionPropsRef).actionColOptions || { span: BASIC_COL_LEN },
  169 + itemColSum,
  170 + true
  171 + );
  172 + emit('advanced-change');
  173 + }
  174 +
  175 + function handleToggleAdvanced() {
  176 + advanceState.isAdvanced = !advanceState.isAdvanced;
  177 + }
  178 + return { getActionPropsRef, handleToggleAdvanced };
  179 +}
src/components/Form/src/hooks/useComponentRegister.ts
  1 +import type { ComponentType } from '../types/index';
1 import { tryOnUnmounted } from '/@/utils/helper/vueHelper'; 2 import { tryOnUnmounted } from '/@/utils/helper/vueHelper';
2 import { add, del } from '../componentMap'; 3 import { add, del } from '../componentMap';
3 -  
4 -import { ComponentType } from '../types/index';  
5 export function useComponentRegister(compName: ComponentType, comp: any) { 4 export function useComponentRegister(compName: ComponentType, comp: any) {
6 add(compName, comp); 5 add(compName, comp);
7 tryOnUnmounted(() => { 6 tryOnUnmounted(() => {
src/components/Form/src/hooks/useForm.ts
1 import { ref, onUnmounted, unref } from 'vue'; 1 import { ref, onUnmounted, unref } from 'vue';
2 2
3 import { isInSetup } from '/@/utils/helper/vueHelper'; 3 import { isInSetup } from '/@/utils/helper/vueHelper';
  4 +import { isProdMode } from '/@/utils/env';
4 5
5 import type { FormProps, FormActionType, UseFormReturnType, FormSchema } from '../types/form'; 6 import type { FormProps, FormActionType, UseFormReturnType, FormSchema } from '../types/form';
6 -import { isProdMode } from '/@/utils/env';  
7 import type { NamePath } from 'ant-design-vue/types/form/form-item'; 7 import type { NamePath } from 'ant-design-vue/types/form/form-item';
8 import type { ValidateFields } from 'ant-design-vue/types/form/form'; 8 import type { ValidateFields } from 'ant-design-vue/types/form/form';
9 9
@@ -11,6 +11,7 @@ export function useForm(props?: Partial&lt;FormProps&gt;): UseFormReturnType { @@ -11,6 +11,7 @@ export function useForm(props?: Partial&lt;FormProps&gt;): UseFormReturnType {
11 isInSetup(); 11 isInSetup();
12 const formRef = ref<FormActionType | null>(null); 12 const formRef = ref<FormActionType | null>(null);
13 const loadedRef = ref<boolean | null>(false); 13 const loadedRef = ref<boolean | null>(false);
  14 +
14 function getForm() { 15 function getForm() {
15 const form = unref(formRef); 16 const form = unref(formRef);
16 if (!form) { 17 if (!form) {
src/components/Form/src/hooks/useFormAction.ts 0 → 100644
  1 +import type { ComputedRef, Ref } from 'vue';
  2 +import type { FormProps, FormSchema } from '../types/form';
  3 +import type { Form as FormType } from 'ant-design-vue/types/form/form';
  4 +import type { NamePath } from 'ant-design-vue/types/form/form-item';
  5 +
  6 +import { unref, toRaw } from 'vue';
  7 +
  8 +import { isArray, isFunction, isObject, isString } from '/@/utils/is';
  9 +import { deepMerge, unique } from '/@/utils';
  10 +import { dateItemType } from '../helper';
  11 +import moment from 'moment';
  12 +import { cloneDeep } from 'lodash-es';
  13 +
  14 +interface UseFormActionContext {
  15 + emit: EmitType;
  16 + getProps: ComputedRef<FormProps>;
  17 + getSchema: ComputedRef<FormSchema[]>;
  18 + formModel: any;
  19 + defaultValueRef: Ref<any>;
  20 + formElRef: Ref<FormType>;
  21 + schemaRef: Ref<FormSchema[]>;
  22 + handleFormValues: Fn;
  23 + actionState: {
  24 + resetAction: any;
  25 + submitAction: any;
  26 + };
  27 +}
  28 +export function useFormAction({
  29 + emit,
  30 + getProps,
  31 + formModel,
  32 + getSchema,
  33 + defaultValueRef,
  34 + formElRef,
  35 + schemaRef,
  36 + handleFormValues,
  37 + actionState,
  38 +}: UseFormActionContext) {
  39 + async function resetFields(): Promise<any> {
  40 + const { resetFunc, submitOnReset } = unref(getProps);
  41 + resetFunc && isFunction(resetFunc) && (await resetFunc());
  42 + const formEl = unref(formElRef);
  43 + if (!formEl) return;
  44 + Object.keys(formModel).forEach((key) => {
  45 + (formModel as any)[key] = defaultValueRef.value[key];
  46 + });
  47 + // @ts-ignore
  48 + // TODO 官方组件库类型定义错误,可以不传参数
  49 + formEl.clearValidate();
  50 + emit('reset', toRaw(formModel));
  51 + // return values;
  52 + submitOnReset && handleSubmit();
  53 + }
  54 +
  55 + /**
  56 + * @description: 设置表单值
  57 + */
  58 + async function setFieldsValue(values: any): Promise<void> {
  59 + const fields = unref(getSchema)
  60 + .map((item) => item.field)
  61 + .filter(Boolean);
  62 + const formEl = unref(formElRef);
  63 + Object.keys(values).forEach((key) => {
  64 + const element = values[key];
  65 + if (fields.includes(key) && element !== undefined && element !== null) {
  66 + // 时间
  67 + if (itemIsDateType(key)) {
  68 + if (Array.isArray(element)) {
  69 + const arr: any[] = [];
  70 + for (const ele of element) {
  71 + arr.push(moment(ele));
  72 + }
  73 + (formModel as any)[key] = arr;
  74 + } else {
  75 + (formModel as any)[key] = moment(element);
  76 + }
  77 + } else {
  78 + (formModel as any)[key] = element;
  79 + }
  80 + if (formEl) {
  81 + formEl.validateFields([key]);
  82 + }
  83 + }
  84 + });
  85 + }
  86 + /**
  87 + * @description: 根据字段名删除
  88 + */
  89 + function removeSchemaByFiled(fields: string | string[]): void {
  90 + const schemaList: FormSchema[] = cloneDeep(unref(getSchema));
  91 + if (!fields) {
  92 + return;
  93 + }
  94 + let fieldList: string[] = fields as string[];
  95 + if (isString(fields)) {
  96 + fieldList = [fields];
  97 + }
  98 + for (const field of fieldList) {
  99 + _removeSchemaByFiled(field, schemaList);
  100 + }
  101 + schemaRef.value = schemaList as any;
  102 + }
  103 +
  104 + /**
  105 + * @description: 根据字段名删除
  106 + */
  107 + function _removeSchemaByFiled(field: string, schemaList: FormSchema[]): void {
  108 + if (isString(field)) {
  109 + const index = schemaList.findIndex((schema) => schema.field === field);
  110 + if (index !== -1) {
  111 + schemaList.splice(index, 1);
  112 + }
  113 + }
  114 + }
  115 +
  116 + /**
  117 + * @description: 往某个字段后面插入,如果没有插入最后一个
  118 + */
  119 + function appendSchemaByField(schema: FormSchema, prefixField?: string) {
  120 + const schemaList: FormSchema[] = cloneDeep(unref(getSchema));
  121 +
  122 + const index = schemaList.findIndex((schema) => schema.field === prefixField);
  123 + const hasInList = schemaList.find((item) => item.field === schema.field);
  124 +
  125 + if (hasInList) {
  126 + return;
  127 + }
  128 + if (!prefixField || index === -1) {
  129 + schemaList.push(schema);
  130 + schemaRef.value = schemaList as any;
  131 + return;
  132 + }
  133 + if (index !== -1) {
  134 + schemaList.splice(index + 1, 0, schema);
  135 + }
  136 + schemaRef.value = schemaList as any;
  137 + }
  138 +
  139 + function updateSchema(data: Partial<FormSchema> | Partial<FormSchema>[]) {
  140 + let updateData: Partial<FormSchema>[] = [];
  141 + if (isObject(data)) {
  142 + updateData.push(data as FormSchema);
  143 + }
  144 + if (isArray(data)) {
  145 + updateData = [...data];
  146 + }
  147 + const hasField = updateData.every((item) => Reflect.has(item, 'field') && item.field);
  148 + if (!hasField) {
  149 + throw new Error('Must pass in the `field` field!');
  150 + }
  151 + const schema: FormSchema[] = [];
  152 + updateData.forEach((item) => {
  153 + unref(getSchema).forEach((val) => {
  154 + if (val.field === item.field) {
  155 + const newScheam = deepMerge(val, item);
  156 + schema.push(newScheam as FormSchema);
  157 + } else {
  158 + schema.push(val);
  159 + }
  160 + });
  161 + });
  162 + schemaRef.value = unique(schema, 'field') as any;
  163 + }
  164 +
  165 + function getFieldsValue(): any {
  166 + const formEl = unref(formElRef);
  167 + if (!formEl) return;
  168 + return handleFormValues(toRaw(unref(formModel)));
  169 + }
  170 +
  171 + /**
  172 + * @description: 是否是时间
  173 + */
  174 + function itemIsDateType(key: string) {
  175 + return unref(getSchema).some((item) => {
  176 + return item.field === key ? dateItemType.includes(item.component!) : false;
  177 + });
  178 + }
  179 +
  180 + function validateFields(nameList?: NamePath[] | undefined) {
  181 + if (!formElRef.value) return;
  182 + return formElRef.value.validateFields(nameList);
  183 + }
  184 +
  185 + function validate(nameList?: NamePath[] | undefined) {
  186 + if (!formElRef.value) return;
  187 + return formElRef.value.validate(nameList);
  188 + }
  189 +
  190 + function clearValidate(name: string | string[]) {
  191 + if (!formElRef.value) return;
  192 + formElRef.value.clearValidate(name);
  193 + }
  194 +
  195 + /**
  196 + * @description: 表单提交
  197 + */
  198 + async function handleSubmit(e?: Event): Promise<void> {
  199 + e && e.preventDefault();
  200 + const { submitFunc } = unref(getProps);
  201 + if (submitFunc && isFunction(submitFunc)) {
  202 + await submitFunc();
  203 + return;
  204 + }
  205 + const formEl = unref(formElRef);
  206 + if (!formEl) return;
  207 + try {
  208 + const values = await formEl.validate();
  209 + const res = handleFormValues(values);
  210 + emit('submit', res);
  211 + } catch (error) {}
  212 + }
  213 + actionState.resetAction = {
  214 + onClick: resetFields,
  215 + };
  216 +
  217 + actionState.submitAction = {
  218 + onClick: handleSubmit,
  219 + };
  220 +
  221 + return {
  222 + handleSubmit,
  223 + clearValidate,
  224 + validate,
  225 + validateFields,
  226 + getFieldsValue,
  227 + updateSchema,
  228 + appendSchemaByField,
  229 + removeSchemaByFiled,
  230 + resetFields,
  231 + setFieldsValue,
  232 + };
  233 +}
src/components/Form/src/hooks/useFormValues.ts
1 import { isArray, isFunction, isObject, isString } from '/@/utils/is'; 1 import { isArray, isFunction, isObject, isString } from '/@/utils/is';
2 import moment from 'moment'; 2 import moment from 'moment';
3 import { unref } from 'vue'; 3 import { unref } from 'vue';
4 -import type { Ref } from 'vue';  
5 -import type { FieldMapToTime } from '../types/form'; 4 +import type { Ref, ComputedRef } from 'vue';
  5 +import type { FieldMapToTime, FormSchema } from '../types/form';
6 6
7 -export function useFormValues(  
8 - transformDateFuncRef: Ref<Fn>,  
9 - fieldMapToTimeRef: Ref<FieldMapToTime>  
10 -) { 7 +interface UseFormValuesContext {
  8 + transformDateFuncRef: Ref<Fn>;
  9 + fieldMapToTimeRef: Ref<FieldMapToTime>;
  10 + defaultValueRef: Ref<any>;
  11 + getSchema: ComputedRef<FormSchema[]>;
  12 + formModel: any;
  13 +}
  14 +export function useFormValues({
  15 + transformDateFuncRef,
  16 + fieldMapToTimeRef,
  17 + defaultValueRef,
  18 + getSchema,
  19 + formModel,
  20 +}: UseFormValuesContext) {
11 // 处理表单值 21 // 处理表单值
12 function handleFormValues(values: any) { 22 function handleFormValues(values: any) {
13 if (!isObject(values)) { 23 if (!isObject(values)) {
@@ -35,6 +45,7 @@ export function useFormValues( @@ -35,6 +45,7 @@ export function useFormValues(
35 } 45 }
36 return handleRangeTimeValue(resMap); 46 return handleRangeTimeValue(resMap);
37 } 47 }
  48 +
38 /** 49 /**
39 * @description: 处理时间区间参数 50 * @description: 处理时间区间参数
40 */ 51 */
@@ -58,5 +69,18 @@ export function useFormValues( @@ -58,5 +69,18 @@ export function useFormValues(
58 69
59 return values; 70 return values;
60 } 71 }
61 - return handleFormValues; 72 +
  73 + function initDefault() {
  74 + const schemas = unref(getSchema);
  75 + const obj: any = {};
  76 + schemas.forEach((item) => {
  77 + if (item.defaultValue) {
  78 + obj[item.field] = item.defaultValue;
  79 + (formModel as any)[item.field] = item.defaultValue;
  80 + }
  81 + });
  82 + defaultValueRef.value = obj;
  83 + }
  84 +
  85 + return { handleFormValues, initDefault };
62 } 86 }
src/components/Form/src/props.ts
@@ -3,6 +3,10 @@ import type { PropType } from &#39;vue&#39;; @@ -3,6 +3,10 @@ import type { PropType } from &#39;vue&#39;;
3 import type { ColEx } from './types'; 3 import type { ColEx } from './types';
4 4
5 export const basicProps = { 5 export const basicProps = {
  6 + model: {
  7 + type: Object as PropType<any>,
  8 + default: {},
  9 + },
6 // 标签宽度 固定宽度 10 // 标签宽度 固定宽度
7 labelWidth: { 11 labelWidth: {
8 type: [Number, String] as PropType<number | string>, 12 type: [Number, String] as PropType<number | string>,
src/components/Form/src/types/form.ts
@@ -35,6 +35,8 @@ export type RegisterFn = (formInstance: FormActionType) =&gt; void; @@ -35,6 +35,8 @@ export type RegisterFn = (formInstance: FormActionType) =&gt; void;
35 export type UseFormReturnType = [RegisterFn, FormActionType]; 35 export type UseFormReturnType = [RegisterFn, FormActionType];
36 36
37 export interface FormProps { 37 export interface FormProps {
  38 + // 表单值
  39 + model?: any;
38 // 整个表单所有项宽度 40 // 整个表单所有项宽度
39 labelWidth?: number | string; 41 labelWidth?: number | string;
40 // 重置时提交 42 // 重置时提交
src/components/Form/src/types/hooks.ts 0 → 100644
  1 +export interface AdvanceState {
  2 + isAdvanced: boolean;
  3 + hideAdvanceBtn: boolean;
  4 + isLoad: boolean;
  5 + actionSpan: number;
  6 +}
src/components/Modal/src/ModalWrapper.tsx
@@ -15,13 +15,12 @@ import { @@ -15,13 +15,12 @@ import {
15 import { Spin } from 'ant-design-vue'; 15 import { Spin } from 'ant-design-vue';
16 16
17 import { useWindowSizeFn } from '/@/hooks/event/useWindowSize'; 17 import { useWindowSizeFn } from '/@/hooks/event/useWindowSize';
18 -// import { useTimeout } from '/@/hooks/core/useTimeout'; 18 +import { useTimeout } from '/@/hooks/core/useTimeout';
19 19
20 import { getSlot } from '/@/utils/helper/tsxHelper'; 20 import { getSlot } from '/@/utils/helper/tsxHelper';
21 import { useElResize } from '/@/hooks/event/useElResize'; 21 import { useElResize } from '/@/hooks/event/useElResize';
22 export default defineComponent({ 22 export default defineComponent({
23 name: 'ModalWrapper', 23 name: 'ModalWrapper',
24 - emits: ['heightChange', 'getExtHeight'],  
25 props: { 24 props: {
26 loading: { 25 loading: {
27 type: Boolean as PropType<boolean>, 26 type: Boolean as PropType<boolean>,
@@ -52,6 +51,7 @@ export default defineComponent({ @@ -52,6 +51,7 @@ export default defineComponent({
52 default: false, 51 default: false,
53 }, 52 },
54 }, 53 },
  54 + emits: ['heightChange', 'getExtHeight'],
55 setup(props: ModalWrapperProps, { slots, emit }) { 55 setup(props: ModalWrapperProps, { slots, emit }) {
56 const wrapperRef = ref<HTMLElement | null>(null); 56 const wrapperRef = ref<HTMLElement | null>(null);
57 const spinRef = ref<any>(null); 57 const spinRef = ref<any>(null);
@@ -66,7 +66,7 @@ export default defineComponent({ @@ -66,7 +66,7 @@ export default defineComponent({
66 }); 66 });
67 67
68 // 重试次数 68 // 重试次数
69 - // let tryCount = 0; 69 + let tryCount = 0;
70 let stopElResizeFn: Fn = () => {}; 70 let stopElResizeFn: Fn = () => {};
71 71
72 watchEffect(() => { 72 watchEffect(() => {
@@ -123,17 +123,17 @@ export default defineComponent({ @@ -123,17 +123,17 @@ export default defineComponent({
123 } 123 }
124 await nextTick(); 124 await nextTick();
125 const spinEl = unref(spinRef); 125 const spinEl = unref(spinRef);
126 - // if (!spinEl) {  
127 - // useTimeout(() => {  
128 - // // retry  
129 - // if (tryCount < 3) {  
130 - // setModalHeight();  
131 - // }  
132 - // tryCount++;  
133 - // }, 10);  
134 - // return;  
135 - // }  
136 - // tryCount = 0; 126 + if (!spinEl) {
  127 + useTimeout(() => {
  128 + // retry
  129 + if (tryCount < 3) {
  130 + setModalHeight();
  131 + }
  132 + tryCount++;
  133 + }, 10);
  134 + return;
  135 + }
  136 + tryCount = 0;
137 137
138 const spinContainerEl = spinEl.$el.querySelector('.ant-spin-container') as HTMLElement; 138 const spinContainerEl = spinEl.$el.querySelector('.ant-spin-container') as HTMLElement;
139 if (!spinContainerEl) return; 139 if (!spinContainerEl) return;
@@ -142,7 +142,7 @@ export default defineComponent({ @@ -142,7 +142,7 @@ export default defineComponent({
142 142
143 if (props.fullScreen) { 143 if (props.fullScreen) {
144 realHeightRef.value = 144 realHeightRef.value =
145 - window.innerHeight - props.modalFooterHeight - props.modalHeaderHeight - 26; 145 + window.innerHeight - props.modalFooterHeight - props.modalHeaderHeight - 6;
146 } else { 146 } else {
147 realHeightRef.value = realHeight > maxHeight ? maxHeight : realHeight + 16 + 30; 147 realHeightRef.value = realHeight > maxHeight ? maxHeight : realHeight + 16 + 30;
148 } 148 }
src/components/Modal/src/useModal.ts
@@ -5,8 +5,9 @@ import type { @@ -5,8 +5,9 @@ import type {
5 ReturnMethods, 5 ReturnMethods,
6 UseModalInnerReturnType, 6 UseModalInnerReturnType,
7 } from './types'; 7 } from './types';
8 -import { ref, onUnmounted, unref, getCurrentInstance, reactive, computed } from 'vue'; 8 +import { ref, onUnmounted, unref, getCurrentInstance, reactive, computed, watchEffect } from 'vue';
9 import { isProdMode } from '/@/utils/env'; 9 import { isProdMode } from '/@/utils/env';
  10 +import { isFunction } from '/@/utils/is';
10 const dataTransferRef = reactive<any>({}); 11 const dataTransferRef = reactive<any>({});
11 12
12 /** 13 /**
@@ -58,7 +59,7 @@ export function useModal(): UseModalReturnType { @@ -58,7 +59,7 @@ export function useModal(): UseModalReturnType {
58 return [register, methods]; 59 return [register, methods];
59 } 60 }
60 61
61 -export const useModalInner = (): UseModalInnerReturnType => { 62 +export const useModalInner = (callbackFn?: Fn): UseModalInnerReturnType => {
62 const modalInstanceRef = ref<ModalMethods | null>(null); 63 const modalInstanceRef = ref<ModalMethods | null>(null);
63 const currentInstall = getCurrentInstance(); 64 const currentInstall = getCurrentInstance();
64 const uidRef = ref<string>(''); 65 const uidRef = ref<string>('');
@@ -81,6 +82,13 @@ export const useModalInner = (): UseModalInnerReturnType =&gt; { @@ -81,6 +82,13 @@ export const useModalInner = (): UseModalInnerReturnType =&gt; {
81 currentInstall.emit('register', modalInstance); 82 currentInstall.emit('register', modalInstance);
82 }; 83 };
83 84
  85 + watchEffect(() => {
  86 + const data = dataTransferRef[unref(uidRef)];
  87 + if (!data) return;
  88 + if (!callbackFn || !isFunction(callbackFn)) return;
  89 + callbackFn(data);
  90 + });
  91 +
84 return [ 92 return [
85 register, 93 register,
86 { 94 {
src/views/demo/comp/modal/Modal4.vue
1 <template> 1 <template>
2 <BasicModal v-bind="$attrs" @register="register" title="Modal Title"> 2 <BasicModal v-bind="$attrs" @register="register" title="Modal Title">
3 <p class="h-20">外部传递数据: {{ receiveModalDataRef }}</p> 3 <p class="h-20">外部传递数据: {{ receiveModalDataRef }}</p>
  4 + <BasicForm @register="registerForm" :model="model" />
4 </BasicModal> 5 </BasicModal>
5 </template> 6 </template>
6 <script lang="ts"> 7 <script lang="ts">
7 - import { defineComponent } from 'vue'; 8 + import { defineComponent, nextTick, ref } from 'vue';
8 import { BasicModal, useModalInner } from '/@/components/Modal'; 9 import { BasicModal, useModalInner } from '/@/components/Modal';
  10 + import { BasicForm, FormSchema, useForm } from '/@/components/Form/index';
  11 + const schemas: FormSchema[] = [
  12 + {
  13 + field: 'field1',
  14 + component: 'Input',
  15 + label: '字段1',
  16 + colProps: {
  17 + span: 12,
  18 + },
  19 + defaultValue: '111',
  20 + },
  21 + {
  22 + field: 'field2',
  23 + component: 'Input',
  24 + label: '字段2',
  25 + colProps: {
  26 + span: 12,
  27 + },
  28 + },
  29 + ];
9 export default defineComponent({ 30 export default defineComponent({
10 - components: { BasicModal }, 31 + components: { BasicModal, BasicForm },
11 setup() { 32 setup() {
12 - const [register, { receiveModalDataRef }] = useModalInner();  
13 - return { register, receiveModalDataRef }; 33 + const modelRef = ref({});
  34 + const [
  35 + registerForm,
  36 + {
  37 + // setFieldsValue,
  38 + // setProps
  39 + },
  40 + ] = useForm({
  41 + labelWidth: 120,
  42 + schemas,
  43 + showActionButtonGroup: false,
  44 + actionColOptions: {
  45 + span: 24,
  46 + },
  47 + });
  48 +
  49 + const [register, { receiveModalDataRef }] = useModalInner((data) => {
  50 + nextTick(() => {
  51 + // 方式1
  52 + // setFieldsValue({
  53 + // field2: data.data,
  54 + // field1: data.info,
  55 + // });
  56 +
  57 + // 方式2
  58 + modelRef.value = { field2: data.data, field1: data.info };
  59 +
  60 + // setProps({
  61 + // model:{ field2: data.data, field1: data.info }
  62 + // })
  63 + });
  64 + });
  65 + return { register, receiveModalDataRef, schemas, registerForm, model: modelRef };
14 }, 66 },
15 }); 67 });
16 </script> 68 </script>
src/views/demo/comp/modal/index.vue
@@ -48,6 +48,12 @@ @@ -48,6 +48,12 @@
48 data: 'content', 48 data: 'content',
49 info: 'Info', 49 info: 'Info',
50 }); 50 });
  51 + // setTimeout(() => {
  52 + // transferModalData({
  53 + // data: 'content1',
  54 + // info: 'Info1',
  55 + // });
  56 + // }, 3000);
51 openModal4(true); 57 openModal4(true);
52 } 58 }
53 function openModalLoading() { 59 function openModalLoading() {