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
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 144 additions and 0 deletions

View File

@ -295,6 +295,7 @@ export class FormApi {
return true; return true;
}); });
const filteredFields = fieldMergeFn(fields, form.values); const filteredFields = fieldMergeFn(fields, form.values);
this.handleStringToArrayFields(filteredFields);
form.setValues(filteredFields, shouldValidate); form.setValues(filteredFields, shouldValidate);
} }
@ -304,6 +305,7 @@ export class FormApi {
const form = await this.getForm(); const form = await this.getForm();
await form.submitForm(); await form.submitForm();
const rawValues = toRaw(await this.getValues()); const rawValues = toRaw(await this.getValues());
this.handleArrayToStringFields(rawValues);
await this.state?.handleSubmit?.(rawValues); await this.state?.handleSubmit?.(rawValues);
return rawValues; return rawValues;
@ -392,10 +394,53 @@ export class FormApi {
return this.form; 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>) => { private handleRangeTimeValue = (originValues: Record<string, any>) => {
const values = { ...originValues }; const values = { ...originValues };
const fieldMappingTime = this.state?.fieldMappingTime; const fieldMappingTime = this.state?.fieldMappingTime;
this.handleStringToArrayFields(values);
if (!fieldMappingTime || !Array.isArray(fieldMappingTime)) { if (!fieldMappingTime || !Array.isArray(fieldMappingTime)) {
return values; return values;
} }
@ -441,6 +486,80 @@ export class FormApi {
return values; 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() { private updateState() {
const currentSchema = this.state?.schema ?? []; const currentSchema = this.state?.schema ?? [];
const prevSchema = this.prevState?.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< export interface FormSchema<
T extends BaseFormComponentType = BaseFormComponentType, T extends BaseFormComponentType = BaseFormComponentType,
> extends FormCommonConfig { > extends FormCommonConfig {
@ -266,6 +272,10 @@ export interface FormFieldProps extends FormSchema {
export interface FormRenderProps< export interface FormRenderProps<
T extends BaseFormComponentType = BaseFormComponentType, T extends BaseFormComponentType = BaseFormComponentType,
> { > {
/**
* 使","
*/
arrayToStringFields?: ArrayToStringFields;
/** /**
* showCollapseButton=true下生效 * showCollapseButton=true下生效
*/ */
@ -296,6 +306,10 @@ export interface FormRenderProps<
* *
*/ */
componentMap: Record<BaseFormComponentType, Component>; componentMap: Record<BaseFormComponentType, Component>;
/**
*
*/
fieldMappingTime?: FieldMappingTime;
/** /**
* *
*/ */
@ -308,10 +322,15 @@ export interface FormRenderProps<
* *
*/ */
schema?: FormSchema<T>[]; schema?: FormSchema<T>[];
/** /**
* / * /
*/ */
showCollapseButton?: boolean; showCollapseButton?: boolean;
/**
*
*/
/** /**
* *
* @default "grid-cols-1" * @default "grid-cols-1"
@ -339,6 +358,11 @@ export interface VbenFormProps<
* class * class
*/ */
actionWrapperClass?: ClassType; actionWrapperClass?: ClassType;
/**
* 使","
*/
arrayToStringFields?: ArrayToStringFields;
/** /**
* *
*/ */
@ -359,6 +383,7 @@ export interface VbenFormProps<
* *
*/ */
resetButtonOptions?: ActionButtonOptions; resetButtonOptions?: ActionButtonOptions;
/** /**
* *
* @default true * @default true