import React, { useRef } from 'react'; import { Card, Space, Typography, message, Button, Divider, Input, Tag } from 'antd'; import XinForm from '@/components/XinForm'; import type { XinFormRef } from '@/components/XinForm'; import type { FormColumn } from '@/components/XinFormField/FieldRender/typings'; const { Title, Paragraph, Text } = Typography; // 基础表单字段配置 const basicColumns: FormColumn[] = [ { dataIndex: 'username', title: '用户名', valueType: 'text', rules: [{ required: true, message: '请输入用户名' }], fieldProps: { placeholder: '请输入用户名', }, }, { dataIndex: 'password', title: '密码', valueType: 'password', rules: [{ required: true, message: '请输入密码' }], fieldProps: { placeholder: '请输入密码', }, }, { dataIndex: 'email', title: '邮箱', valueType: 'text', rules: [ { required: true, message: '请输入邮箱' }, { type: 'email', message: '请输入有效的邮箱地址' }, ], fieldProps: { placeholder: '请输入邮箱地址', }, }, { dataIndex: 'description', title: '个人简介', valueType: 'textarea', fieldProps: { placeholder: '请输入个人简介', rows: 3, }, }, ]; // Grid 布局表单字段配置 const gridColumns: FormColumn[] = [ { dataIndex: 'name', title: '姓名', valueType: 'text', colProps: { span: 12 }, rules: [{ required: true, message: '请输入姓名' }], fieldProps: { placeholder: '请输入姓名' }, }, { dataIndex: 'age', title: '年龄', valueType: 'digit', colProps: { span: 12 }, fieldProps: { placeholder: '请输入年龄', min: 0, max: 150, style: { width: '100%' } }, }, { dataIndex: 'gender', title: '性别', valueType: 'radio', colProps: { span: 12 }, fieldProps: { options: [ { label: '男', value: 'male' }, { label: '女', value: 'female' }, ], }, }, { dataIndex: 'status', title: '状态', valueType: 'switch', colProps: { span: 12 }, valuePropName: 'checked', }, { dataIndex: 'birthDate', title: '出生日期', valueType: 'date', colProps: { span: 12 }, fieldProps: { style: { width: '100%' } }, }, { dataIndex: 'salary', title: '薪资', valueType: 'money', colProps: { span: 12 }, fieldProps: { style: { width: '100%' }, placeholder: '请输入薪资' }, }, ]; // 完整表单字段配置 - 展示所有字段类型 const fullColumns: FormColumn[] = [ { dataIndex: 'text', title: '文本输入', valueType: 'text', tooltip: '这是一个帮助提示', fieldProps: { placeholder: '普通文本输入' }, }, { dataIndex: 'password', title: '密码输入', valueType: 'password', fieldProps: { placeholder: '密码输入' }, }, { dataIndex: 'digit', title: '数字输入', valueType: 'digit', extra: '请输入0-100之间的数字', fieldProps: { placeholder: '数字输入', min: 0, max: 100, }, }, { dataIndex: 'money', title: '金额输入', valueType: 'money', fieldProps: { placeholder: '金额输入', width: '100%', }, }, { dataIndex: 'select', title: '下拉选择', valueType: 'select', fieldProps: { placeholder: '请选择', options: [ { label: '选项一', value: 'option1' }, { label: '选项二', value: 'option2' }, { label: '选项三', value: 'option3' }, ], }, }, { dataIndex: 'treeSelect', title: '树形选择', valueType: 'treeSelect', fieldProps: { placeholder: '请选择', treeData: [ { title: '父节点1', value: 'parent1', children: [ { title: '子节点1-1', value: 'child1-1' }, { title: '子节点1-2', value: 'child1-2' }, ]}, { title: '父节点2', value: 'parent2' }, ], }, }, { dataIndex: 'cascader', title: '级联选择', valueType: 'cascader', fieldProps: { placeholder: '请选择', options: [ { label: '浙江', value: 'zhejiang', children: [ { label: '杭州', value: 'hangzhou' }, { label: '宁波', value: 'ningbo' }, ]}, { label: '江苏', value: 'jiangsu', children: [ { label: '南京', value: 'nanjing' }, { label: '苏州', value: 'suzhou' }, ]}, ], }, }, { dataIndex: 'radio', title: '单选框', valueType: 'radio', fieldProps: { options: [ { label: '选项A', value: 'a' }, { label: '选项B', value: 'b' }, { label: '选项C', value: 'c' }, ], }, }, { dataIndex: 'radioButton', title: '单选按钮', valueType: 'radioButton', fieldProps: { options: [ { label: '按钮A', value: 'a' }, { label: '按钮B', value: 'b' }, { label: '按钮C', value: 'c' }, ], }, }, { dataIndex: 'checkbox', title: '多选框', valueType: 'checkbox', fieldProps: { options: [ { label: '选项1', value: '1' }, { label: '选项2', value: '2' }, { label: '选项3', value: '3' }, ], }, }, { dataIndex: 'switch', title: '开关', valueType: 'switch', valuePropName: 'checked', }, { dataIndex: 'rate', title: '评分', valueType: 'rate', }, { dataIndex: 'slider', title: '滑动条', valueType: 'slider', }, { dataIndex: 'date', title: '日期选择', valueType: 'date', }, { dataIndex: 'dateTime', title: '日期时间', valueType: 'dateTime', }, { dataIndex: 'dateRange', title: '日期范围', valueType: 'dateRange', }, { dataIndex: 'time', title: '时间选择', valueType: 'time', }, { dataIndex: 'color', title: '颜色选择', valueType: 'color', }, { dataIndex: 'icon', title: '图标选择', valueType: 'icon', }, { dataIndex: 'image', title: '图片上传', valueType: 'image', fieldProps: { action: '/file/upload', // 假设的上传接口 maxCount: 1, } }, { dataIndex: 'user', title: '用户选择', valueType: 'user', fieldProps: { placeholder: '请选择用户', } }, { dataIndex: 'textarea', title: '多行文本', valueType: 'textarea', fieldProps: { placeholder: '请输入多行文本', rows: 3 }, }, ]; // 字段分组配置 const groupColumns: FormColumn[] = [ { valueType: 'text', colProps: { span: 24 }, fieldRender: () => 基本信息 }, { dataIndex: 'name', title: '姓名', valueType: 'text', colProps: { span: 12 }, rules: [{ required: true, message: '请输入姓名' }], }, { dataIndex: 'phone', title: '电话', valueType: 'text', colProps: { span: 12 }, tooltip: '请输入11位手机号', }, { valueType: 'text', colProps: { span: 24 }, fieldRender: () => 部门信息 }, { dataIndex: 'department', title: '部门', valueType: 'select', colProps: { span: 12 }, fieldProps: { options: [ { label: '技术部', value: 'tech' }, { label: '产品部', value: 'product' }, { label: '运营部', value: 'operation' }, ], }, }, { dataIndex: 'position', title: '职位', valueType: 'text', colProps: { span: 12 }, }, { dataIndex: 'remark', title: '备注', valueType: 'textarea', extra: '可选填写', }, ]; // 依赖联动配置 interface DependencyFormData { hasDiscount: boolean; discount: number; productType: string; subType: string; } const dependencyColumns: FormColumn[] = [ { dataIndex: 'hasDiscount', title: '是否有折扣', valueType: 'switch', valuePropName: 'checked', tooltip: '开启后可设置折扣比例', }, { dataIndex: 'discount', title: '折扣比例', valueType: 'slider', dependency: { dependencies: ['hasDiscount'], visible: (values) => values.hasDiscount === true, }, fieldProps: { min: 0, max: 100, marks: { 0: '0%', 50: '50%', 100: '100%' }, }, }, { dataIndex: 'productType', title: '产品类型', valueType: 'select', fieldProps: { placeholder: '请选择产品类型', options: [ { label: '电子产品', value: 'electronics' }, { label: '服装', value: 'clothing' }, { label: '食品', value: 'food' }, ], }, }, { dataIndex: 'subType', title: '子类型', valueType: 'select', dependency: { dependencies: ['productType'], visible: (values) => !!values.productType, disabled: (values) => !values.productType, fieldProps: (values) => { const subTypeOptions: Record = { electronics: [ { label: '手机', value: 'phone' }, { label: '电脑', value: 'computer' }, { label: '平板', value: 'tablet' }, ], clothing: [ { label: '上衣', value: 'top' }, { label: '裤子', value: 'pants' }, { label: '鞋子', value: 'shoes' }, ], food: [ { label: '零食', value: 'snack' }, { label: '饮料', value: 'drink' }, { label: '水果', value: 'fruit' }, ], }; return { placeholder: '请先选择产品类型', options: subTypeOptions[values.productType as string] || [], }; }, }, }, ]; // 自定义渲染配置 const customColumns: FormColumn[] = [ { dataIndex: 'username', title: '用户名', valueType: 'text', rules: [{ required: true, message: '请输入用户名' }], }, { dataIndex: 'tags', title: '标签', valueType: 'text', fieldRender: (form) => ( { const value = (e.target as HTMLInputElement).value; const tags = form.getFieldValue('tags') || []; if (value && !tags.includes(value)) { form.setFieldValue('tags', [...tags, value]); } (e.target as HTMLInputElement).value = ''; }} /> {(form.getFieldValue('tags') || []).map((tag: string, index: number) => ( { const tags = form.getFieldValue('tags') || []; form.setFieldValue('tags', tags.filter((_: string, i: number) => i !== index)); }} > {tag} ))} ), }, { dataIndex: 'hiddenField', title: '隐藏字段', valueType: 'text', hidden: true, }, ]; // Modal/Drawer 表单字段配置 const modalColumns: FormColumn[] = [ { dataIndex: 'title', title: '标题', valueType: 'text', rules: [{ required: true, message: '请输入标题' }], fieldProps: { placeholder: '请输入标题' }, }, { dataIndex: 'type', title: '类型', valueType: 'select', rules: [{ required: true, message: '请选择类型' }], fieldProps: { placeholder: '请选择类型', options: [ { label: '类型一', value: 'type1' }, { label: '类型二', value: 'type2' }, ], }, }, { dataIndex: 'priority', title: '优先级', valueType: 'radioButton', fieldProps: { options: [ { label: '低', value: 'low' }, { label: '中', value: 'medium' }, { label: '高', value: 'high' }, ], }, }, { dataIndex: 'content', title: '内容', valueType: 'textarea', fieldProps: { placeholder: '请输入内容', rows: 4 }, }, ]; /** * XinForm 组件使用示例页面 */ const XinFormExample: React.FC = () => { const modalFormRef = useRef(undefined); const drawerFormRef = useRef(undefined); const handleFinish = async (values: any) => { console.log('表单提交:', values); message.success('表单提交成功!'); return true; }; return (
XinForm 动态表单组件示例 基于 Ant Design Form 封装的 JSON 配置动态表单组件,支持多种布局和丰富的表单字段类型。 {/* 基础表单 */} 最简单的表单用法,通过 columns 配置表单字段。 {/* Grid 布局表单 */} 使用 grid 属性开启栅格布局,通过 colProps 控制每列宽度。 {/* 所有字段类型 */} 展示 XinForm 支持的所有字段类型:text、password、digit、money、select、treeSelect、cascader、radio、checkbox、switch、rate、slider、date、time、color、icon、textarea 等。
新增功能:tooltip 提示信息、extra 额外说明、width 组件宽度。
{/* 字段分组 */} 使用 group 属性对表单字段进行分组,自动显示分割线和标题。 {/* 依赖联动 */} 使用 dependency 属性实现字段间的依赖联动:
- visible:根据其他字段值控制显示/隐藏
- disabled:根据其他字段值控制禁用状态
- fieldProps:根据其他字段值动态设置组件属性
columns={dependencyColumns} layout="vertical" initialValues={{ hasDiscount: false }} onFinish={handleFinish} />
{/* 自定义渲染 */} 使用 valueType="custom" + renderField 实现完全自定义的表单字段渲染。
使用 hidden 属性隐藏字段(支持布尔值或函数)。
{/* ModalForm 弹窗表单 */} 使用 layoutType="ModalForm" 实现弹窗表单,支持 trigger 触发器或 formRef 控制打开/关闭。 使用 Trigger 打开} modalProps={{ title: '新建任务', width: 520 }} onFinish={handleFinish} /> {/* DrawerForm 抽屉表单 */} 使用 layoutType="DrawerForm" 实现抽屉表单,适用于复杂表单或需要更大空间的场景。 使用 Trigger 打开} drawerProps={{ title: '新建任务', width: 520 }} onFinish={handleFinish} /> {/* 自定义提交按钮 */} 通过 submitter 配置项自定义提交按钮文本、样式,或完全自定义渲染。 自定义按钮文本 隐藏提交按钮 设置 submitter.render = false 隐藏提交按钮
); }; export default XinFormExample;