Skip to content

Commit d864085

Browse files
lztb米山
lztb
and
米山
authored
feat: vben-form添加arrayToStringFields属性 (vbenjs#5957)
* feat: vben-form添加arrayToStringFields属性 * feat: 修改handleArrayToStringFields和handleStringToArrayFields中嵌套数组格式的处理不一致 --------- Co-authored-by: 米山 <[email protected]>
1 parent fcdc1a1 commit d864085

File tree

2 files changed

+144
-0
lines changed

2 files changed

+144
-0
lines changed

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

+119
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,7 @@ export class FormApi {
295295
return true;
296296
});
297297
const filteredFields = fieldMergeFn(fields, form.values);
298+
this.handleStringToArrayFields(filteredFields);
298299
form.setValues(filteredFields, shouldValidate);
299300
}
300301

@@ -304,6 +305,7 @@ export class FormApi {
304305
const form = await this.getForm();
305306
await form.submitForm();
306307
const rawValues = toRaw(await this.getValues());
308+
this.handleArrayToStringFields(rawValues);
307309
await this.state?.handleSubmit?.(rawValues);
308310

309311
return rawValues;
@@ -392,10 +394,53 @@ export class FormApi {
392394
return this.form;
393395
}
394396

397+
private handleArrayToStringFields = (originValues: Record<string, any>) => {
398+
const arrayToStringFields = this.state?.arrayToStringFields;
399+
if (!arrayToStringFields || !Array.isArray(arrayToStringFields)) {
400+
return;
401+
}
402+
403+
const processFields = (fields: string[], separator: string = ',') => {
404+
this.processFields(fields, separator, originValues, (value, sep) =>
405+
Array.isArray(value) ? value.join(sep) : value,
406+
);
407+
};
408+
409+
// 处理简单数组格式 ['field1', 'field2', ';'] 或 ['field1', 'field2']
410+
if (arrayToStringFields.every((item) => typeof item === 'string')) {
411+
const lastItem =
412+
arrayToStringFields[arrayToStringFields.length - 1] || '';
413+
const fields =
414+
lastItem.length === 1
415+
? arrayToStringFields.slice(0, -1)
416+
: arrayToStringFields;
417+
const separator = lastItem.length === 1 ? lastItem : ',';
418+
processFields(fields, separator);
419+
return;
420+
}
421+
422+
// 处理嵌套数组格式 [['field1'], ';']
423+
arrayToStringFields.forEach((fieldConfig) => {
424+
if (Array.isArray(fieldConfig)) {
425+
const [fields, separator = ','] = fieldConfig;
426+
// 根据类型定义,fields 应该始终是字符串数组
427+
if (!Array.isArray(fields)) {
428+
console.warn(
429+
`Invalid field configuration: fields should be an array of strings, got ${typeof fields}`,
430+
);
431+
return;
432+
}
433+
processFields(fields, separator);
434+
}
435+
});
436+
};
437+
395438
private handleRangeTimeValue = (originValues: Record<string, any>) => {
396439
const values = { ...originValues };
397440
const fieldMappingTime = this.state?.fieldMappingTime;
398441

442+
this.handleStringToArrayFields(values);
443+
399444
if (!fieldMappingTime || !Array.isArray(fieldMappingTime)) {
400445
return values;
401446
}
@@ -441,6 +486,80 @@ export class FormApi {
441486
return values;
442487
};
443488

489+
private handleStringToArrayFields = (originValues: Record<string, any>) => {
490+
const arrayToStringFields = this.state?.arrayToStringFields;
491+
if (!arrayToStringFields || !Array.isArray(arrayToStringFields)) {
492+
return;
493+
}
494+
495+
const processFields = (fields: string[], separator: string = ',') => {
496+
this.processFields(fields, separator, originValues, (value, sep) => {
497+
if (typeof value !== 'string') {
498+
return value;
499+
}
500+
// 处理空字符串的情况
501+
if (value === '') {
502+
return [];
503+
}
504+
// 处理复杂分隔符的情况
505+
const escapedSeparator = sep.replaceAll(
506+
/[.*+?^${}()|[\]\\]/g,
507+
String.raw`\$&`,
508+
);
509+
return value.split(new RegExp(escapedSeparator));
510+
});
511+
};
512+
513+
// 处理简单数组格式 ['field1', 'field2', ';'] 或 ['field1', 'field2']
514+
if (arrayToStringFields.every((item) => typeof item === 'string')) {
515+
const lastItem =
516+
arrayToStringFields[arrayToStringFields.length - 1] || '';
517+
const fields =
518+
lastItem.length === 1
519+
? arrayToStringFields.slice(0, -1)
520+
: arrayToStringFields;
521+
const separator = lastItem.length === 1 ? lastItem : ',';
522+
processFields(fields, separator);
523+
return;
524+
}
525+
526+
// 处理嵌套数组格式 [['field1'], ';']
527+
arrayToStringFields.forEach((fieldConfig) => {
528+
if (Array.isArray(fieldConfig)) {
529+
const [fields, separator = ','] = fieldConfig;
530+
if (Array.isArray(fields)) {
531+
processFields(fields, separator);
532+
} else if (typeof originValues[fields] === 'string') {
533+
const value = originValues[fields];
534+
if (value === '') {
535+
originValues[fields] = [];
536+
} else {
537+
const escapedSeparator = separator.replaceAll(
538+
/[.*+?^${}()|[\]\\]/g,
539+
String.raw`\$&`,
540+
);
541+
originValues[fields] = value.split(new RegExp(escapedSeparator));
542+
}
543+
}
544+
}
545+
});
546+
};
547+
548+
private processFields = (
549+
fields: string[],
550+
separator: string,
551+
originValues: Record<string, any>,
552+
transformFn: (value: any, separator: string) => any,
553+
) => {
554+
fields.forEach((field) => {
555+
const value = originValues[field];
556+
if (value === undefined || value === null) {
557+
return;
558+
}
559+
originValues[field] = transformFn(value, separator);
560+
});
561+
};
562+
444563
private updateState() {
445564
const currentSchema = this.state?.schema ?? [];
446565
const prevSchema = this.prevState?.schema ?? [];

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

+25
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,12 @@ export type FieldMappingTime = [
232232
)?,
233233
][];
234234

235+
export type ArrayToStringFields = Array<
236+
| [string[], string?] // 嵌套数组格式,可选分隔符
237+
| string // 单个字段,使用默认分隔符
238+
| string[] // 简单数组格式,最后一个元素可以是分隔符
239+
>;
240+
235241
export interface FormSchema<
236242
T extends BaseFormComponentType = BaseFormComponentType,
237243
> extends FormCommonConfig {
@@ -266,6 +272,10 @@ export interface FormFieldProps extends FormSchema {
266272
export interface FormRenderProps<
267273
T extends BaseFormComponentType = BaseFormComponentType,
268274
> {
275+
/**
276+
* 表单字段数组映射字符串配置 默认使用","
277+
*/
278+
arrayToStringFields?: ArrayToStringFields;
269279
/**
270280
* 是否展开,在showCollapseButton=true下生效
271281
*/
@@ -296,6 +306,10 @@ export interface FormRenderProps<
296306
* 组件集合
297307
*/
298308
componentMap: Record<BaseFormComponentType, Component>;
309+
/**
310+
* 表单字段映射到时间格式
311+
*/
312+
fieldMappingTime?: FieldMappingTime;
299313
/**
300314
* 表单实例
301315
*/
@@ -308,10 +322,15 @@ export interface FormRenderProps<
308322
* 表单定义
309323
*/
310324
schema?: FormSchema<T>[];
325+
311326
/**
312327
* 是否显示展开/折叠
313328
*/
314329
showCollapseButton?: boolean;
330+
/**
331+
* 格式化日期
332+
*/
333+
315334
/**
316335
* 表单栅格布局
317336
* @default "grid-cols-1"
@@ -339,6 +358,11 @@ export interface VbenFormProps<
339358
* 表单操作区域class
340359
*/
341360
actionWrapperClass?: ClassType;
361+
/**
362+
* 表单字段数组映射字符串配置 默认使用","
363+
*/
364+
arrayToStringFields?: ArrayToStringFields;
365+
342366
/**
343367
* 表单字段映射
344368
*/
@@ -359,6 +383,7 @@ export interface VbenFormProps<
359383
* 重置按钮参数
360384
*/
361385
resetButtonOptions?: ActionButtonOptions;
386+
362387
/**
363388
* 是否显示默认操作按钮
364389
* @default true

0 commit comments

Comments
 (0)