# 工作流动态表单设计方案 ## 1. 整体架构 ### 1.1 数据流向 ``` 1. 流程设计阶段 ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ 表单设计器 │ │ 流程设计器 │ │ 后端存储 │ │ Form Designer │ ──> │ Flow Designer │ ──> │ Database │ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ │ │ │ 设计表单 │ 配置节点表单 │ 保存定义 │ JSON Schema │ 配置数据映射 │ - 表单定义 │ UI Schema │ 配置权限 │ - 流程定义 ▼ ▼ ▼ 2. 流程运行阶段 ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ 流程发起 │ │ 节点激活 │ │ 表单实例化 │ │ Start Flow │ ──> │ Node Activated │ ──> │ Form Instance │ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ │ │ 触发监听器 │ 创建表单实例 │ │ 初始化数据 ▼ ▼ 3. 表单处理阶段 ┌─────────────��───┐ ┌─────────────────┐ ┌─────────────────┐ │ 表单渲染 │ │ 表单交互 │ │ 数据处理 │ │ Form Render │ ──> │ Form Interact │ ──> │ Data Process │ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ │ │ │ 加载表单定义 │ 用户输入 │ 数据验证 │ 加载实例数据 │ 数据提交 │ 数据转换 │ 应用权限 │ │ 变量映射 ▼ ▼ ▼ 4. 节点完成阶段 ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ 表单提交 │ │ 节点完成 │ │ 流程推进 │ │ Form Submit │ ──> │ Node Complete │ ──> │ Flow Progress │ └─────────────────┘ └─────────────���───┘ └─────────────────┘ │ │ │ 触发监听器 │ 流转到下一节点 │ 更新流程变量 │ ▼ ▼ ``` ### 1.2 数据模型设计 1. **表单定义(FormDefinition)** ```java @Data @Table(name = "workflow_form_definition") @Entity @LogicDelete public class FormDefinition extends Entity { @Column(nullable = false) private String name; // 表单名称 @Column(nullable = false, unique = true) private String code; // 表单编码 @Column(columnDefinition = "TEXT") private String description; // 表单描述 @Type(JsonType.class) @Column(columnDefinition = "json", nullable = false) private JsonNode schema; // 表单JSON Schema @Type(JsonType.class) @Column(columnDefinition = "json") private JsonNode uiSchema; // UI渲染Schema @Column(nullable = false) private Boolean enabled = true; // 是否启用 @Column(nullable = false) private Integer version = 1; // 版本号 } ``` 2. **表单实例(FormInstance)** ```java @Data @Table(name = "workflow_form_instance") @Entity @LogicDelete public class FormInstance extends Entity { @Column(nullable = false) private Long formDefinitionId; // 表单定义ID @Column(nullable = false) private String processInstanceId; // 流程实例ID @Column(nullable = false) private String taskId; // 任务ID @Type(JsonType.class) @Column(columnDefinition = "json", nullable = false) private JsonNode formData; // 表单数据 @Column(nullable = false) @Enumerated(EnumType.STRING) private FormInstanceStatus status; // 状态 } ``` ## 2. 节点表单集成 ### 2.1 工作流上下文设计 ```java @Data public class WorkflowContext { // 系统上下文 private SystemContext systemContext; // 表单上下文 private FormContext formContext; // 流程变量上下文 private ProcessContext processContext; @Data public static class SystemContext { private JsonNode systemConfig; // 系统配置 private String executionId; // 执行ID private String processInstanceId; // 流程实例ID private String nodeId; // 节点ID } @Data public static class FormContext { private Long formInstanceId; // 表单实例ID private JsonNode formData; // 表单数据 private JsonNode formConfig; // 表单配置 private Map mappedData; // 映射后的数据 } @Data public static class ProcessContext { private Map variables; // 流程变量 private Map localVariables; // 节点本地变量 } } ``` ### 2.2 节点定义中的表单配置 ```java @Data @Table(name = "workflow_node_definition") @Entity @LogicDelete public class WorkflowNodeDefinition extends Entity { // ... 现有字段 ... /** * 表单配置 */ @Type(JsonType.class) @Column(columnDefinition = "json") private JsonNode formConfig; // 节点默认的表单配置 /** * 表单Schema */ @Type(JsonType.class) @Column(columnDefinition = "json") private JsonNode formSchema; // 节点默认的表单结构 /** * 表单UI Schema */ @Type(JsonType.class) @Column(columnDefinition = "json") private JsonNode formUiSchema; // 节点默认的UI渲染配置 } ``` ## 3. 动态接口支持 ### 3.1 表单配置中的接口定义 ```json { "formSchema": { "type": "object", "properties": { "department": { "type": "string", "title": "部门", "enum": "@api:getDepartments", "enumNames": "@api:getDepartmentNames" }, "employee": { "type": "string", "title": "员工", "enum": "@api:getEmployeesByDepartment(department)", "enumNames": "@api:getEmployeeNamesByDepartment(department)" } } } } ``` ### 3.2 动态接口注册 ```java @Service public class DynamicApiRegistry { private final Map apiRegistry = new ConcurrentHashMap<>(); @PostConstruct public void init() { // 注册系统内置API registerSystemApis(); } // 注册API public void register(String apiKey, DynamicApi api) { apiRegistry.put(apiKey, api); } // 获取API public DynamicApi getApi(String apiKey) { return apiRegistry.get(apiKey); } } ``` ### 3.3 动态API定义 ```java @Data @Builder public class DynamicApi { private String url; // API地址 private HttpMethod method; // 请求方法 private Function, Map> paramsBuilder; // 参数构建器 private String transform; // 数据转换路径 private Map mapping; // 数据映射 private List dependencies; // 依赖字段 } ``` ## 4. 使用示例 ### 4.1 定义节点表单 ```json { "systemConfig": { "timeout": 3600, "retryTimes": 3, "notifyEmail": "admin@example.com" }, "formConfig": { "formSchema": { /* 表单结构 */ }, "formUiSchema": { /* UI渲染配置 */ }, "permissions": { /* 权限配置 */ }, "dataMapping": { "input": { /* 输入映射 */ }, "output": { /* 输出映射 */ } } } } ``` ### 4.2 注册动态接口 ```java @Component public class CustomApiConfig { @Resource private DynamicApiRegistry apiRegistry; @PostConstruct public void init() { // 注册项目查询API apiRegistry.register("getProjects", new DynamicApi.builder() .url("/api/v1/projects") .method(HttpMethod.GET) .paramsBuilder(context -> Map.of( "departmentId", context.get("department"), "employeeId", context.get("employee") )) .transform("data.list") .mapping(Map.of("value", "id", "label", "name")) .dependencies(List.of("department", "employee")) .build() ); } } ``` ### 4.3 实现委派类 ```java @Component @Slf4j public class ApprovalTaskDelegate extends BaseWorkflowDelegate { @Override protected void doExecute(WorkflowContext context) throws Exception { // 1. 获取表单数据 FormContext formContext = context.getFormContext(); Map mappedData = formContext.getMappedData(); String approvalResult = (String) mappedData.get("approvalResult"); String comments = (String) mappedData.get("comments"); // 2. 获取系统配置 SystemContext systemContext = context.getSystemContext(); JsonNode systemConfig = systemContext.getSystemConfig(); String notifyEmail = systemConfig.get("notifyEmail").asText(); // 3. 处理审批结果 ProcessContext processContext = context.getProcessContext(); processContext.getVariables().put("approved", "APPROVED".equals(approvalResult)); processContext.getVariables().put("approvalComments", comments); // 4. 发送通知 if (notifyEmail != null) { notificationService.sendApprovalNotification(notifyEmail, approvalResult, comments); } } } ```