diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmBoundaryEventType.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmBoundaryEventType.java index 1d3dd5e294..242bfcbf8d 100644 --- a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmBoundaryEventType.java +++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmBoundaryEventType.java @@ -14,7 +14,7 @@ import lombok.Getter; public enum BpmBoundaryEventType { USER_TASK_TIMEOUT(1, "用户任务超时"), - DELAY_TIMER_TIMEOUT(2, "触发器超时"); + DELAY_TIMER_TIMEOUT(2, "延迟器超时"); private final Integer type; private final String name; diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmDelayTimerType.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmDelayTimerType.java index 1e0fc162d6..db7829958b 100644 --- a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmDelayTimerType.java +++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmDelayTimerType.java @@ -7,7 +7,7 @@ import lombok.Getter; import java.util.Arrays; /** - * BPM 延时器类型枚举 + * BPM 延迟器类型枚举 * * @author Lesan */ diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmSimpleModelNodeType.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmSimpleModelNodeType.java index ac001cf3e0..e95c59dcdc 100644 --- a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmSimpleModelNodeType.java +++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmSimpleModelNodeType.java @@ -33,6 +33,7 @@ public enum BpmSimpleModelNodeType implements IntArrayValuable { CONDITION_BRANCH_NODE(51, "条件分支", "exclusiveGateway"), PARALLEL_BRANCH_NODE(52, "并行分支", "parallelGateway"), INCLUSIVE_BRANCH_NODE(53, "包容分支", "inclusiveGateway"), + ROUTE_BRANCH_NODE(54, "路由分支", "exclusiveGateway") ; public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BpmSimpleModelNodeType::getType).toArray(); @@ -49,7 +50,8 @@ public enum BpmSimpleModelNodeType implements IntArrayValuable { public static boolean isBranchNode(Integer type) { return Objects.equals(CONDITION_BRANCH_NODE.getType(), type) || Objects.equals(PARALLEL_BRANCH_NODE.getType(), type) - || Objects.equals(INCLUSIVE_BRANCH_NODE.getType(), type); + || Objects.equals(INCLUSIVE_BRANCH_NODE.getType(), type) + || Objects.equals(ROUTE_BRANCH_NODE.getType(), type); } public static BpmSimpleModelNodeType valueOf(Integer type) { diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/simple/BpmSimpleModelNodeVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/simple/BpmSimpleModelNodeVO.java index 46c755e14d..382cd7c318 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/simple/BpmSimpleModelNodeVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/simple/BpmSimpleModelNodeVO.java @@ -271,4 +271,31 @@ public class BpmSimpleModelNodeVO { private String delayTime; } + @Schema(description = "路由分支组", example = "[]") + private List routeGroup; + + @Schema(description = "默认分支id", example = "Flow_xxx") + private String defaultFlowId; // 仅用于路由分支节点 BpmSimpleModelNodeType.ROUTE_BRANCH_NODE + + @Schema(description = "路由分支") + @Data + @Valid + public static class RouteCondition { + + @Schema(description = "节点Id", example = "Activity_xxx") + @NotEmpty(message = "节点Id不能为空") + private String nodeId; + + @Schema(description = "条件类型", example = "1") + @InEnum(BpmSimpleModeConditionType.class) + @NotNull(message = "条件类型不能为空") + private Integer conditionType; + + @Schema(description = "条件表达式", example = "${day>3}") + private String conditionExpression; + + @Schema(description = "条件组", example = "{}") + private ConditionGroups conditionGroups; + } + } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/BpmTaskEventListener.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/BpmTaskEventListener.java index 134871b01a..9968c1c4bf 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/BpmTaskEventListener.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/BpmTaskEventListener.java @@ -106,7 +106,7 @@ public class BpmTaskEventListener extends AbstractFlowableEngineEventListener { BpmnModelConstants.USER_TASK_TIMEOUT_HANDLER_TYPE); String taskKey = boundaryEvent.getAttachedToRefId(); taskService.processTaskTimeout(event.getProcessInstanceId(), taskKey, NumberUtils.parseInt(timeoutHandlerType)); - // 2.2 触发器超时处理 + // 2.2 延迟器超时处理 } else if (ObjectUtil.equal(bpmTimerBoundaryEventType, BpmBoundaryEventType.DELAY_TIMER_TIMEOUT)) { String taskKey = boundaryEvent.getAttachedToRefId(); taskService.processDelayTimerTimeout(event.getProcessInstanceId(), taskKey); diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java index f4464ef2b4..6922b0a453 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java @@ -42,7 +42,8 @@ public class SimpleModelUtils { List converts = asList(new StartNodeConvert(), new EndNodeConvert(), new StartUserNodeConvert(), new ApproveNodeConvert(), new CopyNodeConvert(), new DelayTimerNodeConvert(), - new ConditionBranchNodeConvert(), new ParallelBranchNodeConvert(), new InclusiveBranchNodeConvert()); + new ConditionBranchNodeConvert(), new ParallelBranchNodeConvert(), new InclusiveBranchNodeConvert(), + new RouteBranchNodeConvert()); converts.forEach(convert -> NODE_CONVERTS.put(convert.getType(), convert)); } @@ -184,10 +185,12 @@ public class SimpleModelUtils { BpmSimpleModelNodeType nodeType = BpmSimpleModelNodeType.valueOf(node.getType()); BpmSimpleModelNodeVO childNode = node.getChildNode(); List conditionNodes = node.getConditionNodes(); - Assert.notEmpty(conditionNodes, "分支节点的条件节点不能为空"); + // TODO @芋艿 路由分支没有conditionNodes 这里注释会影响吗? +// Assert.notEmpty(conditionNodes, "分支节点的条件节点不能为空"); // 分支终点节点 ID String branchEndNodeId = null; - if (nodeType == BpmSimpleModelNodeType.CONDITION_BRANCH_NODE) { // 条件分支 + if (nodeType == BpmSimpleModelNodeType.CONDITION_BRANCH_NODE + || nodeType == BpmSimpleModelNodeType.ROUTE_BRANCH_NODE) { // 条件分支或路由分支 // 分两种情况 1. 分支节点有孩子节点为孩子节点 Id 2. 分支节点孩子为无效节点时 (分支嵌套且为分支最后一个节点) 为分支终点节点 ID branchEndNodeId = isValidNode(childNode) ? childNode.getId() : targetNodeId; } else if (nodeType == BpmSimpleModelNodeType.PARALLEL_BRANCH_NODE @@ -198,31 +201,45 @@ public class SimpleModelUtils { Assert.notEmpty(branchEndNodeId, "分支终点节点 Id 不能为空"); // 3. 遍历分支节点 - // 下面的注释,以如下情况举例子。分支 1:A->B->C->D->E,分支 2:A->D->E。其中,A 为分支节点, D 为 A 孩子节点 - for (BpmSimpleModelNodeVO item : conditionNodes) { - Assert.isTrue(Objects.equals(item.getType(), BpmSimpleModelNodeType.CONDITION_NODE.getType()), - "条件节点类型({})不符合", item.getType()); - BpmSimpleModelNodeVO conditionChildNode = item.getChildNode(); - // 3.1 分支有后续节点。即分支 1: A->B->C->D 的情况 - if (isValidNode(conditionChildNode)) { - // 3.1.1 建立与后续的节点的连线。例如说,建立 A->B 的连线 - SequenceFlow sequenceFlow = ConditionNodeConvert.buildSequenceFlow(node.getId(), conditionChildNode.getId(), item); - process.addFlowElement(sequenceFlow); - // 3.1.2 递归调用后续节点连线。例如说,建立 B->C->D 的连线 - traverseNodeToBuildSequenceFlow(process, conditionChildNode, branchEndNodeId); - } else { - // 3.2 分支没有后续节点。例如说,建立 A->D 的连线 - SequenceFlow sequenceFlow = ConditionNodeConvert.buildSequenceFlow(node.getId(), branchEndNodeId, item); - process.addFlowElement(sequenceFlow); + if (nodeType == BpmSimpleModelNodeType.ROUTE_BRANCH_NODE) { + // 路由分支遍历 + for (BpmSimpleModelNodeVO.RouteCondition route : node.getRouteGroup()) { + SequenceFlow sFlow = RouteBranchNodeConvert.buildSequenceFlow(node.getId(), route); + process.addFlowElement(sFlow); + } + } else { + // 下面的注释,以如下情况举例子。分支 1:A->B->C->D->E,分支 2:A->D->E。其中,A 为分支节点, D 为 A 孩子节点 + for (BpmSimpleModelNodeVO item : conditionNodes) { + Assert.isTrue(Objects.equals(item.getType(), BpmSimpleModelNodeType.CONDITION_NODE.getType()), + "条件节点类型({})不符合", item.getType()); + BpmSimpleModelNodeVO conditionChildNode = item.getChildNode(); + // 3.1 分支有后续节点。即分支 1: A->B->C->D 的情况 + if (isValidNode(conditionChildNode)) { + // 3.1.1 建立与后续的节点的连线。例如说,建立 A->B 的连线 + SequenceFlow sequenceFlow = ConditionNodeConvert.buildSequenceFlow(node.getId(), conditionChildNode.getId(), item); + process.addFlowElement(sequenceFlow); + // 3.1.2 递归调用后续节点连线。例如说,建立 B->C->D 的连线 + traverseNodeToBuildSequenceFlow(process, conditionChildNode, branchEndNodeId); + } else { + // 3.2 分支没有后续节点。例如说,建立 A->D 的连线 + SequenceFlow sequenceFlow = ConditionNodeConvert.buildSequenceFlow(node.getId(), branchEndNodeId, item); + process.addFlowElement(sequenceFlow); + } } } - // 4. 如果是并行分支、包容分支,由于是程序创建的聚合网关,需要手工创建聚合网关和下一个节点的连线 + // 4. 各分支节点所需特殊处理 if (nodeType == BpmSimpleModelNodeType.PARALLEL_BRANCH_NODE || nodeType == BpmSimpleModelNodeType.INCLUSIVE_BRANCH_NODE ) { + // 如果是并行分支、包容分支,由于是程序创建的聚合网关,需要手工创建聚合网关和下一个节点的连线 String nextNodeId = isValidNode(childNode) ? childNode.getId() : targetNodeId; SequenceFlow sequenceFlow = buildBpmnSequenceFlow(branchEndNodeId, nextNodeId); process.addFlowElement(sequenceFlow); + } else if (nodeType == BpmSimpleModelNodeType.ROUTE_BRANCH_NODE) { + // 如果是路由分支,需要连接后续节点为默认路由 + SequenceFlow sequenceFlow = buildBpmnSequenceFlow(node.getId(), branchEndNodeId, node.getDefaultFlowId(), + null, null); + process.addFlowElement(sequenceFlow); } // 5. 递归调用后续节点 继续递归。例如说,建立 D->E 的连线 @@ -597,12 +614,20 @@ public class SimpleModelUtils { * @param node 条件节点 */ public static String buildConditionExpression(BpmSimpleModelNodeVO node) { - BpmSimpleModeConditionType conditionTypeEnum = BpmSimpleModeConditionType.valueOf(node.getConditionType()); + return buildConditionExpression(node.getConditionType(), node.getConditionExpression(), + node.getConditionGroups()); + } + public static String buildConditionExpression(BpmSimpleModelNodeVO.RouteCondition route) { + return buildConditionExpression(route.getConditionType(), route.getConditionExpression(), + route.getConditionGroups()); + } + public static String buildConditionExpression(Integer conditionType, String conditionExpression, + ConditionGroups conditionGroups) { + BpmSimpleModeConditionType conditionTypeEnum = BpmSimpleModeConditionType.valueOf(conditionType); if (conditionTypeEnum == BpmSimpleModeConditionType.EXPRESSION) { - return node.getConditionExpression(); + return conditionExpression; } if (conditionTypeEnum == BpmSimpleModeConditionType.RULE) { - ConditionGroups conditionGroups = node.getConditionGroups(); if (conditionGroups == null || CollUtil.isEmpty(conditionGroups.getConditions())) { return null; } @@ -665,6 +690,29 @@ public class SimpleModelUtils { } } + public static class RouteBranchNodeConvert implements NodeConvert { + + @Override + public ExclusiveGateway convert(BpmSimpleModelNodeVO node) { + ExclusiveGateway exclusiveGateway = new ExclusiveGateway(); + exclusiveGateway.setId(node.getId()); + + // 设置默认的序列流(条件) + exclusiveGateway.setDefaultFlow(node.getDefaultFlowId()); + return exclusiveGateway; + } + + @Override + public BpmSimpleModelNodeType getType() { + return BpmSimpleModelNodeType.ROUTE_BRANCH_NODE; + } + + public static SequenceFlow buildSequenceFlow(String nodeId, BpmSimpleModelNodeVO.RouteCondition route) { + String conditionExpression = ConditionNodeConvert.buildConditionExpression(route); + return buildBpmnSequenceFlow(nodeId, route.getNodeId(), null, null, conditionExpression); + } + } + private static String buildGatewayJoinId(String id) { return id + "_join"; } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskService.java index 46ba1ef3bc..dd83d287e6 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskService.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskService.java @@ -276,7 +276,7 @@ public interface BpmTaskService { void processTaskTimeout(String processInstanceId, String taskDefineKey, Integer handlerType); /** - * 处理 延时器 超时事件 + * 处理 延迟器 超时事件 * * @param processInstanceId 流程示例编号 * @param taskDefineKey 任务 Key