Ver Fonte

feat: Simple设计器-延时器

Lesan há 7 meses atrás
pai
commit
4c8b83d46f

+ 2 - 1
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;
 @AllArgsConstructor
 public enum BpmBoundaryEventType {
 
-    USER_TASK_TIMEOUT(1,"用户任务超时");
+    USER_TASK_TIMEOUT(1,"用户任务超时"),
+    DELAY_TIMER_TIMEOUT(2,"触发器超时");
 
     private final Integer type;
     private final String name;

+ 30 - 0
yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmDelayTimerType.java

@@ -0,0 +1,30 @@
+package cn.iocoder.yudao.module.bpm.enums.definition;
+
+import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.Arrays;
+
+/**
+ * BPM 延时器类型枚举
+ *
+ * @author Lesan
+ */
+@Getter
+@AllArgsConstructor
+public enum BpmDelayTimerType implements IntArrayValuable {
+
+    FIXED_TIME_DURATION(1, "固定时长"),
+    FIXED_DATE_TIME(2, "固定日期时间");
+
+    private final Integer type;
+    private final String name;
+
+    public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BpmDelayTimerType::getType).toArray();
+
+    @Override
+    public int[] array() {
+        return ARRAYS;
+    }
+}

+ 1 - 0
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 {
     START_USER_NODE(10, "发起人", "userTask"), // 发起人节点。前端的开始节点,Id 固定
     APPROVE_NODE(11, "审批人", "userTask"),
     COPY_NODE(12, "抄送人", "serviceTask"),
+    DELAY_TIMER_NODE(13, "延迟器", "receiveTask"),
 
     // 50 ~ 条件分支
     CONDITION_NODE(50, "条件", "sequenceFlow"), // 用于构建流转条件的表达式

+ 17 - 0
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 {
         private String rightSide;
     }
 
+    @Schema(description = "延迟器设置", example = "{}")
+    private DelaySetting delaySetting;
+
+    @Schema(description = "延迟器")
+    @Data
+    @Valid
+    public static class DelaySetting {
+
+        @Schema(description = "延迟时间类型", example = "1")
+        @NotNull(message = "延迟时间类型不能为空")
+        private Integer delayType;
+
+        @Schema(description = "延迟时间表达式", example = "PT1H,2025-01-01T00:00:00")
+        @NotEmpty(message = "延迟时间表达式不能为空")
+        private String delayTime;
+    }
+
     // TODO @芋艿:条件;建议可以固化的一些选项;然后有个表达式兜底;要支持
 }

+ 12 - 7
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 {
         String boundaryEventType = BpmnModelUtils.parseBoundaryEventExtensionElement(boundaryEvent,
                 BpmnModelConstants.BOUNDARY_EVENT_TYPE);
         BpmBoundaryEventType bpmTimerBoundaryEventType = BpmBoundaryEventType.typeOf(NumberUtils.parseInt(boundaryEventType));
-        if (ObjectUtil.notEqual(bpmTimerBoundaryEventType, BpmBoundaryEventType.USER_TASK_TIMEOUT)) {
-            return;
-        }
 
         // 2. 处理超时
-        String timeoutHandlerType = BpmnModelUtils.parseBoundaryEventExtensionElement(boundaryEvent,
-                BpmnModelConstants.USER_TASK_TIMEOUT_HANDLER_TYPE);
-        String taskKey = boundaryEvent.getAttachedToRefId();
-        taskService.processTaskTimeout(event.getProcessInstanceId(), taskKey, NumberUtils.parseInt(timeoutHandlerType));
+        // 2.1 用户任务超时处理
+        if (ObjectUtil.equal(bpmTimerBoundaryEventType, BpmBoundaryEventType.USER_TASK_TIMEOUT)) {
+            String timeoutHandlerType = BpmnModelUtils.parseBoundaryEventExtensionElement(boundaryEvent,
+                    BpmnModelConstants.USER_TASK_TIMEOUT_HANDLER_TYPE);
+            String taskKey = boundaryEvent.getAttachedToRefId();
+            taskService.processTaskTimeout(event.getProcessInstanceId(), taskKey, NumberUtils.parseInt(timeoutHandlerType));
+        }
+        // 2.2 触发器超时处理
+        if (ObjectUtil.equal(bpmTimerBoundaryEventType, BpmBoundaryEventType.DELAY_TIMER_TIMEOUT)) {
+            String taskKey = boundaryEvent.getAttachedToRefId();
+            taskService.processDelayTimerTimeout(event.getProcessInstanceId(), taskKey);
+        }
     }
 
 }

+ 40 - 0
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 {
     static {
         List<NodeConvert> converts = asList(new StartNodeConvert(), new EndNodeConvert(),
                 new StartUserNodeConvert(), new ApproveNodeConvert(), new CopyNodeConvert(),
+                new DelayTimerNodeConvert(),
                 new ConditionBranchNodeConvert(), new ParallelBranchNodeConvert(), new InclusiveBranchNodeConvert());
         converts.forEach(convert -> NODE_CONVERTS.put(convert.getType(), convert));
     }
@@ -605,6 +606,45 @@ public class SimpleModelUtils {
 
     }
 
+    public static class DelayTimerNodeConvert implements NodeConvert {
+
+        @Override
+        public List<FlowElement> convertList(BpmSimpleModelNodeVO node) {
+            List<FlowElement> flowElements = new ArrayList<>(2);
+            // 1. 构建接收任务,通过接收任务可卡住节点
+            ReceiveTask receiveTask = new ReceiveTask();
+            receiveTask.setId(node.getId());
+            receiveTask.setName(node.getName());
+            flowElements.add(receiveTask);
+
+            // 2. 添加接收任务的 Timer Boundary Event
+            if (node.getDelaySetting() != null) {
+                // 2.1 定时器边界事件
+                BoundaryEvent boundaryEvent = new BoundaryEvent();
+                boundaryEvent.setId("Event-" + IdUtil.fastUUID());
+                boundaryEvent.setCancelActivity(false);
+                boundaryEvent.setAttachedToRef(receiveTask);
+                // 2.2 定义超时时间
+                TimerEventDefinition eventDefinition = new TimerEventDefinition();
+                if (node.getDelaySetting().getDelayType().equals(BpmDelayTimerType.FIXED_DATE_TIME.getType())){
+                    eventDefinition.setTimeDuration(node.getDelaySetting().getDelayTime());
+                }
+                if (node.getDelaySetting().getDelayType().equals(BpmDelayTimerType.FIXED_TIME_DURATION.getType())){
+                    eventDefinition.setTimeDate(node.getDelaySetting().getDelayTime());
+                }
+                boundaryEvent.addEventDefinition(eventDefinition);
+                addExtensionElement(boundaryEvent, BOUNDARY_EVENT_TYPE, BpmBoundaryEventType.DELAY_TIMER_TIMEOUT.getType());
+                flowElements.add(boundaryEvent);
+            }
+            return flowElements;
+        }
+
+        @Override
+        public BpmSimpleModelNodeType getType() {
+            return BpmSimpleModelNodeType.DELAY_TIMER_NODE;
+        }
+    }
+
     private static String buildGatewayJoinId(String id) {
         return id + "_join";
     }

+ 7 - 0
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 {
      */
     void processTaskTimeout(String processInstanceId, String taskDefineKey, Integer handlerType);
 
+    /**
+     * 处理 延时器 超时事件
+     *
+     * @param processInstanceId 流程示例编号
+     * @param taskDefineKey     任务 Key
+     */
+    void processDelayTimerTimeout(String processInstanceId, String taskDefineKey);
 }

+ 19 - 0
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;
 import org.flowable.engine.RuntimeService;
 import org.flowable.engine.TaskService;
 import org.flowable.engine.history.HistoricActivityInstance;
+import org.flowable.engine.runtime.Execution;
 import org.flowable.engine.runtime.ProcessInstance;
 import org.flowable.task.api.DelegationState;
 import org.flowable.task.api.Task;
@@ -1238,6 +1239,24 @@ public class BpmTaskServiceImpl implements BpmTaskService {
         }));
     }
 
+    @Override
+    public void processDelayTimerTimeout(String processInstanceId, String taskDefineKey) {
+        Execution execution = runtimeService.createExecutionQuery()
+                .processInstanceId(processInstanceId)
+                .activityId(taskDefineKey)
+                .singleResult();
+        if (execution == null) {
+            log.error("[processDelayTimerTimeout][processInstanceId({})activityId({}) 没有找到执行活动]",
+                    processInstanceId, taskDefineKey);
+            return;
+        }
+        // 若存在直接触发接收任务,执行后续节点
+        // TODO @芋艿 这里需要帮助看一下,我不懂为啥开启了租户后就一直报错:不存在租户编号
+        FlowableUtils.execute(execution.getTenantId(), () -> {
+            runtimeService.trigger(execution.getId());
+        });
+    }
+
     /**
      * 获得自身的代理对象,解决 AOP 生效问题
      *