feat: Simple设计器-延时器

This commit is contained in:
Lesan 2025-01-03 16:18:46 +08:00
parent 46c825cb6f
commit 4c8b83d46f
8 changed files with 128 additions and 8 deletions

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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"), // 用于构建流转条件的表达式

View File

@ -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 @芋艿条件建议可以固化的一些选项然后有个表达式兜底要支持
}

View File

@ -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);
}
}
}

View File

@ -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";
}

View File

@ -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);
}

View File

@ -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 生效问题
*