反序列化问题。
This commit is contained in:
parent
78c35ce6e4
commit
09489b3e11
18
.windsurfrules
Normal file
18
.windsurfrules
Normal file
@ -0,0 +1,18 @@
|
||||
你是一名java前端开发工程师,对你有以下要求
|
||||
1. 缺陷修正:
|
||||
- 在提出修复建议前,应充分分析问题
|
||||
- 提供精准、有针对性的解决方案
|
||||
- 解释bug的根本原因
|
||||
|
||||
2. 保持简单:
|
||||
- 优先考虑可读性和可维护性
|
||||
- 避免过度工程化的解决方案
|
||||
- 尽可能使用标准库和模式
|
||||
- 遵循正确、最佳实践、DRY原则、无错误、功能齐全的代码编写原则
|
||||
|
||||
3. 代码更改:
|
||||
- 在做出改变之前提出一个清晰的计划
|
||||
- 一次将所有修改应用于单个文件
|
||||
- 请勿修改不相关的文件
|
||||
|
||||
记住要始终考虑每个项目的背景和特定需求。
|
||||
@ -2,7 +2,7 @@ package com.qqchen.deploy.backend.workflow.dto;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.qqchen.deploy.backend.framework.dto.BaseDTO;
|
||||
import com.qqchen.deploy.backend.workflow.dto.graph.WorkflowGraph;
|
||||
import com.qqchen.deploy.backend.workflow.dto.graph.WorkflowDefinitionGraph;
|
||||
import com.qqchen.deploy.backend.workflow.enums.WorkflowStatusEnums;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
@ -39,7 +39,7 @@ public class WorkflowDefinitionDTO extends BaseDTO {
|
||||
/**
|
||||
* 图形数据
|
||||
*/
|
||||
private WorkflowGraph graph;
|
||||
private WorkflowDefinitionGraph graph;
|
||||
|
||||
/**
|
||||
* 表单配置
|
||||
|
||||
@ -1,19 +0,0 @@
|
||||
package com.qqchen.deploy.backend.workflow.dto.graph;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import lombok.Data;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 节点配置
|
||||
* @author cascade
|
||||
* @date 2024-12-11
|
||||
*/
|
||||
@Data
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL) // 只序列化非空字段
|
||||
public class NodeConfig {
|
||||
|
||||
|
||||
|
||||
}
|
||||
@ -9,7 +9,7 @@ import java.util.Map;
|
||||
* @date 2024-12-11
|
||||
*/
|
||||
@Data
|
||||
public class WorkflowEdge {
|
||||
public class WorkflowDefinitionEdge {
|
||||
/**
|
||||
* 边ID
|
||||
*/
|
||||
@ -18,12 +18,12 @@ public class WorkflowEdge {
|
||||
/**
|
||||
* 源节点ID
|
||||
*/
|
||||
private String source;
|
||||
private String from;
|
||||
|
||||
/**
|
||||
* 目标节点ID
|
||||
*/
|
||||
private String target;
|
||||
private String to;
|
||||
|
||||
/**
|
||||
* 边名称
|
||||
@ -33,7 +33,7 @@ public class WorkflowEdge {
|
||||
/**
|
||||
* 边配置
|
||||
*/
|
||||
private EdgeConfig config;
|
||||
private WorkflowDefinitionEdgeConfig config;
|
||||
|
||||
/**
|
||||
* 边属性
|
||||
@ -10,7 +10,7 @@ import lombok.Data;
|
||||
*/
|
||||
@Data
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL) // 只序列化非空字段
|
||||
public class EdgeConfig {
|
||||
public class WorkflowDefinitionEdgeConfig {
|
||||
/**
|
||||
* 条件
|
||||
*/
|
||||
@ -31,14 +31,4 @@ public class EdgeConfig {
|
||||
*/
|
||||
private String type;
|
||||
|
||||
public void setConditionExpression(String conditionExpression) {
|
||||
this.conditionExpression = conditionExpression;
|
||||
// 同时设置 condition 字段,保持兼容性
|
||||
this.condition = conditionExpression;
|
||||
}
|
||||
|
||||
public String getConditionExpression() {
|
||||
// 如果 conditionExpression 为空但 condition 不为空,返回 condition
|
||||
return conditionExpression != null ? conditionExpression : condition;
|
||||
}
|
||||
}
|
||||
@ -8,7 +8,7 @@ import lombok.Data;
|
||||
* @date 2024-12-11
|
||||
*/
|
||||
@Data
|
||||
public class Size {
|
||||
public class WorkflowDefinitionEdgeSize {
|
||||
/**
|
||||
* 宽度
|
||||
*/
|
||||
@ -2,7 +2,6 @@ package com.qqchen.deploy.backend.workflow.dto.graph;
|
||||
|
||||
import lombok.Data;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 工作流图形数据传输对象
|
||||
@ -10,15 +9,15 @@ import java.util.Map;
|
||||
* @date 2024-12-11
|
||||
*/
|
||||
@Data
|
||||
public class WorkflowGraph {
|
||||
public class WorkflowDefinitionGraph {
|
||||
/**
|
||||
* 节点列表
|
||||
*/
|
||||
private List<WorkflowNode> nodes;
|
||||
private List<WorkflowDefinitionNode> nodes;
|
||||
|
||||
/**
|
||||
* 边列表
|
||||
*/
|
||||
private List<WorkflowEdge> edges;
|
||||
private List<WorkflowDefinitionEdge> edges;
|
||||
|
||||
}
|
||||
@ -2,47 +2,36 @@ package com.qqchen.deploy.backend.workflow.dto.graph;
|
||||
|
||||
import com.qqchen.deploy.backend.workflow.enums.NodeTypeEnums;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 工作流节点数据传输对象
|
||||
*
|
||||
* @author cascade
|
||||
* @date 2024-12-11
|
||||
*/
|
||||
@Data
|
||||
public class WorkflowNode {
|
||||
public class WorkflowDefinitionNode {
|
||||
/**
|
||||
* 节点ID
|
||||
*/
|
||||
private String id;
|
||||
|
||||
|
||||
/**
|
||||
* 节点类型
|
||||
*/
|
||||
private NodeTypeEnums type;
|
||||
|
||||
|
||||
/**
|
||||
* 节点名称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 节点位置
|
||||
*/
|
||||
private Position position;
|
||||
|
||||
|
||||
|
||||
private WorkflowNodeGraph graph;
|
||||
/**
|
||||
* 节点配置
|
||||
*/
|
||||
private NodeConfig config;
|
||||
|
||||
/**
|
||||
* 节点属性
|
||||
*/
|
||||
private Map<String, Object> properties;
|
||||
|
||||
/**
|
||||
* 节点大小
|
||||
*/
|
||||
private Size size;
|
||||
private Map<String, Object> config;
|
||||
}
|
||||
@ -12,7 +12,7 @@ import lombok.AllArgsConstructor;
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class Position {
|
||||
public class WorkflowDefinitionPosition {
|
||||
/**
|
||||
* X坐标
|
||||
*/
|
||||
@ -1,8 +1,9 @@
|
||||
package com.qqchen.deploy.backend.workflow.config;
|
||||
package com.qqchen.deploy.backend.workflow.dto.graph;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -13,42 +14,46 @@ import java.util.Map;
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class NodeUiConfig {
|
||||
public class WorkflowNodeGraph {
|
||||
|
||||
private String shape;
|
||||
|
||||
private Size size;
|
||||
|
||||
private Style style;
|
||||
|
||||
private Ports ports;
|
||||
|
||||
public NodeUiConfig setSize(int width, int height) {
|
||||
public WorkflowNodeGraph setSize(int width, int height) {
|
||||
this.size = new Size(width, height);
|
||||
return this;
|
||||
}
|
||||
|
||||
public NodeUiConfig setStyle(String fill, String stroke, String icon) {
|
||||
public WorkflowNodeGraph setStyle(String fill, String stroke, String icon) {
|
||||
this.style = new Style(fill, stroke, icon);
|
||||
return this;
|
||||
}
|
||||
|
||||
public NodeUiConfig setPorts(List<String> types) {
|
||||
public WorkflowNodeGraph configPorts(List<String> types) {
|
||||
this.ports = new Ports();
|
||||
Map<String, PortGroup> groups = new HashMap<>();
|
||||
|
||||
|
||||
types.forEach(type -> {
|
||||
PortGroup group = new PortGroup();
|
||||
group.setPosition(type.equals("in") ? "left" : "right");
|
||||
|
||||
|
||||
PortCircle circle = new PortCircle();
|
||||
circle.setR(4);
|
||||
circle.setFill("#ffffff");
|
||||
circle.setStroke("#1890ff");
|
||||
|
||||
|
||||
PortAttrs attrs = new PortAttrs();
|
||||
attrs.setCircle(circle);
|
||||
|
||||
|
||||
group.setAttrs(attrs);
|
||||
groups.put(type, group);
|
||||
});
|
||||
|
||||
|
||||
this.ports.setGroups(groups);
|
||||
return this;
|
||||
}
|
||||
@ -59,6 +64,7 @@ public class NodeUiConfig {
|
||||
@Data
|
||||
public static class Size {
|
||||
private int width;
|
||||
|
||||
private int height;
|
||||
|
||||
public Size(int width, int height) {
|
||||
@ -73,9 +79,13 @@ public class NodeUiConfig {
|
||||
@Data
|
||||
public static class Style {
|
||||
private String fill; // 填充颜色
|
||||
|
||||
private String stroke; // 边框颜色
|
||||
|
||||
private String icon; // 图标名称
|
||||
|
||||
private String iconColor; // 图标颜色
|
||||
|
||||
private int strokeWidth = 2;// 边框宽度
|
||||
|
||||
public Style(String fill, String stroke, String icon) {
|
||||
@ -92,32 +102,34 @@ public class NodeUiConfig {
|
||||
@Data
|
||||
public static class Ports {
|
||||
private Map<String, PortGroup> groups;
|
||||
|
||||
/**
|
||||
* 获取端口类型列表
|
||||
* @return 端口类型列表("in"/"out")
|
||||
*/
|
||||
public List<String> getTypes() {
|
||||
if (groups == null) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
return new ArrayList<>(groups.keySet());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 连接点分组配置
|
||||
*/
|
||||
@Data
|
||||
public static class PortGroup {
|
||||
private String position; // 位置:left, right, top, bottom
|
||||
private PortAttrs attrs; // 连接点属性
|
||||
private String position;
|
||||
private PortAttrs attrs;
|
||||
}
|
||||
|
||||
/**
|
||||
* 连接点属性配置
|
||||
*/
|
||||
@Data
|
||||
public static class PortAttrs {
|
||||
private PortCircle circle; // 圆形连接点
|
||||
private PortCircle circle;
|
||||
}
|
||||
|
||||
/**
|
||||
* 圆形连接点配置
|
||||
*/
|
||||
@Data
|
||||
public static class PortCircle {
|
||||
private int r; // 半径
|
||||
private String fill; // 填充颜色
|
||||
private String stroke; // 边框颜色
|
||||
private int r;
|
||||
private String fill;
|
||||
private String stroke;
|
||||
}
|
||||
}
|
||||
@ -1,36 +0,0 @@
|
||||
package com.qqchen.deploy.backend.workflow.dto.graph;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 工作流属性
|
||||
* @author cascade
|
||||
* @date 2024-12-11
|
||||
*/
|
||||
@Data
|
||||
public class WorkflowProperties {
|
||||
/**
|
||||
* 工作流名称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 工作流标识
|
||||
*/
|
||||
private String key;
|
||||
|
||||
/**
|
||||
* 工作流描述
|
||||
*/
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 工作流版本
|
||||
*/
|
||||
private Integer version;
|
||||
|
||||
/**
|
||||
* 工作流类别
|
||||
*/
|
||||
private String category;
|
||||
}
|
||||
@ -7,6 +7,6 @@ import lombok.Data;
|
||||
* 事件节点基础配置
|
||||
*/
|
||||
@Data
|
||||
public class BaseEventNodeConfig extends BaseNodeConfig {
|
||||
public abstract class BaseEventNodeConfig extends BaseNodeConfig {
|
||||
|
||||
}
|
||||
|
||||
@ -2,7 +2,7 @@ package com.qqchen.deploy.backend.workflow.entity;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.qqchen.deploy.backend.framework.annotation.LogicDelete;
|
||||
import com.qqchen.deploy.backend.workflow.dto.graph.WorkflowGraph;
|
||||
import com.qqchen.deploy.backend.workflow.dto.graph.WorkflowDefinitionGraph;
|
||||
import com.qqchen.deploy.backend.workflow.enums.WorkflowStatusEnums;
|
||||
import com.qqchen.deploy.backend.workflow.hibernate.WorkflowGraphType;
|
||||
import com.qqchen.deploy.backend.framework.domain.Entity;
|
||||
@ -54,7 +54,7 @@ public class WorkflowDefinition extends Entity<Long> {
|
||||
*/
|
||||
@Type(WorkflowGraphType.class)
|
||||
@Column(name = "graph", columnDefinition = "json")
|
||||
private WorkflowGraph graph;
|
||||
private WorkflowDefinitionGraph graph;
|
||||
|
||||
/**
|
||||
* 表单配置
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
package com.qqchen.deploy.backend.workflow.enums;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonValue;
|
||||
import com.qqchen.deploy.backend.workflow.config.NodeUiConfig;
|
||||
import com.qqchen.deploy.backend.workflow.dto.graph.WorkflowNodeGraph;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 工作流节点类型枚举
|
||||
@ -20,11 +21,27 @@ public enum NodeTypeEnums {
|
||||
* - 只能有出边,不能有入边
|
||||
* - 用于触发工作流的执行
|
||||
*/
|
||||
START_EVENT("START_EVENT", "开始节点", new NodeUiConfig()
|
||||
.setShape("circle")
|
||||
.setSize(40, 40)
|
||||
.setStyle("#e8f7ff", "#1890ff", "play-circle")
|
||||
.setPorts(Arrays.asList("out"))),
|
||||
START_EVENT(
|
||||
"START_EVENT", // 节点类型编码
|
||||
"开始节点", // 节点显示名称
|
||||
"工作流的起点", // 节点简要描述
|
||||
"标记流程的开始位置,可以定义流程启动条件和初始化流程变量", // 节点详细描述
|
||||
Arrays.asList( // 节点功能列表
|
||||
"标记流程的开始位置",
|
||||
"定义流程启动条件",
|
||||
"初始化流程变量"
|
||||
),
|
||||
Arrays.asList( // 使用场景列表
|
||||
"用户手动启动流程",
|
||||
"定时触发流程",
|
||||
"外部系统调用启动"
|
||||
),
|
||||
new WorkflowNodeGraph() // UI配置
|
||||
.setShape("circle")
|
||||
.setSize(40, 40)
|
||||
.setStyle("#e8f7ff", "#1890ff", "play-circle")
|
||||
.configPorts(Arrays.asList("out"))
|
||||
),
|
||||
|
||||
/**
|
||||
* 结束节点
|
||||
@ -33,11 +50,27 @@ public enum NodeTypeEnums {
|
||||
* - 只能有入边,不能有出边
|
||||
* - 标志着工作流的结束
|
||||
*/
|
||||
END_EVENT("END_EVENT", "结束节点", new NodeUiConfig()
|
||||
.setShape("circle")
|
||||
.setSize(40, 40)
|
||||
.setStyle("#fff1f0", "#ff4d4f", "stop")
|
||||
.setPorts(Arrays.asList("in"))),
|
||||
END_EVENT(
|
||||
"END_EVENT",
|
||||
"结束节点",
|
||||
"工作流的终点",
|
||||
"标记流程的结束位置,可以定义流程结束时的清理操作和设置返回值",
|
||||
Arrays.asList(
|
||||
"标记流程的结束位置",
|
||||
"定义结束时清理操作",
|
||||
"设置流程结果和返回值"
|
||||
),
|
||||
Arrays.asList(
|
||||
"流程正常结束",
|
||||
"流程异常终止",
|
||||
"需要返回处理结果"
|
||||
),
|
||||
new WorkflowNodeGraph()
|
||||
.setShape("circle")
|
||||
.setSize(40, 40)
|
||||
.setStyle("#fff1f0", "#ff4d4f", "stop")
|
||||
.configPorts(Arrays.asList("in"))
|
||||
),
|
||||
|
||||
/**
|
||||
* 用户任务节点
|
||||
@ -47,11 +80,29 @@ public enum NodeTypeEnums {
|
||||
* - 可以分配给特定用户或角色
|
||||
* - 支持审批、填写表单等操作
|
||||
*/
|
||||
USER_TASK("USER_TASK", "用户任务", new NodeUiConfig()
|
||||
.setShape("rectangle")
|
||||
.setSize(120, 60)
|
||||
.setStyle("#ffffff", "#1890ff", "user")
|
||||
.setPorts(Arrays.asList("in", "out"))),
|
||||
USER_TASK(
|
||||
"USER_TASK",
|
||||
"用户任务",
|
||||
"人工处理任务",
|
||||
"需要人工处理的任务节点,支持任务分配、表单填写、处理期限等功能",
|
||||
Arrays.asList(
|
||||
"分配任务给指定用户或角色",
|
||||
"支持任务表单的填写",
|
||||
"设置处理期限和提醒",
|
||||
"支持任务的转办、委托、退回"
|
||||
),
|
||||
Arrays.asList(
|
||||
"审批流程",
|
||||
"表单填写",
|
||||
"人工审核",
|
||||
"数据确认"
|
||||
),
|
||||
new WorkflowNodeGraph()
|
||||
.setShape("rectangle")
|
||||
.setSize(120, 60)
|
||||
.setStyle("#ffffff", "#1890ff", "user")
|
||||
.configPorts(Arrays.asList("in", "out"))
|
||||
),
|
||||
|
||||
/**
|
||||
* 服务任务节点
|
||||
@ -61,11 +112,29 @@ public enum NodeTypeEnums {
|
||||
* - 可以调用外部服务或系统API
|
||||
* - 支持异步执行
|
||||
*/
|
||||
SERVICE_TASK("SERVICE_TASK", "服务任务", new NodeUiConfig()
|
||||
.setShape("rectangle")
|
||||
.setSize(120, 60)
|
||||
.setStyle("#ffffff", "#1890ff", "api")
|
||||
.setPorts(Arrays.asList("in", "out"))),
|
||||
SERVICE_TASK(
|
||||
"SERVICE_TASK",
|
||||
"服务任务",
|
||||
"系统服务调用",
|
||||
"自动执行的系统服务任务,支持同步/异步调用外部服务和系统API",
|
||||
Arrays.asList(
|
||||
"调用系统服务或外部接口",
|
||||
"执行自动化操作",
|
||||
"支持异步执行和结果回调",
|
||||
"数据转换和处理"
|
||||
),
|
||||
Arrays.asList(
|
||||
"调用外部系统API",
|
||||
"发送通知消息",
|
||||
"数据同步处理",
|
||||
"自动化操作"
|
||||
),
|
||||
new WorkflowNodeGraph()
|
||||
.setShape("rectangle")
|
||||
.setSize(120, 60)
|
||||
.setStyle("#ffffff", "#1890ff", "api")
|
||||
.configPorts(Arrays.asList("in", "out"))
|
||||
),
|
||||
|
||||
/**
|
||||
* 脚本任务节点
|
||||
@ -75,11 +144,29 @@ public enum NodeTypeEnums {
|
||||
* - 可以执行自定义业务逻辑
|
||||
* - 适合复杂的数据处理和计算
|
||||
*/
|
||||
SCRIPT_TASK("SCRIPT_TASK", "脚本任务", new NodeUiConfig()
|
||||
.setShape("rectangle")
|
||||
.setSize(120, 60)
|
||||
.setStyle("#ffffff", "#1890ff", "code")
|
||||
.setPorts(Arrays.asList("in", "out"))),
|
||||
SCRIPT_TASK(
|
||||
"SCRIPT_TASK",
|
||||
"脚本任务",
|
||||
"脚本执行任务",
|
||||
"执行自定义脚本的任务节点,支持多种脚本语言和复杂的业务逻辑",
|
||||
Arrays.asList(
|
||||
"执行自定义脚本代码",
|
||||
"支持多种脚本语言",
|
||||
"访问流程变量",
|
||||
"支持复杂的业务逻辑"
|
||||
),
|
||||
Arrays.asList(
|
||||
"数据处理和转换",
|
||||
"条件判断",
|
||||
"自定义业务规则",
|
||||
"系统集成"
|
||||
),
|
||||
new WorkflowNodeGraph()
|
||||
.setShape("rectangle")
|
||||
.setSize(120, 60)
|
||||
.setStyle("#ffffff", "#1890ff", "code")
|
||||
.configPorts(Arrays.asList("in", "out"))
|
||||
),
|
||||
|
||||
/**
|
||||
* 排他网关
|
||||
@ -89,11 +176,27 @@ public enum NodeTypeEnums {
|
||||
* - 需要设置分支条件
|
||||
* - 适合互斥的业务场景
|
||||
*/
|
||||
EXCLUSIVE_GATEWAY("EXCLUSIVE_GATEWAY", "排他网关", new NodeUiConfig()
|
||||
.setShape("diamond")
|
||||
.setSize(50, 50)
|
||||
.setStyle("#fff7e6", "#faad14", "fork")
|
||||
.setPorts(Arrays.asList("in", "out"))),
|
||||
EXCLUSIVE_GATEWAY(
|
||||
"EXCLUSIVE_GATEWAY",
|
||||
"排他网关",
|
||||
"条件分支控制",
|
||||
"基于条件的分支控制,只会选择一个分支执行",
|
||||
Arrays.asList(
|
||||
"根据条件选择一个分支执行",
|
||||
"支持复杂的条件表达式",
|
||||
"可以设置默认分支"
|
||||
),
|
||||
Arrays.asList(
|
||||
"条件判断",
|
||||
"分支选择",
|
||||
"业务规则路由"
|
||||
),
|
||||
new WorkflowNodeGraph()
|
||||
.setShape("diamond")
|
||||
.setSize(50, 50)
|
||||
.setStyle("#fff7e6", "#faad14", "fork")
|
||||
.configPorts(Arrays.asList("in", "out"))
|
||||
),
|
||||
|
||||
/**
|
||||
* 并行网关
|
||||
@ -103,11 +206,27 @@ public enum NodeTypeEnums {
|
||||
* - 等待所有分支完成才继续
|
||||
* - 适合并行处理的业务场景
|
||||
*/
|
||||
PARALLEL_GATEWAY("PARALLEL_GATEWAY", "并行网关", new NodeUiConfig()
|
||||
.setShape("diamond")
|
||||
.setSize(50, 50)
|
||||
.setStyle("#fff7e6", "#faad14", "branches")
|
||||
.setPorts(Arrays.asList("in", "out"))),
|
||||
PARALLEL_GATEWAY(
|
||||
"PARALLEL_GATEWAY",
|
||||
"并行网关",
|
||||
"并行分支控制",
|
||||
"将流程分成多个并行分支同时执行,等待所有分支完成后合并",
|
||||
Arrays.asList(
|
||||
"将流程分成多个并行分支",
|
||||
"等待所有分支完成后合并",
|
||||
"支持复杂的并行处理"
|
||||
),
|
||||
Arrays.asList(
|
||||
"并行审批",
|
||||
"多任务同时处理",
|
||||
"并行数据处理"
|
||||
),
|
||||
new WorkflowNodeGraph()
|
||||
.setShape("diamond")
|
||||
.setSize(50, 50)
|
||||
.setStyle("#fff7e6", "#faad14", "branches")
|
||||
.configPorts(Arrays.asList("in", "out"))
|
||||
),
|
||||
|
||||
/**
|
||||
* 子流程节点
|
||||
@ -117,11 +236,29 @@ public enum NodeTypeEnums {
|
||||
* - 支持流程的模块化和复用
|
||||
* - 可以独立部署和版本控制
|
||||
*/
|
||||
SUBPROCESS("SUB_PROCESS", "子流程", new NodeUiConfig()
|
||||
.setShape("rectangle")
|
||||
.setSize(120, 60)
|
||||
.setStyle("#ffffff", "#1890ff", "apartment")
|
||||
.setPorts(Arrays.asList("in", "out"))),
|
||||
SUBPROCESS(
|
||||
"SUB_PROCESS",
|
||||
"子流程",
|
||||
"嵌入式子流程",
|
||||
"在当前流程中嵌入子流程,支持流程的模块化和复用",
|
||||
Arrays.asList(
|
||||
"在当前流程中嵌入子流程",
|
||||
"重用流程片段",
|
||||
"支持事务处理",
|
||||
"独立的变量范围"
|
||||
),
|
||||
Arrays.asList(
|
||||
"流程复用",
|
||||
"模块化处理",
|
||||
"事务管理",
|
||||
"错误处理"
|
||||
),
|
||||
new WorkflowNodeGraph()
|
||||
.setShape("rectangle")
|
||||
.setSize(120, 60)
|
||||
.setStyle("#ffffff", "#1890ff", "apartment")
|
||||
.configPorts(Arrays.asList("in", "out"))
|
||||
),
|
||||
|
||||
/**
|
||||
* 调用活动节点
|
||||
@ -131,27 +268,66 @@ public enum NodeTypeEnums {
|
||||
* - 支持流程的复用
|
||||
* - 可以传递参数和接收返回值
|
||||
*/
|
||||
CALL_ACTIVITY("CALL_ACTIVITY", "调用活动", new NodeUiConfig()
|
||||
.setShape("rectangle")
|
||||
.setSize(120, 60)
|
||||
.setStyle("#ffffff", "#1890ff", "api")
|
||||
.setPorts(Arrays.asList("in", "out")));
|
||||
CALL_ACTIVITY(
|
||||
"CALL_ACTIVITY",
|
||||
"调用活动",
|
||||
"外部流程调用",
|
||||
"调用外部定义的流程,支持跨系统流程调用和参数传递",
|
||||
Arrays.asList(
|
||||
"调用外部定义的流程",
|
||||
"支持跨系统流程调用",
|
||||
"传递和接收参数",
|
||||
"支持异步调用"
|
||||
),
|
||||
Arrays.asList(
|
||||
"跨系统流程集成",
|
||||
"公共流程复用",
|
||||
"分布式流程处理",
|
||||
"大型流程解耦"
|
||||
),
|
||||
new WorkflowNodeGraph()
|
||||
.setShape("rectangle")
|
||||
.setSize(120, 60)
|
||||
.setStyle("#ffffff", "#1890ff", "api")
|
||||
.configPorts(Arrays.asList("in", "out"))
|
||||
);
|
||||
|
||||
@JsonValue
|
||||
private final String code;
|
||||
private final String name;
|
||||
private final NodeUiConfig uiConfig;
|
||||
private final String code; // 节点类型编码
|
||||
|
||||
NodeTypeEnums(String code, String name, NodeUiConfig uiConfig) {
|
||||
private final String name; // 节点显示名称
|
||||
|
||||
private final String shortDesc; // 节点简要描述
|
||||
|
||||
private final String description; // 节点详细描述
|
||||
|
||||
private final List<String> features; // 节点功能列表
|
||||
|
||||
private final List<String> scenarios; // 使用场景列表
|
||||
|
||||
private final WorkflowNodeGraph uiConfig; // UI配置
|
||||
|
||||
NodeTypeEnums(
|
||||
String code,
|
||||
String name,
|
||||
String shortDesc,
|
||||
String description,
|
||||
List<String> features,
|
||||
List<String> scenarios,
|
||||
WorkflowNodeGraph uiConfig) {
|
||||
this.code = code;
|
||||
this.name = name;
|
||||
this.shortDesc = shortDesc;
|
||||
this.description = description;
|
||||
this.features = features;
|
||||
this.scenarios = scenarios;
|
||||
this.uiConfig = uiConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据值查找对应的枚举
|
||||
* 根据编码查找对应的枚举
|
||||
*
|
||||
* @param code 枚举值
|
||||
* @param code 节点类型编码
|
||||
* @return 对应的枚举实例
|
||||
* @throws IllegalArgumentException 当找不到对应的枚举值时抛出
|
||||
*/
|
||||
@ -161,6 +337,6 @@ public enum NodeTypeEnums {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("Unknown NodeType value: " + code);
|
||||
throw new IllegalArgumentException("Unknown NodeType code: " + code);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,7 +3,7 @@ package com.qqchen.deploy.backend.workflow.hibernate;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.qqchen.deploy.backend.workflow.dto.graph.WorkflowGraph;
|
||||
import com.qqchen.deploy.backend.workflow.dto.graph.WorkflowDefinitionGraph;
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.usertype.UserType;
|
||||
@ -17,7 +17,7 @@ import java.sql.Types;
|
||||
/**
|
||||
* 自定义 Hibernate 类型,用于处理 WorkflowGraph 的序列化和反序列化
|
||||
*/
|
||||
public class WorkflowGraphType implements UserType<WorkflowGraph> {
|
||||
public class WorkflowGraphType implements UserType<WorkflowDefinitionGraph> {
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
public WorkflowGraphType() {
|
||||
@ -32,12 +32,12 @@ public class WorkflowGraphType implements UserType<WorkflowGraph> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<WorkflowGraph> returnedClass() {
|
||||
return WorkflowGraph.class;
|
||||
public Class<WorkflowDefinitionGraph> returnedClass() {
|
||||
return WorkflowDefinitionGraph.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(WorkflowGraph x, WorkflowGraph y) {
|
||||
public boolean equals(WorkflowDefinitionGraph x, WorkflowDefinitionGraph y) {
|
||||
if (x == y) {
|
||||
return true;
|
||||
}
|
||||
@ -48,26 +48,26 @@ public class WorkflowGraphType implements UserType<WorkflowGraph> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode(WorkflowGraph x) {
|
||||
public int hashCode(WorkflowDefinitionGraph x) {
|
||||
return x == null ? 0 : x.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorkflowGraph nullSafeGet(ResultSet rs, int position, SharedSessionContractImplementor session, Object owner)
|
||||
public WorkflowDefinitionGraph nullSafeGet(ResultSet rs, int position, SharedSessionContractImplementor session, Object owner)
|
||||
throws SQLException {
|
||||
String value = rs.getString(position);
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return objectMapper.readValue(value, WorkflowGraph.class);
|
||||
return objectMapper.readValue(value, WorkflowDefinitionGraph.class);
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new HibernateException("Failed to convert String to WorkflowGraph: " + value, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void nullSafeSet(PreparedStatement st, WorkflowGraph value, int index, SharedSessionContractImplementor session)
|
||||
public void nullSafeSet(PreparedStatement st, WorkflowDefinitionGraph value, int index, SharedSessionContractImplementor session)
|
||||
throws SQLException {
|
||||
if (value == null) {
|
||||
st.setNull(index, Types.VARCHAR);
|
||||
@ -81,12 +81,12 @@ public class WorkflowGraphType implements UserType<WorkflowGraph> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorkflowGraph deepCopy(WorkflowGraph value) {
|
||||
public WorkflowDefinitionGraph deepCopy(WorkflowDefinitionGraph value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return objectMapper.readValue(objectMapper.writeValueAsString(value), WorkflowGraph.class);
|
||||
return objectMapper.readValue(objectMapper.writeValueAsString(value), WorkflowDefinitionGraph.class);
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new HibernateException("Failed to deep copy WorkflowGraph", e);
|
||||
}
|
||||
@ -98,7 +98,7 @@ public class WorkflowGraphType implements UserType<WorkflowGraph> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Serializable disassemble(WorkflowGraph value) {
|
||||
public Serializable disassemble(WorkflowDefinitionGraph value) {
|
||||
try {
|
||||
return value == null ? null : objectMapper.writeValueAsString(value);
|
||||
} catch (JsonProcessingException e) {
|
||||
@ -107,16 +107,16 @@ public class WorkflowGraphType implements UserType<WorkflowGraph> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorkflowGraph assemble(Serializable cached, Object owner) {
|
||||
public WorkflowDefinitionGraph assemble(Serializable cached, Object owner) {
|
||||
try {
|
||||
return cached == null ? null : objectMapper.readValue(cached.toString(), WorkflowGraph.class);
|
||||
return cached == null ? null : objectMapper.readValue(cached.toString(), WorkflowDefinitionGraph.class);
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new HibernateException("Failed to assemble WorkflowGraph", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorkflowGraph replace(WorkflowGraph detached, WorkflowGraph managed, Object owner) {
|
||||
public WorkflowDefinitionGraph replace(WorkflowDefinitionGraph detached, WorkflowDefinitionGraph managed, Object owner) {
|
||||
return deepCopy(detached);
|
||||
}
|
||||
}
|
||||
|
||||
@ -70,7 +70,7 @@ public class WorkflowDefinitionServiceImpl extends BaseServiceImpl<WorkflowDefin
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public WorkflowDefinitionDTO saveWorkflowDesign(WorkflowDefinitionDTO dto) throws Exception {
|
||||
// 转换图形JSON为BPMN XML
|
||||
String bpmnXml = bpmnConverter.convertToXml(dto.getGraph(), dto.getKey());
|
||||
String bpmnXml = bpmnConverter.convertToXml(null, dto.getKey());
|
||||
dto.setFlowVersion(1);
|
||||
dto.setBpmnXml(bpmnXml);
|
||||
// // 创建工作流定义
|
||||
|
||||
@ -7,8 +7,6 @@ import org.flowable.bpmn.model.Process;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* BPMN 模型转换工具
|
||||
@ -26,7 +24,7 @@ public class BpmnConverter {
|
||||
* @param processKey 流程标识
|
||||
* @return BPMN XML字符串
|
||||
*/
|
||||
public String convertToXml(WorkflowGraph graph, String processKey) {
|
||||
public String convertToXml(WorkflowDefinitionGraph graph, String processKey) {
|
||||
BpmnModel bpmnModel = convertToBpmnModel(graph, processKey);
|
||||
byte[] xmlBytes = bpmnXmlConverter.convertToXML(bpmnModel);
|
||||
return new String(xmlBytes, StandardCharsets.UTF_8);
|
||||
@ -38,33 +36,33 @@ public class BpmnConverter {
|
||||
* @param processKey 流程标识
|
||||
* @return BPMN模型
|
||||
*/
|
||||
public BpmnModel convertToBpmnModel(WorkflowGraph graph, String processKey) {
|
||||
public BpmnModel convertToBpmnModel(WorkflowDefinitionGraph graph, String processKey) {
|
||||
BpmnModel bpmnModel = new BpmnModel();
|
||||
Process process = new Process();
|
||||
|
||||
// 设置流程属性
|
||||
process.setId(processKey);
|
||||
if (graph.getProperties() != null) {
|
||||
Map<String, Object> properties = graph.getProperties();
|
||||
process.setName(properties.get("name") != null ? properties.get("name").toString() : null);
|
||||
process.setDocumentation(properties.get("description") != null ? properties.get("description").toString() : null);
|
||||
}
|
||||
// if (graph.getProperties() != null) {
|
||||
// Map<String, Object> properties = graph.getProperties();
|
||||
// process.setName(properties.get("name") != null ? properties.get("name").toString() : null);
|
||||
// process.setDocumentation(properties.get("description") != null ? properties.get("description").toString() : null);
|
||||
// }
|
||||
|
||||
// 转换节点
|
||||
for (WorkflowNode node : graph.getNodes()) {
|
||||
FlowElement element = convertNode(node);
|
||||
if (element != null) {
|
||||
process.addFlowElement(element);
|
||||
}
|
||||
}
|
||||
|
||||
// 转换边
|
||||
for (WorkflowEdge edge : graph.getEdges()) {
|
||||
SequenceFlow flow = convertEdge(edge);
|
||||
if (flow != null) {
|
||||
process.addFlowElement(flow);
|
||||
}
|
||||
}
|
||||
// for (WorkflowDefinitionNode node : graph.getNodes()) {
|
||||
// FlowElement element = convertNode(node);
|
||||
// if (element != null) {
|
||||
// process.addFlowElement(element);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // 转换边
|
||||
// for (WorkflowDefinitionEdge edge : graph.getEdges()) {
|
||||
// SequenceFlow flow = convertEdge(edge);
|
||||
// if (flow != null) {
|
||||
// process.addFlowElement(flow);
|
||||
// }
|
||||
// }
|
||||
|
||||
bpmnModel.addProcess(process);
|
||||
return bpmnModel;
|
||||
@ -75,15 +73,15 @@ public class BpmnConverter {
|
||||
* @param graph 工作流图数据
|
||||
* @return BPMN模型
|
||||
*/
|
||||
public BpmnModel convertToBpmnModel(WorkflowGraph graph) {
|
||||
public BpmnModel convertToBpmnModel(WorkflowDefinitionGraph graph) {
|
||||
String processKey = null;
|
||||
if (graph.getProperties() != null) {
|
||||
Object key = graph.getProperties().get("key");
|
||||
processKey = key != null ? key.toString() : null;
|
||||
}
|
||||
if (processKey == null) {
|
||||
processKey = "process_" + System.currentTimeMillis();
|
||||
}
|
||||
// if (graph.getProperties() != null) {
|
||||
// Object key = graph.getProperties().get("key");
|
||||
// processKey = key != null ? key.toString() : null;
|
||||
// }
|
||||
// if (processKey == null) {
|
||||
// processKey = "process_" + System.currentTimeMillis();
|
||||
// }
|
||||
return convertToBpmnModel(graph, processKey);
|
||||
}
|
||||
|
||||
@ -92,7 +90,7 @@ public class BpmnConverter {
|
||||
* @param node 工作流节点
|
||||
* @return 流程元素
|
||||
*/
|
||||
private FlowElement convertNode(WorkflowNode node) {
|
||||
private FlowElement convertNode(WorkflowDefinitionNode node) {
|
||||
if (node.getType() == null) {
|
||||
return null;
|
||||
}
|
||||
@ -126,7 +124,7 @@ public class BpmnConverter {
|
||||
* @param node 节点数据
|
||||
* @return 开始事件
|
||||
*/
|
||||
private StartEvent createStartEvent(WorkflowNode node) {
|
||||
private StartEvent createStartEvent(WorkflowDefinitionNode node) {
|
||||
StartEvent startEvent = new StartEvent();
|
||||
startEvent.setId(node.getId());
|
||||
startEvent.setName(node.getName());
|
||||
@ -138,7 +136,7 @@ public class BpmnConverter {
|
||||
* @param node 节点数据
|
||||
* @return 结束事件
|
||||
*/
|
||||
private EndEvent createEndEvent(WorkflowNode node) {
|
||||
private EndEvent createEndEvent(WorkflowDefinitionNode node) {
|
||||
EndEvent endEvent = new EndEvent();
|
||||
endEvent.setId(node.getId());
|
||||
endEvent.setName(node.getName());
|
||||
@ -150,13 +148,13 @@ public class BpmnConverter {
|
||||
* @param node 节点数据
|
||||
* @return 服务任务
|
||||
*/
|
||||
private ServiceTask createServiceTask(WorkflowNode node) {
|
||||
private ServiceTask createServiceTask(WorkflowDefinitionNode node) {
|
||||
ServiceTask serviceTask = new ServiceTask();
|
||||
serviceTask.setId(node.getId());
|
||||
serviceTask.setName(node.getName());
|
||||
|
||||
if (node.getConfig() != null) {
|
||||
NodeConfig config = node.getConfig();
|
||||
// WorkflowDefinitionEdgeNodeConfig config = node.getConfig();
|
||||
// serviceTask.setImplementation(config.getImplementation());
|
||||
// if (config.getFields() != null) {
|
||||
// config.getFields().forEach((key, value) -> {
|
||||
@ -176,7 +174,7 @@ public class BpmnConverter {
|
||||
* @param node 节点数据
|
||||
* @return 用户任务
|
||||
*/
|
||||
private UserTask createUserTask(WorkflowNode node) {
|
||||
private UserTask createUserTask(WorkflowDefinitionNode node) {
|
||||
UserTask userTask = new UserTask();
|
||||
userTask.setId(node.getId());
|
||||
userTask.setName(node.getName());
|
||||
@ -200,7 +198,7 @@ public class BpmnConverter {
|
||||
* @param node 节点数据
|
||||
* @return 脚本任务
|
||||
*/
|
||||
private ScriptTask createScriptTask(WorkflowNode node) {
|
||||
private ScriptTask createScriptTask(WorkflowDefinitionNode node) {
|
||||
ScriptTask scriptTask = new ScriptTask();
|
||||
scriptTask.setId(node.getId());
|
||||
scriptTask.setName(node.getName());
|
||||
@ -221,7 +219,7 @@ public class BpmnConverter {
|
||||
* @param node 节点数据
|
||||
* @return 排他网关
|
||||
*/
|
||||
private ExclusiveGateway createExclusiveGateway(WorkflowNode node) {
|
||||
private ExclusiveGateway createExclusiveGateway(WorkflowDefinitionNode node) {
|
||||
ExclusiveGateway gateway = new ExclusiveGateway();
|
||||
gateway.setId(node.getId());
|
||||
gateway.setName(node.getName());
|
||||
@ -233,7 +231,7 @@ public class BpmnConverter {
|
||||
* @param node 节点数据
|
||||
* @return 并行网关
|
||||
*/
|
||||
private ParallelGateway createParallelGateway(WorkflowNode node) {
|
||||
private ParallelGateway createParallelGateway(WorkflowDefinitionNode node) {
|
||||
ParallelGateway gateway = new ParallelGateway();
|
||||
gateway.setId(node.getId());
|
||||
gateway.setName(node.getName());
|
||||
@ -245,7 +243,7 @@ public class BpmnConverter {
|
||||
* @param node 节点数据
|
||||
* @return 子流程
|
||||
*/
|
||||
private SubProcess createSubProcess(WorkflowNode node) {
|
||||
private SubProcess createSubProcess(WorkflowDefinitionNode node) {
|
||||
SubProcess subProcess = new SubProcess();
|
||||
subProcess.setId(node.getId());
|
||||
subProcess.setName(node.getName());
|
||||
@ -257,13 +255,13 @@ public class BpmnConverter {
|
||||
* @param node 节点数据
|
||||
* @return 调用活动
|
||||
*/
|
||||
private CallActivity createCallActivity(WorkflowNode node) {
|
||||
private CallActivity createCallActivity(WorkflowDefinitionNode node) {
|
||||
CallActivity callActivity = new CallActivity();
|
||||
callActivity.setId(node.getId());
|
||||
callActivity.setName(node.getName());
|
||||
|
||||
if (node.getConfig() != null) {
|
||||
NodeConfig config = node.getConfig();
|
||||
// WorkflowDefinitionEdgeNodeConfig config = node.getConfig();
|
||||
// callActivity.setCalledElement(config.getImplementation());
|
||||
// if (config.getFields() != null) {
|
||||
// config.getFields().forEach((key, value) -> {
|
||||
@ -283,15 +281,15 @@ public class BpmnConverter {
|
||||
* @param edge 工作流边
|
||||
* @return 序列流
|
||||
*/
|
||||
private SequenceFlow convertEdge(WorkflowEdge edge) {
|
||||
private SequenceFlow convertEdge(WorkflowDefinitionEdge edge) {
|
||||
SequenceFlow flow = new SequenceFlow();
|
||||
flow.setId(edge.getId());
|
||||
flow.setName(edge.getName());
|
||||
flow.setSourceRef(edge.getSource());
|
||||
flow.setTargetRef(edge.getTarget());
|
||||
// flow.setSourceRef(edge.getSource());
|
||||
// flow.setTargetRef(edge.getTarget());
|
||||
|
||||
if (edge.getConfig() != null) {
|
||||
EdgeConfig config = edge.getConfig();
|
||||
WorkflowDefinitionEdgeConfig config = edge.getConfig();
|
||||
if ("sequence".equals(config.getType())) {
|
||||
if (config.getCondition() != null) {
|
||||
((SequenceFlow) flow).setConditionExpression(config.getCondition());
|
||||
|
||||
@ -5,6 +5,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import com.qqchen.deploy.backend.workflow.annotation.SchemaProperty;
|
||||
import com.qqchen.deploy.backend.workflow.dto.graph.WorkflowNodeGraph;
|
||||
import com.qqchen.deploy.backend.workflow.dto.nodeConfig.*;
|
||||
import com.qqchen.deploy.backend.workflow.enums.NodeTypeEnums;
|
||||
|
||||
@ -16,6 +17,7 @@ import java.util.Set;
|
||||
|
||||
/**
|
||||
* Schema生成器
|
||||
* 用于生成工作流节点的配置Schema和UI Schema
|
||||
*/
|
||||
public class SchemaGenerator {
|
||||
private static final ObjectMapper mapper = new ObjectMapper();
|
||||
@ -72,15 +74,77 @@ public class SchemaGenerator {
|
||||
// 设置基本信息
|
||||
node.put("code", nodeType.getCode());
|
||||
node.put("name", nodeType.getName());
|
||||
node.put("description", nodeType.getName());
|
||||
node.put("description", nodeType.getShortDesc());
|
||||
|
||||
// 添加详细信息
|
||||
ObjectNode details = mapper.createObjectNode();
|
||||
details.put("description", nodeType.getDescription());
|
||||
ArrayNode features = mapper.createArrayNode();
|
||||
nodeType.getFeatures().forEach(features::add);
|
||||
details.set("features", features);
|
||||
ArrayNode scenarios = mapper.createArrayNode();
|
||||
nodeType.getScenarios().forEach(scenarios::add);
|
||||
details.set("scenarios", scenarios);
|
||||
node.set("details", details);
|
||||
|
||||
// 生成配置schema并设置到configSchema字段
|
||||
ObjectNode configSchema = generateConfigSchema(configClass);
|
||||
node.set("configSchema", configSchema);
|
||||
|
||||
// 生成UI schema并设置到uiSchema字段
|
||||
ObjectNode uiSchema = generateUiSchema(nodeType);
|
||||
node.set("uiSchema", uiSchema);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成UI Schema
|
||||
* 包含节点的UI相关配置,如形状、大小、样式等
|
||||
*/
|
||||
private static ObjectNode generateUiSchema(NodeTypeEnums nodeType) {
|
||||
ObjectNode uiSchema = mapper.createObjectNode();
|
||||
WorkflowNodeGraph uiConfig = nodeType.getUiConfig();
|
||||
|
||||
// 设置基本形状和大小
|
||||
uiSchema.put("shape", uiConfig.getShape());
|
||||
ObjectNode size = mapper.createObjectNode();
|
||||
size.put("width", uiConfig.getSize().getWidth());
|
||||
size.put("height", uiConfig.getSize().getHeight());
|
||||
uiSchema.set("size", size);
|
||||
|
||||
// 设置样式
|
||||
ObjectNode style = mapper.createObjectNode();
|
||||
style.put("fill", uiConfig.getStyle().getFill());
|
||||
style.put("stroke", uiConfig.getStyle().getStroke());
|
||||
style.put("strokeWidth", uiConfig.getStyle().getStrokeWidth());
|
||||
style.put("icon", uiConfig.getStyle().getIcon());
|
||||
style.put("iconColor", uiConfig.getStyle().getIconColor());
|
||||
uiSchema.set("style", style);
|
||||
|
||||
// 设置连接点
|
||||
ObjectNode ports = mapper.createObjectNode();
|
||||
ObjectNode groups = mapper.createObjectNode();
|
||||
uiConfig.getPorts().getGroups().forEach((key, group) -> {
|
||||
ObjectNode groupNode = mapper.createObjectNode();
|
||||
groupNode.put("position", group.getPosition());
|
||||
|
||||
ObjectNode attrs = mapper.createObjectNode();
|
||||
ObjectNode circle = mapper.createObjectNode();
|
||||
circle.put("r", group.getAttrs().getCircle().getR());
|
||||
circle.put("fill", group.getAttrs().getCircle().getFill());
|
||||
circle.put("stroke", group.getAttrs().getCircle().getStroke());
|
||||
attrs.set("circle", circle);
|
||||
|
||||
groupNode.set("attrs", attrs);
|
||||
groups.set(key, groupNode);
|
||||
});
|
||||
ports.set("groups", groups);
|
||||
uiSchema.set("ports", ports);
|
||||
|
||||
return uiSchema;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据配置类生成schema
|
||||
*/
|
||||
@ -99,9 +163,12 @@ public class SchemaGenerator {
|
||||
processRemainingFields(properties, required, configClass);
|
||||
|
||||
schema.set("properties", properties);
|
||||
|
||||
// 如果有必填字段,添加到schema中
|
||||
if (!required.isEmpty()) {
|
||||
ArrayNode requiredArray = schema.putArray("required");
|
||||
ArrayNode requiredArray = mapper.createArrayNode();
|
||||
required.forEach(requiredArray::add);
|
||||
schema.set("required", requiredArray);
|
||||
}
|
||||
|
||||
return schema;
|
||||
|
||||
@ -0,0 +1,381 @@
|
||||
package com.qqchen.deploy.backend.workflow.util;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import com.qqchen.deploy.backend.workflow.dto.graph.*;
|
||||
import com.qqchen.deploy.backend.workflow.enums.NodeTypeEnums;
|
||||
import lombok.Data;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 工作流定义图形生成工具类
|
||||
* 用于生成示例工作流定义,包括:
|
||||
* 1. 简单工作流:开始 -> 脚本任务 -> 结束
|
||||
* 2. 复杂工作流:开始 -> 服务任务 -> 用户任务 -> 脚本任务 -> 结束
|
||||
* 3. 网关工作流:开始 -> 服务任务 -> 排他网关 -> (用户任务A/用户任务B) -> 并行网关 -> (脚本任务A/脚本任务B) -> 结束
|
||||
*/
|
||||
@Data
|
||||
@Slf4j
|
||||
public class WorkflowDefinitionGraph {
|
||||
private static final ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
/**
|
||||
* 节点列表
|
||||
*/
|
||||
private List<WorkflowDefinitionNode> nodes;
|
||||
|
||||
/**
|
||||
* 边列表
|
||||
*/
|
||||
private List<WorkflowDefinitionEdge> edges;
|
||||
|
||||
/**
|
||||
* 生成简单工作流
|
||||
* 开始 -> 脚本任务 -> 结束
|
||||
*/
|
||||
public static WorkflowDefinitionGraph generateSimpleWorkflow() {
|
||||
WorkflowDefinitionGraph graph = new WorkflowDefinitionGraph();
|
||||
List<WorkflowDefinitionNode> nodes = new ArrayList<>();
|
||||
List<WorkflowDefinitionEdge> edges = new ArrayList<>();
|
||||
|
||||
// 开始节点
|
||||
WorkflowDefinitionNode startNode = createNode(
|
||||
"startEvent1",
|
||||
NodeTypeEnums.START_EVENT,
|
||||
"开始",
|
||||
100, 100,
|
||||
createNodeConfig("开始节点", "启动流程")
|
||||
);
|
||||
nodes.add(startNode);
|
||||
|
||||
// 脚本任务节点
|
||||
Map<String, Object> scriptConfig = createNodeConfig("脚本任务", "执行一个简单的Shell脚本");
|
||||
scriptConfig.put("script", "echo 'Hello World'");
|
||||
scriptConfig.put("language", "shell");
|
||||
|
||||
WorkflowDefinitionNode scriptNode = createNode(
|
||||
"scriptTask1",
|
||||
NodeTypeEnums.SCRIPT_TASK,
|
||||
"执行脚本",
|
||||
300, 100,
|
||||
scriptConfig
|
||||
);
|
||||
nodes.add(scriptNode);
|
||||
|
||||
// 结束节点
|
||||
WorkflowDefinitionNode endNode = createNode(
|
||||
"endEvent1",
|
||||
NodeTypeEnums.END_EVENT,
|
||||
"结束",
|
||||
500, 100,
|
||||
createNodeConfig("结束节点", "流程结束")
|
||||
);
|
||||
nodes.add(endNode);
|
||||
|
||||
// 添加连线
|
||||
edges.add(createEdge("flow1", "startEvent1", "scriptTask1", "开始到脚本"));
|
||||
edges.add(createEdge("flow2", "scriptTask1", "endEvent1", "脚本到结束"));
|
||||
|
||||
graph.setNodes(nodes);
|
||||
graph.setEdges(edges);
|
||||
return graph;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成复杂工作流
|
||||
* 开始 -> 服务任务 -> 用户任务 -> 脚本任务 -> 结束
|
||||
*/
|
||||
public static WorkflowDefinitionGraph generateComplexWorkflow() {
|
||||
WorkflowDefinitionGraph graph = new WorkflowDefinitionGraph();
|
||||
List<WorkflowDefinitionNode> nodes = new ArrayList<>();
|
||||
List<WorkflowDefinitionEdge> edges = new ArrayList<>();
|
||||
|
||||
// 开始节点
|
||||
WorkflowDefinitionNode startNode = createNode(
|
||||
"startEvent1",
|
||||
NodeTypeEnums.START_EVENT,
|
||||
"开始",
|
||||
100, 100,
|
||||
createNodeConfig("开始节点", "启动流程")
|
||||
);
|
||||
nodes.add(startNode);
|
||||
|
||||
// 服务任务节点
|
||||
Map<String, Object> serviceConfig = createNodeConfig("服务任务", "调用外部服务");
|
||||
serviceConfig.put("url", "http://api.example.com/service");
|
||||
serviceConfig.put("method", "POST");
|
||||
|
||||
WorkflowDefinitionNode serviceNode = createNode(
|
||||
"serviceTask1",
|
||||
NodeTypeEnums.SERVICE_TASK,
|
||||
"调用服务",
|
||||
300, 100,
|
||||
serviceConfig
|
||||
);
|
||||
nodes.add(serviceNode);
|
||||
|
||||
// 用户任务节点
|
||||
Map<String, Object> userConfig = createNodeConfig("用户任务", "人工审批");
|
||||
userConfig.put("assignee", "admin");
|
||||
|
||||
WorkflowDefinitionNode userNode = createNode(
|
||||
"userTask1",
|
||||
NodeTypeEnums.USER_TASK,
|
||||
"人工审批",
|
||||
500, 100,
|
||||
userConfig
|
||||
);
|
||||
nodes.add(userNode);
|
||||
|
||||
// 脚本任务节点
|
||||
Map<String, Object> scriptConfig = createNodeConfig("脚本任务", "执行脚本");
|
||||
scriptConfig.put("script", "process_data.sh");
|
||||
scriptConfig.put("language", "shell");
|
||||
|
||||
WorkflowDefinitionNode scriptNode = createNode(
|
||||
"scriptTask1",
|
||||
NodeTypeEnums.SCRIPT_TASK,
|
||||
"执行脚本",
|
||||
700, 100,
|
||||
scriptConfig
|
||||
);
|
||||
nodes.add(scriptNode);
|
||||
|
||||
// 结束节点
|
||||
WorkflowDefinitionNode endNode = createNode(
|
||||
"endEvent1",
|
||||
NodeTypeEnums.END_EVENT,
|
||||
"结束",
|
||||
900, 100,
|
||||
createNodeConfig("结束节点", "流程结束")
|
||||
);
|
||||
nodes.add(endNode);
|
||||
|
||||
// 添加连线
|
||||
edges.add(createEdge("flow1", "startEvent1", "serviceTask1", "开始到服务"));
|
||||
edges.add(createEdge("flow2", "serviceTask1", "userTask1", "服务到用户"));
|
||||
edges.add(createEdge("flow3", "userTask1", "scriptTask1", "用户到脚本"));
|
||||
edges.add(createEdge("flow4", "scriptTask1", "endEvent1", "脚本到结束"));
|
||||
|
||||
graph.setNodes(nodes);
|
||||
graph.setEdges(edges);
|
||||
return graph;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成网关工作流
|
||||
* 开始 -> 服务任务 -> 排他网关 -> (用户任务A/用户任务B) -> 并行网关 -> (脚本任务A/脚本任务B) -> 结束
|
||||
*/
|
||||
public static WorkflowDefinitionGraph generateGatewayWorkflow() {
|
||||
WorkflowDefinitionGraph graph = new WorkflowDefinitionGraph();
|
||||
List<WorkflowDefinitionNode> nodes = new ArrayList<>();
|
||||
List<WorkflowDefinitionEdge> edges = new ArrayList<>();
|
||||
|
||||
// 开始节点
|
||||
WorkflowDefinitionNode startNode = createNode(
|
||||
"startEvent1",
|
||||
NodeTypeEnums.START_EVENT,
|
||||
"开始",
|
||||
100, 150,
|
||||
createNodeConfig("开始节点", "启动流程")
|
||||
);
|
||||
nodes.add(startNode);
|
||||
|
||||
// 服务任务节点
|
||||
Map<String, Object> serviceConfig = createNodeConfig("服务任务", "获取数据");
|
||||
serviceConfig.put("url", "http://api.example.com/data");
|
||||
serviceConfig.put("method", "GET");
|
||||
|
||||
WorkflowDefinitionNode serviceNode = createNode(
|
||||
"serviceTask1",
|
||||
NodeTypeEnums.SERVICE_TASK,
|
||||
"获取数据",
|
||||
250, 150,
|
||||
serviceConfig
|
||||
);
|
||||
nodes.add(serviceNode);
|
||||
|
||||
// 排他网关
|
||||
WorkflowDefinitionNode exclusiveGateway = createNode(
|
||||
"exclusiveGateway1",
|
||||
NodeTypeEnums.EXCLUSIVE_GATEWAY,
|
||||
"数据路由",
|
||||
400, 150,
|
||||
createNodeConfig("排他网关", "根据数据量选择处理方式")
|
||||
);
|
||||
nodes.add(exclusiveGateway);
|
||||
|
||||
// 用户任务A(大数据量)
|
||||
Map<String, Object> userConfigA = createNodeConfig("用户任务A", "人工处理");
|
||||
userConfigA.put("assignee", "expert");
|
||||
|
||||
WorkflowDefinitionNode userNodeA = createNode(
|
||||
"userTask1",
|
||||
NodeTypeEnums.USER_TASK,
|
||||
"人工处理",
|
||||
550, 50,
|
||||
userConfigA
|
||||
);
|
||||
nodes.add(userNodeA);
|
||||
|
||||
// 用户任务B(小数据量)
|
||||
Map<String, Object> userConfigB = createNodeConfig("用户任务B", "快速处理");
|
||||
userConfigB.put("assignee", "operator");
|
||||
|
||||
WorkflowDefinitionNode userNodeB = createNode(
|
||||
"userTask2",
|
||||
NodeTypeEnums.USER_TASK,
|
||||
"快速处理",
|
||||
550, 250,
|
||||
userConfigB
|
||||
);
|
||||
nodes.add(userNodeB);
|
||||
|
||||
// 并行网关(合并)
|
||||
WorkflowDefinitionNode parallelGateway = createNode(
|
||||
"parallelGateway1",
|
||||
NodeTypeEnums.PARALLEL_GATEWAY,
|
||||
"并行处理",
|
||||
700, 150,
|
||||
createNodeConfig("并行网关", "并行处理数据")
|
||||
);
|
||||
nodes.add(parallelGateway);
|
||||
|
||||
// 脚本任务A
|
||||
Map<String, Object> scriptConfigA = createNodeConfig("脚本任务A", "数据分析");
|
||||
scriptConfigA.put("script", "analyze_data.py");
|
||||
scriptConfigA.put("language", "python");
|
||||
|
||||
WorkflowDefinitionNode scriptNodeA = createNode(
|
||||
"scriptTask1",
|
||||
NodeTypeEnums.SCRIPT_TASK,
|
||||
"数据分析",
|
||||
850, 50,
|
||||
scriptConfigA
|
||||
);
|
||||
nodes.add(scriptNodeA);
|
||||
|
||||
// 脚本任务B
|
||||
Map<String, Object> scriptConfigB = createNodeConfig("脚本任务B", "生成报告");
|
||||
scriptConfigB.put("script", "generate_report.py");
|
||||
scriptConfigB.put("language", "python");
|
||||
|
||||
WorkflowDefinitionNode scriptNodeB = createNode(
|
||||
"scriptTask2",
|
||||
NodeTypeEnums.SCRIPT_TASK,
|
||||
"生成报告",
|
||||
850, 250,
|
||||
scriptConfigB
|
||||
);
|
||||
nodes.add(scriptNodeB);
|
||||
|
||||
// 结束节点
|
||||
WorkflowDefinitionNode endNode = createNode(
|
||||
"endEvent1",
|
||||
NodeTypeEnums.END_EVENT,
|
||||
"结束",
|
||||
1000, 150,
|
||||
createNodeConfig("结束节点", "流程结束")
|
||||
);
|
||||
nodes.add(endNode);
|
||||
|
||||
// 添加连线
|
||||
edges.add(createEdge("flow1", "startEvent1", "serviceTask1", "开始到服务"));
|
||||
edges.add(createEdge("flow2", "serviceTask1", "exclusiveGateway1", "服务到网关"));
|
||||
edges.add(createEdge("flow3", "exclusiveGateway1", "userTask1", "大数据量处理", "#{dataSize > 1000}"));
|
||||
edges.add(createEdge("flow4", "exclusiveGateway1", "userTask2", "小数据量处理", "#{dataSize <= 1000}"));
|
||||
edges.add(createEdge("flow5", "userTask1", "parallelGateway1", "处理完成"));
|
||||
edges.add(createEdge("flow6", "userTask2", "parallelGateway1", "处理完成"));
|
||||
edges.add(createEdge("flow7", "parallelGateway1", "scriptTask1", "执行分析"));
|
||||
edges.add(createEdge("flow8", "parallelGateway1", "scriptTask2", "生成报告"));
|
||||
edges.add(createEdge("flow9", "scriptTask1", "endEvent1", "分析完成"));
|
||||
edges.add(createEdge("flow10", "scriptTask2", "endEvent1", "报告完成"));
|
||||
|
||||
graph.setNodes(nodes);
|
||||
graph.setEdges(edges);
|
||||
return graph;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建节点
|
||||
*/
|
||||
private static WorkflowDefinitionNode createNode(String id, NodeTypeEnums type, String name, int x, int y, Map<String, Object> config) {
|
||||
WorkflowDefinitionNode node = new WorkflowDefinitionNode();
|
||||
node.setId(id);
|
||||
node.setType(type);
|
||||
node.setName(name);
|
||||
node.setConfig(config);
|
||||
|
||||
// 从枚举的uiConfig中获取配置并创建新的图形配置
|
||||
WorkflowNodeGraph originalConfig = type.getUiConfig();
|
||||
WorkflowNodeGraph nodeGraph = new WorkflowNodeGraph()
|
||||
.setShape(originalConfig.getShape())
|
||||
.setSize(originalConfig.getSize().getWidth(), originalConfig.getSize().getHeight())
|
||||
.setStyle(originalConfig.getStyle().getFill(),
|
||||
originalConfig.getStyle().getStroke(),
|
||||
originalConfig.getStyle().getIcon())
|
||||
.configPorts(originalConfig.getPorts().getTypes());
|
||||
|
||||
node.setGraph(nodeGraph);
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建节点配置
|
||||
*/
|
||||
private static Map<String, Object> createNodeConfig(String name, String description) {
|
||||
Map<String, Object> config = new HashMap<>();
|
||||
config.put("name", name);
|
||||
config.put("description", description);
|
||||
return config;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建连线
|
||||
*/
|
||||
private static WorkflowDefinitionEdge createEdge(String id, String from, String to, String name) {
|
||||
return createEdge(id, from, to, name, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建带条件的连线
|
||||
*/
|
||||
private static WorkflowDefinitionEdge createEdge(String id, String from, String to, String name, String condition) {
|
||||
WorkflowDefinitionEdge edge = new WorkflowDefinitionEdge();
|
||||
edge.setId(id);
|
||||
edge.setFrom(from);
|
||||
edge.setTo(to);
|
||||
edge.setName(name);
|
||||
|
||||
// 设置边配置
|
||||
WorkflowDefinitionEdgeConfig config = new WorkflowDefinitionEdgeConfig();
|
||||
config.setType("sequence");
|
||||
if (condition != null) {
|
||||
config.setCondition(condition);
|
||||
config.setConditionExpression(condition);
|
||||
}
|
||||
edge.setConfig(config);
|
||||
|
||||
return edge;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
try {
|
||||
System.out.println("=== 简单工作流 ===");
|
||||
System.out.println(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(generateSimpleWorkflow()));
|
||||
System.out.println("\n=== 复杂工作流 ===");
|
||||
System.out.println(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(generateComplexWorkflow()));
|
||||
System.out.println("\n=== 网关工作流 ===");
|
||||
System.out.println(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(generateGatewayWorkflow()));
|
||||
} catch (Exception e) {
|
||||
log.error("生成工作流定义失败", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -490,7 +490,6 @@ CREATE TABLE workflow_node_definition (
|
||||
name VARCHAR(100) NOT NULL COMMENT '节点名称',
|
||||
description VARCHAR(500) COMMENT '节点描述',
|
||||
category VARCHAR(50) NOT NULL COMMENT '节点分类',
|
||||
flowable_config TEXT COMMENT 'Flowable引擎配置JSON',
|
||||
graph_config TEXT NOT NULL COMMENT 'X6图形配置JSON',
|
||||
order_num INT NOT NULL DEFAULT 0 COMMENT '排序号',
|
||||
enabled BOOLEAN NOT NULL DEFAULT TRUE COMMENT '是否启用',
|
||||
|
||||
@ -201,220 +201,502 @@ INSERT INTO workflow_definition (
|
||||
-- --------------------------------------------------------------------------------------
|
||||
|
||||
-- 事件节点
|
||||
INSERT INTO workflow_node_definition (type, name, description, category, flowable_config, graph_config, form_config, order_num, enabled, create_time, create_by, update_time, update_by, version, deleted)
|
||||
INSERT INTO workflow_node_definition (id, create_time, type, name, description, category, graph_config, enabled)
|
||||
VALUES
|
||||
-- 开始事件
|
||||
('startEvent', '开始事件', '流程的开始节点', 'EVENT',
|
||||
'{}',
|
||||
'{
|
||||
"shape": "circle",
|
||||
"width": 40,
|
||||
"height": 40,
|
||||
"ports": {
|
||||
"groups": {
|
||||
"top": {"position": "top", "attrs": {"circle": {"r": 4, "magnet": true}}},
|
||||
"right": {"position": "right", "attrs": {"circle": {"r": 4, "magnet": true}}},
|
||||
"bottom": {"position": "bottom", "attrs": {"circle": {"r": 4, "magnet": true}}},
|
||||
"left": {"position": "left", "attrs": {"circle": {"r": 4, "magnet": true}}}
|
||||
}
|
||||
(1, NOW(), 'START_EVENT', '开始节点', '工作流的起点', 'EVENT', '{
|
||||
"code": "START_EVENT",
|
||||
"name": "开始节点",
|
||||
"description": "工作流的起点",
|
||||
"details": {
|
||||
"description": "标记流程的开始位置,可以定义流程启动条件和初始化流程变量",
|
||||
"features": ["标记流程的开始位置", "定义流程启动条件", "初始化流程变量"],
|
||||
"scenarios": ["用户手动启动流程", "定时触发流程", "外部系统调用启动"]
|
||||
},
|
||||
"configSchema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"code": {"type": "string", "title": "节点Code", "description": "工作流节点的Code"},
|
||||
"name": {"type": "string", "title": "节点名称", "description": "工作流节点的显示名称"},
|
||||
"description": {"type": "string", "title": "节点描述", "description": "工作流节点的详细描述"}
|
||||
},
|
||||
"attrs": {
|
||||
"body": {"fill": "#ffffff", "stroke": "#333333", "strokeWidth": 2},
|
||||
"label": {"text": "开始", "fill": "#333333"}
|
||||
"required": ["code", "name"]
|
||||
},
|
||||
"uiSchema": {
|
||||
"shape": "circle",
|
||||
"size": {"width": 40, "height": 40},
|
||||
"style": {
|
||||
"fill": "#e8f7ff",
|
||||
"stroke": "#1890ff",
|
||||
"strokeWidth": 2,
|
||||
"icon": "play-circle",
|
||||
"iconColor": "#1890ff"
|
||||
},
|
||||
"ports": {
|
||||
"groups": {
|
||||
"out": {
|
||||
"position": "right",
|
||||
"attrs": {
|
||||
"circle": {
|
||||
"r": 4,
|
||||
"fill": "#ffffff",
|
||||
"stroke": "#1890ff"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}',
|
||||
'{
|
||||
"properties": [
|
||||
{"name": "id", "label": "节点标识", "type": "string", "required": true},
|
||||
{"name": "name", "label": "节点名称", "type": "string", "required": true}
|
||||
]
|
||||
}',
|
||||
10, true, NOW(), 'system', NOW(), 'system', 1, false),
|
||||
}
|
||||
}', 1),
|
||||
|
||||
-- 结束事件
|
||||
('endEvent', '结束事件', '流程的结束节点', 'EVENT',
|
||||
'{}',
|
||||
'{
|
||||
"shape": "circle",
|
||||
"width": 40,
|
||||
"height": 40,
|
||||
"ports": {
|
||||
"groups": {
|
||||
"top": {"position": "top", "attrs": {"circle": {"r": 4, "magnet": true}}},
|
||||
"right": {"position": "right", "attrs": {"circle": {"r": 4, "magnet": true}}},
|
||||
"bottom": {"position": "bottom", "attrs": {"circle": {"r": 4, "magnet": true}}},
|
||||
"left": {"position": "left", "attrs": {"circle": {"r": 4, "magnet": true}}}
|
||||
}
|
||||
(2, NOW(), 'END_EVENT', '结束节点', '工作流的终点', 'EVENT', '{
|
||||
"code": "END_EVENT",
|
||||
"name": "结束节点",
|
||||
"description": "工作流的终点",
|
||||
"details": {
|
||||
"description": "标记流程的结束位置,可以定义流程结束时的清理操作和设置返回值",
|
||||
"features": ["标记流程的结束位置", "定义结束时清理操作", "设置流程结果和返回值"],
|
||||
"scenarios": ["流程正常结束", "流程异常终止", "需要返回处理结果"]
|
||||
},
|
||||
"configSchema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"code": {"type": "string", "title": "节点Code", "description": "工作流节点的Code"},
|
||||
"name": {"type": "string", "title": "节点名称", "description": "工作流节点的显示名称"},
|
||||
"description": {"type": "string", "title": "节点描述", "description": "工作流节点的详细描述"}
|
||||
},
|
||||
"attrs": {
|
||||
"body": {"fill": "#ffffff", "stroke": "#333333", "strokeWidth": 4},
|
||||
"label": {"text": "结束", "fill": "#333333"}
|
||||
"required": ["code", "name"]
|
||||
},
|
||||
"uiSchema": {
|
||||
"shape": "circle",
|
||||
"size": {"width": 40, "height": 40},
|
||||
"style": {
|
||||
"fill": "#fff1f0",
|
||||
"stroke": "#ff4d4f",
|
||||
"strokeWidth": 2,
|
||||
"icon": "stop",
|
||||
"iconColor": "#ff4d4f"
|
||||
},
|
||||
"ports": {
|
||||
"groups": {
|
||||
"in": {
|
||||
"position": "left",
|
||||
"attrs": {
|
||||
"circle": {
|
||||
"r": 4,
|
||||
"fill": "#ffffff",
|
||||
"stroke": "#1890ff"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}',
|
||||
'{
|
||||
"properties": [
|
||||
{"name": "id", "label": "节点标识", "type": "string", "required": true},
|
||||
{"name": "name", "label": "节点名称", "type": "string", "required": true}
|
||||
]
|
||||
}',
|
||||
20, true, NOW(), 'system', NOW(), 'system', 1, false),
|
||||
}
|
||||
}', 1);
|
||||
|
||||
-- 任务节点
|
||||
-- 用户任务
|
||||
('userTask', '用户任务', '需要人工处理的任务节点', 'TASK',
|
||||
'{
|
||||
"assignee": "$${assignee}",
|
||||
"candidateUsers": "$${candidateUsers}",
|
||||
"candidateGroups": "$${candidateGroups}"
|
||||
}',
|
||||
'{
|
||||
"shape": "rect",
|
||||
"width": 120,
|
||||
"height": 60,
|
||||
"ports": {
|
||||
"groups": {
|
||||
"top": {"position": "top", "attrs": {"circle": {"r": 4, "magnet": true}}},
|
||||
"right": {"position": "right", "attrs": {"circle": {"r": 4, "magnet": true}}},
|
||||
"bottom": {"position": "bottom", "attrs": {"circle": {"r": 4, "magnet": true}}},
|
||||
"left": {"position": "left", "attrs": {"circle": {"r": 4, "magnet": true}}}
|
||||
}
|
||||
INSERT INTO workflow_node_definition (id, create_time, type, name, description, category, graph_config, enabled)
|
||||
VALUES
|
||||
(3, NOW(), 'USER_TASK', '用户任务', '人工处理任务', 'TASK', '{
|
||||
"code": "USER_TASK",
|
||||
"name": "用户任务",
|
||||
"description": "人工处理任务",
|
||||
"details": {
|
||||
"description": "需要人工处理的任务节点,支持任务分配、表单填写、处理期限等功能",
|
||||
"features": ["分配任务给指定用户或角色", "支持任务表单的填写", "设置处理期限和提醒", "支持任务的转办、委托、退回"],
|
||||
"scenarios": ["审批流程", "表单填写", "人工审核", "数据确认"]
|
||||
},
|
||||
"configSchema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"code": {"type": "string", "title": "节点Code", "description": "工作流节点的Code"},
|
||||
"name": {"type": "string", "title": "节点名称", "description": "工作流节点的显示名称"},
|
||||
"description": {"type": "string", "title": "节点描述", "description": "工作流节点的详细描述"}
|
||||
},
|
||||
"attrs": {
|
||||
"body": {"fill": "#ffffff", "stroke": "#333333", "strokeWidth": 2},
|
||||
"label": {"text": "用户任务", "fill": "#333333"}
|
||||
"required": ["code", "name"]
|
||||
},
|
||||
"uiSchema": {
|
||||
"shape": "rectangle",
|
||||
"size": {"width": 120, "height": 60},
|
||||
"style": {
|
||||
"fill": "#ffffff",
|
||||
"stroke": "#1890ff",
|
||||
"strokeWidth": 2,
|
||||
"icon": "user",
|
||||
"iconColor": "#1890ff"
|
||||
},
|
||||
"ports": {
|
||||
"groups": {
|
||||
"in": {
|
||||
"position": "left",
|
||||
"attrs": {
|
||||
"circle": {
|
||||
"r": 4,
|
||||
"fill": "#ffffff",
|
||||
"stroke": "#1890ff"
|
||||
}
|
||||
}
|
||||
},
|
||||
"out": {
|
||||
"position": "right",
|
||||
"attrs": {
|
||||
"circle": {
|
||||
"r": 4,
|
||||
"fill": "#ffffff",
|
||||
"stroke": "#1890ff"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}',
|
||||
'{
|
||||
"properties": [
|
||||
{"name": "id", "label": "节点标识", "type": "string", "required": true},
|
||||
{"name": "name", "label": "节点名称", "type": "string", "required": true},
|
||||
{"name": "assignee", "label": "处理人", "type": "string"},
|
||||
{"name": "candidateUsers", "label": "候选用户", "type": "string"},
|
||||
{"name": "candidateGroups", "label": "候选组", "type": "string"},
|
||||
{"name": "dueDate", "label": "到期时间", "type": "date"}
|
||||
]
|
||||
}',
|
||||
30, true, NOW(), 'system', NOW(), 'system', 1, false),
|
||||
}
|
||||
}', 1),
|
||||
|
||||
-- 服务任务
|
||||
('serviceTask', '服务任务', '自动执行的系统服务任务', 'TASK',
|
||||
'{
|
||||
"class": "com.example.ServiceTaskDelegate"
|
||||
}',
|
||||
'{
|
||||
"shape": "rect",
|
||||
"width": 120,
|
||||
"height": 60,
|
||||
"ports": {
|
||||
"groups": {
|
||||
"top": {"position": "top", "attrs": {"circle": {"r": 4, "magnet": true}}},
|
||||
"right": {"position": "right", "attrs": {"circle": {"r": 4, "magnet": true}}},
|
||||
"bottom": {"position": "bottom", "attrs": {"circle": {"r": 4, "magnet": true}}},
|
||||
"left": {"position": "left", "attrs": {"circle": {"r": 4, "magnet": true}}}
|
||||
}
|
||||
(4, NOW(), 'SERVICE_TASK', '服务任务', '系统服务调用', 'TASK', '{
|
||||
"code": "SERVICE_TASK",
|
||||
"name": "服务任务",
|
||||
"description": "系统服务调用",
|
||||
"details": {
|
||||
"description": "自动执行的系统服务任务,支持同步/异步调用外部服务和系统API",
|
||||
"features": ["调用系统服务或外部接口", "执行自动化操作", "支持异步执行和结果回调", "数据转换和处理"],
|
||||
"scenarios": ["调用外部系统API", "发送通知消息", "数据同步处理", "自动化操作"]
|
||||
},
|
||||
"configSchema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"code": {"type": "string", "title": "节点Code", "description": "工作流节点的Code"},
|
||||
"name": {"type": "string", "title": "节点名称", "description": "工作流节点的显示名称"},
|
||||
"description": {"type": "string", "title": "节点描述", "description": "工作流节点的详细描述"}
|
||||
},
|
||||
"attrs": {
|
||||
"body": {"fill": "#ffffff", "stroke": "#333333", "strokeWidth": 2},
|
||||
"label": {"text": "服务任务", "fill": "#333333"}
|
||||
"required": ["code", "name"]
|
||||
},
|
||||
"uiSchema": {
|
||||
"shape": "rectangle",
|
||||
"size": {"width": 120, "height": 60},
|
||||
"style": {
|
||||
"fill": "#ffffff",
|
||||
"stroke": "#1890ff",
|
||||
"strokeWidth": 2,
|
||||
"icon": "api",
|
||||
"iconColor": "#1890ff"
|
||||
},
|
||||
"ports": {
|
||||
"groups": {
|
||||
"in": {
|
||||
"position": "left",
|
||||
"attrs": {
|
||||
"circle": {
|
||||
"r": 4,
|
||||
"fill": "#ffffff",
|
||||
"stroke": "#1890ff"
|
||||
}
|
||||
}
|
||||
},
|
||||
"out": {
|
||||
"position": "right",
|
||||
"attrs": {
|
||||
"circle": {
|
||||
"r": 4,
|
||||
"fill": "#ffffff",
|
||||
"stroke": "#1890ff"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}',
|
||||
'{
|
||||
"properties": [
|
||||
{"name": "id", "label": "节点标识", "type": "string", "required": true},
|
||||
{"name": "name", "label": "节点名称", "type": "string", "required": true},
|
||||
{"name": "class", "label": "实现类", "type": "string", "required": true},
|
||||
{"name": "async", "label": "异步执行", "type": "boolean"}
|
||||
]
|
||||
}',
|
||||
40, true, NOW(), 'system', NOW(), 'system', 1, false),
|
||||
}
|
||||
}', 1),
|
||||
|
||||
-- Shell任务
|
||||
('shellTask', 'Shell任务', '执行Shell命令或脚本的任务节点', 'TASK',
|
||||
'{
|
||||
"class": "com.qqchen.deploy.backend.workflow.delegate.ShellTaskDelegate"
|
||||
}',
|
||||
'{
|
||||
"shape": "rect",
|
||||
"width": 120,
|
||||
"height": 60,
|
||||
"ports": {
|
||||
"groups": {
|
||||
"top": {"position": "top", "attrs": {"circle": {"r": 4, "magnet": true}}},
|
||||
"right": {"position": "right", "attrs": {"circle": {"r": 4, "magnet": true}}},
|
||||
"bottom": {"position": "bottom", "attrs": {"circle": {"r": 4, "magnet": true}}},
|
||||
"left": {"position": "left", "attrs": {"circle": {"r": 4, "magnet": true}}}
|
||||
}
|
||||
(5, NOW(), 'SCRIPT_TASK', '脚本任务', '脚本执行任务', 'TASK', '{
|
||||
"code": "SCRIPT_TASK",
|
||||
"name": "脚本任务",
|
||||
"description": "脚本执行任务",
|
||||
"details": {
|
||||
"description": "执行自定义脚本的任务节点,支持多种脚本语言和复杂的业务逻辑",
|
||||
"features": ["执行自定义脚本代码", "支持多种脚本语言", "访问流程变量", "支持复杂的业务逻辑"],
|
||||
"scenarios": ["数据处理和转换", "条件判断", "自定义业务规则", "系统集成"]
|
||||
},
|
||||
"configSchema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"code": {"type": "string", "title": "节点Code", "description": "工作流节点的Code"},
|
||||
"name": {"type": "string", "title": "节点名称", "description": "工作流节点的显示名称"},
|
||||
"description": {"type": "string", "title": "节点描述", "description": "工作流节点的详细描述"},
|
||||
"script": {
|
||||
"type": "string",
|
||||
"title": "脚本内容",
|
||||
"description": "需要执行的脚本内容",
|
||||
"format": "textarea"
|
||||
},
|
||||
"language": {
|
||||
"type": "string",
|
||||
"title": "脚本语言",
|
||||
"description": "脚本语言类型",
|
||||
"default": "shell",
|
||||
"enum": ["shell", "python", "javascript", "groovy"],
|
||||
"enumNames": ["Shell脚本 (已支持)", "Python脚本 (开发中)", "JavaScript脚本 (开发中)", "Groovy脚本 (开发中)"]
|
||||
}
|
||||
},
|
||||
"attrs": {
|
||||
"body": {"fill": "#ffffff", "stroke": "#333333", "strokeWidth": 2},
|
||||
"label": {"text": "Shell任务", "fill": "#333333"}
|
||||
"required": ["code", "name", "script", "language"]
|
||||
},
|
||||
"uiSchema": {
|
||||
"shape": "rectangle",
|
||||
"size": {"width": 120, "height": 60},
|
||||
"style": {
|
||||
"fill": "#ffffff",
|
||||
"stroke": "#1890ff",
|
||||
"strokeWidth": 2,
|
||||
"icon": "code",
|
||||
"iconColor": "#1890ff"
|
||||
},
|
||||
"ports": {
|
||||
"groups": {
|
||||
"in": {
|
||||
"position": "left",
|
||||
"attrs": {
|
||||
"circle": {
|
||||
"r": 4,
|
||||
"fill": "#ffffff",
|
||||
"stroke": "#1890ff"
|
||||
}
|
||||
}
|
||||
},
|
||||
"out": {
|
||||
"position": "right",
|
||||
"attrs": {
|
||||
"circle": {
|
||||
"r": 4,
|
||||
"fill": "#ffffff",
|
||||
"stroke": "#1890ff"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}',
|
||||
'{
|
||||
"properties": [
|
||||
{"name": "id", "label": "节点标识", "type": "string", "required": true},
|
||||
{"name": "name", "label": "节点名称", "type": "string", "required": true},
|
||||
{"name": "script", "label": "脚本内容", "type": "textarea", "required": true},
|
||||
{"name": "workDir", "label": "工作目录", "type": "string", "required": true},
|
||||
{"name": "async", "label": "异步执行", "type": "boolean"}
|
||||
]
|
||||
}',
|
||||
50, true, NOW(), 'system', NOW(), 'system', 1, false),
|
||||
}
|
||||
}', 1);
|
||||
|
||||
-- 网关节点
|
||||
-- 排他网关
|
||||
('exclusiveGateway', '排他网关', '基于条件的分支网关,只会选择一个分支执行', 'GATEWAY',
|
||||
'{}',
|
||||
'{
|
||||
"shape": "diamond",
|
||||
"width": 60,
|
||||
"height": 60,
|
||||
"ports": {
|
||||
"groups": {
|
||||
"top": {"position": "top", "attrs": {"circle": {"r": 4, "magnet": true}}},
|
||||
"right": {"position": "right", "attrs": {"circle": {"r": 4, "magnet": true}}},
|
||||
"bottom": {"position": "bottom", "attrs": {"circle": {"r": 4, "magnet": true}}},
|
||||
"left": {"position": "left", "attrs": {"circle": {"r": 4, "magnet": true}}}
|
||||
}
|
||||
INSERT INTO workflow_node_definition (id, create_time, type, name, description, category, graph_config, enabled)
|
||||
VALUES
|
||||
(6, NOW(), 'EXCLUSIVE_GATEWAY', '排他网关', '条件分支控制', 'GATEWAY', '{
|
||||
"code": "EXCLUSIVE_GATEWAY",
|
||||
"name": "排他网关",
|
||||
"description": "条件分支控制",
|
||||
"details": {
|
||||
"description": "基于条件的分支控制,只会选择一个分支执行",
|
||||
"features": ["根据条件选择一个分支执行", "支持复杂的条件表达式", "可以设置默认分支"],
|
||||
"scenarios": ["条件判断", "分支选择", "业务规则路由"]
|
||||
},
|
||||
"configSchema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"code": {"type": "string", "title": "节点Code", "description": "工作流节点的Code"},
|
||||
"name": {"type": "string", "title": "节点名称", "description": "工作流节点的显示名称"},
|
||||
"description": {"type": "string", "title": "节点描述", "description": "工作流节点的详细描述"}
|
||||
},
|
||||
"attrs": {
|
||||
"body": {"fill": "#ffffff", "stroke": "#333333", "strokeWidth": 2},
|
||||
"label": {"text": "×", "fill": "#333333", "fontSize": 40}
|
||||
"required": ["code", "name"]
|
||||
},
|
||||
"uiSchema": {
|
||||
"shape": "diamond",
|
||||
"size": {"width": 50, "height": 50},
|
||||
"style": {
|
||||
"fill": "#fff7e6",
|
||||
"stroke": "#faad14",
|
||||
"strokeWidth": 2,
|
||||
"icon": "fork",
|
||||
"iconColor": "#faad14"
|
||||
},
|
||||
"ports": {
|
||||
"groups": {
|
||||
"in": {
|
||||
"position": "left",
|
||||
"attrs": {
|
||||
"circle": {
|
||||
"r": 4,
|
||||
"fill": "#ffffff",
|
||||
"stroke": "#1890ff"
|
||||
}
|
||||
}
|
||||
},
|
||||
"out": {
|
||||
"position": "right",
|
||||
"attrs": {
|
||||
"circle": {
|
||||
"r": 4,
|
||||
"fill": "#ffffff",
|
||||
"stroke": "#1890ff"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}',
|
||||
'{
|
||||
"properties": [
|
||||
{"name": "id", "label": "节点标识", "type": "string", "required": true},
|
||||
{"name": "name", "label": "网关名称", "type": "string", "required": true},
|
||||
{"name": "defaultFlow", "label": "默认路径", "type": "string"}
|
||||
]
|
||||
}',
|
||||
60, true, NOW(), 'system', NOW(), 'system', 1, false),
|
||||
}
|
||||
}', 1),
|
||||
|
||||
-- 并行网关
|
||||
('parallelGateway', '并行网关', '并行执行所有分支', 'GATEWAY',
|
||||
'{}',
|
||||
'{
|
||||
"shape": "diamond",
|
||||
"width": 60,
|
||||
"height": 60,
|
||||
"ports": {
|
||||
"groups": {
|
||||
"top": {"position": "top", "attrs": {"circle": {"r": 4, "magnet": true}}},
|
||||
"right": {"position": "right", "attrs": {"circle": {"r": 4, "magnet": true}}},
|
||||
"bottom": {"position": "bottom", "attrs": {"circle": {"r": 4, "magnet": true}}},
|
||||
"left": {"position": "left", "attrs": {"circle": {"r": 4, "magnet": true}}}
|
||||
}
|
||||
(7, NOW(), 'PARALLEL_GATEWAY', '并行网关', '并行分支控制', 'GATEWAY', '{
|
||||
"code": "PARALLEL_GATEWAY",
|
||||
"name": "并行网关",
|
||||
"description": "并行分支控制",
|
||||
"details": {
|
||||
"description": "将流程分成多个并行分支同时执行,等待所有分支完成后合并",
|
||||
"features": ["将流程分成多个并行分支", "等待所有分支完成后合并", "支持复杂的并行处理"],
|
||||
"scenarios": ["并行审批", "多任务同时处理", "并行数据处理"]
|
||||
},
|
||||
"configSchema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"code": {"type": "string", "title": "节点Code", "description": "工作流节点的Code"},
|
||||
"name": {"type": "string", "title": "节点名称", "description": "工作流节点的显示名称"},
|
||||
"description": {"type": "string", "title": "节点描述", "description": "工作流节点的详细描述"}
|
||||
},
|
||||
"attrs": {
|
||||
"body": {"fill": "#ffffff", "stroke": "#333333", "strokeWidth": 2},
|
||||
"label": {"text": "+", "fill": "#333333", "fontSize": 40}
|
||||
"required": ["code", "name"]
|
||||
},
|
||||
"uiSchema": {
|
||||
"shape": "diamond",
|
||||
"size": {"width": 50, "height": 50},
|
||||
"style": {
|
||||
"fill": "#fff7e6",
|
||||
"stroke": "#faad14",
|
||||
"strokeWidth": 2,
|
||||
"icon": "branches",
|
||||
"iconColor": "#faad14"
|
||||
},
|
||||
"ports": {
|
||||
"groups": {
|
||||
"in": {
|
||||
"position": "left",
|
||||
"attrs": {
|
||||
"circle": {
|
||||
"r": 4,
|
||||
"fill": "#ffffff",
|
||||
"stroke": "#1890ff"
|
||||
}
|
||||
}
|
||||
},
|
||||
"out": {
|
||||
"position": "right",
|
||||
"attrs": {
|
||||
"circle": {
|
||||
"r": 4,
|
||||
"fill": "#ffffff",
|
||||
"stroke": "#1890ff"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}',
|
||||
'{
|
||||
"properties": [
|
||||
{"name": "id", "label": "节点标识", "type": "string", "required": true},
|
||||
{"name": "name", "label": "网关名称", "type": "string", "required": true}
|
||||
]
|
||||
}',
|
||||
70, true, NOW(), 'system', NOW(), 'system', 1, false);
|
||||
}
|
||||
}', 1);
|
||||
|
||||
-- 容器节点
|
||||
INSERT INTO workflow_node_definition (id, create_time, type, name, description, category, graph_config, enabled)
|
||||
VALUES
|
||||
(8, NOW(), 'SUB_PROCESS', '子流程', '嵌入式子流程', 'CONTAINER', '{
|
||||
"code": "SUB_PROCESS",
|
||||
"name": "子流程",
|
||||
"description": "嵌入式子流程",
|
||||
"details": {
|
||||
"description": "在当前流程中嵌入子流程,支持流程的模块化和复用",
|
||||
"features": ["在当前流程中嵌入子流程", "重用流程片段", "支持事务处理", "独立的变量范围"],
|
||||
"scenarios": ["流程复用", "模块化处理", "事务管理", "错误处理"]
|
||||
},
|
||||
"configSchema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"code": {"type": "string", "title": "节点Code", "description": "工作流节点的Code"},
|
||||
"name": {"type": "string", "title": "节点名称", "description": "工作流节点的显示名称"},
|
||||
"description": {"type": "string", "title": "节点描述", "description": "工作流节点的详细描述"}
|
||||
},
|
||||
"required": ["code", "name"]
|
||||
},
|
||||
"uiSchema": {
|
||||
"shape": "rectangle",
|
||||
"size": {"width": 120, "height": 60},
|
||||
"style": {
|
||||
"fill": "#ffffff",
|
||||
"stroke": "#1890ff",
|
||||
"strokeWidth": 2,
|
||||
"icon": "apartment",
|
||||
"iconColor": "#1890ff"
|
||||
},
|
||||
"ports": {
|
||||
"groups": {
|
||||
"in": {
|
||||
"position": "left",
|
||||
"attrs": {
|
||||
"circle": {
|
||||
"r": 4,
|
||||
"fill": "#ffffff",
|
||||
"stroke": "#1890ff"
|
||||
}
|
||||
}
|
||||
},
|
||||
"out": {
|
||||
"position": "right",
|
||||
"attrs": {
|
||||
"circle": {
|
||||
"r": 4,
|
||||
"fill": "#ffffff",
|
||||
"stroke": "#1890ff"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}', 1),
|
||||
|
||||
(9, NOW(), 'CALL_ACTIVITY', '调用活动', '外部流程调用', 'CONTAINER', '{
|
||||
"code": "CALL_ACTIVITY",
|
||||
"name": "调用活动",
|
||||
"description": "外部流程调用",
|
||||
"details": {
|
||||
"description": "调用外部定义的流程,支持跨系统流程调用和参数传递",
|
||||
"features": ["调用外部定义的流程", "支持跨系统流程调用", "传递和接收参数", "支持异步调用"],
|
||||
"scenarios": ["跨系统流程集成", "公共流程复用", "分布式流程处理", "大型流程解耦"]
|
||||
},
|
||||
"configSchema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"code": {"type": "string", "title": "节点Code", "description": "工作流节点的Code"},
|
||||
"name": {"type": "string", "title": "节点名称", "description": "工作流节点的显示名称"},
|
||||
"description": {"type": "string", "title": "节点描述", "description": "工作流节点的详细描述"}
|
||||
},
|
||||
"required": ["code", "name"]
|
||||
},
|
||||
"uiSchema": {
|
||||
"shape": "rectangle",
|
||||
"size": {"width": 120, "height": 60},
|
||||
"style": {
|
||||
"fill": "#ffffff",
|
||||
"stroke": "#1890ff",
|
||||
"strokeWidth": 2,
|
||||
"icon": "api",
|
||||
"iconColor": "#1890ff"
|
||||
},
|
||||
"ports": {
|
||||
"groups": {
|
||||
"in": {
|
||||
"position": "left",
|
||||
"attrs": {
|
||||
"circle": {
|
||||
"r": 4,
|
||||
"fill": "#ffffff",
|
||||
"stroke": "#1890ff"
|
||||
}
|
||||
}
|
||||
},
|
||||
"out": {
|
||||
"position": "right",
|
||||
"attrs": {
|
||||
"circle": {
|
||||
"r": 4,
|
||||
"fill": "#ffffff",
|
||||
"stroke": "#1890ff"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}', 1);
|
||||
|
||||
@ -1,439 +0,0 @@
|
||||
package com.qqchen.deploy.backend.workflow.util;
|
||||
|
||||
import com.qqchen.deploy.backend.workflow.dto.graph.*;
|
||||
import com.qqchen.deploy.backend.workflow.enums.NodeTypeEnums;
|
||||
import org.flowable.bpmn.converter.BpmnXMLConverter;
|
||||
import org.flowable.bpmn.model.*;
|
||||
import org.flowable.bpmn.model.Process;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* BPMN转换器测试
|
||||
*/
|
||||
@SpringBootTest(properties = {
|
||||
"spring.flyway.enabled=false"
|
||||
})
|
||||
class BpmnConverterTest {
|
||||
|
||||
@Autowired
|
||||
private BpmnConverter bpmnConverter;
|
||||
|
||||
@Test
|
||||
void testConvertSimpleWorkflow() {
|
||||
// 创建一个简单的工作流图:开始 -> 服务任务 -> 结束
|
||||
WorkflowGraph graph = new WorkflowGraph();
|
||||
|
||||
// 创建节点
|
||||
List<WorkflowNode> nodes = new ArrayList<>();
|
||||
|
||||
// 开始节点
|
||||
WorkflowNode startNode = new WorkflowNode();
|
||||
startNode.setId("startEvent1");
|
||||
startNode.setType(NodeTypeEnums.START_EVENT);
|
||||
startNode.setName("开始");
|
||||
startNode.setPosition(new Position(100.0, 100.0));
|
||||
nodes.add(startNode);
|
||||
|
||||
// 服务任务节点
|
||||
WorkflowNode serviceNode = new WorkflowNode();
|
||||
serviceNode.setId("service1");
|
||||
serviceNode.setType(NodeTypeEnums.SERVICE_TASK);
|
||||
serviceNode.setName("服务任务");
|
||||
serviceNode.setPosition(new Position(300.0, 100.0));
|
||||
|
||||
NodeConfig serviceConfig = new NodeConfig();
|
||||
serviceConfig.setImplementation("$${shellTaskDelegate}");
|
||||
Map<String, Object> fields = new HashMap<>();
|
||||
fields.put("script", "echo 'Hello World'");
|
||||
fields.put("workDir", "/tmp");
|
||||
fields.put("timeout", "30");
|
||||
serviceConfig.setFields(fields);
|
||||
serviceNode.setConfig(serviceConfig);
|
||||
nodes.add(serviceNode);
|
||||
|
||||
// 结束节点
|
||||
WorkflowNode endNode = new WorkflowNode();
|
||||
endNode.setId("endEvent1");
|
||||
endNode.setType(NodeTypeEnums.END_EVENT);
|
||||
endNode.setName("结束");
|
||||
endNode.setPosition(new Position(500.0, 100.0));
|
||||
nodes.add(endNode);
|
||||
|
||||
// 创建边
|
||||
List<WorkflowEdge> edges = new ArrayList<>();
|
||||
|
||||
// 开始 -> 服务任务
|
||||
WorkflowEdge edge1 = new WorkflowEdge();
|
||||
edge1.setId("flow1");
|
||||
edge1.setSource("startEvent1");
|
||||
edge1.setTarget("service1");
|
||||
edge1.setName("流转到服务任务");
|
||||
edges.add(edge1);
|
||||
|
||||
// 服务任务 -> 结束
|
||||
WorkflowEdge edge2 = new WorkflowEdge();
|
||||
edge2.setId("flow2");
|
||||
edge2.setSource("service1");
|
||||
edge2.setTarget("endEvent1");
|
||||
edge2.setName("流转到结束");
|
||||
edges.add(edge2);
|
||||
|
||||
graph.setNodes(nodes);
|
||||
graph.setEdges(edges);
|
||||
|
||||
// 执行转换
|
||||
BpmnModel bpmnModel = bpmnConverter.convertToBpmnModel(graph);
|
||||
|
||||
// 打印XML
|
||||
try {
|
||||
System.out.println("\n=== Simple Workflow XML ===");
|
||||
System.out.println(new String(new BpmnXMLConverter().convertToXML(bpmnModel)));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// 验证结果
|
||||
assertNotNull(bpmnModel);
|
||||
Process process = bpmnModel.getMainProcess();
|
||||
assertNotNull(process);
|
||||
|
||||
// 验证节点数量
|
||||
assertEquals(5, process.getFlowElements().size());
|
||||
|
||||
// 验证开始节点
|
||||
StartEvent startEvent = (StartEvent) process.getFlowElement("startEvent1");
|
||||
assertNotNull(startEvent);
|
||||
assertEquals("开始", startEvent.getName());
|
||||
|
||||
// 验证服务任务节点
|
||||
ServiceTask serviceTask = (ServiceTask) process.getFlowElement("service1");
|
||||
assertNotNull(serviceTask);
|
||||
assertEquals("服务任务", serviceTask.getName());
|
||||
assertEquals("$${shellTaskDelegate}", serviceTask.getImplementation());
|
||||
|
||||
// 验证服务任务字段
|
||||
List<FieldExtension> fieldExtensions = serviceTask.getFieldExtensions();
|
||||
assertNotNull(fieldExtensions);
|
||||
assertEquals(3, fieldExtensions.size());
|
||||
|
||||
Map<String, String> fieldMap = new HashMap<>();
|
||||
for (FieldExtension field : fieldExtensions) {
|
||||
fieldMap.put(field.getFieldName(), field.getStringValue());
|
||||
}
|
||||
|
||||
assertEquals("echo 'Hello World'", fieldMap.get("script"));
|
||||
assertEquals("/tmp", fieldMap.get("workDir"));
|
||||
assertEquals("30", fieldMap.get("timeout"));
|
||||
|
||||
// 验证结束节点
|
||||
EndEvent endEvent = (EndEvent) process.getFlowElement("endEvent1");
|
||||
assertNotNull(endEvent);
|
||||
assertEquals("结束", endEvent.getName());
|
||||
|
||||
// 验证边
|
||||
SequenceFlow flow1 = (SequenceFlow) process.getFlowElement("flow1");
|
||||
assertNotNull(flow1);
|
||||
assertEquals("流转到服务任务", flow1.getName());
|
||||
assertEquals("startEvent1", flow1.getSourceRef());
|
||||
assertEquals("service1", flow1.getTargetRef());
|
||||
|
||||
SequenceFlow flow2 = (SequenceFlow) process.getFlowElement("flow2");
|
||||
assertNotNull(flow2);
|
||||
assertEquals("流转到结束", flow2.getName());
|
||||
assertEquals("service1", flow2.getSourceRef());
|
||||
assertEquals("endEvent1", flow2.getTargetRef());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testConvertUserTask() {
|
||||
// 创建一个包含用户任务的工作流图
|
||||
WorkflowGraph graph = new WorkflowGraph();
|
||||
|
||||
// 创建节点
|
||||
List<WorkflowNode> nodes = new ArrayList<>();
|
||||
|
||||
// 开始节点
|
||||
WorkflowNode startNode = new WorkflowNode();
|
||||
startNode.setId("startEvent1");
|
||||
startNode.setType(NodeTypeEnums.START_EVENT);
|
||||
startNode.setName("开始");
|
||||
startNode.setPosition(new Position(100.0, 100.0));
|
||||
nodes.add(startNode);
|
||||
|
||||
// 用户任务节点
|
||||
WorkflowNode userNode = new WorkflowNode();
|
||||
userNode.setId("user1");
|
||||
userNode.setType(NodeTypeEnums.USER_TASK);
|
||||
userNode.setName("审批任务");
|
||||
userNode.setPosition(new Position(300.0, 100.0));
|
||||
|
||||
NodeConfig userConfig = new NodeConfig();
|
||||
userConfig.setAssignee("$${initiator}");
|
||||
userConfig.setCandidateUsers(Arrays.asList("user1", "user2"));
|
||||
userConfig.setCandidateGroups(Arrays.asList("group1", "group2"));
|
||||
userConfig.setDueDate("$${dueDate}");
|
||||
userConfig.setPriority(1);
|
||||
userConfig.setFormKey("form1");
|
||||
userNode.setConfig(userConfig);
|
||||
nodes.add(userNode);
|
||||
|
||||
// 结束节点
|
||||
WorkflowNode endNode = new WorkflowNode();
|
||||
endNode.setId("endEvent1");
|
||||
endNode.setType(NodeTypeEnums.END_EVENT);
|
||||
endNode.setName("结束");
|
||||
endNode.setPosition(new Position(500.0, 100.0));
|
||||
nodes.add(endNode);
|
||||
|
||||
// 创建边
|
||||
List<WorkflowEdge> edges = new ArrayList<>();
|
||||
|
||||
// 开始 -> 用户任务
|
||||
WorkflowEdge edge1 = new WorkflowEdge();
|
||||
edge1.setId("flow1");
|
||||
edge1.setSource("startEvent1");
|
||||
edge1.setTarget("user1");
|
||||
edge1.setName("提交审批");
|
||||
edges.add(edge1);
|
||||
|
||||
// 用户任务 -> 结束
|
||||
WorkflowEdge edge2 = new WorkflowEdge();
|
||||
edge2.setId("flow2");
|
||||
edge2.setSource("user1");
|
||||
edge2.setTarget("endEvent1");
|
||||
edge2.setName("审批完成");
|
||||
edges.add(edge2);
|
||||
|
||||
graph.setNodes(nodes);
|
||||
graph.setEdges(edges);
|
||||
|
||||
// 执行转换
|
||||
BpmnModel bpmnModel = bpmnConverter.convertToBpmnModel(graph);
|
||||
|
||||
// 打印XML
|
||||
try {
|
||||
System.out.println("\n=== User Task Workflow XML ===");
|
||||
System.out.println(new String(new BpmnXMLConverter().convertToXML(bpmnModel)));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// 验证结果
|
||||
assertNotNull(bpmnModel);
|
||||
Process process = bpmnModel.getMainProcess();
|
||||
assertNotNull(process);
|
||||
|
||||
// 验证用户任务节点
|
||||
UserTask userTask = (UserTask) process.getFlowElement("user1");
|
||||
assertNotNull(userTask);
|
||||
assertEquals("审批任务", userTask.getName());
|
||||
assertEquals("$${initiator}", userTask.getAssignee());
|
||||
assertEquals(Arrays.asList("user1", "user2"), userTask.getCandidateUsers());
|
||||
assertEquals(Arrays.asList("group1", "group2"), userTask.getCandidateGroups());
|
||||
assertEquals("$${dueDate}", userTask.getDueDate());
|
||||
assertEquals("1", userTask.getPriority());
|
||||
assertEquals("form1", userTask.getFormKey());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testConvertComplexWorkflow() {
|
||||
// 创建一个复杂的工作流图:开始 -> 服务任务 -> 用户任务 -> 脚本任务 -> 结束
|
||||
WorkflowGraph graph = new WorkflowGraph();
|
||||
|
||||
// 设置流程属性
|
||||
Map<String, Object> properties = new HashMap<>();
|
||||
properties.put("name", "测试流程");
|
||||
properties.put("key", "test_process");
|
||||
properties.put("description", "这是一个测试流程");
|
||||
graph.setProperties(properties);
|
||||
|
||||
// 创建节点
|
||||
List<WorkflowNode> nodes = new ArrayList<>();
|
||||
|
||||
// 开始节点
|
||||
WorkflowNode startNode = new WorkflowNode();
|
||||
startNode.setId("startEvent1");
|
||||
startNode.setType(NodeTypeEnums.START_EVENT);
|
||||
startNode.setName("开始");
|
||||
startNode.setPosition(new Position(100.0, 100.0));
|
||||
nodes.add(startNode);
|
||||
|
||||
// 服务任务节点
|
||||
WorkflowNode serviceNode = new WorkflowNode();
|
||||
serviceNode.setId("service1");
|
||||
serviceNode.setType(NodeTypeEnums.SERVICE_TASK);
|
||||
serviceNode.setName("服务任务");
|
||||
serviceNode.setPosition(new Position(250.0, 100.0));
|
||||
|
||||
NodeConfig serviceConfig = new NodeConfig();
|
||||
serviceConfig.setImplementation("$${shellTaskDelegate}");
|
||||
Map<String, Object> serviceFields = new HashMap<>();
|
||||
serviceFields.put("script", "echo 'Hello World'");
|
||||
serviceFields.put("workDir", "/tmp");
|
||||
serviceConfig.setFields(serviceFields);
|
||||
serviceNode.setConfig(serviceConfig);
|
||||
nodes.add(serviceNode);
|
||||
|
||||
// 用户任务节点
|
||||
WorkflowNode userNode = new WorkflowNode();
|
||||
userNode.setId("user1");
|
||||
userNode.setType(NodeTypeEnums.USER_TASK);
|
||||
userNode.setName("用户任务");
|
||||
userNode.setPosition(new Position(400.0, 100.0));
|
||||
|
||||
NodeConfig userConfig = new NodeConfig();
|
||||
userConfig.setAssignee("$${initiator}");
|
||||
List<String> candidateUsers = Arrays.asList("user1", "user2");
|
||||
List<String> candidateGroups = Arrays.asList("group1", "group2");
|
||||
userConfig.setCandidateUsers(candidateUsers);
|
||||
userConfig.setCandidateGroups(candidateGroups);
|
||||
userConfig.setPriority(1);
|
||||
userConfig.setFormKey("form1");
|
||||
userNode.setConfig(userConfig);
|
||||
nodes.add(userNode);
|
||||
|
||||
// 脚本任务节点
|
||||
WorkflowNode scriptNode = new WorkflowNode();
|
||||
scriptNode.setId("script1");
|
||||
scriptNode.setType(NodeTypeEnums.SCRIPT_TASK);
|
||||
scriptNode.setName("脚本任务");
|
||||
scriptNode.setPosition(new Position(550.0, 100.0));
|
||||
|
||||
NodeConfig scriptConfig = new NodeConfig();
|
||||
scriptConfig.setImplementation("groovy");
|
||||
Map<String, Object> scriptFields = new HashMap<>();
|
||||
scriptFields.put("script", "println 'Hello from Groovy'");
|
||||
scriptConfig.setFields(scriptFields);
|
||||
scriptNode.setConfig(scriptConfig);
|
||||
nodes.add(scriptNode);
|
||||
|
||||
// 结束节点
|
||||
WorkflowNode endNode = new WorkflowNode();
|
||||
endNode.setId("endEvent1");
|
||||
endNode.setType(NodeTypeEnums.END_EVENT);
|
||||
endNode.setName("结束");
|
||||
endNode.setPosition(new Position(700.0, 100.0));
|
||||
nodes.add(endNode);
|
||||
|
||||
// 创建边
|
||||
List<WorkflowEdge> edges = new ArrayList<>();
|
||||
|
||||
// 开始 -> 服务任务
|
||||
WorkflowEdge edge1 = new WorkflowEdge();
|
||||
edge1.setId("flow1");
|
||||
edge1.setSource("startEvent1");
|
||||
edge1.setTarget("service1");
|
||||
edge1.setName("流转到服务任务");
|
||||
EdgeConfig edgeConfig1 = new EdgeConfig();
|
||||
edgeConfig1.setType("sequence");
|
||||
edge1.setConfig(edgeConfig1);
|
||||
edges.add(edge1);
|
||||
|
||||
// 服务任务 -> 用户任务
|
||||
WorkflowEdge edge2 = new WorkflowEdge();
|
||||
edge2.setId("flow2");
|
||||
edge2.setSource("service1");
|
||||
edge2.setTarget("user1");
|
||||
edge2.setName("流转到用户任务");
|
||||
EdgeConfig edgeConfig2 = new EdgeConfig();
|
||||
edgeConfig2.setType("sequence");
|
||||
edgeConfig2.setCondition("$${approved}");
|
||||
edge2.setConfig(edgeConfig2);
|
||||
edges.add(edge2);
|
||||
|
||||
// 用户任务 -> 脚本任务
|
||||
WorkflowEdge edge3 = new WorkflowEdge();
|
||||
edge3.setId("flow3");
|
||||
edge3.setSource("user1");
|
||||
edge3.setTarget("script1");
|
||||
edge3.setName("流转到脚本任务");
|
||||
EdgeConfig edgeConfig3 = new EdgeConfig();
|
||||
edgeConfig3.setType("sequence");
|
||||
edge3.setConfig(edgeConfig3);
|
||||
edges.add(edge3);
|
||||
|
||||
// 脚本任务 -> 结束
|
||||
WorkflowEdge edge4 = new WorkflowEdge();
|
||||
edge4.setId("flow4");
|
||||
edge4.setSource("script1");
|
||||
edge4.setTarget("endEvent1");
|
||||
edge4.setName("流转到结束");
|
||||
EdgeConfig edgeConfig4 = new EdgeConfig();
|
||||
edgeConfig4.setType("sequence");
|
||||
edge4.setConfig(edgeConfig4);
|
||||
edges.add(edge4);
|
||||
|
||||
graph.setNodes(nodes);
|
||||
graph.setEdges(edges);
|
||||
|
||||
// 执行转换并获取XML
|
||||
String xml = bpmnConverter.convertToXml(graph, "test_process");
|
||||
System.out.println("Generated BPMN XML:");
|
||||
System.out.println(xml);
|
||||
|
||||
// 执行转换
|
||||
BpmnModel bpmnModel = bpmnConverter.convertToBpmnModel(graph);
|
||||
|
||||
// 打印XML
|
||||
try {
|
||||
System.out.println("\n=== Complex Workflow XML ===");
|
||||
System.out.println(new String(new BpmnXMLConverter().convertToXML(bpmnModel)));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// 验证结果
|
||||
assertNotNull(bpmnModel);
|
||||
Process process = bpmnModel.getMainProcess();
|
||||
assertNotNull(process);
|
||||
|
||||
// 验证流程属性
|
||||
assertEquals("测试流程", process.getName());
|
||||
assertEquals("test_process", process.getId());
|
||||
assertEquals("这是一个测试流程", process.getDocumentation());
|
||||
|
||||
// 验证节点数量
|
||||
assertEquals(9, process.getFlowElements().size()); // 5个节点 + 4个连线
|
||||
|
||||
// 验证开始节点
|
||||
StartEvent startEvent = (StartEvent) process.getFlowElement("startEvent1");
|
||||
assertNotNull(startEvent);
|
||||
assertEquals("开始", startEvent.getName());
|
||||
|
||||
// 验证服务任务
|
||||
ServiceTask serviceTask = (ServiceTask) process.getFlowElement("service1");
|
||||
assertNotNull(serviceTask);
|
||||
assertEquals("服务任务", serviceTask.getName());
|
||||
assertEquals("$${shellTaskDelegate}", serviceTask.getImplementation());
|
||||
|
||||
// 验证用户任务
|
||||
UserTask userTask = (UserTask) process.getFlowElement("user1");
|
||||
assertNotNull(userTask);
|
||||
assertEquals("用户任务", userTask.getName());
|
||||
assertEquals("$${initiator}", userTask.getAssignee());
|
||||
assertEquals(Arrays.asList("user1", "user2"), userTask.getCandidateUsers());
|
||||
assertEquals(Arrays.asList("group1", "group2"), userTask.getCandidateGroups());
|
||||
|
||||
// 验证脚本任务
|
||||
ScriptTask scriptTask = (ScriptTask) process.getFlowElement("script1");
|
||||
assertNotNull(scriptTask);
|
||||
assertEquals("脚本任务", scriptTask.getName());
|
||||
assertEquals("groovy", scriptTask.getScriptFormat());
|
||||
|
||||
// 验证结束节点
|
||||
EndEvent endEvent = (EndEvent) process.getFlowElement("endEvent1");
|
||||
assertNotNull(endEvent);
|
||||
assertEquals("结束", endEvent.getName());
|
||||
|
||||
// 验证连线
|
||||
SequenceFlow flow2 = (SequenceFlow) process.getFlowElement("flow2");
|
||||
assertNotNull(flow2);
|
||||
assertEquals("$${approved}", flow2.getConditionExpression());
|
||||
}
|
||||
}
|
||||
18
frontend/.windsurfrules
Normal file
18
frontend/.windsurfrules
Normal file
@ -0,0 +1,18 @@
|
||||
你是一名java前端开发工程师,对你有以下要求
|
||||
1. 缺陷修正:
|
||||
- 在提出修复建议前,应充分分析问题
|
||||
- 提供精准、有针对性的解决方案
|
||||
- 解释bug的根本原因
|
||||
|
||||
2. 保持简单:
|
||||
- 优先考虑可读性和可维护性
|
||||
- 避免过度工程化的解决方案
|
||||
- 尽可能使用标准库和模式
|
||||
- 遵循正确、最佳实践、DRY原则、无错误、功能齐全的代码编写原则
|
||||
|
||||
3. 代码更改:
|
||||
- 在做出改变之前提出一个清晰的计划
|
||||
- 一次将所有修改应用于单个文件
|
||||
- 请勿修改不相关的文件
|
||||
|
||||
记住要始终考虑每个项目的背景和特定需求。
|
||||
Loading…
Reference in New Issue
Block a user