瀏覽代碼

perf: formApi added validateAndSubmitForm & filedMapToTime renamed fieldMappingTime (#4842)

* perf: formApi added validateAndSubmitForm & filedMapToTime renamed fieldMappingTime
Vben 4 月之前
父節點
當前提交
8617d3dd1e

+ 2 - 0
docs/src/components/common-ui/vben-form.md

@@ -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 |

+ 1 - 0
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:",

+ 18 - 0
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');
+}

+ 1 - 0
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';

+ 13 - 36
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<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,
   () => {

+ 9 - 0
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();
+  }
 }

+ 5 - 5
packages/@core/ui-kit/form-ui/src/types.ts

@@ -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;
   /**
    * 表单重置回调
    */

+ 3 - 5
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);
     },
   });
 }

+ 2 - 1
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',

+ 2 - 2
playground/src/views/examples/modal/form-model-demo.vue → 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) {

+ 1 - 1
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({

+ 0 - 6
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,

+ 3 - 0
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