Commit 4c8b83d46f378386e3cb3a0b3148a2a19e64cca1
1 parent
46c825cb
feat: Simple设计器-延时器
Showing
8 changed files
with
128 additions
and
8 deletions
yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmBoundaryEventType.java
| ... | ... | @@ -13,7 +13,8 @@ import lombok.Getter; |
| 13 | 13 | @AllArgsConstructor |
| 14 | 14 | public enum BpmBoundaryEventType { |
| 15 | 15 | |
| 16 | - USER_TASK_TIMEOUT(1,"用户任务超时"); | |
| 16 | + USER_TASK_TIMEOUT(1,"用户任务超时"), | |
| 17 | + DELAY_TIMER_TIMEOUT(2,"触发器超时"); | |
| 17 | 18 | |
| 18 | 19 | private final Integer type; |
| 19 | 20 | private final String name; | ... | ... |
yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmDelayTimerType.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.bpm.enums.definition; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; | |
| 4 | +import lombok.AllArgsConstructor; | |
| 5 | +import lombok.Getter; | |
| 6 | + | |
| 7 | +import java.util.Arrays; | |
| 8 | + | |
| 9 | +/** | |
| 10 | + * BPM 延时器类型枚举 | |
| 11 | + * | |
| 12 | + * @author Lesan | |
| 13 | + */ | |
| 14 | +@Getter | |
| 15 | +@AllArgsConstructor | |
| 16 | +public enum BpmDelayTimerType implements IntArrayValuable { | |
| 17 | + | |
| 18 | + FIXED_TIME_DURATION(1, "固定时长"), | |
| 19 | + FIXED_DATE_TIME(2, "固定日期时间"); | |
| 20 | + | |
| 21 | + private final Integer type; | |
| 22 | + private final String name; | |
| 23 | + | |
| 24 | + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BpmDelayTimerType::getType).toArray(); | |
| 25 | + | |
| 26 | + @Override | |
| 27 | + public int[] array() { | |
| 28 | + return ARRAYS; | |
| 29 | + } | |
| 30 | +} | ... | ... |
yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmSimpleModelNodeType.java
| ... | ... | @@ -25,6 +25,7 @@ public enum BpmSimpleModelNodeType implements IntArrayValuable { |
| 25 | 25 | START_USER_NODE(10, "发起人", "userTask"), // 发起人节点。前端的开始节点,Id 固定 |
| 26 | 26 | APPROVE_NODE(11, "审批人", "userTask"), |
| 27 | 27 | COPY_NODE(12, "抄送人", "serviceTask"), |
| 28 | + DELAY_TIMER_NODE(13, "延迟器", "receiveTask"), | |
| 28 | 29 | |
| 29 | 30 | // 50 ~ 条件分支 |
| 30 | 31 | CONDITION_NODE(50, "条件", "sequenceFlow"), // 用于构建流转条件的表达式 | ... | ... |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/simple/BpmSimpleModelNodeVO.java
| ... | ... | @@ -208,5 +208,22 @@ public class BpmSimpleModelNodeVO { |
| 208 | 208 | private String rightSide; |
| 209 | 209 | } |
| 210 | 210 | |
| 211 | + @Schema(description = "延迟器设置", example = "{}") | |
| 212 | + private DelaySetting delaySetting; | |
| 213 | + | |
| 214 | + @Schema(description = "延迟器") | |
| 215 | + @Data | |
| 216 | + @Valid | |
| 217 | + public static class DelaySetting { | |
| 218 | + | |
| 219 | + @Schema(description = "延迟时间类型", example = "1") | |
| 220 | + @NotNull(message = "延迟时间类型不能为空") | |
| 221 | + private Integer delayType; | |
| 222 | + | |
| 223 | + @Schema(description = "延迟时间表达式", example = "PT1H,2025-01-01T00:00:00") | |
| 224 | + @NotEmpty(message = "延迟时间表达式不能为空") | |
| 225 | + private String delayTime; | |
| 226 | + } | |
| 227 | + | |
| 211 | 228 | // TODO @芋艿:条件;建议可以固化的一些选项;然后有个表达式兜底;要支持 |
| 212 | 229 | } | ... | ... |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/BpmTaskEventListener.java
| ... | ... | @@ -98,15 +98,20 @@ public class BpmTaskEventListener extends AbstractFlowableEngineEventListener { |
| 98 | 98 | String boundaryEventType = BpmnModelUtils.parseBoundaryEventExtensionElement(boundaryEvent, |
| 99 | 99 | BpmnModelConstants.BOUNDARY_EVENT_TYPE); |
| 100 | 100 | BpmBoundaryEventType bpmTimerBoundaryEventType = BpmBoundaryEventType.typeOf(NumberUtils.parseInt(boundaryEventType)); |
| 101 | - if (ObjectUtil.notEqual(bpmTimerBoundaryEventType, BpmBoundaryEventType.USER_TASK_TIMEOUT)) { | |
| 102 | - return; | |
| 103 | - } | |
| 104 | 101 | |
| 105 | 102 | // 2. 处理超时 |
| 106 | - String timeoutHandlerType = BpmnModelUtils.parseBoundaryEventExtensionElement(boundaryEvent, | |
| 107 | - BpmnModelConstants.USER_TASK_TIMEOUT_HANDLER_TYPE); | |
| 108 | - String taskKey = boundaryEvent.getAttachedToRefId(); | |
| 109 | - taskService.processTaskTimeout(event.getProcessInstanceId(), taskKey, NumberUtils.parseInt(timeoutHandlerType)); | |
| 103 | + // 2.1 用户任务超时处理 | |
| 104 | + if (ObjectUtil.equal(bpmTimerBoundaryEventType, BpmBoundaryEventType.USER_TASK_TIMEOUT)) { | |
| 105 | + String timeoutHandlerType = BpmnModelUtils.parseBoundaryEventExtensionElement(boundaryEvent, | |
| 106 | + BpmnModelConstants.USER_TASK_TIMEOUT_HANDLER_TYPE); | |
| 107 | + String taskKey = boundaryEvent.getAttachedToRefId(); | |
| 108 | + taskService.processTaskTimeout(event.getProcessInstanceId(), taskKey, NumberUtils.parseInt(timeoutHandlerType)); | |
| 109 | + } | |
| 110 | + // 2.2 触发器超时处理 | |
| 111 | + if (ObjectUtil.equal(bpmTimerBoundaryEventType, BpmBoundaryEventType.DELAY_TIMER_TIMEOUT)) { | |
| 112 | + String taskKey = boundaryEvent.getAttachedToRefId(); | |
| 113 | + taskService.processDelayTimerTimeout(event.getProcessInstanceId(), taskKey); | |
| 114 | + } | |
| 110 | 115 | } |
| 111 | 116 | |
| 112 | 117 | } | ... | ... |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java
| ... | ... | @@ -37,6 +37,7 @@ public class SimpleModelUtils { |
| 37 | 37 | static { |
| 38 | 38 | List<NodeConvert> converts = asList(new StartNodeConvert(), new EndNodeConvert(), |
| 39 | 39 | new StartUserNodeConvert(), new ApproveNodeConvert(), new CopyNodeConvert(), |
| 40 | + new DelayTimerNodeConvert(), | |
| 40 | 41 | new ConditionBranchNodeConvert(), new ParallelBranchNodeConvert(), new InclusiveBranchNodeConvert()); |
| 41 | 42 | converts.forEach(convert -> NODE_CONVERTS.put(convert.getType(), convert)); |
| 42 | 43 | } |
| ... | ... | @@ -605,6 +606,45 @@ public class SimpleModelUtils { |
| 605 | 606 | |
| 606 | 607 | } |
| 607 | 608 | |
| 609 | + public static class DelayTimerNodeConvert implements NodeConvert { | |
| 610 | + | |
| 611 | + @Override | |
| 612 | + public List<FlowElement> convertList(BpmSimpleModelNodeVO node) { | |
| 613 | + List<FlowElement> flowElements = new ArrayList<>(2); | |
| 614 | + // 1. 构建接收任务,通过接收任务可卡住节点 | |
| 615 | + ReceiveTask receiveTask = new ReceiveTask(); | |
| 616 | + receiveTask.setId(node.getId()); | |
| 617 | + receiveTask.setName(node.getName()); | |
| 618 | + flowElements.add(receiveTask); | |
| 619 | + | |
| 620 | + // 2. 添加接收任务的 Timer Boundary Event | |
| 621 | + if (node.getDelaySetting() != null) { | |
| 622 | + // 2.1 定时器边界事件 | |
| 623 | + BoundaryEvent boundaryEvent = new BoundaryEvent(); | |
| 624 | + boundaryEvent.setId("Event-" + IdUtil.fastUUID()); | |
| 625 | + boundaryEvent.setCancelActivity(false); | |
| 626 | + boundaryEvent.setAttachedToRef(receiveTask); | |
| 627 | + // 2.2 定义超时时间 | |
| 628 | + TimerEventDefinition eventDefinition = new TimerEventDefinition(); | |
| 629 | + if (node.getDelaySetting().getDelayType().equals(BpmDelayTimerType.FIXED_DATE_TIME.getType())){ | |
| 630 | + eventDefinition.setTimeDuration(node.getDelaySetting().getDelayTime()); | |
| 631 | + } | |
| 632 | + if (node.getDelaySetting().getDelayType().equals(BpmDelayTimerType.FIXED_TIME_DURATION.getType())){ | |
| 633 | + eventDefinition.setTimeDate(node.getDelaySetting().getDelayTime()); | |
| 634 | + } | |
| 635 | + boundaryEvent.addEventDefinition(eventDefinition); | |
| 636 | + addExtensionElement(boundaryEvent, BOUNDARY_EVENT_TYPE, BpmBoundaryEventType.DELAY_TIMER_TIMEOUT.getType()); | |
| 637 | + flowElements.add(boundaryEvent); | |
| 638 | + } | |
| 639 | + return flowElements; | |
| 640 | + } | |
| 641 | + | |
| 642 | + @Override | |
| 643 | + public BpmSimpleModelNodeType getType() { | |
| 644 | + return BpmSimpleModelNodeType.DELAY_TIMER_NODE; | |
| 645 | + } | |
| 646 | + } | |
| 647 | + | |
| 608 | 648 | private static String buildGatewayJoinId(String id) { |
| 609 | 649 | return id + "_join"; |
| 610 | 650 | } | ... | ... |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskService.java
| ... | ... | @@ -275,4 +275,11 @@ public interface BpmTaskService { |
| 275 | 275 | */ |
| 276 | 276 | void processTaskTimeout(String processInstanceId, String taskDefineKey, Integer handlerType); |
| 277 | 277 | |
| 278 | + /** | |
| 279 | + * 处理 延时器 超时事件 | |
| 280 | + * | |
| 281 | + * @param processInstanceId 流程示例编号 | |
| 282 | + * @param taskDefineKey 任务 Key | |
| 283 | + */ | |
| 284 | + void processDelayTimerTimeout(String processInstanceId, String taskDefineKey); | |
| 278 | 285 | } | ... | ... |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java
| ... | ... | @@ -42,6 +42,7 @@ import org.flowable.engine.ManagementService; |
| 42 | 42 | import org.flowable.engine.RuntimeService; |
| 43 | 43 | import org.flowable.engine.TaskService; |
| 44 | 44 | import org.flowable.engine.history.HistoricActivityInstance; |
| 45 | +import org.flowable.engine.runtime.Execution; | |
| 45 | 46 | import org.flowable.engine.runtime.ProcessInstance; |
| 46 | 47 | import org.flowable.task.api.DelegationState; |
| 47 | 48 | import org.flowable.task.api.Task; |
| ... | ... | @@ -1238,6 +1239,24 @@ public class BpmTaskServiceImpl implements BpmTaskService { |
| 1238 | 1239 | })); |
| 1239 | 1240 | } |
| 1240 | 1241 | |
| 1242 | + @Override | |
| 1243 | + public void processDelayTimerTimeout(String processInstanceId, String taskDefineKey) { | |
| 1244 | + Execution execution = runtimeService.createExecutionQuery() | |
| 1245 | + .processInstanceId(processInstanceId) | |
| 1246 | + .activityId(taskDefineKey) | |
| 1247 | + .singleResult(); | |
| 1248 | + if (execution == null) { | |
| 1249 | + log.error("[processDelayTimerTimeout][processInstanceId({})activityId({}) 没有找到执行活动]", | |
| 1250 | + processInstanceId, taskDefineKey); | |
| 1251 | + return; | |
| 1252 | + } | |
| 1253 | + // 若存在直接触发接收任务,执行后续节点 | |
| 1254 | + // TODO @芋艿 这里需要帮助看一下,我不懂为啥开启了租户后就一直报错:不存在租户编号 | |
| 1255 | + FlowableUtils.execute(execution.getTenantId(), () -> { | |
| 1256 | + runtimeService.trigger(execution.getId()); | |
| 1257 | + }); | |
| 1258 | + } | |
| 1259 | + | |
| 1241 | 1260 | /** |
| 1242 | 1261 | * 获得自身的代理对象,解决 AOP 生效问题 |
| 1243 | 1262 | * | ... | ... |