反序列化问题。
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.fasterxml.jackson.databind.JsonNode;
|
||||||
import com.qqchen.deploy.backend.framework.dto.BaseDTO;
|
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 com.qqchen.deploy.backend.workflow.enums.WorkflowStatusEnums;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
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
|
* @date 2024-12-11
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
public class WorkflowEdge {
|
public class WorkflowDefinitionEdge {
|
||||||
/**
|
/**
|
||||||
* 边ID
|
* 边ID
|
||||||
*/
|
*/
|
||||||
@ -18,12 +18,12 @@ public class WorkflowEdge {
|
|||||||
/**
|
/**
|
||||||
* 源节点ID
|
* 源节点ID
|
||||||
*/
|
*/
|
||||||
private String source;
|
private String from;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 目标节点ID
|
* 目标节点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
|
@Data
|
||||||
@JsonInclude(JsonInclude.Include.NON_NULL) // 只序列化非空字段
|
@JsonInclude(JsonInclude.Include.NON_NULL) // 只序列化非空字段
|
||||||
public class EdgeConfig {
|
public class WorkflowDefinitionEdgeConfig {
|
||||||
/**
|
/**
|
||||||
* 条件
|
* 条件
|
||||||
*/
|
*/
|
||||||
@ -31,14 +31,4 @@ public class EdgeConfig {
|
|||||||
*/
|
*/
|
||||||
private String type;
|
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
|
* @date 2024-12-11
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
public class Size {
|
public class WorkflowDefinitionEdgeSize {
|
||||||
/**
|
/**
|
||||||
* 宽度
|
* 宽度
|
||||||
*/
|
*/
|
||||||
@ -2,7 +2,6 @@ package com.qqchen.deploy.backend.workflow.dto.graph;
|
|||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 工作流图形数据传输对象
|
* 工作流图形数据传输对象
|
||||||
@ -10,15 +9,15 @@ import java.util.Map;
|
|||||||
* @date 2024-12-11
|
* @date 2024-12-11
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
public class WorkflowGraph {
|
public class WorkflowDefinitionGraph {
|
||||||
/**
|
/**
|
||||||
* 节点列表
|
* 节点列表
|
||||||
*/
|
*/
|
||||||
private List<WorkflowNode> nodes;
|
private List<WorkflowDefinitionNode> nodes;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 边列表
|
* 边列表
|
||||||
*/
|
*/
|
||||||
private List<WorkflowEdge> edges;
|
private List<WorkflowDefinitionEdge> edges;
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -2,15 +2,17 @@ package com.qqchen.deploy.backend.workflow.dto.graph;
|
|||||||
|
|
||||||
import com.qqchen.deploy.backend.workflow.enums.NodeTypeEnums;
|
import com.qqchen.deploy.backend.workflow.enums.NodeTypeEnums;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 工作流节点数据传输对象
|
* 工作流节点数据传输对象
|
||||||
|
*
|
||||||
* @author cascade
|
* @author cascade
|
||||||
* @date 2024-12-11
|
* @date 2024-12-11
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
public class WorkflowNode {
|
public class WorkflowDefinitionNode {
|
||||||
/**
|
/**
|
||||||
* 节点ID
|
* 节点ID
|
||||||
*/
|
*/
|
||||||
@ -26,23 +28,10 @@ public class WorkflowNode {
|
|||||||
*/
|
*/
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
/**
|
|
||||||
* 节点位置
|
|
||||||
*/
|
|
||||||
private Position position;
|
|
||||||
|
|
||||||
|
private WorkflowNodeGraph graph;
|
||||||
/**
|
/**
|
||||||
* 节点配置
|
* 节点配置
|
||||||
*/
|
*/
|
||||||
private NodeConfig config;
|
private Map<String, Object> config;
|
||||||
|
|
||||||
/**
|
|
||||||
* 节点属性
|
|
||||||
*/
|
|
||||||
private Map<String, Object> properties;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 节点大小
|
|
||||||
*/
|
|
||||||
private Size size;
|
|
||||||
}
|
}
|
||||||
@ -12,7 +12,7 @@ import lombok.AllArgsConstructor;
|
|||||||
@Data
|
@Data
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class Position {
|
public class WorkflowDefinitionPosition {
|
||||||
/**
|
/**
|
||||||
* X坐标
|
* 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.Data;
|
||||||
import lombok.experimental.Accessors;
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -13,23 +14,27 @@ import java.util.Map;
|
|||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
@Accessors(chain = true)
|
@Accessors(chain = true)
|
||||||
public class NodeUiConfig {
|
public class WorkflowNodeGraph {
|
||||||
|
|
||||||
private String shape;
|
private String shape;
|
||||||
|
|
||||||
private Size size;
|
private Size size;
|
||||||
|
|
||||||
private Style style;
|
private Style style;
|
||||||
|
|
||||||
private Ports ports;
|
private Ports ports;
|
||||||
|
|
||||||
public NodeUiConfig setSize(int width, int height) {
|
public WorkflowNodeGraph setSize(int width, int height) {
|
||||||
this.size = new Size(width, height);
|
this.size = new Size(width, height);
|
||||||
return this;
|
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);
|
this.style = new Style(fill, stroke, icon);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public NodeUiConfig setPorts(List<String> types) {
|
public WorkflowNodeGraph configPorts(List<String> types) {
|
||||||
this.ports = new Ports();
|
this.ports = new Ports();
|
||||||
Map<String, PortGroup> groups = new HashMap<>();
|
Map<String, PortGroup> groups = new HashMap<>();
|
||||||
|
|
||||||
@ -59,6 +64,7 @@ public class NodeUiConfig {
|
|||||||
@Data
|
@Data
|
||||||
public static class Size {
|
public static class Size {
|
||||||
private int width;
|
private int width;
|
||||||
|
|
||||||
private int height;
|
private int height;
|
||||||
|
|
||||||
public Size(int width, int height) {
|
public Size(int width, int height) {
|
||||||
@ -73,9 +79,13 @@ public class NodeUiConfig {
|
|||||||
@Data
|
@Data
|
||||||
public static class Style {
|
public static class Style {
|
||||||
private String fill; // 填充颜色
|
private String fill; // 填充颜色
|
||||||
|
|
||||||
private String stroke; // 边框颜色
|
private String stroke; // 边框颜色
|
||||||
|
|
||||||
private String icon; // 图标名称
|
private String icon; // 图标名称
|
||||||
|
|
||||||
private String iconColor; // 图标颜色
|
private String iconColor; // 图标颜色
|
||||||
|
|
||||||
private int strokeWidth = 2;// 边框宽度
|
private int strokeWidth = 2;// 边框宽度
|
||||||
|
|
||||||
public Style(String fill, String stroke, String icon) {
|
public Style(String fill, String stroke, String icon) {
|
||||||
@ -92,32 +102,34 @@ public class NodeUiConfig {
|
|||||||
@Data
|
@Data
|
||||||
public static class Ports {
|
public static class Ports {
|
||||||
private Map<String, PortGroup> groups;
|
private Map<String, PortGroup> groups;
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 连接点分组配置
|
* 获取端口类型列表
|
||||||
|
* @return 端口类型列表("in"/"out")
|
||||||
*/
|
*/
|
||||||
|
public List<String> getTypes() {
|
||||||
|
if (groups == null) {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
return new ArrayList<>(groups.keySet());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public static class PortGroup {
|
public static class PortGroup {
|
||||||
private String position; // 位置:left, right, top, bottom
|
private String position;
|
||||||
private PortAttrs attrs; // 连接点属性
|
private PortAttrs attrs;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 连接点属性配置
|
|
||||||
*/
|
|
||||||
@Data
|
@Data
|
||||||
public static class PortAttrs {
|
public static class PortAttrs {
|
||||||
private PortCircle circle; // 圆形连接点
|
private PortCircle circle;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 圆形连接点配置
|
|
||||||
*/
|
|
||||||
@Data
|
@Data
|
||||||
public static class PortCircle {
|
public static class PortCircle {
|
||||||
private int r; // 半径
|
private int r;
|
||||||
private String fill; // 填充颜色
|
private String fill;
|
||||||
private String stroke; // 边框颜色
|
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
|
@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.fasterxml.jackson.databind.JsonNode;
|
||||||
import com.qqchen.deploy.backend.framework.annotation.LogicDelete;
|
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.enums.WorkflowStatusEnums;
|
||||||
import com.qqchen.deploy.backend.workflow.hibernate.WorkflowGraphType;
|
import com.qqchen.deploy.backend.workflow.hibernate.WorkflowGraphType;
|
||||||
import com.qqchen.deploy.backend.framework.domain.Entity;
|
import com.qqchen.deploy.backend.framework.domain.Entity;
|
||||||
@ -54,7 +54,7 @@ public class WorkflowDefinition extends Entity<Long> {
|
|||||||
*/
|
*/
|
||||||
@Type(WorkflowGraphType.class)
|
@Type(WorkflowGraphType.class)
|
||||||
@Column(name = "graph", columnDefinition = "json")
|
@Column(name = "graph", columnDefinition = "json")
|
||||||
private WorkflowGraph graph;
|
private WorkflowDefinitionGraph graph;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 表单配置
|
* 表单配置
|
||||||
|
|||||||
@ -1,10 +1,11 @@
|
|||||||
package com.qqchen.deploy.backend.workflow.enums;
|
package com.qqchen.deploy.backend.workflow.enums;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonValue;
|
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 lombok.Getter;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 工作流节点类型枚举
|
* 工作流节点类型枚举
|
||||||
@ -20,11 +21,27 @@ public enum NodeTypeEnums {
|
|||||||
* - 只能有出边,不能有入边
|
* - 只能有出边,不能有入边
|
||||||
* - 用于触发工作流的执行
|
* - 用于触发工作流的执行
|
||||||
*/
|
*/
|
||||||
START_EVENT("START_EVENT", "开始节点", new NodeUiConfig()
|
START_EVENT(
|
||||||
|
"START_EVENT", // 节点类型编码
|
||||||
|
"开始节点", // 节点显示名称
|
||||||
|
"工作流的起点", // 节点简要描述
|
||||||
|
"标记流程的开始位置,可以定义流程启动条件和初始化流程变量", // 节点详细描述
|
||||||
|
Arrays.asList( // 节点功能列表
|
||||||
|
"标记流程的开始位置",
|
||||||
|
"定义流程启动条件",
|
||||||
|
"初始化流程变量"
|
||||||
|
),
|
||||||
|
Arrays.asList( // 使用场景列表
|
||||||
|
"用户手动启动流程",
|
||||||
|
"定时触发流程",
|
||||||
|
"外部系统调用启动"
|
||||||
|
),
|
||||||
|
new WorkflowNodeGraph() // UI配置
|
||||||
.setShape("circle")
|
.setShape("circle")
|
||||||
.setSize(40, 40)
|
.setSize(40, 40)
|
||||||
.setStyle("#e8f7ff", "#1890ff", "play-circle")
|
.setStyle("#e8f7ff", "#1890ff", "play-circle")
|
||||||
.setPorts(Arrays.asList("out"))),
|
.configPorts(Arrays.asList("out"))
|
||||||
|
),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 结束节点
|
* 结束节点
|
||||||
@ -33,11 +50,27 @@ public enum NodeTypeEnums {
|
|||||||
* - 只能有入边,不能有出边
|
* - 只能有入边,不能有出边
|
||||||
* - 标志着工作流的结束
|
* - 标志着工作流的结束
|
||||||
*/
|
*/
|
||||||
END_EVENT("END_EVENT", "结束节点", new NodeUiConfig()
|
END_EVENT(
|
||||||
|
"END_EVENT",
|
||||||
|
"结束节点",
|
||||||
|
"工作流的终点",
|
||||||
|
"标记流程的结束位置,可以定义流程结束时的清理操作和设置返回值",
|
||||||
|
Arrays.asList(
|
||||||
|
"标记流程的结束位置",
|
||||||
|
"定义结束时清理操作",
|
||||||
|
"设置流程结果和返回值"
|
||||||
|
),
|
||||||
|
Arrays.asList(
|
||||||
|
"流程正常结束",
|
||||||
|
"流程异常终止",
|
||||||
|
"需要返回处理结果"
|
||||||
|
),
|
||||||
|
new WorkflowNodeGraph()
|
||||||
.setShape("circle")
|
.setShape("circle")
|
||||||
.setSize(40, 40)
|
.setSize(40, 40)
|
||||||
.setStyle("#fff1f0", "#ff4d4f", "stop")
|
.setStyle("#fff1f0", "#ff4d4f", "stop")
|
||||||
.setPorts(Arrays.asList("in"))),
|
.configPorts(Arrays.asList("in"))
|
||||||
|
),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 用户任务节点
|
* 用户任务节点
|
||||||
@ -47,11 +80,29 @@ public enum NodeTypeEnums {
|
|||||||
* - 可以分配给特定用户或角色
|
* - 可以分配给特定用户或角色
|
||||||
* - 支持审批、填写表单等操作
|
* - 支持审批、填写表单等操作
|
||||||
*/
|
*/
|
||||||
USER_TASK("USER_TASK", "用户任务", new NodeUiConfig()
|
USER_TASK(
|
||||||
|
"USER_TASK",
|
||||||
|
"用户任务",
|
||||||
|
"人工处理任务",
|
||||||
|
"需要人工处理的任务节点,支持任务分配、表单填写、处理期限等功能",
|
||||||
|
Arrays.asList(
|
||||||
|
"分配任务给指定用户或角色",
|
||||||
|
"支持任务表单的填写",
|
||||||
|
"设置处理期限和提醒",
|
||||||
|
"支持任务的转办、委托、退回"
|
||||||
|
),
|
||||||
|
Arrays.asList(
|
||||||
|
"审批流程",
|
||||||
|
"表单填写",
|
||||||
|
"人工审核",
|
||||||
|
"数据确认"
|
||||||
|
),
|
||||||
|
new WorkflowNodeGraph()
|
||||||
.setShape("rectangle")
|
.setShape("rectangle")
|
||||||
.setSize(120, 60)
|
.setSize(120, 60)
|
||||||
.setStyle("#ffffff", "#1890ff", "user")
|
.setStyle("#ffffff", "#1890ff", "user")
|
||||||
.setPorts(Arrays.asList("in", "out"))),
|
.configPorts(Arrays.asList("in", "out"))
|
||||||
|
),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 服务任务节点
|
* 服务任务节点
|
||||||
@ -61,11 +112,29 @@ public enum NodeTypeEnums {
|
|||||||
* - 可以调用外部服务或系统API
|
* - 可以调用外部服务或系统API
|
||||||
* - 支持异步执行
|
* - 支持异步执行
|
||||||
*/
|
*/
|
||||||
SERVICE_TASK("SERVICE_TASK", "服务任务", new NodeUiConfig()
|
SERVICE_TASK(
|
||||||
|
"SERVICE_TASK",
|
||||||
|
"服务任务",
|
||||||
|
"系统服务调用",
|
||||||
|
"自动执行的系统服务任务,支持同步/异步调用外部服务和系统API",
|
||||||
|
Arrays.asList(
|
||||||
|
"调用系统服务或外部接口",
|
||||||
|
"执行自动化操作",
|
||||||
|
"支持异步执行和结果回调",
|
||||||
|
"数据转换和处理"
|
||||||
|
),
|
||||||
|
Arrays.asList(
|
||||||
|
"调用外部系统API",
|
||||||
|
"发送通知消息",
|
||||||
|
"数据同步处理",
|
||||||
|
"自动化操作"
|
||||||
|
),
|
||||||
|
new WorkflowNodeGraph()
|
||||||
.setShape("rectangle")
|
.setShape("rectangle")
|
||||||
.setSize(120, 60)
|
.setSize(120, 60)
|
||||||
.setStyle("#ffffff", "#1890ff", "api")
|
.setStyle("#ffffff", "#1890ff", "api")
|
||||||
.setPorts(Arrays.asList("in", "out"))),
|
.configPorts(Arrays.asList("in", "out"))
|
||||||
|
),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 脚本任务节点
|
* 脚本任务节点
|
||||||
@ -75,11 +144,29 @@ public enum NodeTypeEnums {
|
|||||||
* - 可以执行自定义业务逻辑
|
* - 可以执行自定义业务逻辑
|
||||||
* - 适合复杂的数据处理和计算
|
* - 适合复杂的数据处理和计算
|
||||||
*/
|
*/
|
||||||
SCRIPT_TASK("SCRIPT_TASK", "脚本任务", new NodeUiConfig()
|
SCRIPT_TASK(
|
||||||
|
"SCRIPT_TASK",
|
||||||
|
"脚本任务",
|
||||||
|
"脚本执行任务",
|
||||||
|
"执行自定义脚本的任务节点,支持多种脚本语言和复杂的业务逻辑",
|
||||||
|
Arrays.asList(
|
||||||
|
"执行自定义脚本代码",
|
||||||
|
"支持多种脚本语言",
|
||||||
|
"访问流程变量",
|
||||||
|
"支持复杂的业务逻辑"
|
||||||
|
),
|
||||||
|
Arrays.asList(
|
||||||
|
"数据处理和转换",
|
||||||
|
"条件判断",
|
||||||
|
"自定义业务规则",
|
||||||
|
"系统集成"
|
||||||
|
),
|
||||||
|
new WorkflowNodeGraph()
|
||||||
.setShape("rectangle")
|
.setShape("rectangle")
|
||||||
.setSize(120, 60)
|
.setSize(120, 60)
|
||||||
.setStyle("#ffffff", "#1890ff", "code")
|
.setStyle("#ffffff", "#1890ff", "code")
|
||||||
.setPorts(Arrays.asList("in", "out"))),
|
.configPorts(Arrays.asList("in", "out"))
|
||||||
|
),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 排他网关
|
* 排他网关
|
||||||
@ -89,11 +176,27 @@ public enum NodeTypeEnums {
|
|||||||
* - 需要设置分支条件
|
* - 需要设置分支条件
|
||||||
* - 适合互斥的业务场景
|
* - 适合互斥的业务场景
|
||||||
*/
|
*/
|
||||||
EXCLUSIVE_GATEWAY("EXCLUSIVE_GATEWAY", "排他网关", new NodeUiConfig()
|
EXCLUSIVE_GATEWAY(
|
||||||
|
"EXCLUSIVE_GATEWAY",
|
||||||
|
"排他网关",
|
||||||
|
"条件分支控制",
|
||||||
|
"基于条件的分支控制,只会选择一个分支执行",
|
||||||
|
Arrays.asList(
|
||||||
|
"根据条件选择一个分支执行",
|
||||||
|
"支持复杂的条件表达式",
|
||||||
|
"可以设置默认分支"
|
||||||
|
),
|
||||||
|
Arrays.asList(
|
||||||
|
"条件判断",
|
||||||
|
"分支选择",
|
||||||
|
"业务规则路由"
|
||||||
|
),
|
||||||
|
new WorkflowNodeGraph()
|
||||||
.setShape("diamond")
|
.setShape("diamond")
|
||||||
.setSize(50, 50)
|
.setSize(50, 50)
|
||||||
.setStyle("#fff7e6", "#faad14", "fork")
|
.setStyle("#fff7e6", "#faad14", "fork")
|
||||||
.setPorts(Arrays.asList("in", "out"))),
|
.configPorts(Arrays.asList("in", "out"))
|
||||||
|
),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 并行网关
|
* 并行网关
|
||||||
@ -103,11 +206,27 @@ public enum NodeTypeEnums {
|
|||||||
* - 等待所有分支完成才继续
|
* - 等待所有分支完成才继续
|
||||||
* - 适合并行处理的业务场景
|
* - 适合并行处理的业务场景
|
||||||
*/
|
*/
|
||||||
PARALLEL_GATEWAY("PARALLEL_GATEWAY", "并行网关", new NodeUiConfig()
|
PARALLEL_GATEWAY(
|
||||||
|
"PARALLEL_GATEWAY",
|
||||||
|
"并行网关",
|
||||||
|
"并行分支控制",
|
||||||
|
"将流程分成多个并行分支同时执行,等待所有分支完成后合并",
|
||||||
|
Arrays.asList(
|
||||||
|
"将流程分成多个并行分支",
|
||||||
|
"等待所有分支完成后合并",
|
||||||
|
"支持复杂的并行处理"
|
||||||
|
),
|
||||||
|
Arrays.asList(
|
||||||
|
"并行审批",
|
||||||
|
"多任务同时处理",
|
||||||
|
"并行数据处理"
|
||||||
|
),
|
||||||
|
new WorkflowNodeGraph()
|
||||||
.setShape("diamond")
|
.setShape("diamond")
|
||||||
.setSize(50, 50)
|
.setSize(50, 50)
|
||||||
.setStyle("#fff7e6", "#faad14", "branches")
|
.setStyle("#fff7e6", "#faad14", "branches")
|
||||||
.setPorts(Arrays.asList("in", "out"))),
|
.configPorts(Arrays.asList("in", "out"))
|
||||||
|
),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 子流程节点
|
* 子流程节点
|
||||||
@ -117,11 +236,29 @@ public enum NodeTypeEnums {
|
|||||||
* - 支持流程的模块化和复用
|
* - 支持流程的模块化和复用
|
||||||
* - 可以独立部署和版本控制
|
* - 可以独立部署和版本控制
|
||||||
*/
|
*/
|
||||||
SUBPROCESS("SUB_PROCESS", "子流程", new NodeUiConfig()
|
SUBPROCESS(
|
||||||
|
"SUB_PROCESS",
|
||||||
|
"子流程",
|
||||||
|
"嵌入式子流程",
|
||||||
|
"在当前流程中嵌入子流程,支持流程的模块化和复用",
|
||||||
|
Arrays.asList(
|
||||||
|
"在当前流程中嵌入子流程",
|
||||||
|
"重用流程片段",
|
||||||
|
"支持事务处理",
|
||||||
|
"独立的变量范围"
|
||||||
|
),
|
||||||
|
Arrays.asList(
|
||||||
|
"流程复用",
|
||||||
|
"模块化处理",
|
||||||
|
"事务管理",
|
||||||
|
"错误处理"
|
||||||
|
),
|
||||||
|
new WorkflowNodeGraph()
|
||||||
.setShape("rectangle")
|
.setShape("rectangle")
|
||||||
.setSize(120, 60)
|
.setSize(120, 60)
|
||||||
.setStyle("#ffffff", "#1890ff", "apartment")
|
.setStyle("#ffffff", "#1890ff", "apartment")
|
||||||
.setPorts(Arrays.asList("in", "out"))),
|
.configPorts(Arrays.asList("in", "out"))
|
||||||
|
),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 调用活动节点
|
* 调用活动节点
|
||||||
@ -131,27 +268,66 @@ public enum NodeTypeEnums {
|
|||||||
* - 支持流程的复用
|
* - 支持流程的复用
|
||||||
* - 可以传递参数和接收返回值
|
* - 可以传递参数和接收返回值
|
||||||
*/
|
*/
|
||||||
CALL_ACTIVITY("CALL_ACTIVITY", "调用活动", new NodeUiConfig()
|
CALL_ACTIVITY(
|
||||||
|
"CALL_ACTIVITY",
|
||||||
|
"调用活动",
|
||||||
|
"外部流程调用",
|
||||||
|
"调用外部定义的流程,支持跨系统流程调用和参数传递",
|
||||||
|
Arrays.asList(
|
||||||
|
"调用外部定义的流程",
|
||||||
|
"支持跨系统流程调用",
|
||||||
|
"传递和接收参数",
|
||||||
|
"支持异步调用"
|
||||||
|
),
|
||||||
|
Arrays.asList(
|
||||||
|
"跨系统流程集成",
|
||||||
|
"公共流程复用",
|
||||||
|
"分布式流程处理",
|
||||||
|
"大型流程解耦"
|
||||||
|
),
|
||||||
|
new WorkflowNodeGraph()
|
||||||
.setShape("rectangle")
|
.setShape("rectangle")
|
||||||
.setSize(120, 60)
|
.setSize(120, 60)
|
||||||
.setStyle("#ffffff", "#1890ff", "api")
|
.setStyle("#ffffff", "#1890ff", "api")
|
||||||
.setPorts(Arrays.asList("in", "out")));
|
.configPorts(Arrays.asList("in", "out"))
|
||||||
|
);
|
||||||
|
|
||||||
@JsonValue
|
@JsonValue
|
||||||
private final String code;
|
private final String code; // 节点类型编码
|
||||||
private final String name;
|
|
||||||
private final NodeUiConfig uiConfig;
|
|
||||||
|
|
||||||
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.code = code;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
this.shortDesc = shortDesc;
|
||||||
|
this.description = description;
|
||||||
|
this.features = features;
|
||||||
|
this.scenarios = scenarios;
|
||||||
this.uiConfig = uiConfig;
|
this.uiConfig = uiConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据值查找对应的枚举
|
* 根据编码查找对应的枚举
|
||||||
*
|
*
|
||||||
* @param code 枚举值
|
* @param code 节点类型编码
|
||||||
* @return 对应的枚举实例
|
* @return 对应的枚举实例
|
||||||
* @throws IllegalArgumentException 当找不到对应的枚举值时抛出
|
* @throws IllegalArgumentException 当找不到对应的枚举值时抛出
|
||||||
*/
|
*/
|
||||||
@ -161,6 +337,6 @@ public enum NodeTypeEnums {
|
|||||||
return type;
|
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.core.JsonProcessingException;
|
||||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
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.HibernateException;
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
import org.hibernate.usertype.UserType;
|
import org.hibernate.usertype.UserType;
|
||||||
@ -17,7 +17,7 @@ import java.sql.Types;
|
|||||||
/**
|
/**
|
||||||
* 自定义 Hibernate 类型,用于处理 WorkflowGraph 的序列化和反序列化
|
* 自定义 Hibernate 类型,用于处理 WorkflowGraph 的序列化和反序列化
|
||||||
*/
|
*/
|
||||||
public class WorkflowGraphType implements UserType<WorkflowGraph> {
|
public class WorkflowGraphType implements UserType<WorkflowDefinitionGraph> {
|
||||||
private final ObjectMapper objectMapper;
|
private final ObjectMapper objectMapper;
|
||||||
|
|
||||||
public WorkflowGraphType() {
|
public WorkflowGraphType() {
|
||||||
@ -32,12 +32,12 @@ public class WorkflowGraphType implements UserType<WorkflowGraph> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Class<WorkflowGraph> returnedClass() {
|
public Class<WorkflowDefinitionGraph> returnedClass() {
|
||||||
return WorkflowGraph.class;
|
return WorkflowDefinitionGraph.class;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(WorkflowGraph x, WorkflowGraph y) {
|
public boolean equals(WorkflowDefinitionGraph x, WorkflowDefinitionGraph y) {
|
||||||
if (x == y) {
|
if (x == y) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -48,26 +48,26 @@ public class WorkflowGraphType implements UserType<WorkflowGraph> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode(WorkflowGraph x) {
|
public int hashCode(WorkflowDefinitionGraph x) {
|
||||||
return x == null ? 0 : x.hashCode();
|
return x == null ? 0 : x.hashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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 {
|
throws SQLException {
|
||||||
String value = rs.getString(position);
|
String value = rs.getString(position);
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
return objectMapper.readValue(value, WorkflowGraph.class);
|
return objectMapper.readValue(value, WorkflowDefinitionGraph.class);
|
||||||
} catch (JsonProcessingException e) {
|
} catch (JsonProcessingException e) {
|
||||||
throw new HibernateException("Failed to convert String to WorkflowGraph: " + value, e);
|
throw new HibernateException("Failed to convert String to WorkflowGraph: " + value, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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 {
|
throws SQLException {
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
st.setNull(index, Types.VARCHAR);
|
st.setNull(index, Types.VARCHAR);
|
||||||
@ -81,12 +81,12 @@ public class WorkflowGraphType implements UserType<WorkflowGraph> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WorkflowGraph deepCopy(WorkflowGraph value) {
|
public WorkflowDefinitionGraph deepCopy(WorkflowDefinitionGraph value) {
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
return objectMapper.readValue(objectMapper.writeValueAsString(value), WorkflowGraph.class);
|
return objectMapper.readValue(objectMapper.writeValueAsString(value), WorkflowDefinitionGraph.class);
|
||||||
} catch (JsonProcessingException e) {
|
} catch (JsonProcessingException e) {
|
||||||
throw new HibernateException("Failed to deep copy WorkflowGraph", e);
|
throw new HibernateException("Failed to deep copy WorkflowGraph", e);
|
||||||
}
|
}
|
||||||
@ -98,7 +98,7 @@ public class WorkflowGraphType implements UserType<WorkflowGraph> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Serializable disassemble(WorkflowGraph value) {
|
public Serializable disassemble(WorkflowDefinitionGraph value) {
|
||||||
try {
|
try {
|
||||||
return value == null ? null : objectMapper.writeValueAsString(value);
|
return value == null ? null : objectMapper.writeValueAsString(value);
|
||||||
} catch (JsonProcessingException e) {
|
} catch (JsonProcessingException e) {
|
||||||
@ -107,16 +107,16 @@ public class WorkflowGraphType implements UserType<WorkflowGraph> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WorkflowGraph assemble(Serializable cached, Object owner) {
|
public WorkflowDefinitionGraph assemble(Serializable cached, Object owner) {
|
||||||
try {
|
try {
|
||||||
return cached == null ? null : objectMapper.readValue(cached.toString(), WorkflowGraph.class);
|
return cached == null ? null : objectMapper.readValue(cached.toString(), WorkflowDefinitionGraph.class);
|
||||||
} catch (JsonProcessingException e) {
|
} catch (JsonProcessingException e) {
|
||||||
throw new HibernateException("Failed to assemble WorkflowGraph", e);
|
throw new HibernateException("Failed to assemble WorkflowGraph", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WorkflowGraph replace(WorkflowGraph detached, WorkflowGraph managed, Object owner) {
|
public WorkflowDefinitionGraph replace(WorkflowDefinitionGraph detached, WorkflowDefinitionGraph managed, Object owner) {
|
||||||
return deepCopy(detached);
|
return deepCopy(detached);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -70,7 +70,7 @@ public class WorkflowDefinitionServiceImpl extends BaseServiceImpl<WorkflowDefin
|
|||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public WorkflowDefinitionDTO saveWorkflowDesign(WorkflowDefinitionDTO dto) throws Exception {
|
public WorkflowDefinitionDTO saveWorkflowDesign(WorkflowDefinitionDTO dto) throws Exception {
|
||||||
// 转换图形JSON为BPMN XML
|
// 转换图形JSON为BPMN XML
|
||||||
String bpmnXml = bpmnConverter.convertToXml(dto.getGraph(), dto.getKey());
|
String bpmnXml = bpmnConverter.convertToXml(null, dto.getKey());
|
||||||
dto.setFlowVersion(1);
|
dto.setFlowVersion(1);
|
||||||
dto.setBpmnXml(bpmnXml);
|
dto.setBpmnXml(bpmnXml);
|
||||||
// // 创建工作流定义
|
// // 创建工作流定义
|
||||||
|
|||||||
@ -7,8 +7,6 @@ import org.flowable.bpmn.model.Process;
|
|||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BPMN 模型转换工具
|
* BPMN 模型转换工具
|
||||||
@ -26,7 +24,7 @@ public class BpmnConverter {
|
|||||||
* @param processKey 流程标识
|
* @param processKey 流程标识
|
||||||
* @return BPMN XML字符串
|
* @return BPMN XML字符串
|
||||||
*/
|
*/
|
||||||
public String convertToXml(WorkflowGraph graph, String processKey) {
|
public String convertToXml(WorkflowDefinitionGraph graph, String processKey) {
|
||||||
BpmnModel bpmnModel = convertToBpmnModel(graph, processKey);
|
BpmnModel bpmnModel = convertToBpmnModel(graph, processKey);
|
||||||
byte[] xmlBytes = bpmnXmlConverter.convertToXML(bpmnModel);
|
byte[] xmlBytes = bpmnXmlConverter.convertToXML(bpmnModel);
|
||||||
return new String(xmlBytes, StandardCharsets.UTF_8);
|
return new String(xmlBytes, StandardCharsets.UTF_8);
|
||||||
@ -38,33 +36,33 @@ public class BpmnConverter {
|
|||||||
* @param processKey 流程标识
|
* @param processKey 流程标识
|
||||||
* @return BPMN模型
|
* @return BPMN模型
|
||||||
*/
|
*/
|
||||||
public BpmnModel convertToBpmnModel(WorkflowGraph graph, String processKey) {
|
public BpmnModel convertToBpmnModel(WorkflowDefinitionGraph graph, String processKey) {
|
||||||
BpmnModel bpmnModel = new BpmnModel();
|
BpmnModel bpmnModel = new BpmnModel();
|
||||||
Process process = new Process();
|
Process process = new Process();
|
||||||
|
|
||||||
// 设置流程属性
|
// 设置流程属性
|
||||||
process.setId(processKey);
|
process.setId(processKey);
|
||||||
if (graph.getProperties() != null) {
|
// if (graph.getProperties() != null) {
|
||||||
Map<String, Object> properties = graph.getProperties();
|
// Map<String, Object> properties = graph.getProperties();
|
||||||
process.setName(properties.get("name") != null ? properties.get("name").toString() : null);
|
// process.setName(properties.get("name") != null ? properties.get("name").toString() : null);
|
||||||
process.setDocumentation(properties.get("description") != null ? properties.get("description").toString() : null);
|
// process.setDocumentation(properties.get("description") != null ? properties.get("description").toString() : null);
|
||||||
}
|
// }
|
||||||
|
|
||||||
// 转换节点
|
// 转换节点
|
||||||
for (WorkflowNode node : graph.getNodes()) {
|
// for (WorkflowDefinitionNode node : graph.getNodes()) {
|
||||||
FlowElement element = convertNode(node);
|
// FlowElement element = convertNode(node);
|
||||||
if (element != null) {
|
// if (element != null) {
|
||||||
process.addFlowElement(element);
|
// process.addFlowElement(element);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
// 转换边
|
// // 转换边
|
||||||
for (WorkflowEdge edge : graph.getEdges()) {
|
// for (WorkflowDefinitionEdge edge : graph.getEdges()) {
|
||||||
SequenceFlow flow = convertEdge(edge);
|
// SequenceFlow flow = convertEdge(edge);
|
||||||
if (flow != null) {
|
// if (flow != null) {
|
||||||
process.addFlowElement(flow);
|
// process.addFlowElement(flow);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
bpmnModel.addProcess(process);
|
bpmnModel.addProcess(process);
|
||||||
return bpmnModel;
|
return bpmnModel;
|
||||||
@ -75,15 +73,15 @@ public class BpmnConverter {
|
|||||||
* @param graph 工作流图数据
|
* @param graph 工作流图数据
|
||||||
* @return BPMN模型
|
* @return BPMN模型
|
||||||
*/
|
*/
|
||||||
public BpmnModel convertToBpmnModel(WorkflowGraph graph) {
|
public BpmnModel convertToBpmnModel(WorkflowDefinitionGraph graph) {
|
||||||
String processKey = null;
|
String processKey = null;
|
||||||
if (graph.getProperties() != null) {
|
// if (graph.getProperties() != null) {
|
||||||
Object key = graph.getProperties().get("key");
|
// Object key = graph.getProperties().get("key");
|
||||||
processKey = key != null ? key.toString() : null;
|
// processKey = key != null ? key.toString() : null;
|
||||||
}
|
// }
|
||||||
if (processKey == null) {
|
// if (processKey == null) {
|
||||||
processKey = "process_" + System.currentTimeMillis();
|
// processKey = "process_" + System.currentTimeMillis();
|
||||||
}
|
// }
|
||||||
return convertToBpmnModel(graph, processKey);
|
return convertToBpmnModel(graph, processKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,7 +90,7 @@ public class BpmnConverter {
|
|||||||
* @param node 工作流节点
|
* @param node 工作流节点
|
||||||
* @return 流程元素
|
* @return 流程元素
|
||||||
*/
|
*/
|
||||||
private FlowElement convertNode(WorkflowNode node) {
|
private FlowElement convertNode(WorkflowDefinitionNode node) {
|
||||||
if (node.getType() == null) {
|
if (node.getType() == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -126,7 +124,7 @@ public class BpmnConverter {
|
|||||||
* @param node 节点数据
|
* @param node 节点数据
|
||||||
* @return 开始事件
|
* @return 开始事件
|
||||||
*/
|
*/
|
||||||
private StartEvent createStartEvent(WorkflowNode node) {
|
private StartEvent createStartEvent(WorkflowDefinitionNode node) {
|
||||||
StartEvent startEvent = new StartEvent();
|
StartEvent startEvent = new StartEvent();
|
||||||
startEvent.setId(node.getId());
|
startEvent.setId(node.getId());
|
||||||
startEvent.setName(node.getName());
|
startEvent.setName(node.getName());
|
||||||
@ -138,7 +136,7 @@ public class BpmnConverter {
|
|||||||
* @param node 节点数据
|
* @param node 节点数据
|
||||||
* @return 结束事件
|
* @return 结束事件
|
||||||
*/
|
*/
|
||||||
private EndEvent createEndEvent(WorkflowNode node) {
|
private EndEvent createEndEvent(WorkflowDefinitionNode node) {
|
||||||
EndEvent endEvent = new EndEvent();
|
EndEvent endEvent = new EndEvent();
|
||||||
endEvent.setId(node.getId());
|
endEvent.setId(node.getId());
|
||||||
endEvent.setName(node.getName());
|
endEvent.setName(node.getName());
|
||||||
@ -150,13 +148,13 @@ public class BpmnConverter {
|
|||||||
* @param node 节点数据
|
* @param node 节点数据
|
||||||
* @return 服务任务
|
* @return 服务任务
|
||||||
*/
|
*/
|
||||||
private ServiceTask createServiceTask(WorkflowNode node) {
|
private ServiceTask createServiceTask(WorkflowDefinitionNode node) {
|
||||||
ServiceTask serviceTask = new ServiceTask();
|
ServiceTask serviceTask = new ServiceTask();
|
||||||
serviceTask.setId(node.getId());
|
serviceTask.setId(node.getId());
|
||||||
serviceTask.setName(node.getName());
|
serviceTask.setName(node.getName());
|
||||||
|
|
||||||
if (node.getConfig() != null) {
|
if (node.getConfig() != null) {
|
||||||
NodeConfig config = node.getConfig();
|
// WorkflowDefinitionEdgeNodeConfig config = node.getConfig();
|
||||||
// serviceTask.setImplementation(config.getImplementation());
|
// serviceTask.setImplementation(config.getImplementation());
|
||||||
// if (config.getFields() != null) {
|
// if (config.getFields() != null) {
|
||||||
// config.getFields().forEach((key, value) -> {
|
// config.getFields().forEach((key, value) -> {
|
||||||
@ -176,7 +174,7 @@ public class BpmnConverter {
|
|||||||
* @param node 节点数据
|
* @param node 节点数据
|
||||||
* @return 用户任务
|
* @return 用户任务
|
||||||
*/
|
*/
|
||||||
private UserTask createUserTask(WorkflowNode node) {
|
private UserTask createUserTask(WorkflowDefinitionNode node) {
|
||||||
UserTask userTask = new UserTask();
|
UserTask userTask = new UserTask();
|
||||||
userTask.setId(node.getId());
|
userTask.setId(node.getId());
|
||||||
userTask.setName(node.getName());
|
userTask.setName(node.getName());
|
||||||
@ -200,7 +198,7 @@ public class BpmnConverter {
|
|||||||
* @param node 节点数据
|
* @param node 节点数据
|
||||||
* @return 脚本任务
|
* @return 脚本任务
|
||||||
*/
|
*/
|
||||||
private ScriptTask createScriptTask(WorkflowNode node) {
|
private ScriptTask createScriptTask(WorkflowDefinitionNode node) {
|
||||||
ScriptTask scriptTask = new ScriptTask();
|
ScriptTask scriptTask = new ScriptTask();
|
||||||
scriptTask.setId(node.getId());
|
scriptTask.setId(node.getId());
|
||||||
scriptTask.setName(node.getName());
|
scriptTask.setName(node.getName());
|
||||||
@ -221,7 +219,7 @@ public class BpmnConverter {
|
|||||||
* @param node 节点数据
|
* @param node 节点数据
|
||||||
* @return 排他网关
|
* @return 排他网关
|
||||||
*/
|
*/
|
||||||
private ExclusiveGateway createExclusiveGateway(WorkflowNode node) {
|
private ExclusiveGateway createExclusiveGateway(WorkflowDefinitionNode node) {
|
||||||
ExclusiveGateway gateway = new ExclusiveGateway();
|
ExclusiveGateway gateway = new ExclusiveGateway();
|
||||||
gateway.setId(node.getId());
|
gateway.setId(node.getId());
|
||||||
gateway.setName(node.getName());
|
gateway.setName(node.getName());
|
||||||
@ -233,7 +231,7 @@ public class BpmnConverter {
|
|||||||
* @param node 节点数据
|
* @param node 节点数据
|
||||||
* @return 并行网关
|
* @return 并行网关
|
||||||
*/
|
*/
|
||||||
private ParallelGateway createParallelGateway(WorkflowNode node) {
|
private ParallelGateway createParallelGateway(WorkflowDefinitionNode node) {
|
||||||
ParallelGateway gateway = new ParallelGateway();
|
ParallelGateway gateway = new ParallelGateway();
|
||||||
gateway.setId(node.getId());
|
gateway.setId(node.getId());
|
||||||
gateway.setName(node.getName());
|
gateway.setName(node.getName());
|
||||||
@ -245,7 +243,7 @@ public class BpmnConverter {
|
|||||||
* @param node 节点数据
|
* @param node 节点数据
|
||||||
* @return 子流程
|
* @return 子流程
|
||||||
*/
|
*/
|
||||||
private SubProcess createSubProcess(WorkflowNode node) {
|
private SubProcess createSubProcess(WorkflowDefinitionNode node) {
|
||||||
SubProcess subProcess = new SubProcess();
|
SubProcess subProcess = new SubProcess();
|
||||||
subProcess.setId(node.getId());
|
subProcess.setId(node.getId());
|
||||||
subProcess.setName(node.getName());
|
subProcess.setName(node.getName());
|
||||||
@ -257,13 +255,13 @@ public class BpmnConverter {
|
|||||||
* @param node 节点数据
|
* @param node 节点数据
|
||||||
* @return 调用活动
|
* @return 调用活动
|
||||||
*/
|
*/
|
||||||
private CallActivity createCallActivity(WorkflowNode node) {
|
private CallActivity createCallActivity(WorkflowDefinitionNode node) {
|
||||||
CallActivity callActivity = new CallActivity();
|
CallActivity callActivity = new CallActivity();
|
||||||
callActivity.setId(node.getId());
|
callActivity.setId(node.getId());
|
||||||
callActivity.setName(node.getName());
|
callActivity.setName(node.getName());
|
||||||
|
|
||||||
if (node.getConfig() != null) {
|
if (node.getConfig() != null) {
|
||||||
NodeConfig config = node.getConfig();
|
// WorkflowDefinitionEdgeNodeConfig config = node.getConfig();
|
||||||
// callActivity.setCalledElement(config.getImplementation());
|
// callActivity.setCalledElement(config.getImplementation());
|
||||||
// if (config.getFields() != null) {
|
// if (config.getFields() != null) {
|
||||||
// config.getFields().forEach((key, value) -> {
|
// config.getFields().forEach((key, value) -> {
|
||||||
@ -283,15 +281,15 @@ public class BpmnConverter {
|
|||||||
* @param edge 工作流边
|
* @param edge 工作流边
|
||||||
* @return 序列流
|
* @return 序列流
|
||||||
*/
|
*/
|
||||||
private SequenceFlow convertEdge(WorkflowEdge edge) {
|
private SequenceFlow convertEdge(WorkflowDefinitionEdge edge) {
|
||||||
SequenceFlow flow = new SequenceFlow();
|
SequenceFlow flow = new SequenceFlow();
|
||||||
flow.setId(edge.getId());
|
flow.setId(edge.getId());
|
||||||
flow.setName(edge.getName());
|
flow.setName(edge.getName());
|
||||||
flow.setSourceRef(edge.getSource());
|
// flow.setSourceRef(edge.getSource());
|
||||||
flow.setTargetRef(edge.getTarget());
|
// flow.setTargetRef(edge.getTarget());
|
||||||
|
|
||||||
if (edge.getConfig() != null) {
|
if (edge.getConfig() != null) {
|
||||||
EdgeConfig config = edge.getConfig();
|
WorkflowDefinitionEdgeConfig config = edge.getConfig();
|
||||||
if ("sequence".equals(config.getType())) {
|
if ("sequence".equals(config.getType())) {
|
||||||
if (config.getCondition() != null) {
|
if (config.getCondition() != null) {
|
||||||
((SequenceFlow) flow).setConditionExpression(config.getCondition());
|
((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.ArrayNode;
|
||||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||||
import com.qqchen.deploy.backend.workflow.annotation.SchemaProperty;
|
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.dto.nodeConfig.*;
|
||||||
import com.qqchen.deploy.backend.workflow.enums.NodeTypeEnums;
|
import com.qqchen.deploy.backend.workflow.enums.NodeTypeEnums;
|
||||||
|
|
||||||
@ -16,6 +17,7 @@ import java.util.Set;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Schema生成器
|
* Schema生成器
|
||||||
|
* 用于生成工作流节点的配置Schema和UI Schema
|
||||||
*/
|
*/
|
||||||
public class SchemaGenerator {
|
public class SchemaGenerator {
|
||||||
private static final ObjectMapper mapper = new ObjectMapper();
|
private static final ObjectMapper mapper = new ObjectMapper();
|
||||||
@ -72,15 +74,77 @@ public class SchemaGenerator {
|
|||||||
// 设置基本信息
|
// 设置基本信息
|
||||||
node.put("code", nodeType.getCode());
|
node.put("code", nodeType.getCode());
|
||||||
node.put("name", nodeType.getName());
|
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字段
|
// 生成配置schema并设置到configSchema字段
|
||||||
ObjectNode configSchema = generateConfigSchema(configClass);
|
ObjectNode configSchema = generateConfigSchema(configClass);
|
||||||
node.set("configSchema", configSchema);
|
node.set("configSchema", configSchema);
|
||||||
|
|
||||||
|
// 生成UI schema并设置到uiSchema字段
|
||||||
|
ObjectNode uiSchema = generateUiSchema(nodeType);
|
||||||
|
node.set("uiSchema", uiSchema);
|
||||||
|
|
||||||
return node;
|
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
|
* 根据配置类生成schema
|
||||||
*/
|
*/
|
||||||
@ -99,9 +163,12 @@ public class SchemaGenerator {
|
|||||||
processRemainingFields(properties, required, configClass);
|
processRemainingFields(properties, required, configClass);
|
||||||
|
|
||||||
schema.set("properties", properties);
|
schema.set("properties", properties);
|
||||||
|
|
||||||
|
// 如果有必填字段,添加到schema中
|
||||||
if (!required.isEmpty()) {
|
if (!required.isEmpty()) {
|
||||||
ArrayNode requiredArray = schema.putArray("required");
|
ArrayNode requiredArray = mapper.createArrayNode();
|
||||||
required.forEach(requiredArray::add);
|
required.forEach(requiredArray::add);
|
||||||
|
schema.set("required", requiredArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
return schema;
|
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 '节点名称',
|
name VARCHAR(100) NOT NULL COMMENT '节点名称',
|
||||||
description VARCHAR(500) COMMENT '节点描述',
|
description VARCHAR(500) COMMENT '节点描述',
|
||||||
category VARCHAR(50) NOT NULL COMMENT '节点分类',
|
category VARCHAR(50) NOT NULL COMMENT '节点分类',
|
||||||
flowable_config TEXT COMMENT 'Flowable引擎配置JSON',
|
|
||||||
graph_config TEXT NOT NULL COMMENT 'X6图形配置JSON',
|
graph_config TEXT NOT NULL COMMENT 'X6图形配置JSON',
|
||||||
order_num INT NOT NULL DEFAULT 0 COMMENT '排序号',
|
order_num INT NOT NULL DEFAULT 0 COMMENT '排序号',
|
||||||
enabled BOOLEAN NOT NULL DEFAULT TRUE 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
|
VALUES
|
||||||
-- 开始事件
|
(1, NOW(), 'START_EVENT', '开始节点', '工作流的起点', 'EVENT', '{
|
||||||
('startEvent', '开始事件', '流程的开始节点', '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": "工作流节点的详细描述"}
|
||||||
|
},
|
||||||
|
"required": ["code", "name"]
|
||||||
|
},
|
||||||
|
"uiSchema": {
|
||||||
"shape": "circle",
|
"shape": "circle",
|
||||||
"width": 40,
|
"size": {"width": 40, "height": 40},
|
||||||
"height": 40,
|
"style": {
|
||||||
|
"fill": "#e8f7ff",
|
||||||
|
"stroke": "#1890ff",
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"icon": "play-circle",
|
||||||
|
"iconColor": "#1890ff"
|
||||||
|
},
|
||||||
"ports": {
|
"ports": {
|
||||||
"groups": {
|
"groups": {
|
||||||
"top": {"position": "top", "attrs": {"circle": {"r": 4, "magnet": true}}},
|
"out": {
|
||||||
"right": {"position": "right", "attrs": {"circle": {"r": 4, "magnet": true}}},
|
"position": "right",
|
||||||
"bottom": {"position": "bottom", "attrs": {"circle": {"r": 4, "magnet": true}}},
|
|
||||||
"left": {"position": "left", "attrs": {"circle": {"r": 4, "magnet": true}}}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"attrs": {
|
"attrs": {
|
||||||
"body": {"fill": "#ffffff", "stroke": "#333333", "strokeWidth": 2},
|
"circle": {
|
||||||
"label": {"text": "开始", "fill": "#333333"}
|
"r": 4,
|
||||||
|
"fill": "#ffffff",
|
||||||
|
"stroke": "#1890ff"
|
||||||
}
|
}
|
||||||
}',
|
}
|
||||||
'{
|
}
|
||||||
"properties": [
|
}
|
||||||
{"name": "id", "label": "节点标识", "type": "string", "required": true},
|
}
|
||||||
{"name": "name", "label": "节点名称", "type": "string", "required": true}
|
}
|
||||||
]
|
}', 1),
|
||||||
}',
|
|
||||||
10, true, NOW(), 'system', NOW(), 'system', 1, false),
|
|
||||||
|
|
||||||
-- 结束事件
|
(2, NOW(), 'END_EVENT', '结束节点', '工作流的终点', 'EVENT', '{
|
||||||
('endEvent', '结束事件', '流程的结束节点', '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": "工作流节点的详细描述"}
|
||||||
|
},
|
||||||
|
"required": ["code", "name"]
|
||||||
|
},
|
||||||
|
"uiSchema": {
|
||||||
"shape": "circle",
|
"shape": "circle",
|
||||||
"width": 40,
|
"size": {"width": 40, "height": 40},
|
||||||
"height": 40,
|
"style": {
|
||||||
|
"fill": "#fff1f0",
|
||||||
|
"stroke": "#ff4d4f",
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"icon": "stop",
|
||||||
|
"iconColor": "#ff4d4f"
|
||||||
|
},
|
||||||
"ports": {
|
"ports": {
|
||||||
"groups": {
|
"groups": {
|
||||||
"top": {"position": "top", "attrs": {"circle": {"r": 4, "magnet": true}}},
|
"in": {
|
||||||
"right": {"position": "right", "attrs": {"circle": {"r": 4, "magnet": true}}},
|
"position": "left",
|
||||||
"bottom": {"position": "bottom", "attrs": {"circle": {"r": 4, "magnet": true}}},
|
|
||||||
"left": {"position": "left", "attrs": {"circle": {"r": 4, "magnet": true}}}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"attrs": {
|
"attrs": {
|
||||||
"body": {"fill": "#ffffff", "stroke": "#333333", "strokeWidth": 4},
|
"circle": {
|
||||||
"label": {"text": "结束", "fill": "#333333"}
|
"r": 4,
|
||||||
|
"fill": "#ffffff",
|
||||||
|
"stroke": "#1890ff"
|
||||||
}
|
}
|
||||||
}',
|
}
|
||||||
'{
|
}
|
||||||
"properties": [
|
}
|
||||||
{"name": "id", "label": "节点标识", "type": "string", "required": true},
|
}
|
||||||
{"name": "name", "label": "节点名称", "type": "string", "required": true}
|
}
|
||||||
]
|
}', 1);
|
||||||
}',
|
|
||||||
20, true, NOW(), 'system', NOW(), 'system', 1, false),
|
|
||||||
|
|
||||||
-- 任务节点
|
-- 任务节点
|
||||||
-- 用户任务
|
INSERT INTO workflow_node_definition (id, create_time, type, name, description, category, graph_config, enabled)
|
||||||
('userTask', '用户任务', '需要人工处理的任务节点', 'TASK',
|
VALUES
|
||||||
'{
|
(3, NOW(), 'USER_TASK', '用户任务', '人工处理任务', 'TASK', '{
|
||||||
"assignee": "$${assignee}",
|
"code": "USER_TASK",
|
||||||
"candidateUsers": "$${candidateUsers}",
|
"name": "用户任务",
|
||||||
"candidateGroups": "$${candidateGroups}"
|
"description": "人工处理任务",
|
||||||
}',
|
"details": {
|
||||||
'{
|
"description": "需要人工处理的任务节点,支持任务分配、表单填写、处理期限等功能",
|
||||||
"shape": "rect",
|
"features": ["分配任务给指定用户或角色", "支持任务表单的填写", "设置处理期限和提醒", "支持任务的转办、委托、退回"],
|
||||||
"width": 120,
|
"scenarios": ["审批流程", "表单填写", "人工审核", "数据确认"]
|
||||||
"height": 60,
|
},
|
||||||
|
"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": "user",
|
||||||
|
"iconColor": "#1890ff"
|
||||||
|
},
|
||||||
"ports": {
|
"ports": {
|
||||||
"groups": {
|
"groups": {
|
||||||
"top": {"position": "top", "attrs": {"circle": {"r": 4, "magnet": true}}},
|
"in": {
|
||||||
"right": {"position": "right", "attrs": {"circle": {"r": 4, "magnet": true}}},
|
"position": "left",
|
||||||
"bottom": {"position": "bottom", "attrs": {"circle": {"r": 4, "magnet": true}}},
|
"attrs": {
|
||||||
"left": {"position": "left", "attrs": {"circle": {"r": 4, "magnet": true}}}
|
"circle": {
|
||||||
|
"r": 4,
|
||||||
|
"fill": "#ffffff",
|
||||||
|
"stroke": "#1890ff"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"out": {
|
||||||
|
"position": "right",
|
||||||
"attrs": {
|
"attrs": {
|
||||||
"body": {"fill": "#ffffff", "stroke": "#333333", "strokeWidth": 2},
|
"circle": {
|
||||||
"label": {"text": "用户任务", "fill": "#333333"}
|
"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"},
|
}', 1),
|
||||||
{"name": "candidateUsers", "label": "候选用户", "type": "string"},
|
|
||||||
{"name": "candidateGroups", "label": "候选组", "type": "string"},
|
|
||||||
{"name": "dueDate", "label": "到期时间", "type": "date"}
|
|
||||||
]
|
|
||||||
}',
|
|
||||||
30, true, NOW(), 'system', NOW(), 'system', 1, false),
|
|
||||||
|
|
||||||
-- 服务任务
|
(4, NOW(), 'SERVICE_TASK', '服务任务', '系统服务调用', 'TASK', '{
|
||||||
('serviceTask', '服务任务', '自动执行的系统服务任务', 'TASK',
|
"code": "SERVICE_TASK",
|
||||||
'{
|
"name": "服务任务",
|
||||||
"class": "com.example.ServiceTaskDelegate"
|
"description": "系统服务调用",
|
||||||
}',
|
"details": {
|
||||||
'{
|
"description": "自动执行的系统服务任务,支持同步/异步调用外部服务和系统API",
|
||||||
"shape": "rect",
|
"features": ["调用系统服务或外部接口", "执行自动化操作", "支持异步执行和结果回调", "数据转换和处理"],
|
||||||
"width": 120,
|
"scenarios": ["调用外部系统API", "发送通知消息", "数据同步处理", "自动化操作"]
|
||||||
"height": 60,
|
},
|
||||||
|
"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": {
|
"ports": {
|
||||||
"groups": {
|
"groups": {
|
||||||
"top": {"position": "top", "attrs": {"circle": {"r": 4, "magnet": true}}},
|
"in": {
|
||||||
"right": {"position": "right", "attrs": {"circle": {"r": 4, "magnet": true}}},
|
"position": "left",
|
||||||
"bottom": {"position": "bottom", "attrs": {"circle": {"r": 4, "magnet": true}}},
|
"attrs": {
|
||||||
"left": {"position": "left", "attrs": {"circle": {"r": 4, "magnet": true}}}
|
"circle": {
|
||||||
|
"r": 4,
|
||||||
|
"fill": "#ffffff",
|
||||||
|
"stroke": "#1890ff"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"out": {
|
||||||
|
"position": "right",
|
||||||
"attrs": {
|
"attrs": {
|
||||||
"body": {"fill": "#ffffff", "stroke": "#333333", "strokeWidth": 2},
|
"circle": {
|
||||||
"label": {"text": "服务任务", "fill": "#333333"}
|
"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},
|
}', 1),
|
||||||
{"name": "async", "label": "异步执行", "type": "boolean"}
|
|
||||||
]
|
|
||||||
}',
|
|
||||||
40, true, NOW(), 'system', NOW(), 'system', 1, false),
|
|
||||||
|
|
||||||
-- Shell任务
|
(5, NOW(), 'SCRIPT_TASK', '脚本任务', '脚本执行任务', 'TASK', '{
|
||||||
('shellTask', 'Shell任务', '执行Shell命令或脚本的任务节点', 'TASK',
|
"code": "SCRIPT_TASK",
|
||||||
'{
|
"name": "脚本任务",
|
||||||
"class": "com.qqchen.deploy.backend.workflow.delegate.ShellTaskDelegate"
|
"description": "脚本执行任务",
|
||||||
}',
|
"details": {
|
||||||
'{
|
"description": "执行自定义脚本的任务节点,支持多种脚本语言和复杂的业务逻辑",
|
||||||
"shape": "rect",
|
"features": ["执行自定义脚本代码", "支持多种脚本语言", "访问流程变量", "支持复杂的业务逻辑"],
|
||||||
"width": 120,
|
"scenarios": ["数据处理和转换", "条件判断", "自定义业务规则", "系统集成"]
|
||||||
"height": 60,
|
},
|
||||||
"ports": {
|
"configSchema": {
|
||||||
"groups": {
|
"type": "object",
|
||||||
"top": {"position": "top", "attrs": {"circle": {"r": 4, "magnet": true}}},
|
"properties": {
|
||||||
"right": {"position": "right", "attrs": {"circle": {"r": 4, "magnet": true}}},
|
"code": {"type": "string", "title": "节点Code", "description": "工作流节点的Code"},
|
||||||
"bottom": {"position": "bottom", "attrs": {"circle": {"r": 4, "magnet": true}}},
|
"name": {"type": "string", "title": "节点名称", "description": "工作流节点的显示名称"},
|
||||||
"left": {"position": "left", "attrs": {"circle": {"r": 4, "magnet": true}}}
|
"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脚本 (开发中)"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"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": {
|
"attrs": {
|
||||||
"body": {"fill": "#ffffff", "stroke": "#333333", "strokeWidth": 2},
|
"circle": {
|
||||||
"label": {"text": "Shell任务", "fill": "#333333"}
|
"r": 4,
|
||||||
|
"fill": "#ffffff",
|
||||||
|
"stroke": "#1890ff"
|
||||||
}
|
}
|
||||||
}',
|
}
|
||||||
'{
|
},
|
||||||
"properties": [
|
"out": {
|
||||||
{"name": "id", "label": "节点标识", "type": "string", "required": true},
|
"position": "right",
|
||||||
{"name": "name", "label": "节点名称", "type": "string", "required": true},
|
"attrs": {
|
||||||
{"name": "script", "label": "脚本内容", "type": "textarea", "required": true},
|
"circle": {
|
||||||
{"name": "workDir", "label": "工作目录", "type": "string", "required": true},
|
"r": 4,
|
||||||
{"name": "async", "label": "异步执行", "type": "boolean"}
|
"fill": "#ffffff",
|
||||||
]
|
"stroke": "#1890ff"
|
||||||
}',
|
}
|
||||||
50, true, NOW(), 'system', NOW(), 'system', 1, false),
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}', 1);
|
||||||
|
|
||||||
-- 网关节点
|
-- 网关节点
|
||||||
-- 排他网关
|
INSERT INTO workflow_node_definition (id, create_time, type, name, description, category, graph_config, enabled)
|
||||||
('exclusiveGateway', '排他网关', '基于条件的分支网关,只会选择一个分支执行', 'GATEWAY',
|
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": "工作流节点的详细描述"}
|
||||||
|
},
|
||||||
|
"required": ["code", "name"]
|
||||||
|
},
|
||||||
|
"uiSchema": {
|
||||||
"shape": "diamond",
|
"shape": "diamond",
|
||||||
"width": 60,
|
"size": {"width": 50, "height": 50},
|
||||||
"height": 60,
|
"style": {
|
||||||
|
"fill": "#fff7e6",
|
||||||
|
"stroke": "#faad14",
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"icon": "fork",
|
||||||
|
"iconColor": "#faad14"
|
||||||
|
},
|
||||||
"ports": {
|
"ports": {
|
||||||
"groups": {
|
"groups": {
|
||||||
"top": {"position": "top", "attrs": {"circle": {"r": 4, "magnet": true}}},
|
"in": {
|
||||||
"right": {"position": "right", "attrs": {"circle": {"r": 4, "magnet": true}}},
|
"position": "left",
|
||||||
"bottom": {"position": "bottom", "attrs": {"circle": {"r": 4, "magnet": true}}},
|
"attrs": {
|
||||||
"left": {"position": "left", "attrs": {"circle": {"r": 4, "magnet": true}}}
|
"circle": {
|
||||||
|
"r": 4,
|
||||||
|
"fill": "#ffffff",
|
||||||
|
"stroke": "#1890ff"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"out": {
|
||||||
|
"position": "right",
|
||||||
"attrs": {
|
"attrs": {
|
||||||
"body": {"fill": "#ffffff", "stroke": "#333333", "strokeWidth": 2},
|
"circle": {
|
||||||
"label": {"text": "×", "fill": "#333333", "fontSize": 40}
|
"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"}
|
}', 1),
|
||||||
]
|
|
||||||
}',
|
|
||||||
60, true, NOW(), 'system', NOW(), 'system', 1, false),
|
|
||||||
|
|
||||||
-- 并行网关
|
(7, NOW(), 'PARALLEL_GATEWAY', '并行网关', '并行分支控制', 'GATEWAY', '{
|
||||||
('parallelGateway', '并行网关', '并行执行所有分支', '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": "工作流节点的详细描述"}
|
||||||
|
},
|
||||||
|
"required": ["code", "name"]
|
||||||
|
},
|
||||||
|
"uiSchema": {
|
||||||
"shape": "diamond",
|
"shape": "diamond",
|
||||||
"width": 60,
|
"size": {"width": 50, "height": 50},
|
||||||
"height": 60,
|
"style": {
|
||||||
|
"fill": "#fff7e6",
|
||||||
|
"stroke": "#faad14",
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"icon": "branches",
|
||||||
|
"iconColor": "#faad14"
|
||||||
|
},
|
||||||
"ports": {
|
"ports": {
|
||||||
"groups": {
|
"groups": {
|
||||||
"top": {"position": "top", "attrs": {"circle": {"r": 4, "magnet": true}}},
|
"in": {
|
||||||
"right": {"position": "right", "attrs": {"circle": {"r": 4, "magnet": true}}},
|
"position": "left",
|
||||||
"bottom": {"position": "bottom", "attrs": {"circle": {"r": 4, "magnet": true}}},
|
"attrs": {
|
||||||
"left": {"position": "left", "attrs": {"circle": {"r": 4, "magnet": true}}}
|
"circle": {
|
||||||
|
"r": 4,
|
||||||
|
"fill": "#ffffff",
|
||||||
|
"stroke": "#1890ff"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"out": {
|
||||||
|
"position": "right",
|
||||||
"attrs": {
|
"attrs": {
|
||||||
"body": {"fill": "#ffffff", "stroke": "#333333", "strokeWidth": 2},
|
"circle": {
|
||||||
"label": {"text": "+", "fill": "#333333", "fontSize": 40}
|
"r": 4,
|
||||||
|
"fill": "#ffffff",
|
||||||
|
"stroke": "#1890ff"
|
||||||
}
|
}
|
||||||
}',
|
}
|
||||||
'{
|
}
|
||||||
"properties": [
|
}
|
||||||
{"name": "id", "label": "节点标识", "type": "string", "required": true},
|
}
|
||||||
{"name": "name", "label": "网关名称", "type": "string", "required": true}
|
}
|
||||||
]
|
}', 1);
|
||||||
}',
|
|
||||||
70, true, NOW(), 'system', NOW(), 'system', 1, false);
|
-- 容器节点
|
||||||
|
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