perf: formApi added validateAndSubmitForm & filedMapToTime renamed fieldMappingTime (#4842)
* perf: formApi added validateAndSubmitForm & filedMapToTime renamed fieldMappingTimepull/48/MERGE
							parent
							
								
									632081e828
								
							
						
					
					
						commit
						8617d3dd1e
					
				|  | @ -280,6 +280,7 @@ useVbenForm 返回的第二个参数,是一个对象,包含了一些表单 | |||
| | 方法名 | 描述 | 类型 | | ||||
| | --- | --- | --- | | ||||
| | submitForm | 提交表单 | `(e:Event)=>Promise<Record<string,any>>` | | ||||
| | validateAndSubmitForm | 提交并校验表单 | `(e:Event)=>Promise<Record<string,any>>` | | ||||
| | resetForm | 重置表单 | `()=>Promise<void>` | | ||||
| | setValues | 设置表单值, 默认会过滤不在schema中定义的field, 可通过filterFields形参关闭过滤 | `(fields: Record<string, any>, filterFields?: boolean, shouldValidate?: boolean) => Promise<void>` | | ||||
| | getValues | 获取表单值 | `(fields:Record<string, any>,shouldValidate: boolean = false)=>Promise<void>` | | ||||
|  | @ -309,6 +310,7 @@ useVbenForm 返回的第二个参数,是一个对象,包含了一些表单 | |||
| | collapsed | 是否折叠,在`是否展开,在showCollapseButton=true`时生效 | `boolean` | `false` | | ||||
| | collapseTriggerResize | 折叠时,触发`resize`事件 | `boolean` | `false` | | ||||
| | collapsedRows | 折叠时保持的行数 | `number` | `1` | | ||||
| | fieldMappingTime | 用于将表单内时间区域的应设成 2 个字段 | `[string, [string, string], string?][]` | - | | ||||
| | commonConfig | 表单项的通用配置,每个配置都会传递到每个表单项,表单项可覆盖 | `FormCommonConfig` | - | | ||||
| | schema | 表单项的每一项配置 | `FormSchema` | - | | ||||
| | submitOnEnter | 按下回车健时提交表单 | `boolean` | false | | ||||
|  |  | |||
|  | @ -84,6 +84,7 @@ | |||
|     "@types/lodash.get": "catalog:", | ||||
|     "@vue/shared": "catalog:", | ||||
|     "clsx": "catalog:", | ||||
|     "dayjs": "^1.11.13", | ||||
|     "defu": "catalog:", | ||||
|     "lodash.clonedeep": "catalog:", | ||||
|     "lodash.get": "catalog:", | ||||
|  |  | |||
|  | @ -0,0 +1,18 @@ | |||
| import dayjs from 'dayjs'; | ||||
| 
 | ||||
| export function formatDate(time: number | string, format = 'YYYY-MM-DD') { | ||||
|   try { | ||||
|     const date = dayjs(time); | ||||
|     if (!date.isValid()) { | ||||
|       throw new Error('Invalid date'); | ||||
|     } | ||||
|     return date.format(format); | ||||
|   } catch (error) { | ||||
|     console.error(`Error formatting date: ${error}`); | ||||
|     return time; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| export function formatDateTime(time: number | string) { | ||||
|   return formatDate(time, 'YYYY-MM-DD HH:mm:ss'); | ||||
| } | ||||
|  | @ -1,4 +1,5 @@ | |||
| export * from './cn'; | ||||
| export * from './date'; | ||||
| export * from './diff'; | ||||
| export * from './dom'; | ||||
| export * from './inference'; | ||||
|  |  | |||
|  | @ -3,7 +3,12 @@ import { computed, toRaw, unref, watch } from 'vue'; | |||
| 
 | ||||
| import { useSimpleLocale } from '@vben-core/composables'; | ||||
| import { VbenExpandableArrow } from '@vben-core/shadcn-ui'; | ||||
| import { cn, isFunction, triggerWindowResize } from '@vben-core/shared/utils'; | ||||
| import { | ||||
|   cn, | ||||
|   formatDate, | ||||
|   isFunction, | ||||
|   triggerWindowResize, | ||||
| } from '@vben-core/shared/utils'; | ||||
| 
 | ||||
| import { COMPONENT_MAP } from '../config'; | ||||
| import { injectFormProps } from '../use-form-context'; | ||||
|  | @ -64,8 +69,8 @@ async function handleReset(e: Event) { | |||
| 
 | ||||
|   const values = toRaw(form.values); | ||||
|   // 清理时间字段 | ||||
|   props.fieldMapToTime && | ||||
|     props.fieldMapToTime.forEach(([_, [startTimeKey, endTimeKey]]) => { | ||||
|   props.fieldMappingTime && | ||||
|     props.fieldMappingTime.forEach(([_, [startTimeKey, endTimeKey]]) => { | ||||
|       delete values[startTimeKey]; | ||||
|       delete values[endTimeKey]; | ||||
|     }); | ||||
|  | @ -78,15 +83,13 @@ async function handleReset(e: Event) { | |||
| } | ||||
| 
 | ||||
| function handleRangeTimeValue(values: Record<string, any>) { | ||||
|   const fieldMapToTime = unref(rootProps).fieldMapToTime; | ||||
|   const fieldMappingTime = unref(rootProps).fieldMappingTime; | ||||
| 
 | ||||
|   if (!fieldMapToTime) return values; | ||||
| 
 | ||||
|   if (!Array.isArray(fieldMapToTime)) { | ||||
|   if (!fieldMappingTime || !Array.isArray(fieldMappingTime)) { | ||||
|     return values; | ||||
|   } | ||||
| 
 | ||||
|   fieldMapToTime.forEach( | ||||
|   fieldMappingTime.forEach( | ||||
|     ([field, [startTimeKey, endTimeKey], format = 'YYYY-MM-DD']) => { | ||||
|       if (!values[field]) { | ||||
|         delete values[field]; | ||||
|  | @ -99,10 +102,10 @@ function handleRangeTimeValue(values: Record<string, any>) { | |||
|         : [format, format]; | ||||
| 
 | ||||
|       values[startTimeKey] = startTime | ||||
|         ? formatTime(startTime, startTimeFormat) | ||||
|         ? formatDate(startTime, startTimeFormat) | ||||
|         : undefined; | ||||
|       values[endTimeKey] = endTime | ||||
|         ? formatTime(endTime, endTimeFormat) | ||||
|         ? formatDate(endTime, endTimeFormat) | ||||
|         : undefined; | ||||
| 
 | ||||
|       delete values[field]; | ||||
|  | @ -112,32 +115,6 @@ function handleRangeTimeValue(values: Record<string, any>) { | |||
|   return values; | ||||
| } | ||||
| 
 | ||||
| function formatTime(time: string, format: string): number | string { | ||||
|   const date = new Date(time); | ||||
|   const timestamp = (date: Date) => Math.floor(date.getTime() / 1000); | ||||
| 
 | ||||
|   if (format === 'timestamp') return timestamp(date); | ||||
|   if (format === 'timestampStartDay') | ||||
|     return timestamp( | ||||
|       new Date(date.getFullYear(), date.getMonth(), date.getDate()), | ||||
|     ); | ||||
| 
 | ||||
|   const padZero = (num: number) => num.toString().padStart(2, '0'); | ||||
|   const replacements: Record<string, string> = { | ||||
|     DD: padZero(date.getDate()), | ||||
|     HH: padZero(date.getHours()), | ||||
|     MM: padZero(date.getMonth() + 1), | ||||
|     mm: padZero(date.getMinutes()), | ||||
|     ss: padZero(date.getSeconds()), | ||||
|     YYYY: date.getFullYear().toString(), | ||||
|   }; | ||||
| 
 | ||||
|   return format.replaceAll( | ||||
|     /YYYY|MM|DD|HH|mm|ss/g, | ||||
|     (match) => replacements[match] || match, | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
| watch( | ||||
|   () => collapsed.value, | ||||
|   () => { | ||||
|  |  | |||
|  | @ -303,4 +303,13 @@ export class FormApi { | |||
|     } | ||||
|     return validateResult; | ||||
|   } | ||||
| 
 | ||||
|   async validateAndSubmitForm() { | ||||
|     const form = await this.getForm(); | ||||
|     const { valid } = await form.validate(); | ||||
|     if (!valid) { | ||||
|       return; | ||||
|     } | ||||
|     return await this.submitForm(); | ||||
|   } | ||||
| } | ||||
|  |  | |||
|  | @ -206,7 +206,7 @@ export type HandleResetFn = ( | |||
|   values: Record<string, any>, | ||||
| ) => Promise<void> | void; | ||||
| 
 | ||||
| export type FieldMapToTime = [ | ||||
| export type FieldMappingTime = [ | ||||
|   string, | ||||
|   [string, string], | ||||
|   ([string, string] | string)?, | ||||
|  | @ -272,10 +272,6 @@ export interface FormRenderProps< | |||
|    * 组件集合 | ||||
|    */ | ||||
|   componentMap: Record<BaseFormComponentType, Component>; | ||||
|   /** | ||||
|    * 表单字段映射成时间格式 | ||||
|    */ | ||||
|   fieldMapToTime?: FieldMapToTime; | ||||
|   /** | ||||
|    * 表单实例 | ||||
|    */ | ||||
|  | @ -315,6 +311,10 @@ export interface VbenFormProps< | |||
|    * 表单操作区域class | ||||
|    */ | ||||
|   actionWrapperClass?: ClassType; | ||||
|   /** | ||||
|    * 表单字段映射成时间格式 | ||||
|    */ | ||||
|   fieldMappingTime?: FieldMappingTime; | ||||
|   /** | ||||
|    * 表单重置回调 | ||||
|    */ | ||||
|  |  | |||
|  | @ -2,9 +2,7 @@ import type { VxeGridProps, VxeUIExport } from 'vxe-table'; | |||
| 
 | ||||
| import type { VxeGridApi } from './api'; | ||||
| 
 | ||||
| import { isFunction } from '@vben/utils'; | ||||
| 
 | ||||
| import dayjs from 'dayjs'; | ||||
| import { formatDate, formatDateTime, isFunction } from '@vben/utils'; | ||||
| 
 | ||||
| export function extendProxyOptions( | ||||
|   api: VxeGridApi, | ||||
|  | @ -54,13 +52,13 @@ function extendProxyOption( | |||
| export function extendsDefaultFormatter(vxeUI: VxeUIExport) { | ||||
|   vxeUI.formats.add('formatDate', { | ||||
|     tableCellFormatMethod({ cellValue }) { | ||||
|       return dayjs(cellValue).format('YYYY-MM-DD'); | ||||
|       return formatDate(cellValue); | ||||
|     }, | ||||
|   }); | ||||
| 
 | ||||
|   vxeUI.formats.add('formatDateTime', { | ||||
|     tableCellFormatMethod({ cellValue }) { | ||||
|       return dayjs(cellValue).format('YYYY-MM-DD HH:mm:ss'); | ||||
|       return formatDateTime(cellValue); | ||||
|     }, | ||||
|   }); | ||||
| } | ||||
|  |  | |||
|  | @ -16,9 +16,10 @@ const [BaseForm, baseFormApi] = useVbenForm({ | |||
|       class: 'w-full', | ||||
|     }, | ||||
|   }, | ||||
| 
 | ||||
|   fieldMappingTime: [['rangePicker', ['startTime', 'endTime'], 'YYYY-MM-DD']], | ||||
|   // 提交函数 | ||||
|   handleSubmit: onSubmit, | ||||
| 
 | ||||
|   // 垂直布局,label和input在不同行,值为vertical | ||||
|   // 水平布局,label和input在同一行 | ||||
|   layout: 'horizontal', | ||||
|  |  | |||
|  | @ -57,8 +57,8 @@ const [Modal, modalApi] = useVbenModal({ | |||
|     modalApi.close(); | ||||
|   }, | ||||
|   onConfirm: async () => { | ||||
|     await formApi.submitForm(); | ||||
|     modalApi.close(); | ||||
|     await formApi.validateAndSubmitForm(); | ||||
|     // modalApi.close(); | ||||
|   }, | ||||
|   onOpenChange(isOpen: boolean) { | ||||
|     if (isOpen) { | ||||
|  | @ -8,7 +8,7 @@ import AutoHeightDemo from './auto-height-demo.vue'; | |||
| import BaseDemo from './base-demo.vue'; | ||||
| import DragDemo from './drag-demo.vue'; | ||||
| import DynamicDemo from './dynamic-demo.vue'; | ||||
| import FormModalDemo from './form-model-demo.vue'; | ||||
| import FormModalDemo from './form-modal-demo.vue'; | ||||
| import SharedDataDemo from './shared-data-demo.vue'; | ||||
| 
 | ||||
| const [BaseModal, baseModalApi] = useVbenModal({ | ||||
|  |  | |||
|  | @ -21,7 +21,6 @@ interface RowType { | |||
| const formOptions: VbenFormProps = { | ||||
|   // 默认展开 | ||||
|   collapsed: false, | ||||
|   fieldMapToTime: [['dateRangePicker', ['startTime', 'endTime'], 'YYYY-MM']], | ||||
|   schema: [ | ||||
|     { | ||||
|       component: 'Input', | ||||
|  | @ -63,11 +62,6 @@ const formOptions: VbenFormProps = { | |||
|       fieldName: 'datePicker', | ||||
|       label: 'Date', | ||||
|     }, | ||||
|     { | ||||
|       component: 'RangePicker', | ||||
|       fieldName: 'dateRangePicker', | ||||
|       label: 'DateRange', | ||||
|     }, | ||||
|   ], | ||||
|   // 控制表单是否显示折叠按钮 | ||||
|   showCollapseButton: true, | ||||
|  |  | |||
|  | @ -1209,6 +1209,9 @@ importers: | |||
|       clsx: | ||||
|         specifier: ^2.1.1 | ||||
|         version: 2.1.1 | ||||
|       dayjs: | ||||
|         specifier: ^1.11.13 | ||||
|         version: 1.11.13 | ||||
|       defu: | ||||
|         specifier: 'catalog:' | ||||
|         version: 6.1.4 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Vben
						Vben