From 8617d3dd1e65077c92c0308164ca6cdca7211e14 Mon Sep 17 00:00:00 2001 From: Vben Date: Sat, 9 Nov 2024 15:00:59 +0800 Subject: [PATCH] perf: formApi added validateAndSubmitForm & filedMapToTime renamed fieldMappingTime (#4842) * perf: formApi added validateAndSubmitForm & filedMapToTime renamed fieldMappingTime --- docs/src/components/common-ui/vben-form.md | 2 + packages/@core/base/shared/package.json | 1 + packages/@core/base/shared/src/utils/date.ts | 18 +++++++ packages/@core/base/shared/src/utils/index.ts | 1 + .../form-ui/src/components/form-actions.vue | 49 +++++-------------- packages/@core/ui-kit/form-ui/src/form-api.ts | 9 ++++ packages/@core/ui-kit/form-ui/src/types.ts | 10 ++-- .../effects/plugins/src/vxe-table/extends.ts | 8 ++- playground/src/views/examples/form/basic.vue | 3 +- ...orm-model-demo.vue => form-modal-demo.vue} | 4 +- playground/src/views/examples/modal/index.vue | 2 +- .../src/views/examples/vxe-table/form.vue | 6 --- pnpm-lock.yaml | 3 ++ 13 files changed, 60 insertions(+), 56 deletions(-) create mode 100644 packages/@core/base/shared/src/utils/date.ts rename playground/src/views/examples/modal/{form-model-demo.vue => form-modal-demo.vue} (95%) diff --git a/docs/src/components/common-ui/vben-form.md b/docs/src/components/common-ui/vben-form.md index f881cfb1b..0ed4db404 100644 --- a/docs/src/components/common-ui/vben-form.md +++ b/docs/src/components/common-ui/vben-form.md @@ -280,6 +280,7 @@ useVbenForm 返回的第二个参数,是一个对象,包含了一些表单 | 方法名 | 描述 | 类型 | | --- | --- | --- | | submitForm | 提交表单 | `(e:Event)=>Promise>` | +| validateAndSubmitForm | 提交并校验表单 | `(e:Event)=>Promise>` | | resetForm | 重置表单 | `()=>Promise` | | setValues | 设置表单值, 默认会过滤不在schema中定义的field, 可通过filterFields形参关闭过滤 | `(fields: Record, filterFields?: boolean, shouldValidate?: boolean) => Promise` | | getValues | 获取表单值 | `(fields:Record,shouldValidate: boolean = false)=>Promise` | @@ -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 | diff --git a/packages/@core/base/shared/package.json b/packages/@core/base/shared/package.json index 6541b7772..d83006ee5 100644 --- a/packages/@core/base/shared/package.json +++ b/packages/@core/base/shared/package.json @@ -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:", diff --git a/packages/@core/base/shared/src/utils/date.ts b/packages/@core/base/shared/src/utils/date.ts new file mode 100644 index 000000000..522e99465 --- /dev/null +++ b/packages/@core/base/shared/src/utils/date.ts @@ -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'); +} diff --git a/packages/@core/base/shared/src/utils/index.ts b/packages/@core/base/shared/src/utils/index.ts index e5526edf0..8b8da01bd 100644 --- a/packages/@core/base/shared/src/utils/index.ts +++ b/packages/@core/base/shared/src/utils/index.ts @@ -1,4 +1,5 @@ export * from './cn'; +export * from './date'; export * from './diff'; export * from './dom'; export * from './inference'; diff --git a/packages/@core/ui-kit/form-ui/src/components/form-actions.vue b/packages/@core/ui-kit/form-ui/src/components/form-actions.vue index 0904fd6cb..0a713567f 100644 --- a/packages/@core/ui-kit/form-ui/src/components/form-actions.vue +++ b/packages/@core/ui-kit/form-ui/src/components/form-actions.vue @@ -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) { - 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) { : [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) { 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 = { - 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, () => { diff --git a/packages/@core/ui-kit/form-ui/src/form-api.ts b/packages/@core/ui-kit/form-ui/src/form-api.ts index 55adca4fb..a834a2828 100644 --- a/packages/@core/ui-kit/form-ui/src/form-api.ts +++ b/packages/@core/ui-kit/form-ui/src/form-api.ts @@ -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(); + } } diff --git a/packages/@core/ui-kit/form-ui/src/types.ts b/packages/@core/ui-kit/form-ui/src/types.ts index 9d2b28074..5855ccc60 100644 --- a/packages/@core/ui-kit/form-ui/src/types.ts +++ b/packages/@core/ui-kit/form-ui/src/types.ts @@ -206,7 +206,7 @@ export type HandleResetFn = ( values: Record, ) => Promise | void; -export type FieldMapToTime = [ +export type FieldMappingTime = [ string, [string, string], ([string, string] | string)?, @@ -272,10 +272,6 @@ export interface FormRenderProps< * 组件集合 */ componentMap: Record; - /** - * 表单字段映射成时间格式 - */ - fieldMapToTime?: FieldMapToTime; /** * 表单实例 */ @@ -315,6 +311,10 @@ export interface VbenFormProps< * 表单操作区域class */ actionWrapperClass?: ClassType; + /** + * 表单字段映射成时间格式 + */ + fieldMappingTime?: FieldMappingTime; /** * 表单重置回调 */ diff --git a/packages/effects/plugins/src/vxe-table/extends.ts b/packages/effects/plugins/src/vxe-table/extends.ts index f5d91fcb6..70a0ba44a 100644 --- a/packages/effects/plugins/src/vxe-table/extends.ts +++ b/packages/effects/plugins/src/vxe-table/extends.ts @@ -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); }, }); } diff --git a/playground/src/views/examples/form/basic.vue b/playground/src/views/examples/form/basic.vue index 0930350c2..5124a3cfd 100644 --- a/playground/src/views/examples/form/basic.vue +++ b/playground/src/views/examples/form/basic.vue @@ -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', diff --git a/playground/src/views/examples/modal/form-model-demo.vue b/playground/src/views/examples/modal/form-modal-demo.vue similarity index 95% rename from playground/src/views/examples/modal/form-model-demo.vue rename to playground/src/views/examples/modal/form-modal-demo.vue index d04a40f11..5179ffebf 100644 --- a/playground/src/views/examples/modal/form-model-demo.vue +++ b/playground/src/views/examples/modal/form-modal-demo.vue @@ -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) { diff --git a/playground/src/views/examples/modal/index.vue b/playground/src/views/examples/modal/index.vue index 9d250603c..d6db2fba2 100644 --- a/playground/src/views/examples/modal/index.vue +++ b/playground/src/views/examples/modal/index.vue @@ -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({ diff --git a/playground/src/views/examples/vxe-table/form.vue b/playground/src/views/examples/vxe-table/form.vue index 18a1a038f..fad0cf58f 100644 --- a/playground/src/views/examples/vxe-table/form.vue +++ b/playground/src/views/examples/vxe-table/form.vue @@ -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, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1c64c867d..a44eeda7e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -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