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

* feat: vben-form添加arrayToStringFields属性

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

---------

Co-authored-by: 米山 <17726957223@189.cn>
This commit is contained in:
lztb
2025-04-15 16:03:20 +08:00
committed by GitHub
parent fcdc1a1602
commit d864085c13
2 changed files with 144 additions and 0 deletions

View File

@@ -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 ?? [];

View File

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