Commit 4c8b83d46f378386e3cb3a0b3148a2a19e64cca1

Authored by Lesan
1 parent 46c825cb

feat: Simple设计器-延时器

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 *
... ...