feat(formBuilder): 支持动态 col 样式及标题,增强 FormList 行定制能力

- 新增 colStyle 属性,支持 Col 内联样式函数动态计算
- 新增 colTitle 属性,支持 Col 内部标题节点动态渲染
- 新增 rowStyle 属性,允许 FormList 每行样式动态定义
- 新增 rowTitle 属性,支持 FormList 每行标题动态渲染
2.0
LiuJiaNan 2026-06-23 13:51:16 +08:00
parent 585b03329b
commit 05621be758
2 changed files with 48 additions and 6 deletions

View File

@ -1,9 +1,9 @@
import type { NamePath } from "@rc-component/form/lib/interface";
import type { ColProps } from "antd/es/col";
import type { FormItemProps, Rule } from "antd/es/form";
import type { FormListFieldData } from "antd/es/form/FormList";
import type { Gutter } from "antd/es/grid/row";
import type { NamePath } from "rc-field-form/lib/interface";
import type { ReactElement, ReactNode } from "react";
import type { CSSProperties, ReactElement, ReactNode } from "react";
import type { FORM_ITEM_RENDER_TYPE_MAP } from "../../enum/formItemRender";
import type { DeepPartial } from "./FormBuilder";
@ -131,6 +131,10 @@ export interface FormOptionBase<
dependencies?: FormOptionProperty<IsOnlyForLabel, IsCustomizeRender, Dependencies[]>;
/** 是否仅用于保存标签,不渲染到页面上,只在表单中保存数据,默认 false */
onlyForLabel?: IsOnlyForLabel;
/** Col 的内联样式,会合并到 Col 的 style 上,支持函数动态计算 */
colStyle?: FormOptionProperty<IsOnlyForLabel, IsCustomizeRender, CSSProperties | ((formValues: AllValues) => CSSProperties)>;
/** Col 内部、Form.Item 之前渲染的标题节点,支持函数动态计算 */
colTitle?: FormOptionProperty<IsOnlyForLabel, IsCustomizeRender, ReactNode | ((formValues: AllValues) => ReactNode)>;
}
/**
@ -157,6 +161,10 @@ export type FormOptionByRender<
checkboxCol?: FormOptionProperty<IsOnlyForLabel, IsCustomizeRender, RenderType extends "checkbox" ? number : never>;
/** Form.List 独有的属性 */
formListUniqueProps?: FormOptionProperty<IsOnlyForLabel, IsCustomizeRender, RenderType extends "formList" ? FormListUniqueProps | ((formValues: AllValues) => FormListUniqueProps) : never>;
/** FormList 每行的内联样式,仅 render 为 formList 时可用,支持函数按行计算 */
rowStyle?: FormOptionProperty<IsOnlyForLabel, IsCustomizeRender, RenderType extends "formList" ? CSSProperties | ((field: FormListFieldData, fieldIndex: number) => CSSProperties) : never>;
/** FormList 每行起始位置渲染的标题节点,仅 render 为 formList 时可用,支持函数按行计算 */
rowTitle?: FormOptionProperty<IsOnlyForLabel, IsCustomizeRender, RenderType extends "formList" ? ReactNode | ((field: FormListFieldData, fieldIndex: number) => ReactNode) : never>;
};
/**

View File

@ -223,6 +223,34 @@ const FormItemsRenderer = ({
return { span: itemSpan, labelCol: itemLabelCol, wrapperCol: itemWrapperCol };
};
// 获取 col 样式
const getColStyle = (option) => {
return typeof option.colStyle === "function"
? option.colStyle(getFormValues())
: option.colStyle;
};
// 获取 col 标题Col 内部、Form.Item 之后)
const getColTitle = (option) => {
return typeof option.colTitle === "function"
? option.colTitle(getFormValues())
: option.colTitle;
};
// 获取 row 样式FormList 的每一行)
const getRowStyle = (option, field, fieldIndex) => {
return typeof option.rowStyle === "function"
? option.rowStyle(field, fieldIndex)
: option.rowStyle;
};
// 获取 row 标题FormList 每行末尾)
const getRowTitle = (option, field, fieldIndex) => {
return typeof option.rowTitle === "function"
? option.rowTitle(field, fieldIndex)
: option.rowTitle;
};
// 获取是否动态表单项
const getIsDynamicFormItem = (option, formItemProps) => {
return (option.shouldUpdate ?? option.dependencies) || (formItemProps.shouldUpdate ?? formItemProps.dependencies);
@ -434,7 +462,8 @@ const FormItemsRenderer = ({
return null;
return (
<Col key={getKey(option) || index} span={col.span} style={style}>
<Col key={getKey(option) || index} span={col.span} style={{ ...style, ...getColStyle(option) }}>
{getColTitle(option)}
<Form.Item
name={option.name}
label={renderLabel(option)}
@ -516,14 +545,18 @@ const FormItemsRenderer = ({
const componentProps = getComponentProps(option);
return (
<Col key={getKey(option) || index} span={col.span} style={style}>
<Col key={getKey(option) || index} span={col.span} style={{ ...style, ...getColStyle(option) }}>
{getColTitle(option)}
<Form.List name={option.name} {...componentProps}>
{(fields, { add, remove, move }) => (
<>
{fields.map((field, fieldIndex) => {
const listOptions = getListOptions(formListUniqueProps.options, field, fieldIndex, add, remove, move);
const rowStyle = getRowStyle(option, field, fieldIndex);
const rowTitle = getRowTitle(option, field, fieldIndex);
return (
<Row gutter={gutter} key={field.key}>
<Row gutter={gutter} key={field.key} style={rowStyle}>
{rowTitle}
{listOptions.map((listOption, listIndex) => {
const col = getCol(listOption);
const formItemProps = getFormItemProps(listOption);
@ -574,7 +607,8 @@ const FormItemsRenderer = ({
delete formItemProps.shouldUpdate;
return (
<Col key={getKey(listOption) || listIndex} span={col.span} style={style}>
<Col key={getKey(listOption) || listIndex} span={col.span} style={{ ...style, ...getColStyle(listOption) }}>
{getColTitle(listOption)}
<Form.Item
label={renderLabel(listOption)}
labelCol={col.labelCol}