627 lines
21 KiB
TypeScript
627 lines
21 KiB
TypeScript
/**
|
||
* FormDesigner 组件使用示例页面
|
||
*
|
||
* 展示如何使用 @/components/FormDesigner 中的组件:
|
||
* - FormDesigner: 表单设计器(设计时)
|
||
* - FormRenderer: 表单渲染器(运行时)
|
||
*/
|
||
|
||
import React, { useState } from 'react';
|
||
import { message, Tabs, Card, Button, Modal, Space, Divider, Alert } from 'antd';
|
||
import { FormDesigner, FormRenderer, type FormSchema } from '@/components/FormDesigner';
|
||
import { WORKFLOW_COMPONENTS } from '@/components/FormDesigner/extensions/workflow';
|
||
|
||
const FormDesignerExamplesPage: React.FC = () => {
|
||
// ==================== 示例 1: 普通表单设计器 ====================
|
||
const [designerSchema, setDesignerSchema] = useState<FormSchema>();
|
||
|
||
const handleDesignerSave = async (schema: FormSchema) => {
|
||
console.log('💾 保存的表单 Schema:', JSON.stringify(schema, null, 2));
|
||
message.success('表单设计已保存!请查看控制台');
|
||
setPreviewSchema(schema); // 保存后更新预览
|
||
// 实际项目中这里会调用后端 API 保存
|
||
// await formSchemaService.save(schema);
|
||
};
|
||
|
||
// ==================== 示例 1.5: 工作流表单设计器(带审批字段) ====================
|
||
const [workflowDesignerSchema, setWorkflowDesignerSchema] = useState<FormSchema>();
|
||
|
||
const handleWorkflowDesignerSave = async (schema: FormSchema) => {
|
||
console.log('🔄 保存的工作流表单 Schema:', JSON.stringify(schema, null, 2));
|
||
message.success('工作流表单设计已保存!请查看控制台');
|
||
setWorkflowPreviewSchema(schema);
|
||
// 实际项目中这里会调用后端 API 保存
|
||
// await workflowFormService.save(schema);
|
||
};
|
||
|
||
const [workflowPreviewSchema, setWorkflowPreviewSchema] = useState<FormSchema>();
|
||
|
||
// ==================== 示例 2: 表单渲染器(静态) ====================
|
||
const [previewSchema, setPreviewSchema] = useState<FormSchema>();
|
||
|
||
const handleStaticFormSubmit = async (data: Record<string, any>) => {
|
||
console.log('📤 静态表单提交数据:', data);
|
||
message.success('表单提交成功!请查看控制台');
|
||
};
|
||
|
||
// ==================== 示例 3: 工作流表单(弹窗) ====================
|
||
const [workflowModalVisible, setWorkflowModalVisible] = useState(false);
|
||
|
||
const workflowFormSchema: FormSchema = {
|
||
version: '1.0',
|
||
formConfig: {
|
||
labelAlign: 'right',
|
||
size: 'middle',
|
||
formWidth: 600
|
||
},
|
||
fields: [
|
||
{
|
||
id: 'wf_field_1',
|
||
type: 'input',
|
||
label: '工作流名称',
|
||
name: 'workflowName',
|
||
placeholder: '请输入工作流名称',
|
||
required: true
|
||
},
|
||
{
|
||
id: 'wf_field_2',
|
||
type: 'select',
|
||
label: '目标环境',
|
||
name: 'environment',
|
||
placeholder: '请选择环境',
|
||
required: true,
|
||
dataSourceType: 'static',
|
||
options: [
|
||
{ label: '开发环境', value: 'dev' },
|
||
{ label: '测试环境', value: 'test' },
|
||
{ label: '生产环境', value: 'prod' }
|
||
]
|
||
},
|
||
{
|
||
id: 'wf_field_3',
|
||
type: 'textarea',
|
||
label: '执行说明',
|
||
name: 'description',
|
||
placeholder: '请输入执行说明',
|
||
rows: 4
|
||
},
|
||
],
|
||
};
|
||
|
||
const handleWorkflowSubmit = async (data: Record<string, any>) => {
|
||
console.log('🚀 工作流启动参数:', data);
|
||
message.success('工作流已启动!');
|
||
setWorkflowModalVisible(false);
|
||
};
|
||
|
||
// ==================== 示例 4: 只读模式 ====================
|
||
const readonlySchema: FormSchema = {
|
||
version: '1.0',
|
||
formConfig: {
|
||
labelAlign: 'right',
|
||
size: 'middle',
|
||
formWidth: 600
|
||
},
|
||
fields: [
|
||
{
|
||
id: 'ro_field_1',
|
||
type: 'input',
|
||
label: '申请人',
|
||
name: 'applicant'
|
||
},
|
||
{
|
||
id: 'ro_field_2',
|
||
type: 'date',
|
||
label: '申请日期',
|
||
name: 'applyDate'
|
||
},
|
||
{
|
||
id: 'ro_field_3',
|
||
type: 'select',
|
||
label: '审批状态',
|
||
name: 'approvalStatus',
|
||
dataSourceType: 'static',
|
||
options: [
|
||
{ label: '待审批', value: 'pending' },
|
||
{ label: '已通过', value: 'approved' },
|
||
{ label: '已拒绝', value: 'rejected' }
|
||
]
|
||
},
|
||
{
|
||
id: 'ro_field_4',
|
||
type: 'textarea',
|
||
label: '审批意见',
|
||
name: 'approvalComment'
|
||
},
|
||
],
|
||
};
|
||
|
||
const readonlyData = {
|
||
applicant: '张三',
|
||
applyDate: '2024-07-20',
|
||
approvalStatus: 'approved',
|
||
approvalComment: '同意申请,准予执行。',
|
||
};
|
||
|
||
// ==================== 示例 5: 复杂表单(带栅格布局) ====================
|
||
|
||
const complexFormSchema: FormSchema = {
|
||
version: '1.0',
|
||
formConfig: {
|
||
labelAlign: 'right',
|
||
size: 'middle',
|
||
formWidth: 800,
|
||
title: '用户信息登记表'
|
||
},
|
||
fields: [
|
||
{
|
||
id: 'grid_1',
|
||
type: 'grid',
|
||
label: '基本信息',
|
||
name: 'grid_basic',
|
||
columns: 2,
|
||
columnSpans: [12, 12],
|
||
gutter: 16,
|
||
children: [
|
||
[
|
||
{ id: 'f1', type: 'input', label: '姓名', name: 'name', placeholder: '请输入姓名', required: true },
|
||
{ id: 'f2', type: 'number', label: '年龄', name: 'age', placeholder: '请输入年龄', min: 1, max: 150 },
|
||
],
|
||
[
|
||
{ id: 'f3', type: 'radio', label: '性别', name: 'gender', dataSourceType: 'static', options: [{ label: '男', value: 'male' }, { label: '女', value: 'female' }] },
|
||
{ id: 'f4', type: 'date', label: '出生日期', name: 'birthday', placeholder: '请选择日期' },
|
||
],
|
||
],
|
||
},
|
||
{
|
||
id: 'grid_2',
|
||
type: 'grid',
|
||
label: '联系方式',
|
||
name: 'grid_contact',
|
||
columns: 2,
|
||
columnSpans: [12, 12],
|
||
gutter: 16,
|
||
children: [
|
||
[
|
||
{ id: 'f5', type: 'input', label: '手机号', name: 'phone', placeholder: '请输入手机号' },
|
||
{ id: 'f6', type: 'input', label: '邮箱', name: 'email', placeholder: '请输入邮箱' },
|
||
],
|
||
[
|
||
{ id: 'f7', type: 'input', label: '微信', name: 'wechat', placeholder: '请输入微信号' },
|
||
{ id: 'f8', type: 'input', label: 'QQ', name: 'qq', placeholder: '请输入QQ号' },
|
||
],
|
||
],
|
||
},
|
||
{
|
||
id: 'f9',
|
||
type: 'textarea',
|
||
label: '个人简介',
|
||
name: 'bio',
|
||
placeholder: '请输入个人简介',
|
||
rows: 4,
|
||
},
|
||
],
|
||
};
|
||
|
||
const handleComplexFormSubmit = async (data: Record<string, any>) => {
|
||
console.log('📋 复杂表单提交数据:', data);
|
||
message.success('表单提交成功!');
|
||
};
|
||
|
||
// ==================== 示例 6: 带生命周期钩子的表单 ====================
|
||
const lifecycleFormSchema: FormSchema = {
|
||
version: '1.0',
|
||
formConfig: {
|
||
labelAlign: 'right',
|
||
size: 'middle',
|
||
formWidth: 600
|
||
},
|
||
fields: [
|
||
{
|
||
id: 'lc_field_1',
|
||
type: 'input',
|
||
label: '用户名',
|
||
name: 'username',
|
||
placeholder: '请输入用户名',
|
||
required: true
|
||
},
|
||
{
|
||
id: 'lc_field_2',
|
||
type: 'input',
|
||
label: '邮箱',
|
||
name: 'email',
|
||
placeholder: '请输入邮箱',
|
||
required: true,
|
||
validationRules: [
|
||
{ type: 'email', message: '请输入有效的邮箱地址' }
|
||
]
|
||
},
|
||
{
|
||
id: 'lc_field_3',
|
||
type: 'select',
|
||
label: '用户角色',
|
||
name: 'role',
|
||
placeholder: '请选择角色',
|
||
required: true,
|
||
dataSourceType: 'static',
|
||
options: [
|
||
{ label: '管理员', value: 'admin' },
|
||
{ label: '普通用户', value: 'user' },
|
||
{ label: '访客', value: 'guest' }
|
||
]
|
||
},
|
||
],
|
||
};
|
||
|
||
const handleLifecycleBeforeSubmit = async (values: Record<string, any>) => {
|
||
console.log('🎣 beforeSubmit 钩子被调用:', values);
|
||
|
||
// 模拟数据处理
|
||
const processedValues = {
|
||
...values,
|
||
email: values.email?.toLowerCase(), // 邮箱转小写
|
||
submitTime: new Date().toISOString(), // 添加提交时间
|
||
};
|
||
|
||
message.info('正在处理表单数据...');
|
||
await new Promise(resolve => setTimeout(resolve, 500));
|
||
|
||
console.log('✅ beforeSubmit 处理完成,返回修改后的数据:', processedValues);
|
||
return processedValues;
|
||
};
|
||
|
||
const handleLifecycleSubmit = async (data: Record<string, any>) => {
|
||
console.log('📤 提交到服务器:', data);
|
||
|
||
// 模拟 API 调用
|
||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||
|
||
const response = { id: Math.random(), success: true, data };
|
||
console.log('✅ 服务器响应:', response);
|
||
message.success('用户创建成功!');
|
||
|
||
return response;
|
||
};
|
||
|
||
const handleLifecycleAfterSubmit = async (response: any) => {
|
||
console.log('🎣 afterSubmit 钩子被调用,服务器响应:', response);
|
||
|
||
// 模拟后续操作(如跳转、刷新列表等)
|
||
await new Promise(resolve => setTimeout(resolve, 300));
|
||
|
||
message.success(`用户 ID: ${response.id.toFixed(0)} 已成功创建`);
|
||
console.log('✅ afterSubmit 完成,可以执行跳转或刷新操作');
|
||
};
|
||
|
||
const handleLifecycleError = async (error: any) => {
|
||
console.error('🎣 onError 钩子被调用:', error);
|
||
|
||
// 可以在这里做错误上报、记录等
|
||
message.error(`操作失败: ${error.message || '未知错误'}`);
|
||
};
|
||
|
||
// ==================== Tab 配置 ====================
|
||
const tabItems = [
|
||
{
|
||
key: '1',
|
||
label: '📝 示例 1: 普通表单设计器',
|
||
children: (
|
||
<Card>
|
||
<h2>普通表单设计器(FormDesigner)</h2>
|
||
<p style={{ marginBottom: 16, color: '#666' }}>
|
||
可视化拖拽设计表单,支持导入/导出 JSON Schema,支持字段属性配置、验证规则、联动规则等。
|
||
</p>
|
||
<Alert
|
||
message="核心组件列表"
|
||
description="此设计器仅包含核心表单组件(输入框、下拉框、日期等),不包含工作流扩展字段。"
|
||
type="info"
|
||
showIcon
|
||
style={{ marginBottom: 16 }}
|
||
/>
|
||
<Divider />
|
||
<FormDesigner
|
||
value={designerSchema}
|
||
onChange={setDesignerSchema}
|
||
onSave={handleDesignerSave}
|
||
/>
|
||
</Card>
|
||
),
|
||
},
|
||
{
|
||
key: '1.5',
|
||
label: '🔄 示例 1.5: 工作流表单设计器',
|
||
children: (
|
||
<Card>
|
||
<h2>工作流表单设计器(带审批字段)</h2>
|
||
<p style={{ marginBottom: 16, color: '#666' }}>
|
||
通过 <code>extraComponents</code> 参数注入工作流扩展字段(审批人选择器等),实现插件式扩展。
|
||
</p>
|
||
<Alert
|
||
message="🔌 插件式架构展示"
|
||
description={
|
||
<div>
|
||
<p>✅ 核心组件 + 工作流扩展组件(审批人选择器)</p>
|
||
<p>✅ 左侧"高级字段"分类中可以看到"审批人"组件</p>
|
||
<p>✅ 拖拽到画布后,右侧显示完整的审批配置(9项)</p>
|
||
<p>✅ 支持审批模式、审批人类型、超时设置等</p>
|
||
</div>
|
||
}
|
||
type="success"
|
||
showIcon
|
||
style={{ marginBottom: 16 }}
|
||
/>
|
||
<div style={{
|
||
padding: 12,
|
||
background: '#f5f5f5',
|
||
borderRadius: 4,
|
||
marginBottom: 16,
|
||
fontFamily: 'monospace',
|
||
fontSize: 12
|
||
}}>
|
||
<strong>使用方式:</strong><br />
|
||
{`<FormDesigner`}<br />
|
||
{` value={schema}`}<br />
|
||
{` onChange={setSchema}`}<br />
|
||
{` extraComponents={WORKFLOW_COMPONENTS}`}<br />
|
||
{`/>`}
|
||
</div>
|
||
<Divider />
|
||
<FormDesigner
|
||
value={workflowDesignerSchema}
|
||
onChange={setWorkflowDesignerSchema}
|
||
onSave={handleWorkflowDesignerSave}
|
||
extraComponents={WORKFLOW_COMPONENTS}
|
||
/>
|
||
</Card>
|
||
),
|
||
},
|
||
{
|
||
key: '2',
|
||
label: '🎨 示例 2: 普通表单渲染',
|
||
children: (
|
||
<Card>
|
||
<h2>表单渲染器(普通表单)</h2>
|
||
<p style={{ marginBottom: 16, color: '#666' }}>
|
||
根据设计器保存的 Schema 渲染表单,支持数据收集、验证和提交。
|
||
</p>
|
||
<Divider />
|
||
<Alert
|
||
message="✅ 正确用法"
|
||
description="FormRenderer 现在是非受控组件,不需要传递 value 和 onChange。表单内部自动管理状态,onSubmit 会返回完整数据。"
|
||
type="success"
|
||
showIcon
|
||
style={{ marginBottom: 16 }}
|
||
/>
|
||
{previewSchema ? (
|
||
<FormRenderer
|
||
schema={previewSchema}
|
||
onSubmit={handleStaticFormSubmit}
|
||
showSubmit
|
||
showCancel
|
||
/>
|
||
) : (
|
||
<div style={{ padding: 40, textAlign: 'center', color: '#999' }}>
|
||
请先在"示例 1"中设计表单并保存
|
||
</div>
|
||
)}
|
||
</Card>
|
||
),
|
||
},
|
||
{
|
||
key: '2.5',
|
||
label: '🔄 示例 2.5: 工作流表单渲染',
|
||
children: (
|
||
<Card>
|
||
<h2>工作流表单渲染(带审批字段)</h2>
|
||
<p style={{ marginBottom: 16, color: '#666' }}>
|
||
渲染包含审批字段的表单,必须传递 <code>extraComponents</code> 参数以支持扩展组件。
|
||
</p>
|
||
<Alert
|
||
message="重要提示"
|
||
description="使用 FormRenderer 渲染包含扩展字段的表单时,必须传递 extraComponents={WORKFLOW_COMPONENTS},否则扩展字段无法正确渲染。"
|
||
type="warning"
|
||
showIcon
|
||
style={{ marginBottom: 16 }}
|
||
/>
|
||
<Alert
|
||
message="✅ 下拉框可选中"
|
||
description="FormRenderer 现已修复,下拉框可以正常选中。不需要传递 value 和 onChange,表单内部自动管理状态。"
|
||
type="success"
|
||
showIcon
|
||
style={{ marginBottom: 16 }}
|
||
/>
|
||
<Divider />
|
||
{workflowPreviewSchema ? (
|
||
<FormRenderer
|
||
schema={workflowPreviewSchema}
|
||
extraComponents={WORKFLOW_COMPONENTS}
|
||
onSubmit={async (data) => {
|
||
console.log('🔄 工作流表单提交数据:', data);
|
||
message.success('工作流表单提交成功!');
|
||
}}
|
||
showSubmit
|
||
showCancel
|
||
/>
|
||
) : (
|
||
<div style={{ padding: 40, textAlign: 'center', color: '#999' }}>
|
||
请先在"示例 1.5"中设计工作流表单并保存
|
||
</div>
|
||
)}
|
||
</Card>
|
||
),
|
||
},
|
||
{
|
||
key: '3',
|
||
label: '🚀 示例 3: 工作流表单',
|
||
children: (
|
||
<Card>
|
||
<h2>工作流表单(弹窗模式)</h2>
|
||
<p style={{ marginBottom: 16, color: '#666' }}>
|
||
模拟工作流启动场景,在 Modal 中使用表单渲染器收集参数。
|
||
</p>
|
||
<Divider />
|
||
<Space direction="vertical" size="large" style={{ width: '100%' }}>
|
||
<div>
|
||
<h3>使用场景</h3>
|
||
<ul>
|
||
<li>工作流启动参数收集</li>
|
||
<li>任务审批表单</li>
|
||
<li>快捷操作弹窗</li>
|
||
</ul>
|
||
</div>
|
||
<Button type="primary" size="large" onClick={() => setWorkflowModalVisible(true)}>
|
||
启动工作流
|
||
</Button>
|
||
</Space>
|
||
<Modal
|
||
title="启动工作流"
|
||
open={workflowModalVisible}
|
||
onCancel={() => setWorkflowModalVisible(false)}
|
||
footer={null}
|
||
width={workflowFormSchema.formConfig.formWidth || 600}
|
||
>
|
||
<FormRenderer
|
||
schema={workflowFormSchema}
|
||
onSubmit={handleWorkflowSubmit}
|
||
onCancel={() => setWorkflowModalVisible(false)}
|
||
showCancel
|
||
submitText="启动"
|
||
cancelText="取消"
|
||
/>
|
||
</Modal>
|
||
</Card>
|
||
),
|
||
},
|
||
{
|
||
key: '4',
|
||
label: '👁️ 示例 4: 只读模式',
|
||
children: (
|
||
<Card>
|
||
<h2>只读模式</h2>
|
||
<p style={{ marginBottom: 16, color: '#666' }}>
|
||
查看已提交的表单数据,所有字段禁用编辑,不显示提交按钮。
|
||
</p>
|
||
<Divider />
|
||
<div>
|
||
<h3>使用场景</h3>
|
||
<ul>
|
||
<li>审批流程详情查看</li>
|
||
<li>历史数据展示</li>
|
||
<li>表单归档查看</li>
|
||
</ul>
|
||
</div>
|
||
<Divider />
|
||
<FormRenderer
|
||
schema={readonlySchema}
|
||
value={readonlyData}
|
||
readonly={true}
|
||
/>
|
||
</Card>
|
||
),
|
||
},
|
||
{
|
||
key: '5',
|
||
label: '📋 示例 5: 复杂表单',
|
||
children: (
|
||
<Card>
|
||
<h2>复杂表单(带栅格布局)</h2>
|
||
<p style={{ marginBottom: 16, color: '#666' }}>
|
||
展示包含栅格布局的复杂表单,支持多列排版。
|
||
</p>
|
||
<Divider />
|
||
<FormRenderer
|
||
schema={complexFormSchema}
|
||
onSubmit={handleComplexFormSubmit}
|
||
showSubmit
|
||
showCancel
|
||
/>
|
||
</Card>
|
||
),
|
||
},
|
||
{
|
||
key: '6',
|
||
label: '🎣 示例 6: 生命周期钩子',
|
||
children: (
|
||
<Card>
|
||
<h2>生命周期钩子(beforeSubmit / afterSubmit / onError)</h2>
|
||
<p style={{ marginBottom: 16, color: '#666' }}>
|
||
演示表单提交的完整生命周期钩子,支持数据预处理、提交后处理和错误处理。
|
||
</p>
|
||
<Alert
|
||
message="🎣 生命周期钩子"
|
||
description={
|
||
<div>
|
||
<p><strong>beforeSubmit</strong>: 提交前处理,可修改数据或取消提交(返回 false)</p>
|
||
<p><strong>onSubmit</strong>: 执行实际提交操作</p>
|
||
<p><strong>afterSubmit</strong>: 提交成功后的处理(跳转、刷新等)</p>
|
||
<p><strong>onError</strong>: 错误处理(验证失败、提交失败等)</p>
|
||
</div>
|
||
}
|
||
type="info"
|
||
showIcon
|
||
style={{ marginBottom: 16 }}
|
||
/>
|
||
<div style={{
|
||
padding: 12,
|
||
background: '#f5f5f5',
|
||
borderRadius: 4,
|
||
marginBottom: 16,
|
||
fontFamily: 'monospace',
|
||
fontSize: 12
|
||
}}>
|
||
<strong>使用方式:</strong><br />
|
||
{`<FormRenderer`}<br />
|
||
{` schema={schema}`}<br />
|
||
{` beforeSubmit={async (values) => {`}<br />
|
||
{` // 数据预处理`}<br />
|
||
{` return modifiedValues;`}<br />
|
||
{` }}`}<br />
|
||
{` onSubmit={async (data) => {`}<br />
|
||
{` // 提交到服务器`}<br />
|
||
{` return response;`}<br />
|
||
{` }}`}<br />
|
||
{` afterSubmit={async (response) => {`}<br />
|
||
{` // 提交后处理`}<br />
|
||
{` }}`}<br />
|
||
{` onError={async (error) => {`}<br />
|
||
{` // 错误处理`}<br />
|
||
{` }}`}<br />
|
||
{`/>`}
|
||
</div>
|
||
<Divider />
|
||
<FormRenderer
|
||
schema={lifecycleFormSchema}
|
||
beforeSubmit={handleLifecycleBeforeSubmit}
|
||
onSubmit={handleLifecycleSubmit}
|
||
afterSubmit={handleLifecycleAfterSubmit}
|
||
onError={handleLifecycleError}
|
||
showSubmit
|
||
showCancel
|
||
/>
|
||
<Alert
|
||
message="📝 提示"
|
||
description="打开浏览器控制台查看完整的钩子执行流程,包括 beforeSubmit、onSubmit、afterSubmit 的详细日志输出。"
|
||
type="success"
|
||
showIcon
|
||
style={{ marginTop: 16 }}
|
||
/>
|
||
</Card>
|
||
),
|
||
},
|
||
];
|
||
|
||
return (
|
||
<div style={{ padding: 24 }}>
|
||
<div style={{ marginBottom: 24 }}>
|
||
<h1>FormDesigner 组件使用示例</h1>
|
||
<p style={{ color: '#666', fontSize: 14 }}>
|
||
本页面展示如何使用 <code>@/components/FormDesigner</code> 中的 <strong>FormDesigner</strong> 和 <strong>FormRenderer</strong> 组件。
|
||
</p>
|
||
</div>
|
||
<Tabs defaultActiveKey="1" items={tabItems} />
|
||
</div>
|
||
);
|
||
};
|
||
|
||
export default FormDesignerExamplesPage;
|