#Schema Form - JSON 表单
SchemaForm 是根据 JSON Schema 来生成表单的工具。SchemaForm 会根据 valueType 来映射成不同的表单项。
Tips: 如您遇到卡顿问题或有更高的性能要求可参考示例使用
#API
SchemaForm 提供了与 ProForm 相同的 API,并且增加了部分 API,以下的 SchemaForm 新增的 API。
监听表单值变化请使用 onValuesChange(changedValues, allValues),而不是 onChange。
| 字段名称 | 类型 | 说明 |
|---|---|---|
layoutType | ProFormLayoutType | 使用的表单布局模式 |
steps | StepFormProps[] | layoutType=steps中的分步表单配置,需要配置 columns 为数组使用 |
columns | ProFormColumnsType[] | ProFormColumnsType[][] | 表单的定义,一般是 json 对象,如果是分步表单,需要使用 json 数组来生成多个表单 |
shouldUpdate | boolean | ((newValues: Record<string, any>, oldValues?: Record<string, any>) => boolean) | 细粒化控制是否渲染。 为 true 时会自动重新渲染表单项。为 false 时不会更新表单项但可以使用 dependencies 触发更新。为 function 时根据返回值判断是否重新渲染表单项 |
title | ReactNode | 表单标题 |
action | MutableRefObject<ProCoreActionType | undefined> | 用于操作表单的 action,支持 reload 等操作 |
formRef | MutableRefObject<ProFormInstance | undefined> | 获取 form 实例,支持 antd form 的所有方法 |
open | boolean | 控制 ModalForm 和 DrawerForm 的显示隐藏 |
#ProFormLayoutType
| 字段名称 | 说明 |
|---|---|
Form | ProForm 是基本的表单类型 |
ModalForm | 弹框表单,配置之后支持 ModalForm 的所有配置 |
DrawerForm | 抽屉表单,配置之后支持 DrawerForm 的所有配置 |
StepsForm|StepForm | 配置之后为分步表单,有两种模式一种使用 steps 和 columns 来生成,一种是通过 layoutType=StepsForm 嵌套 layoutType=StepForm 来实现 |
LightFilter | 轻量筛选,配置之后支持 LightFilter 的所有配置 |
QueryFilter | 查询表单,配置之后支持 QueryFilter 的所有配置 |
Embed | 内嵌模式,只生成表单项,不生成 Form 可以混合使用 |
#Schema 定义
SchemaForm 表单最重要就是 Schema 的类型定义,我们使用了与 table 的相同的表单定义,同时扩展了部分字段。
| 字段名称 | 类型 | 说明 |
|---|---|---|
key | React.Key | 确定这个列的唯一值,一般用于 dataIndex 重复的情况 |
dataIndex | React.Key | React.Key[] | 与实体映射的 key,数组会被转化 [a,b] => Entity.a.b |
valueType | ProFieldValueType | 数据的渲染方式,我们自带了一部分,你也可以自定义 valueType |
title | ReactNode |(props,type,dom)=> ReactNode | 标题的内容,在 form 中是 label |
tooltip | LabelTooltipType | string | 会在 title 旁边展示一个 icon,鼠标浮动之后展示 |
width | number | string | 宽度。xs: 104px - 短数字、短文本sm: 216px - 短字段(姓名、电话)md: 328px - 标准宽度lg: 440px - 长字段(网址、标签组)xl: 552px - 长文本(描述、备注) |
colSize | number | 每个表单占据的格子大小,总宽度 = span * colSize,默认为 1 |
readonly | boolean | 是否只读模式 |
initialValue | any | 表单的默认值 |
valueEnum | (Entity)=> ValueEnum | ValueEnum | 支持 object 和 Map,Map 是支持其他基础类型作为 key |
fieldProps | (form,config)=>fieldProps| fieldProps | 传给渲染的组件的 props,自定义的时候也会传递 |
formItemProps | (form,config)=>formItemProps | formItemProps | 传递给 Form.Item 的配置 |
formItemProps.rules | Rule[] | 表单项的校验规则。需要注意的是,如果当前表单项为formList时,此规则仅校 验列表是否为空,且仅接受元组[{required: boolean, message: string}],用于开启和关闭非空校验及指定空列表提示消息 |
proFieldProps | proFieldProps | 设置到 ProField 上面的 props,内部属性 |
renderText | (text: any, record: Entity, index: number, action: ProCoreActionType) => any | 修改的数据是会被 valueType 定义的渲染组件消费 |
render | (dom,entity,index, action, schema) => React.ReactNode | 自定义只读模式的 dom,render 方法只管理的只读模式,编辑模式需要使用 formItemRender |
formItemRender | (schema,config,form,action) => React.ReactNode | 自定义编辑模式,返回一个 ReactNode,会自动包裹 value 和 onChange。 |
request | (params,props) => Promise<{label,value}[]> | 从远程请求网络数据,一般用于选择类组件 |
params | Record<string, any> | 额外传递给 request 的参数,组件不做处理,但是变化会引起request 重新请求数据 |
dependencies | NamePath[] | 所依赖的 values 变化后,触发 formItemRender,fieldProps,formItemProps 重新执行,并把 values 注入到 params 里 示例 |
hideInDescriptions | boolean | 在 descriptions 中隐藏 |
hideInForm | boolean | 在 Form 中隐藏 |
hideInTable | boolean | 在 Table 中隐藏 |
search | boolean | { transform: (value: any) => any } | 在 Table 的查询表格中隐藏可设为 false,对象配置 transform 用于转化提交的 key |
columns | ProFormColumnsType[] | (values) => ProFormColumnsType[] | 嵌套子项,valueType 为 dependency 时,请使用(values) => ProFormColumnsType[]其他情况使用 ProFormColumnsType[] |
colProps | ColProps | 在开启 grid 模式时传递给 Col |
rowProps | RowProps | 开启栅格化模式时传递给 Row |
convertValue | (value, namePath)=> any | 获取时转化值,一般用于将数据格式化为组件接收的格式,如 [a,b] => a,b |
transform | (value, namePath, allValues)=> any | 提交时转化值,一般用于将值转化为提交的数据,如 string => { newName: string } |
order | number | Form 的排序,默认是 index,order 越大越靠前 |
debounceTime | number | request 防抖时间 |
defaultKeyWords | string | 搜索时的默认关键字 |
ignoreFormItem | boolean | 不包裹 Form.Item,直接渲染组件 |
#valueEnum
valueEnum 用值作为 key 映射展示文本和状态,支持 object、Map,也支持根据当前数据返回枚举的函数。
#常见 ValueType
| 值类型 | 描述 |
|---|---|
text | 文本输入框 |
textarea | 多行文本域 |
password | 密码输入框 |
digit | 数字输入框 |
money | 金额输入框 |
select | 下拉选择器 |
checkbox | 多选框 |
radio | 单选框 |
date | 日期选择器 |
dateRange | 日期范围选择器 |
time | 时间选择器 |
switch | 开关 |
group | 表单分组 |
dependency | 依赖联动 |
formList | 列表表单 |
#fieldProps 与 formItemProps 的区别
- fieldProps: 传递给具体输入组件(如 Input, Select, DatePicker)的属性。例如
placeholder,allowClear,style等。 - formItemProps: 传递给 Ant Design 的
Form.Item的属性。例如label,name,rules,extra,help等。
{
title: '标题',
dataIndex: 'title',
formItemProps: {
rules: [{ required: true, message: '此项必填' }],
extra: '这是一段辅助说明',
},
fieldProps: {
placeholder: '请输入标题',
allowClear: true,
},
}#代码示例 - 布局类型
#基础表单 (Form)
SchemaForm 最基础的用法,通过 JSON 配置生成标准的表单页面。支持通过 columns 定义表单项,通过 layoutType 切换布局。
import type {
ProFormColumnsType,
ProFormLayoutType,
} from '@ant-design/pro-components';
import { BetaSchemaForm, ProFormSelect } from '@ant-design/pro-components';
import { Alert, DatePicker, Space } from 'antd';
import { useState } from 'react';
import { FIXED_BASE_DATE } from '../../mockData';
const valueEnum = {
all: { text: '全部', status: 'Default' },
open: {
text: '未解决',
status: 'Error',
},
closed: {
text: '已解决',
status: 'Success',
disabled: true,
},
processing: {
text: '解决中',
status: 'Processing',
},
};
type DataItem = {
name: string;
state: string;
};
const columns: ProFormColumnsType<DataItem>[] = [
{
title: '标题',
dataIndex: 'title',
formItemProps: {
rules: [
{
required: true,
message: '此项为必填项',
},
],
},
width: 'md',
colProps: {
xs: 24,
md: 12,
},
initialValue: '默认值',
convertValue: (value) => {
return `标题:${value}`;
},
transform: (value) => {
return {
title: `${value}-转换`,
};
},
},
{
title: '状态',
dataIndex: 'state',
valueType: 'select',
valueEnum,
width: 'md',
colProps: {
xs: 24,
md: 12,
},
},
{
title: '标签',
dataIndex: 'labels',
width: 'md',
colProps: {
xs: 12,
md: 4,
},
},
{
valueType: 'switch',
title: '开关',
dataIndex: 'Switch',
fieldProps: {
style: {
width: '200px',
},
},
width: 'md',
colProps: {
xs: 12,
md: 20,
},
},
{
title: '创建时间',
key: 'showTime',
valueType: 'dateRange',
dataIndex: 'createName',
initialValue: [FIXED_BASE_DATE.add(-1, 'm'), FIXED_BASE_DATE],
formItemRender: () => <DatePicker.RangePicker />,
width: 'md',
colProps: {
xs: 24,
md: 12,
},
},
{
title: '更新时间',
dataIndex: 'updateName',
valueType: 'dateRange',
initialValue: [FIXED_BASE_DATE.add(-1, 'm'), FIXED_BASE_DATE],
formItemRender: () => <DatePicker.RangePicker />,
width: 'md',
colProps: {
xs: 24,
md: 12,
},
},
{
title: '分组',
valueType: 'group',
columns: [
{
title: '状态',
dataIndex: 'groupState',
valueType: 'select',
width: 'xs',
colProps: {
xs: 12,
},
valueEnum,
},
{
title: '标题',
width: 'md',
dataIndex: 'groupTitle',
colProps: {
xs: 12,
},
formItemProps: {
rules: [
{
required: true,
message: '此项为必填项',
},
],
},
},
],
},
{
title: '列表',
valueType: 'formList',
dataIndex: 'list',
initialValue: [{ state: 'all', title: '标题' }],
colProps: {
xs: 24,
sm: 12,
},
columns: [
{
valueType: 'group',
columns: [
{
title: '状态',
dataIndex: 'state',
valueType: 'select',
colProps: {
xs: 24,
sm: 12,
},
width: 'xs',
valueEnum,
},
{
title: '标题',
dataIndex: 'title',
width: 'md',
formItemProps: {
rules: [
{
required: true,
message: '此项为必 填项',
},
],
},
colProps: {
xs: 24,
sm: 12,
},
},
],
},
{
valueType: 'dateTime',
initialValue: FIXED_BASE_DATE.toDate(),
dataIndex: 'currentTime',
width: 'md',
},
],
},
{
title: 'FormSet',
valueType: 'formSet',
dataIndex: 'formSet',
colProps: {
xs: 24,
sm: 12,
},
rowProps: {
gutter: [16, 0],
},
columns: [
{
title: '状态',
dataIndex: 'groupState',
valueType: 'select',
width: 'md',
valueEnum,
},
{
width: 'xs',
title: '标题',
dataIndex: 'groupTitle',
tooltip: '标题过长会自动收缩',
formItemProps: {
rules: [
{
required: true,
message: '此项为必填项',
},
],
},
},
],
},
{
title: '创建时间',
dataIndex: 'created_at',
valueType: 'dateRange',
width: 'md',
colProps: {
span: 24,
},
transform: (value) => {
return {
startTime: value[0],
endTime: value[1],
};
},
},
];
const Demo = () => {
const [layoutType, setLayoutType] = useState<ProFormLayoutType>('Form');
return (
<>
<Space
style={{
width: '100%',
}}
orientation="vertical"
>
<Alert
type="warning"
title="QueryFilter 和 lightFilter 暂不支持grid模式"
style={{
marginBlockEnd: 24,
}}
/>
<ProFormSelect
label="布局方式"
options={[
'Form',
'ModalForm',
'DrawerForm',
'LightFilter',
'QueryFilter',
'StepsForm',
'StepForm',
'Embed',
]}
fieldProps={{
value: layoutType,
onChange: (e) => setLayoutType(e),
}}
/>
</Space>
<BetaSchemaForm<DataItem>
name="schema-form-schema-demo"
trigger={<a>点击我</a>}
layoutType={layoutType}
steps={[
{
title: 'ProComponent',
},
]}
rowProps={{
gutter: [16, 16],
}}
colProps={{
span: 12,
}}
grid={layoutType !== 'LightFilter' && layoutType !== 'QueryFilter'}
onFinish={async () => {
}}
columns={(layoutType === 'StepsForm' ? [columns] : columns) as any}
/>
</>
);
};
export default () => (
<div style={{ padding: 24 }}>
<Demo />
</div>
);
#浮层表单 (ModalForm & DrawerForm)
通过设置 layoutType 为 ModalForm 或 DrawerForm,可以快速将表单转换为弹窗或抽屉模式,无需手动维护 open 状态。
import type { ProFormLayoutType } from '@ant-design/pro-components';
import { BetaSchemaForm, ProFormSelect } from '@ant-design/pro-components';
import { Alert, Button, Space } from 'antd';
import { useState } from 'react';
type DataItem = {
name: string;
state: string;
};
const Demo = () => {
const [layoutType, setLayoutType] = useState<ProFormLayoutType>('ModalForm');
return (
<>
<Space
style={{
width: '100%',
}}
orientation="vertical"
>
<Alert
type="warning"
title="QueryFilter 和 lightFilter 暂不支持grid模式"
style={{
marginBlockEnd: 24,
}}
/>
<ProFormSelect
label="布局方式"
options={['ModalForm', 'DrawerForm']}
fieldProps={{
value: layoutType,
onChange: (e) => setLayoutType(e),
}}
/>
</Space>
<BetaSchemaForm<DataItem>
name="schema-form-modal-and-drawer-form-demo"
trigger={<Button>点击我</Button>}
layoutType={layoutType as 'ModalForm'}
onFinish={async () => {
}}
{...(layoutType === 'ModalForm'
? {
modalProps: { destroyOnHidden: true },
}
: {
drawerProps: { destroyOnHidden: true },
})}
columns={[
{
title: '标题',
dataIndex: 'title',
formItemProps: {
rules: [
{
required: true,
message: '此项为必填项',
},
],
},
width: 'md',
},
]}
/>
</>
);
};
export default () => (
<div style={{ padding: 24 }}>
<Demo />
</div>
);
#分步表单 (StepsForm)
通过设置 layoutType 为 StepsForm 或 StepForm,可以生成分步表单。此时 columns 应该是一个二维数组,每个数组元素代表一步的表单项配置。
import type {
ProFormColumnsType,
ProFormInstance,
} from '@ant-design/pro-components';
import { BetaSchemaForm } from '@ant-design/pro-components';
import { message } from 'antd';
import { useRef } from 'react';
const valueEnum = {
all: { text: '全部', status: 'Default' },
open: {
text: '未解决',
status: 'Error',
},
closed: {
text: '已解决',
status: 'Success',
disabled: true,
},
processing: {
text: '解决中',
status: 'Processing',
},
};
type DataItem = {
name: string;
state: string;
};
const columns: ProFormColumnsType<DataItem>[][] = [
[
{
title: '标题',
dataIndex: 'title',
formItemProps: {
rules: [
{
required: true,
message: '此项为必填项',
},
],
},
width: 'm',
},
{
title: '状态',
dataIndex: 'state',
valueType: 'select',
valueEnum,
width: 'm',
},
],
[
{
title: '标签',
dataIndex: 'labels',
width: 'm',
},
{
title: '创建时间',
key: 'showTime',
dataIndex: 'createName',
valueType: 'date',
},
{
title: '分组',
valueType: 'group',
columns: [
{
title: '状态',
dataIndex: 'groupState',
valueType: 'select',
width: 'xs',
valueEnum,
},
{
title: '标题',
width: 'md',
dataIndex: 'groupTitle',
formItemProps: {
rules: [
{
required: true,
message: '此项为必填项',
},
],
},
},
],
},
],
[
{
title: '列表',
valueType: 'formList',
dataIndex: 'list',
initialValue: [{ state: 'all', title: '标题' }],
columns: [
{
valueType: 'group',
columns: [
{
title: '状态',
dataIndex: 'state',
valueType: 'select',
width: 'xs',
valueEnum,
},
{
title: '标题',
dataIndex: 'title',
formItemProps: {
rules: [
{
required: true,
message: '此项为必填项',
},
],
},
width: 'm',
},
],
},
],
},
{
title: 'FormSet',
valueType: 'formSet',
dataIndex: 'formSet',
columns: [
{
title: '状态',
dataIndex: 'groupState',
valueType: 'select',
width: 'xs',
valueEnum,
},
{
title: '标题',
dataIndex: 'groupTitle',
tooltip: '标题过长会自动收缩',
formItemProps: {
rules: [
{
required: true,
message: '此项为必填项',
},
],
},
width: 'm',
},
],
},
{
title: '创建时间',
dataIndex: 'created_at',
valueType: 'dateRange',
transform: (value) => {
return {
startTime: value[0],
endTime: value[1],
};
},
},
],
];
const Demo = () => {
const formRef = useRef<ProFormInstance>();
return (
<BetaSchemaForm<DataItem>
name="schema-form-steps-form-demo"
layoutType="StepsForm"
steps={[
{
title: '第一步',
},
{
title: '第二步',
},
{
title: '第三步',
},
]}
onCurrentChange={(_current) => {
}}
formRef={formRef}
onFinish={async () => {
return new Promise((resolve) => {
message.success('提交成功');
setTimeout(() => {
resolve(true);
formRef.current?.resetFields();
}, 2000);
});
}}
columns={columns}
/>
);
};
export default () => (
<div style={{ padding: 24 }}>
<Demo />
</div>
);
#嵌入模式 (Embed)
通过设置 layoutType 为 Embed,可以只生成表单项而不生成 Form 容器。这在需要将 SchemaForm 嵌入到已有的 ProForm 或其他容器中时非常有用。
import type { ProFormColumnsType } from '@ant-design/pro-components';
import {
BetaSchemaForm,
ProForm,
ProFormSelect,
ProFormText,
} from '@ant-design/pro-components';
const valueEnum = {
all: { text: '全部', status: 'Default' },
open: {
text: '未解决',
status: 'Error',
},
closed: {
text: '已解决',
status: 'Success',
disabled: true,
},
processing: {
text: '解决中',
status: 'Processing',
},
};
type DataItem = {
name: string;
state: string;
};
const columns: ProFormColumnsType<DataItem>[] = [
{
title: '标题',
dataIndex: 'title',
formItemProps: {
rules: [
{
required: true,
message: '此项为必填项',
},
],
},
width: 'm',
},
{
title: '状态',
dataIndex: 'state',
valueType: 'select',
valueEnum,
width: 'm',
},
];
const Demo = () => {
return (
<ProForm name="schema-form-embed-demo">
<h1>ProForm </h1>
<ProFormText name="username" />
<ProFormSelect
name="select-multiple"
label="多选"
valueEnum={{
red: 'Red',
green: 'Green',
blue: 'Blue',
}}
fieldProps={{
mode: 'multiple',
}}
placeholder="Please select favorite colors"
rules={[
{
required: true,
message: 'Please select your favorite colors!',
type: 'array',
},
]}
/>
<h1>表单1 </h1>
<BetaSchemaForm<DataItem> layoutType="Embed" columns={columns} />
<h1>表单2</h1>
<BetaSchemaForm<DataItem>
layoutType="Embed"
columns={[
{
title: '创建时间',
key: 'showTime',
dataIndex: 'createName',
valueType: 'date',
},
{
title: '分组',
valueType: 'group',
columns: [
{
title: '状态',
dataIndex: 'groupState',
valueType: 'select',
width: 'xs',
valueEnum,
},
{
title: '标题',
width: 'md',
dataIndex: 'groupTitle',
formItemProps: {
rules: [
{
required: true,
message: '此项为必填项',
},
],
},
},
],
},
]}
/>
</ProForm>
);
};
export default () => (
<div style={{ padding: 24 }}>
<Demo />
</div>
);
#高级用法
#表单联动
使用 valueType: 'dependency' 可以实现复杂的表单联动。当依赖的字段发生变化时,会自动触发当前项的更新。
普通json表单
嵌套json表单
import type { ProFormColumnsType } from '@ant-design/pro-components';
import { BetaSchemaForm, ProForm } from '@ant-design/pro-components';
const valueEnum = {
money: { text: '按金额' },
discount: { text: '按折扣' },
};
type DataItem = {
name: string;
state: string;
};
const columns: ProFormColumnsType<DataItem>[] = [
{
title: '优惠方式',
dataIndex: 'type',
formItemProps: {
rules: [
{
required: true,
message: '此项为必填项',
},
],
},
valueType: 'select',
valueEnum,
width: 'm',
},
{
valueType: 'dependency',
name: ['type'],
columns: ({ type }) => {
if (type === 'money') {
return [
{
dataIndex: 'money',
title: '优惠金额',
width: 'm',
valueType: 'money',
},
];
}
if (type === 'discount') {
return [
{
dataIndex: 'discount',
title: '折扣',
valueType: 'digit',
width: 'm',
fieldProps: {
precision: 2,
},
},
];
}
return [];
},
},
];
const Demo = () => {
return (
<>
<h1>普通json表单</h1>
<BetaSchemaForm<DataItem>
onFinish={async () => {
}}
columns={columns}
/>
<h1>嵌套json表单</h1>
<ProForm
name="schema-form-dependency-demo"
initialValues={{
type: 'money',
}}
>
<BetaSchemaForm<DataItem>
layoutType="Embed"
onFinish={async () => {
}}
columns={columns}
/>
</ProForm>
</>
);
};
export default () => (
<div style={{ padding: 24 }}>
<Demo />
</div>
);
#高性能模式
对于大型表单,可以使用 shouldUpdate 和 dependencies 来进行细粒度的渲染控制,避免整个表单的重复渲染。
- dependencies: 指定依赖字段,仅当依赖字段变化时更新。
- shouldUpdate: 自定义更新逻辑,返回 false 阻止更新。
import type { ProFormColumnsType } from '@ant-design/pro-components';
import { BetaSchemaForm } from '@ant-design/pro-components';
import { Input } from 'antd';
const valueEnum = {
all: { text: '全部', status: 'Default' },
open: {
text: '未解决',
status: 'Error',
},
closed: {
text: '已解决',
status: 'Success',
disabled: true,
},
processing: {
text: '解决中',
status: 'Processing',
},
};
type DataItem = {
name: string;
state: string;
};
const columns: ProFormColumnsType<DataItem>[] = [
{
title: '标题',
dataIndex: 'title',
initialValue: '必填',
formItemProps: {
rules: [
{
required: true,
message: '此项为必填项',
},
],
},
width: 'm',
},
{
title: '状态',
dataIndex: 'state',
valueType: 'select',
valueEnum,
width: 'm',
tooltip: '当title为disabled时状态无法选择',
dependencies: ['title'],
fieldProps: (form) => {
if (form.getFieldValue('title') === 'disabled') {
return {
disabled: true,
placeholder: 'disabled',
};
} else {
return {
placeholder: 'normal',
};
}
},
},
{
title: '标签',
dataIndex: 'labels',
width: 'm',
tooltip: '当title为必填时此项将为必填',
dependencies: ['title'],
formItemProps(form) {
if (form.getFieldValue('title') === '必填') {
return {
rules: [
{
required: true,
},
],
};
} else {
return {};
}
},
},
{
valueType: 'dependency',
name: ['title'],
columns: ({ title }) => {
return title !== 'hidden'
? [
{
title: 'title为hidden时隐藏',
dataIndex: 'hidden',
valueType: 'date',
formItemRender: () => {
return <Input />;
},
},
]
: [];
},
},
{
title: '创建时间',
key: 'showTime',
dataIndex: 'createName',
valueType: 'date',
},
{
valueType: 'divider',
},
];
const Demo = () => {
return (
<>
<BetaSchemaForm<DataItem>
shouldUpdate={false}
layoutType="Form"
onFinish={async () => {
}}
columns={columns}
/>
</>
);
};
export default () => (
<div style={{ padding: 24 }}>
<Demo />
</div>
);
import type { ProFormColumnsType } from '@ant-design/pro-components';
import { BetaSchemaForm } from '@ant-design/pro-components';
import { Input } from 'antd';
const valueEnum = {
all: { text: '全部', status: 'Default' },
open: {
text: '未解决',
status: 'Error',
},
closed: {
text: '已解决',
status: 'Success',
disabled: true,
},
processing: {
text: '解决中',
status: 'Processing',
},
};
type DataItem = {
name: string;
state: string;
title: string;
};
const columns: ProFormColumnsType<DataItem>[] = [
{
title: '标题',
dataIndex: 'title',
initialValue: '必填',
formItemProps: {
rules: [
{
required: true,
message: '此项为必填项',
},
],
},
width: 'm',
},
{
title: '状态',
dataIndex: 'state',
valueType: 'select',
valueEnum,
width: 'm',
tooltip: '当title为disabled时状态无法选择',
fieldProps: (form) => {
if (form.getFieldValue('title') === 'disabled') {
return {
disabled: true,
placeholder: 'disabled',
};
} else {
return {
placeholder: 'normal',
};
}
},
},
{
title: '标签',
dataIndex: 'labels',
width: 'm',
tooltip: '当title为必填时此项将为必填',
dependencies: ['title'],
formItemProps(form) {
if (form.getFieldValue('title') === '必填') {
return {
rules: [
{
required: true,
},
],
};
} else {
return {};
}
},
},
{
valueType: 'dependency',
name: ['title'],
columns: ({ title }) => {
return title !== 'hidden'
? [
{
title: 'title为hidden时隐藏',
dataIndex: 'hidden',
valueType: 'date',
formItemRender: () => {
return <Input />;
},
},
]
: [];
},
},
{
title: '创建时间',
key: 'showTime',
dataIndex: 'createName',
valueType: 'date',
},
];
const Demo = () => {
return (
<>
<BetaSchemaForm<DataItem>
shouldUpdate={(newValues, oldValues) => {
if (newValues.title !== oldValues?.title) {
return true;
}
return false;
}}
layoutType="Form"
onFinish={async () => {
}}
columns={columns}
/>
</>
);
};
export default () => (
<div style={{ padding: 24 }}>
<Demo />
</div>
);
#列表配置 (FormList)
支持 valueType: 'formList' 来生成动态增减的列表表单。
import type { ProFormColumnsType } from '@ant-design/pro-components';
import { BetaSchemaForm } from '@ant-design/pro-components';
import { Input } from 'antd';
const valueEnum = {
all: { text: '全部', status: 'Default' },
open: {
text: '未解决',
status: 'Error',
},
closed: {
text: '已解决',
status: 'Success',
disabled: true,
},
processing: {
text: '解决中',
status: 'Processing',
},
};
type DataItem = {
name: string;
state: string;
};
const columns: ProFormColumnsType<DataItem>[] = [
{
title: '标题',
dataIndex: 'title',
initialValue: '必填',
formItemProps: {
rules: [
{
required: true,
message: '此项为必填项',
},
],
},
width: 'm',
},
{
title: '必填但没显示*',
dataIndex: 'list',
valueType: 'formList',
formItemProps: {
rules: [{ required: true, message: '请填写列表' }],
},
columns: [
{
dataIndex: 'isSettlement',
valueType: 'switch',
formItemProps: {
rules: [{ required: true, message: '请填写1' }],
},
},
],
},
{
title: '状态',
dataIndex: 'state',
valueType: 'select',
valueEnum,
width: 'm',
tooltip: '当title为disabled时状态无法选择',
dependencies: ['title'],
fieldProps: (form) => {
if (form.getFieldValue('title') === 'disabled') {
return {
disabled: true,
placeholder: 'disabled',
};
} else {
return {
placeholder: 'normal',
};
}
},
},
{
title: '标签',
dataIndex: 'labels',
width: 'm',
tooltip: '当title为必填时此项将为必填',
dependencies: ['title'],
formItemProps(form) {
if (form.getFieldValue('title') === '必填') {
return {
rules: [
{
required: true,
},
],
};
} else {
return {};
}
},
},
{
valueType: 'dependency',
name: ['title'],
columns: ({ title }) => {
return title !== 'hidden'
? [
{
title: 'title为hidden时隐藏',
dataIndex: 'hidden',
valueType: 'date',
formItemRender: () => {
return <Input />;
},
},
]
: [];
},
},
{
title: '创建时间',
key: 'showTime',
dataIndex: 'createName',
valueType: 'date',
},
{
valueType: 'divider',
},
];
const Demo = () => {
return (
<>
<BetaSchemaForm<DataItem>
shouldUpdate={false}
layoutType="Form"
onFinish={async () => {
}}
columns={columns}
/>
</>
);
};
export default () => (
<div style={{ padding: 24 }}>
<Demo />
</div>
);
#valueType 映射
演示内置 valueType 在 BetaSchemaForm 中的基础用法。
import type { ProFieldValueType } from '@ant-design/pro-components';
import { BetaSchemaForm, ProFormSelect } from '@ant-design/pro-components';
import { useState } from 'react';
import { FIXED_BASE_TIMESTAMP } from '../../mockData';
const valueEnum = {
all: { text: '全部', status: 'Default' },
open: {
text: '未解决',
status: 'Error',
},
closed: {
text: '已解决',
status: 'Success',
disabled: true,
},
processing: {
text: '解决中',
status: 'Processing',
},
};
const options = [
{ value: `password`, label: `密码输入框`, initialValue: '123456' },
{ value: `money`, label: `金额输入`, initialValue: '123456' },
{ value: `textarea`, label: `文本域`, initialValue: '123456\n121212' },
{ value: `date`, label: `日期`, initialValue: FIXED_BASE_TIMESTAMP },
{ value: `dateTime`, label: `日期时间`, initialValue: FIXED_BASE_TIMESTAMP },
{ value: `dateWeek`, label: `周`, initialValue: FIXED_BASE_TIMESTAMP },
{ value: `dateMonth`, label: `月`, initialValue: FIXED_BASE_TIMESTAMP },
{
value: `dateQuarter`,
label: `季度输入`,
initialValue: FIXED_BASE_TIMESTAMP,
},
{ value: `dateYear`, label: `年份输入`, initialValue: FIXED_BASE_TIMESTAMP },
{
value: `dateRange`,
label: `日期区间`,
initialValue: [FIXED_BASE_TIMESTAMP, FIXED_BASE_TIMESTAMP],
},
{
value: `dateTimeRange`,
label: `日期时间区间`,
initialValue: [FIXED_BASE_TIMESTAMP, FIXED_BASE_TIMESTAMP],
},
{ value: `time`, label: `时间`, initialValue: FIXED_BASE_TIMESTAMP },
{
value: `timeRange`,
label: `时间区间`,
initialValue: [FIXED_BASE_TIMESTAMP, FIXED_BASE_TIMESTAMP],
},
{ value: `text`, label: `文本框`, initialValue: '123456' },
{ value: `select`, label: `下拉框`, initialValue: 'open' },
{ value: `checkbox`, label: `多选框`, initialValue: 'open' },
{ value: `rate`, label: `星级组件`, initialValue: '' },
{ value: `radio`, label: `单选框`, initialValue: 'open' },
{ value: `radioButton`, label: `按钮单选框`, initialValue: 'open' },
{ value: `progress`, label: `进度条`, initialValue: '10' },
{ value: `percent`, label: `百分比组件`, initialValue: '20' },
{ value: `digit`, label: `数字输入框`, initialValue: '200000' },
{ value: `second`, label: `秒格式化`, initialValue: 20000 },
{
value: `avatar`,
label: `头像`,
initialValue:
'https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg',
},
{ value: `code`, label: `代码框`, initialValue: '# 2121' },
{ value: `switch`, label: `开关`, initialValue: 'open' },
{
value: `fromNow`,
label: `相对于当前时间`,
initialValue: FIXED_BASE_TIMESTAMP,
},
{
value: `image`,
label: `图片`,
initialValue:
'https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg',
},
{
value: `jsonCode`,
label: `JSON代码框`,
initialValue: '{ "name":"demo_user" }',
},
{
value: `color`,
label: `颜色选择器`,
initialValue: '#1890ff',
},
];
type DataItem = {
name: string;
state: string;
};
const Demo = () => {
const [valueType, setValueType] = useState<ProFieldValueType>('text');
return (
<>
<ProFormSelect.SearchSelect
label="valueType 选择"
options={options}
width={200}
mode="single"
fieldProps={{
labelInValue: false,
value: valueType,
onChange: (value) => setValueType(value),
}}
/>
<BetaSchemaForm<DataItem>
name="schema-form-value-type-demo"
layoutType="Form"
onFinish={async () => {
}}
initialValues={options.reduce((pre, item) => {
return {
...pre,
[item.value]: item.initialValue,
};
}, {})}
columns={[
{
title: '分组',
valueType: 'group',
columns: [
{
valueType,
title: '编辑器',
dataIndex: valueType || 'text',
valueEnum,
formItemProps: {
rules: [
{
required: true,
message: '此项为必填项',
},
],
},
width: 'm',
},
{
valueType,
title: '只读',
dataIndex: valueType || 'text',
valueEnum,
readonly: true,
width: 'm',
},
],
},
]}
/>
</>
);
};
export default () => (
<div style={{ padding: 24 }}>
<Demo />
</div>
);
#自定义 valueType
import type { ProFormColumnsType } from '@ant-design/pro-components';
import { BetaSchemaForm, ProProvider } from '@ant-design/pro-components';
import type { InputRef } from 'antd';
import { Input, Space, Tag } from 'antd';
import React, { useContext, useRef, useState } from 'react';
import { DEMO_VALUE_ENUM } from '../../mockData';
const _valueEnum = {
0: 'close',
1: 'running',
2: 'online',
3: 'error',
};
export type TableListItem = {
key: number;
name: string;
status: {
label: string | number;
value: number;
}[];
};
const TagList: React.FC<{
value?: {
key: string;
label: string;
}[];
onChange?: (
value: {
key: string;
label: string;
}[],
) => void;
}> = ({ value, onChange }) => {
const ref = useRef<InputRef | null>(null);
const [newTags, setNewTags] = useState<
{
key: string;
label: string;
}[]
>([]);
const [inputValue, setInputValue] = useState<string>('');
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setInputValue(e.target.value);
};
const handleInputConfirm = () => {
let tempsTags = [...(value || [])];
if (
inputValue &&
tempsTags.filter((tag) => tag.label === inputValue).length === 0
) {
tempsTags = [
...tempsTags,
{ key: `new-${tempsTags.length}`, label: inputValue },
];
}
onChange?.(tempsTags);
setNewTags([]);
setInputValue('');
};
return (
<Space>
{(value || []).concat(newTags).map((item) => (
<Tag key={item.key}>{item.label}</Tag>
))}
<Input
ref={ref}
type="text"
size="small"
style={{ width: 78 }}
value={inputValue}
onChange={handleInputChange}
onBlur={handleInputConfirm}
onPressEnter={handleInputConfirm}
/>
</Space>
);
};
const columns: ProFormColumnsType<TableListItem, 'link' | 'tags'>[] = [
{
title: '标签',
valueType: 'group',
columns: [
{
title: '只读链接',
readonly: true,
dataIndex: 'name',
valueType: 'link',
},
{
title: '链接',
dataIndex: 'name',
valueType: 'link',
},
],
},
{
title: '路径',
valueType: 'group',
columns: [
{
title: '标签',
dataIndex: 'status',
key: 'status',
valueType: 'tags',
},
{
title: '只读标签',
readonly: true,
dataIndex: 'status',
key: 'status',
valueType: 'tags',
},
],
},
];
const Demo = () => {
const values = useContext(ProProvider);
return (
<ProProvider.Provider
value={{
...values,
valueTypeMap: {
link: {
render: (text) => <a>{text}</a>,
formItemRender: (text, props) => (
<Input placeholder="请输入链接" {...props?.fieldProps} />
),
},
tags: {
render: (text) => {
return (
<>
{[text].flat(1).map((item) => (
<Tag key={item.value}>{item.label}</Tag>
))}
</>
);
},
formItemRender: (text, props) => (
<TagList {...props} {...props?.fieldProps} />
),
},
},
}}
>
<BetaSchemaForm<TableListItem, 'link' | 'tags'>
initialValues={{
key: 1,
name: '用户认证服务',
status: [
{
value: 1,
label: DEMO_VALUE_ENUM[1],
},
{
value: 2,
label: DEMO_VALUE_ENUM[2],
},
],
}}
columns={columns}
title="自定义 valueType"
/>
</ProProvider.Provider>
);
};
export default () => (
<div style={{ padding: 24 }}>
<Demo />
</div>
);