Bläddra i källkod

feat: vben-form添加arrayToStringFields属性 (#5957)

* feat: vben-form添加arrayToStringFields属性

* feat: 修改handleArrayToStringFields和handleStringToArrayFields中嵌套数组格式的处理不一致

---------

Co-authored-by: 米山 <17726957223@189.cn>
lztb 5 månader sedan
förälder
incheckning
d864085c13
2 ändrade filer med 144 tillägg och 0 borttagningar
  1. 119 0
      packages/@core/ui-kit/form-ui/src/form-api.ts
  2. 25 0
      packages/@core/ui-kit/form-ui/src/types.ts

+ 119 - 0
packages/@core/ui-kit/form-ui/src/form-api.ts

@@ -295,6 +295,7 @@ export class FormApi {
       return true;
     });
     const filteredFields = fieldMergeFn(fields, form.values);
+    this.handleStringToArrayFields(filteredFields);
     form.setValues(filteredFields, shouldValidate);
   }
 
@@ -304,6 +305,7 @@ export class FormApi {
     const form = await this.getForm();
     await form.submitForm();
     const rawValues = toRaw(await this.getValues());
+    this.handleArrayToStringFields(rawValues);
     await this.state?.handleSubmit?.(rawValues);
 
     return rawValues;
@@ -392,10 +394,53 @@ export class FormApi {
     return this.form;
   }
 
+  private handleArrayToStringFields = (originValues: Record<string, any>) => {
+    const arrayToStringFields = this.state?.arrayToStringFields;
+    if (!arrayToStringFields || !Array.isArray(arrayToStringFields)) {
+      return;
+    }
+
+    const processFields = (fields: string[], separator: string = ',') => {
+      this.processFields(fields, separator, originValues, (value, sep) =>
+        Array.isArray(value) ? value.join(sep) : value,
+      );
+    };
+
+    // 处理简单数组格式 ['field1', 'field2', ';'] 或 ['field1', 'field2']
+    if (arrayToStringFields.every((item) => typeof item === 'string')) {
+      const lastItem =
+        arrayToStringFields[arrayToStringFields.length - 1] || '';
+      const fields =
+        lastItem.length === 1
+          ? arrayToStringFields.slice(0, -1)
+          : arrayToStringFields;
+      const separator = lastItem.length === 1 ? lastItem : ',';
+      processFields(fields, separator);
+      return;
+    }
+
+    // 处理嵌套数组格式 [['field1'], ';']
+    arrayToStringFields.forEach((fieldConfig) => {
+      if (Array.isArray(fieldConfig)) {
+        const [fields, separator = ','] = fieldConfig;
+        // 根据类型定义,fields 应该始终是字符串数组
+        if (!Array.isArray(fields)) {
+          console.warn(
+            `Invalid field configuration: fields should be an array of strings, got ${typeof fields}`,
+          );
+          return;
+        }
+        processFields(fields, separator);
+      }
+    });
+  };
+
   private handleRangeTimeValue = (originValues: Record<string, any>) => {
     const values = { ...originValues };
     const fieldMappingTime = this.state?.fieldMappingTime;
 
+    this.handleStringToArrayFields(values);
+
     if (!fieldMappingTime || !Array.isArray(fieldMappingTime)) {
       return values;
     }
@@ -441,6 +486,80 @@ export class FormApi {
     return values;
   };
 
+  private handleStringToArrayFields = (originValues: Record<string, any>) => {
+    const arrayToStringFields = this.state?.arrayToStringFields;
+    if (!arrayToStringFields || !Array.isArray(arrayToStringFields)) {
+      return;
+    }
+
+    const processFields = (fields: string[], separator: string = ',') => {
+      this.processFields(fields, separator, originValues, (value, sep) => {
+        if (typeof value !== 'string') {
+          return value;
+        }
+        // 处理空字符串的情况
+        if (value === '') {
+          return [];
+        }
+        // 处理复杂分隔符的情况
+        const escapedSeparator = sep.replaceAll(
+          /[.*+?^${}()|[\]\\]/g,
+          String.raw`\$&`,
+        );
+        return value.split(new RegExp(escapedSeparator));
+      });
+    };
+
+    // 处理简单数组格式 ['field1', 'field2', ';'] 或 ['field1', 'field2']
+    if (arrayToStringFields.every((item) => typeof item === 'string')) {
+      const lastItem =
+        arrayToStringFields[arrayToStringFields.length - 1] || '';
+      const fields =
+        lastItem.length === 1
+          ? arrayToStringFields.slice(0, -1)
+          : arrayToStringFields;
+      const separator = lastItem.length === 1 ? lastItem : ',';
+      processFields(fields, separator);
+      return;
+    }
+
+    // 处理嵌套数组格式 [['field1'], ';']
+    arrayToStringFields.forEach((fieldConfig) => {
+      if (Array.isArray(fieldConfig)) {
+        const [fields, separator = ','] = fieldConfig;
+        if (Array.isArray(fields)) {
+          processFields(fields, separator);
+        } else if (typeof originValues[fields] === 'string') {
+          const value = originValues[fields];
+          if (value === '') {
+            originValues[fields] = [];
+          } else {
+            const escapedSeparator = separator.replaceAll(
+              /[.*+?^${}()|[\]\\]/g,
+              String.raw`\$&`,
+            );
+            originValues[fields] = value.split(new RegExp(escapedSeparator));
+          }
+        }
+      }
+    });
+  };
+
+  private processFields = (
+    fields: string[],
+    separator: string,
+    originValues: Record<string, any>,
+    transformFn: (value: any, separator: string) => any,
+  ) => {
+    fields.forEach((field) => {
+      const value = originValues[field];
+      if (value === undefined || value === null) {
+        return;
+      }
+      originValues[field] = transformFn(value, separator);
+    });
+  };
+
   private updateState() {
     const currentSchema = this.state?.schema ?? [];
     const prevSchema = this.prevState?.schema ?? [];

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

@@ -232,6 +232,12 @@ export type FieldMappingTime = [
   )?,
 ][];
 
+export type ArrayToStringFields = Array<
+  | [string[], string?] // 嵌套数组格式,可选分隔符
+  | string // 单个字段,使用默认分隔符
+  | string[] // 简单数组格式,最后一个元素可以是分隔符
+>;
+
 export interface FormSchema<
   T extends BaseFormComponentType = BaseFormComponentType,
 > extends FormCommonConfig {
@@ -266,6 +272,10 @@ export interface FormFieldProps extends FormSchema {
 export interface FormRenderProps<
   T extends BaseFormComponentType = BaseFormComponentType,
 > {
+  /**
+   * 表单字段数组映射字符串配置 默认使用","
+   */
+  arrayToStringFields?: ArrayToStringFields;
   /**
    * 是否展开,在showCollapseButton=true下生效
    */
@@ -296,6 +306,10 @@ export interface FormRenderProps<
    * 组件集合
    */
   componentMap: Record<BaseFormComponentType, Component>;
+  /**
+   * 表单字段映射到时间格式
+   */
+  fieldMappingTime?: FieldMappingTime;
   /**
    * 表单实例
    */
@@ -308,10 +322,15 @@ export interface FormRenderProps<
    * 表单定义
    */
   schema?: FormSchema<T>[];
+
   /**
    * 是否显示展开/折叠
    */
   showCollapseButton?: boolean;
+  /**
+   * 格式化日期
+   */
+
   /**
    * 表单栅格布局
    * @default "grid-cols-1"
@@ -339,6 +358,11 @@ export interface VbenFormProps<
    * 表单操作区域class
    */
   actionWrapperClass?: ClassType;
+  /**
+   * 表单字段数组映射字符串配置 默认使用","
+   */
+  arrayToStringFields?: ArrayToStringFields;
+
   /**
    * 表单字段映射
    */
@@ -359,6 +383,7 @@ export interface VbenFormProps<
    * 重置按钮参数
    */
   resetButtonOptions?: ActionButtonOptions;
+
   /**
    * 是否显示默认操作按钮
    * @default true