Commit d2750f08ce67e6cfa2db4873bdf54bb93bcc439e

Authored by jason
1 parent d34fef67

仿钉钉流程设计- 审批节点添加拒绝处理方式

yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmTimerBoundaryEventType.java renamed to yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmBoundaryEventType.java
@@ -5,20 +5,21 @@ import lombok.AllArgsConstructor; @@ -5,20 +5,21 @@ import lombok.AllArgsConstructor;
5 import lombok.Getter; 5 import lombok.Getter;
6 6
7 /** 7 /**
8 - * 定时器边界事件类型枚举 8 + * BPM 边界事件 (boundary event) 自定义类型枚举
9 * 9 *
10 * @author jason 10 * @author jason
11 */ 11 */
12 @Getter 12 @Getter
13 @AllArgsConstructor 13 @AllArgsConstructor
14 -public enum BpmTimerBoundaryEventType { 14 +public enum BpmBoundaryEventType {
15 15
16 - USER_TASK_TIMEOUT(1,"用户任务超时"); 16 + USER_TASK_TIMEOUT(1,"用户任务超时"),
  17 + USER_TASK_REJECT_POST_PROCESS(2, "用户任务拒绝后处理");
17 18
18 private final Integer type; 19 private final Integer type;
19 private final String name; 20 private final String name;
20 21
21 - public static BpmTimerBoundaryEventType typeOf(Integer type) { 22 + public static BpmBoundaryEventType typeOf(Integer type) {
22 return ArrayUtil.firstMatch(eventType -> eventType.getType().equals(type), values()); 23 return ArrayUtil.firstMatch(eventType -> eventType.getType().equals(type), values());
23 } 24 }
24 } 25 }
yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmUserTaskRejectHandlerType.java 0 → 100644
  1 +package cn.iocoder.yudao.module.bpm.enums.definition;
  2 +
  3 +import cn.hutool.core.util.ArrayUtil;
  4 +import lombok.AllArgsConstructor;
  5 +import lombok.Getter;
  6 +
  7 +/**
  8 + * BPM 用户任务拒绝处理类型枚举
  9 + *
  10 + * @author jason
  11 + */
  12 +@Getter
  13 +@AllArgsConstructor
  14 +public enum BpmUserTaskRejectHandlerType {
  15 +
  16 + TERMINATION(1, "终止流程"),
  17 + RETURN_PRE_USER_TASK(2, "驳回到用户任务");
  18 +
  19 + private final Integer type;
  20 + private final String name;
  21 +
  22 + public static BpmUserTaskRejectHandlerType typeOf(Integer type) {
  23 + return ArrayUtil.firstMatch(item -> item.getType().equals(type), values());
  24 + }
  25 +}
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmnModelConstants.java
@@ -31,14 +31,24 @@ public interface BpmnModelConstants { @@ -31,14 +31,24 @@ public interface BpmnModelConstants {
31 String USER_TASK_CANDIDATE_PARAM = "candidateParam"; 31 String USER_TASK_CANDIDATE_PARAM = "candidateParam";
32 32
33 /** 33 /**
  34 + * BPMN ExtensionElement 的扩展属性,用于标记边界事件类型
  35 + */
  36 + String BOUNDARY_EVENT_TYPE = "boundaryEventType";
  37 +
  38 + /**
34 * BPMN ExtensionElement 的扩展属性,用于标记用户任务超时执行动作 39 * BPMN ExtensionElement 的扩展属性,用于标记用户任务超时执行动作
35 */ 40 */
36 String USER_TASK_TIMEOUT_HANDLER_ACTION = "timeoutAction"; 41 String USER_TASK_TIMEOUT_HANDLER_ACTION = "timeoutAction";
37 42
38 /** 43 /**
39 - * BPMN ExtensionElement 的扩展属性,用于标记定时边界事件类型 44 + * BPMN ExtensionElement 的扩展属性,用于标记用户任务拒绝处理类型
  45 + */
  46 + String USER_TASK_REJECT_HANDLER_TYPE = "rejectHandlerType";
  47 +
  48 + /**
  49 + * BPMN ExtensionElement 的扩展属性,用于标记用户任务拒绝后的回退的任务 Id
40 */ 50 */
41 - String TIMER_BOUNDARY_EVENT_TYPE = "timerBoundaryEventType"; 51 + String USER_TASK_REJECT_RETURN_TASK_ID = "rejectReturnTaskId";
42 52
43 /** 53 /**
44 * BPMN ExtensionElement 流程表单字段权限元素, 用于标记字段权限 54 * BPMN ExtensionElement 流程表单字段权限元素, 用于标记字段权限
@@ -66,4 +76,5 @@ public interface BpmnModelConstants { @@ -66,4 +76,5 @@ public interface BpmnModelConstants {
66 */ 76 */
67 Set<Class<? extends FlowNode>> SUPPORT_CONVERT_SIMPLE_FlOW_NODES = ImmutableSet.of(UserTask.class, EndEvent.class); 77 Set<Class<? extends FlowNode>> SUPPORT_CONVERT_SIMPLE_FlOW_NODES = ImmutableSet.of(UserTask.class, EndEvent.class);
68 78
  79 + String REJECT_POST_PROCESS_MESSAGE_NAME = "message_reject_post_process";
69 } 80 }
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/BpmTaskEventListener.java
@@ -2,23 +2,41 @@ package cn.iocoder.yudao.module.bpm.framework.flowable.core.listener; @@ -2,23 +2,41 @@ package cn.iocoder.yudao.module.bpm.framework.flowable.core.listener;
2 2
3 import cn.hutool.core.collection.CollUtil; 3 import cn.hutool.core.collection.CollUtil;
4 import cn.hutool.core.util.StrUtil; 4 import cn.hutool.core.util.StrUtil;
  5 +import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
  6 +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskReturnReqVO;
  7 +import cn.iocoder.yudao.module.bpm.enums.definition.BpmUserTaskRejectHandlerType;
  8 +import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskStatusEnum;
  9 +import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants;
  10 +import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils;
  11 +import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils;
  12 +import cn.iocoder.yudao.module.bpm.service.definition.BpmModelService;
5 import cn.iocoder.yudao.module.bpm.service.task.BpmActivityService; 13 import cn.iocoder.yudao.module.bpm.service.task.BpmActivityService;
  14 +import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService;
6 import cn.iocoder.yudao.module.bpm.service.task.BpmTaskService; 15 import cn.iocoder.yudao.module.bpm.service.task.BpmTaskService;
7 import com.google.common.collect.ImmutableSet; 16 import com.google.common.collect.ImmutableSet;
  17 +import jakarta.annotation.Resource;
8 import lombok.extern.slf4j.Slf4j; 18 import lombok.extern.slf4j.Slf4j;
  19 +import org.flowable.bpmn.model.BoundaryEvent;
  20 +import org.flowable.bpmn.model.BpmnModel;
  21 +import org.flowable.bpmn.model.FlowElement;
9 import org.flowable.common.engine.api.delegate.event.FlowableEngineEntityEvent; 22 import org.flowable.common.engine.api.delegate.event.FlowableEngineEntityEvent;
10 import org.flowable.common.engine.api.delegate.event.FlowableEngineEventType; 23 import org.flowable.common.engine.api.delegate.event.FlowableEngineEventType;
11 import org.flowable.engine.delegate.event.AbstractFlowableEngineEventListener; 24 import org.flowable.engine.delegate.event.AbstractFlowableEngineEventListener;
12 import org.flowable.engine.delegate.event.FlowableActivityCancelledEvent; 25 import org.flowable.engine.delegate.event.FlowableActivityCancelledEvent;
  26 +import org.flowable.engine.delegate.event.FlowableMessageEvent;
13 import org.flowable.engine.history.HistoricActivityInstance; 27 import org.flowable.engine.history.HistoricActivityInstance;
14 import org.flowable.task.api.Task; 28 import org.flowable.task.api.Task;
15 import org.springframework.context.annotation.Lazy; 29 import org.springframework.context.annotation.Lazy;
16 import org.springframework.stereotype.Component; 30 import org.springframework.stereotype.Component;
17 31
18 -import jakarta.annotation.Resource;  
19 import java.util.List; 32 import java.util.List;
  33 +import java.util.Objects;
20 import java.util.Set; 34 import java.util.Set;
21 35
  36 +import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId;
  37 +import static cn.iocoder.yudao.module.bpm.enums.definition.BpmBoundaryEventType.USER_TASK_REJECT_POST_PROCESS;
  38 +import static cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils.parseBoundaryEventExtensionElement;
  39 +
22 /** 40 /**
23 * 监听 {@link Task} 的开始与完成 41 * 监听 {@link Task} 的开始与完成
24 * 42 *
@@ -34,15 +52,22 @@ public class BpmTaskEventListener extends AbstractFlowableEngineEventListener { @@ -34,15 +52,22 @@ public class BpmTaskEventListener extends AbstractFlowableEngineEventListener {
34 @Resource 52 @Resource
35 @Lazy // 解决循环依赖 53 @Lazy // 解决循环依赖
36 private BpmActivityService activityService; 54 private BpmActivityService activityService;
  55 + @Resource
  56 + @Lazy // 解决循环依赖
  57 + private BpmProcessInstanceService processInstanceService;
  58 + @Resource
  59 + @Lazy // 延迟加载,避免循环依赖
  60 + private BpmModelService bpmModelService;
37 61
38 public static final Set<FlowableEngineEventType> TASK_EVENTS = ImmutableSet.<FlowableEngineEventType>builder() 62 public static final Set<FlowableEngineEventType> TASK_EVENTS = ImmutableSet.<FlowableEngineEventType>builder()
39 .add(FlowableEngineEventType.TASK_CREATED) 63 .add(FlowableEngineEventType.TASK_CREATED)
40 .add(FlowableEngineEventType.TASK_ASSIGNED) 64 .add(FlowableEngineEventType.TASK_ASSIGNED)
41 -// .add(FlowableEngineEventType.TASK_COMPLETED) // 由于审批通过时,已经记录了 task 的 status 为通过,所以不需要监听了。 65 + //.add(FlowableEngineEventType.TASK_COMPLETED) // 由于审批通过时,已经记录了 task 的 status 为通过,所以不需要监听了。
  66 + .add(FlowableEngineEventType.ACTIVITY_MESSAGE_RECEIVED)
42 .add(FlowableEngineEventType.ACTIVITY_CANCELLED) 67 .add(FlowableEngineEventType.ACTIVITY_CANCELLED)
43 .build(); 68 .build();
44 69
45 - public BpmTaskEventListener(){ 70 + public BpmTaskEventListener() {
46 super(TASK_EVENTS); 71 super(TASK_EVENTS);
47 } 72 }
48 73
@@ -53,7 +78,7 @@ public class BpmTaskEventListener extends AbstractFlowableEngineEventListener { @@ -53,7 +78,7 @@ public class BpmTaskEventListener extends AbstractFlowableEngineEventListener {
53 78
54 @Override 79 @Override
55 protected void taskAssigned(FlowableEngineEntityEvent event) { 80 protected void taskAssigned(FlowableEngineEntityEvent event) {
56 - taskService.updateTaskExtAssign((Task)event.getEntity()); 81 + taskService.updateTaskExtAssign((Task) event.getEntity());
57 } 82 }
58 83
59 @Override 84 @Override
@@ -72,4 +97,47 @@ public class BpmTaskEventListener extends AbstractFlowableEngineEventListener { @@ -72,4 +97,47 @@ public class BpmTaskEventListener extends AbstractFlowableEngineEventListener {
72 }); 97 });
73 } 98 }
74 99
  100 + @Override
  101 + protected void activityMessageReceived(FlowableMessageEvent event) {
  102 + BpmnModel bpmnModel = bpmModelService.getBpmnModelByDefinitionId(event.getProcessDefinitionId());
  103 + FlowElement element = BpmnModelUtils.getFlowElementById(bpmnModel, event.getActivityId());
  104 + if (element instanceof BoundaryEvent) {
  105 + BoundaryEvent boundaryEvent = (BoundaryEvent) element;
  106 + String boundaryEventType = parseBoundaryEventExtensionElement(boundaryEvent, BpmnModelConstants.BOUNDARY_EVENT_TYPE);
  107 + // 如果自定义类型为拒绝后处理,进行拒绝处理
  108 + if (Objects.equals(USER_TASK_REJECT_POST_PROCESS.getType(), NumberUtils.parseInt(boundaryEventType))) {
  109 + String rejectHandlerType = parseBoundaryEventExtensionElement((BoundaryEvent) element, BpmnModelConstants.USER_TASK_REJECT_HANDLER_TYPE);
  110 + rejectHandler(boundaryEvent, event.getProcessInstanceId(), boundaryEvent.getAttachedToRefId(), NumberUtils.parseInt(rejectHandlerType));
  111 + }
  112 + }
  113 + }
  114 +
  115 + private void rejectHandler(BoundaryEvent boundaryEvent, String processInstanceId, String taskDefineKey, Integer rejectHandlerType) {
  116 + BpmUserTaskRejectHandlerType userTaskRejectHandlerType = BpmUserTaskRejectHandlerType.typeOf(rejectHandlerType);
  117 + if (userTaskRejectHandlerType != null) {
  118 + List<Task> taskList = taskService.getAssignedTaskListByConditions(processInstanceId, null, taskDefineKey);
  119 + taskList.forEach(task -> {
  120 + Integer taskStatus = FlowableUtils.getTaskStatus(task);
  121 + // 只有处于拒绝状态下才处理
  122 + if (Objects.equals(BpmTaskStatusEnum.REJECT.getStatus(), taskStatus)) {
  123 + // 终止流程
  124 + if (userTaskRejectHandlerType == BpmUserTaskRejectHandlerType.TERMINATION) {
  125 + processInstanceService.updateProcessInstanceReject(task.getProcessInstanceId(), FlowableUtils.getTaskReason(task));
  126 + return;
  127 + }
  128 + // 驳回
  129 + if (userTaskRejectHandlerType == BpmUserTaskRejectHandlerType.RETURN_PRE_USER_TASK) {
  130 + String returnTaskId = parseBoundaryEventExtensionElement(boundaryEvent, BpmnModelConstants.USER_TASK_REJECT_RETURN_TASK_ID);
  131 + if (returnTaskId != null) {
  132 + BpmTaskReturnReqVO reqVO = new BpmTaskReturnReqVO().setId(task.getId())
  133 + .setTargetTaskDefinitionKey(returnTaskId)
  134 + .setReason("任务拒绝回退");
  135 + taskService.returnTask(getLoginUserId(), reqVO);
  136 + }
  137 + }
  138 + }
  139 + });
  140 + }
  141 + }
  142 +
75 } 143 }
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/BpmTimerFiredEventListener.java
1 package cn.iocoder.yudao.module.bpm.framework.flowable.core.listener; 1 package cn.iocoder.yudao.module.bpm.framework.flowable.core.listener;
2 2
3 -import cn.hutool.core.collection.CollUtil;  
4 import cn.iocoder.yudao.framework.common.util.number.NumberUtils; 3 import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
5 import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; 4 import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
6 import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskApproveReqVO; 5 import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskApproveReqVO;
7 import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRejectReqVO; 6 import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRejectReqVO;
8 -import cn.iocoder.yudao.module.bpm.enums.definition.BpmTimerBoundaryEventType; 7 +import cn.iocoder.yudao.module.bpm.enums.definition.BpmBoundaryEventType;
9 import cn.iocoder.yudao.module.bpm.enums.definition.BpmUserTaskTimeoutActionEnum; 8 import cn.iocoder.yudao.module.bpm.enums.definition.BpmUserTaskTimeoutActionEnum;
10 import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants; 9 import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants;
11 import cn.iocoder.yudao.module.bpm.framework.flowable.core.mq.message.task.TodoTaskReminderMessage; 10 import cn.iocoder.yudao.module.bpm.framework.flowable.core.mq.message.task.TodoTaskReminderMessage;
@@ -18,7 +17,6 @@ import jakarta.annotation.Resource; @@ -18,7 +17,6 @@ import jakarta.annotation.Resource;
18 import lombok.extern.slf4j.Slf4j; 17 import lombok.extern.slf4j.Slf4j;
19 import org.flowable.bpmn.model.BoundaryEvent; 18 import org.flowable.bpmn.model.BoundaryEvent;
20 import org.flowable.bpmn.model.BpmnModel; 19 import org.flowable.bpmn.model.BpmnModel;
21 -import org.flowable.bpmn.model.ExtensionElement;  
22 import org.flowable.bpmn.model.FlowElement; 20 import org.flowable.bpmn.model.FlowElement;
23 import org.flowable.common.engine.api.delegate.event.FlowableEngineEntityEvent; 21 import org.flowable.common.engine.api.delegate.event.FlowableEngineEntityEvent;
24 import org.flowable.common.engine.api.delegate.event.FlowableEngineEventType; 22 import org.flowable.common.engine.api.delegate.event.FlowableEngineEventType;
@@ -29,7 +27,6 @@ import org.springframework.context.annotation.Lazy; @@ -29,7 +27,6 @@ import org.springframework.context.annotation.Lazy;
29 import org.springframework.stereotype.Component; 27 import org.springframework.stereotype.Component;
30 28
31 import java.util.List; 29 import java.util.List;
32 -import java.util.Optional;  
33 import java.util.Set; 30 import java.util.Set;
34 31
35 /** 32 /**
@@ -69,23 +66,21 @@ public class BpmTimerFiredEventListener extends AbstractFlowableEngineEventListe @@ -69,23 +66,21 @@ public class BpmTimerFiredEventListener extends AbstractFlowableEngineEventListe
69 // 如果是定时器边界事件 66 // 如果是定时器边界事件
70 if (element instanceof BoundaryEvent) { 67 if (element instanceof BoundaryEvent) {
71 BoundaryEvent boundaryEvent = (BoundaryEvent) element; 68 BoundaryEvent boundaryEvent = (BoundaryEvent) element;
72 - ExtensionElement extensionElement = CollUtil.getFirst(boundaryEvent.getExtensionElements().get(BpmnModelConstants.TIMER_BOUNDARY_EVENT_TYPE));  
73 - Integer timerBoundaryEventType = NumberUtils.parseInt(Optional.ofNullable(extensionElement).map(ExtensionElement::getElementText).orElse(null));  
74 - BpmTimerBoundaryEventType bpmTimerBoundaryEventType = BpmTimerBoundaryEventType.typeOf(timerBoundaryEventType); 69 + String boundaryEventType = BpmnModelUtils.parseBoundaryEventExtensionElement(boundaryEvent, BpmnModelConstants.BOUNDARY_EVENT_TYPE);
  70 + BpmBoundaryEventType bpmTimerBoundaryEventType = BpmBoundaryEventType.typeOf(NumberUtils.parseInt(boundaryEventType));
75 // 类型为用户任务超时未处理的情况 71 // 类型为用户任务超时未处理的情况
76 - if (bpmTimerBoundaryEventType == BpmTimerBoundaryEventType.USER_TASK_TIMEOUT) {  
77 - ExtensionElement timeoutActionElement = CollUtil.getFirst(boundaryEvent.getExtensionElements().get(BpmnModelConstants.USER_TASK_TIMEOUT_HANDLER_ACTION));  
78 - Integer timeoutAction = NumberUtils.parseInt(Optional.ofNullable(timeoutActionElement).map(ExtensionElement::getElementText).orElse(null));  
79 - processUserTaskTimeout(event.getProcessInstanceId(), boundaryEvent.getAttachedToRefId(), timeoutAction); 72 + if (bpmTimerBoundaryEventType == BpmBoundaryEventType.USER_TASK_TIMEOUT) {
  73 + String timeoutAction = BpmnModelUtils.parseBoundaryEventExtensionElement(boundaryEvent, BpmnModelConstants.USER_TASK_TIMEOUT_HANDLER_ACTION);
  74 + userTaskTimeoutHandler(event.getProcessInstanceId(), boundaryEvent.getAttachedToRefId(), NumberUtils.parseInt(timeoutAction));
80 } 75 }
81 } 76 }
82 } 77 }
83 78
84 - private void processUserTaskTimeout(String processInstanceId, String taskDefKey, Integer timeoutAction) { 79 + private void userTaskTimeoutHandler(String processInstanceId, String taskDefKey, Integer timeoutAction) {
85 BpmUserTaskTimeoutActionEnum userTaskTimeoutAction = BpmUserTaskTimeoutActionEnum.actionOf(timeoutAction); 80 BpmUserTaskTimeoutActionEnum userTaskTimeoutAction = BpmUserTaskTimeoutActionEnum.actionOf(timeoutAction);
86 if (userTaskTimeoutAction != null) { 81 if (userTaskTimeoutAction != null) {
87 - // 查询超时未处理的任务  
88 - List<Task> taskList = bpmTaskService.getAssignedTaskListByConditions(processInstanceId, taskDefKey); 82 + // 查询超时未处理的任务 TODO 加签的情况会不会有问题 ???
  83 + List<Task> taskList = bpmTaskService.getAssignedTaskListByConditions(processInstanceId, null, taskDefKey);
89 taskList.forEach(task -> { 84 taskList.forEach(task -> {
90 // 自动提醒 85 // 自动提醒
91 if (userTaskTimeoutAction == BpmUserTaskTimeoutActionEnum.AUTO_REMINDER) { 86 if (userTaskTimeoutAction == BpmUserTaskTimeoutActionEnum.AUTO_REMINDER) {
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/simple/SimpleModelUserTaskConfig.java
1 package cn.iocoder.yudao.module.bpm.framework.flowable.core.simple; 1 package cn.iocoder.yudao.module.bpm.framework.flowable.core.simple;
2 2
  3 +import cn.iocoder.yudao.module.bpm.enums.definition.BpmUserTaskRejectHandlerType;
3 import lombok.Data; 4 import lombok.Data;
4 5
5 import java.util.List; 6 import java.util.List;
@@ -33,12 +34,15 @@ public class SimpleModelUserTaskConfig { @@ -33,12 +34,15 @@ public class SimpleModelUserTaskConfig {
33 */ 34 */
34 private Integer approveMethod; 35 private Integer approveMethod;
35 36
36 -  
37 /** 37 /**
38 * 超时处理 38 * 超时处理
39 */ 39 */
40 private TimeoutHandler timeoutHandler; 40 private TimeoutHandler timeoutHandler;
41 41
  42 + /**
  43 + * 用户任务拒绝处理
  44 + */
  45 + private RejectHandler rejectHandler;
42 46
43 @Data 47 @Data
44 public static class TimeoutHandler { 48 public static class TimeoutHandler {
@@ -62,7 +66,20 @@ public class SimpleModelUserTaskConfig { @@ -62,7 +66,20 @@ public class SimpleModelUserTaskConfig {
62 * 如果执行动作是自动提醒, 最大提醒次数 66 * 如果执行动作是自动提醒, 最大提醒次数
63 */ 67 */
64 private Integer maxRemindCount; 68 private Integer maxRemindCount;
  69 + }
  70 +
  71 + @Data
  72 + public static class RejectHandler {
65 73
  74 + /**
  75 + * 用户任务拒绝处理类型 {@link BpmUserTaskRejectHandlerType}
  76 + */
  77 + private Integer type;
  78 +
  79 + /**
  80 + * 用户任务拒绝后驳回的节点 Id
  81 + */
  82 + private String returnNodeId;
66 } 83 }
67 84
68 } 85 }
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java
@@ -5,6 +5,7 @@ import cn.hutool.core.map.MapUtil; @@ -5,6 +5,7 @@ import cn.hutool.core.map.MapUtil;
5 import cn.hutool.core.util.ArrayUtil; 5 import cn.hutool.core.util.ArrayUtil;
6 import cn.hutool.core.util.StrUtil; 6 import cn.hutool.core.util.StrUtil;
7 import cn.iocoder.yudao.framework.common.util.number.NumberUtils; 7 import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
  8 +import cn.iocoder.yudao.module.bpm.enums.definition.BpmBoundaryEventType;
8 import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants; 9 import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants;
9 import org.flowable.bpmn.converter.BpmnXMLConverter; 10 import org.flowable.bpmn.converter.BpmnXMLConverter;
10 import org.flowable.bpmn.model.Process; 11 import org.flowable.bpmn.model.Process;
@@ -360,4 +361,32 @@ public class BpmnModelUtils { @@ -360,4 +361,32 @@ public class BpmnModelUtils {
360 return userTaskList; 361 return userTaskList;
361 } 362 }
362 363
  364 + /**
  365 + * 在用户任务中查找自定义的边界事件
  366 + *
  367 + * @param userTask 用户任务
  368 + * @param bpmBoundaryEventType 自定义的边界事件类型
  369 + */
  370 + public static BoundaryEvent findCustomBoundaryEventOfUserTask(UserTask userTask, BpmBoundaryEventType bpmBoundaryEventType) {
  371 + if (userTask == null) {
  372 + return null;
  373 + }
  374 + BoundaryEvent result = null;
  375 + for (BoundaryEvent item : userTask.getBoundaryEvents()) {
  376 + String boundaryEventType = parseBoundaryEventExtensionElement(item, BpmnModelConstants.BOUNDARY_EVENT_TYPE);
  377 + if (Objects.equals(bpmBoundaryEventType.getType(), NumberUtils.parseInt(boundaryEventType))) {
  378 + result = item;
  379 + break;
  380 + }
  381 + }
  382 + return result;
  383 + }
  384 +
  385 + public static String parseBoundaryEventExtensionElement(BoundaryEvent boundaryEvent, String customElement) {
  386 + if (boundaryEvent == null) {
  387 + return null;
  388 + }
  389 + ExtensionElement extensionElement = CollUtil.getFirst(boundaryEvent.getExtensionElements().get(customElement));
  390 + return Optional.ofNullable(extensionElement).map(ExtensionElement::getElementText).orElse(null);
  391 + }
363 } 392 }
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java
@@ -14,6 +14,7 @@ import cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeType; @@ -14,6 +14,7 @@ import cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeType;
14 import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants; 14 import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants;
15 import cn.iocoder.yudao.module.bpm.framework.flowable.core.simple.SimpleModelConditionGroups; 15 import cn.iocoder.yudao.module.bpm.framework.flowable.core.simple.SimpleModelConditionGroups;
16 import cn.iocoder.yudao.module.bpm.framework.flowable.core.simple.SimpleModelUserTaskConfig; 16 import cn.iocoder.yudao.module.bpm.framework.flowable.core.simple.SimpleModelUserTaskConfig;
  17 +import cn.iocoder.yudao.module.bpm.framework.flowable.core.simple.SimpleModelUserTaskConfig.RejectHandler;
17 import org.flowable.bpmn.BpmnAutoLayout; 18 import org.flowable.bpmn.BpmnAutoLayout;
18 import org.flowable.bpmn.model.Process; 19 import org.flowable.bpmn.model.Process;
19 import org.flowable.bpmn.model.*; 20 import org.flowable.bpmn.model.*;
@@ -22,13 +23,14 @@ import java.util.List; @@ -22,13 +23,14 @@ import java.util.List;
22 import java.util.Map; 23 import java.util.Map;
23 import java.util.Objects; 24 import java.util.Objects;
24 25
  26 +import static cn.iocoder.yudao.module.bpm.enums.definition.BpmBoundaryEventType.USER_TASK_REJECT_POST_PROCESS;
  27 +import static cn.iocoder.yudao.module.bpm.enums.definition.BpmBoundaryEventType.USER_TASK_TIMEOUT;
25 import static cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeType.END_EVENT; 28 import static cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeType.END_EVENT;
26 -import static cn.iocoder.yudao.module.bpm.enums.definition.BpmTimerBoundaryEventType.USER_TASK_TIMEOUT; 29 +import static cn.iocoder.yudao.module.bpm.enums.definition.BpmUserTaskRejectHandlerType.RETURN_PRE_USER_TASK;
27 import static cn.iocoder.yudao.module.bpm.enums.definition.BpmUserTaskTimeoutActionEnum.AUTO_REMINDER; 30 import static cn.iocoder.yudao.module.bpm.enums.definition.BpmUserTaskTimeoutActionEnum.AUTO_REMINDER;
28 import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.*; 31 import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.*;
29 import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.SimpleModelConstants.*; 32 import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.SimpleModelConstants.*;
30 -import static org.flowable.bpmn.constants.BpmnXMLConstants.FLOWABLE_EXTENSIONS_NAMESPACE;  
31 -import static org.flowable.bpmn.constants.BpmnXMLConstants.FLOWABLE_EXTENSIONS_PREFIX; 33 +import static org.flowable.bpmn.constants.BpmnXMLConstants.*;
32 34
33 /** 35 /**
34 * 仿钉钉快搭模型相关的工具方法 36 * 仿钉钉快搭模型相关的工具方法
@@ -42,12 +44,12 @@ public class SimpleModelUtils { @@ -42,12 +44,12 @@ public class SimpleModelUtils {
42 /** 44 /**
43 * 所有审批人同意的表达式 45 * 所有审批人同意的表达式
44 */ 46 */
45 - public static final String ALL_APPROVE_COMPLETE_EXPRESSION = "${ nrOfCompletedInstances >= 0 }"; 47 + public static final String ALL_APPROVE_COMPLETE_EXPRESSION = "${ nrOfCompletedInstances >= nrOfInstances }";
46 48
47 /** 49 /**
48 * 任一一名审批人同意的表达式 50 * 任一一名审批人同意的表达式
49 */ 51 */
50 - public static final String ANY_OF_APPROVE_COMPLETE_EXPRESSION = "${ nrOfCompletedInstances >= nrOfInstances }"; 52 + public static final String ANY_OF_APPROVE_COMPLETE_EXPRESSION = "${ nrOfCompletedInstances > 0 }";
51 53
52 /** 54 /**
53 * 仿钉钉流程设计模型数据结构(json) 转换成 Bpmn Model (待完善) 55 * 仿钉钉流程设计模型数据结构(json) 转换成 Bpmn Model (待完善)
@@ -59,6 +61,12 @@ public class SimpleModelUtils { @@ -59,6 +61,12 @@ public class SimpleModelUtils {
59 */ 61 */
60 public static BpmnModel convertSimpleModelToBpmnModel(String processId, String processName, BpmSimpleModelNodeVO simpleModelNode) { 62 public static BpmnModel convertSimpleModelToBpmnModel(String processId, String processName, BpmSimpleModelNodeVO simpleModelNode) {
61 BpmnModel bpmnModel = new BpmnModel(); 63 BpmnModel bpmnModel = new BpmnModel();
  64 + // 不加这个 解析 Message 会报 NPE 异常
  65 + bpmnModel.setTargetNamespace(BPMN2_NAMESPACE);
  66 + Message rejectPostProcessMsg = new Message();
  67 + rejectPostProcessMsg.setName(REJECT_POST_PROCESS_MESSAGE_NAME);
  68 + bpmnModel.addMessage(rejectPostProcessMsg);
  69 +
62 Process mainProcess = new Process(); 70 Process mainProcess = new Process();
63 mainProcess.setId(processId); 71 mainProcess.setId(processId);
64 mainProcess.setName(processName); 72 mainProcess.setName(processName);
@@ -214,6 +222,12 @@ public class SimpleModelUtils { @@ -214,6 +222,12 @@ public class SimpleModelUtils {
214 BoundaryEvent boundaryEvent = buildUserTaskTimerBoundaryEvent(userTask, userTaskConfig.getTimeoutHandler()); 222 BoundaryEvent boundaryEvent = buildUserTaskTimerBoundaryEvent(userTask, userTaskConfig.getTimeoutHandler());
215 mainProcess.addFlowElement(boundaryEvent); 223 mainProcess.addFlowElement(boundaryEvent);
216 } 224 }
  225 + if (userTaskConfig.getRejectHandler() != null) {
  226 + // 添加用户任务拒绝 Message Boundary Event, 用于任务的拒绝处理
  227 + BoundaryEvent boundaryEvent = buildUserTaskRejectBoundaryEvent(userTask, userTaskConfig.getRejectHandler());
  228 + mainProcess.addFlowElement(boundaryEvent);
  229 + }
  230 +
217 break; 231 break;
218 } 232 }
219 case COPY_TASK: { 233 case COPY_TASK: {
@@ -270,10 +284,27 @@ public class SimpleModelUtils { @@ -270,10 +284,27 @@ public class SimpleModelUtils {
270 } 284 }
271 } 285 }
272 286
  287 + private static BoundaryEvent buildUserTaskRejectBoundaryEvent(UserTask userTask, RejectHandler rejectHandler) {
  288 + BoundaryEvent messageBoundaryEvent = new BoundaryEvent();
  289 + messageBoundaryEvent.setId("Event-" + IdUtil.fastUUID());
  290 + // 设置关联的任务为不会被中断
  291 + messageBoundaryEvent.setCancelActivity(false);
  292 + messageBoundaryEvent.setAttachedToRef(userTask);
  293 + MessageEventDefinition messageEventDefinition = new MessageEventDefinition();
  294 + messageEventDefinition.setMessageRef(REJECT_POST_PROCESS_MESSAGE_NAME);
  295 + messageBoundaryEvent.addEventDefinition(messageEventDefinition);
  296 + addExtensionElement(messageBoundaryEvent, BOUNDARY_EVENT_TYPE, USER_TASK_REJECT_POST_PROCESS.getType().toString());
  297 + addExtensionElement(messageBoundaryEvent, USER_TASK_REJECT_HANDLER_TYPE, StrUtil.toStringOrNull(rejectHandler.getType()));
  298 + if (Objects.equals(rejectHandler.getType(), RETURN_PRE_USER_TASK.getType())) {
  299 + addExtensionElement(messageBoundaryEvent, USER_TASK_REJECT_RETURN_TASK_ID, rejectHandler.getReturnNodeId());
  300 + }
  301 + return messageBoundaryEvent;
  302 + }
  303 +
273 private static BoundaryEvent buildUserTaskTimerBoundaryEvent(UserTask userTask, SimpleModelUserTaskConfig.TimeoutHandler timeoutHandler) { 304 private static BoundaryEvent buildUserTaskTimerBoundaryEvent(UserTask userTask, SimpleModelUserTaskConfig.TimeoutHandler timeoutHandler) {
274 // 定时器边界事件 305 // 定时器边界事件
275 BoundaryEvent boundaryEvent = new BoundaryEvent(); 306 BoundaryEvent boundaryEvent = new BoundaryEvent();
276 - boundaryEvent.setId(IdUtil.fastUUID()); 307 + boundaryEvent.setId("Event-" + IdUtil.fastUUID());
277 // 设置关联的任务为不会被中断 308 // 设置关联的任务为不会被中断
278 boundaryEvent.setCancelActivity(false); 309 boundaryEvent.setCancelActivity(false);
279 boundaryEvent.setAttachedToRef(userTask); 310 boundaryEvent.setAttachedToRef(userTask);
@@ -286,7 +317,7 @@ public class SimpleModelUtils { @@ -286,7 +317,7 @@ public class SimpleModelUtils {
286 } 317 }
287 boundaryEvent.addEventDefinition(eventDefinition); 318 boundaryEvent.addEventDefinition(eventDefinition);
288 // 添加定时器边界事件类型 319 // 添加定时器边界事件类型
289 - addExtensionElement(boundaryEvent, TIMER_BOUNDARY_EVENT_TYPE, USER_TASK_TIMEOUT.getType().toString()); 320 + addExtensionElement(boundaryEvent, BOUNDARY_EVENT_TYPE, USER_TASK_TIMEOUT.getType().toString());
290 // 添加超时执行动作元素 321 // 添加超时执行动作元素
291 addExtensionElement(boundaryEvent, USER_TASK_TIMEOUT_HANDLER_ACTION, StrUtil.toStringOrNull(timeoutHandler.getAction())); 322 addExtensionElement(boundaryEvent, USER_TASK_TIMEOUT_HANDLER_ACTION, StrUtil.toStringOrNull(timeoutHandler.getAction()));
292 return boundaryEvent; 323 return boundaryEvent;
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskService.java
@@ -90,6 +90,8 @@ public interface BpmTaskService { @@ -90,6 +90,8 @@ public interface BpmTaskService {
90 */ 90 */
91 void rejectTask(Long userId, @Valid BpmTaskRejectReqVO reqVO); 91 void rejectTask(Long userId, @Valid BpmTaskRejectReqVO reqVO);
92 92
  93 +
  94 +
93 /** 95 /**
94 * 将流程任务分配给指定用户 96 * 将流程任务分配给指定用户
95 * 97 *
@@ -129,10 +131,11 @@ public interface BpmTaskService { @@ -129,10 +131,11 @@ public interface BpmTaskService {
129 131
130 /** 132 /**
131 * 根据条件查询已经分配的用户任务列表 133 * 根据条件查询已经分配的用户任务列表
132 - * @param processInstanceId 流程实例编号 134 + * @param processInstanceId 流程实例编号,不允许为空
  135 + * @param executionId execution Id
133 * @param taskDefineKey 任务定义 Key 136 * @param taskDefineKey 任务定义 Key
134 */ 137 */
135 - List<Task> getAssignedTaskListByConditions(String processInstanceId, String taskDefineKey); 138 + List<Task> getAssignedTaskListByConditions(String processInstanceId, String executionId, String taskDefineKey);
136 139
137 /** 140 /**
138 * 获取当前任务的可回退的 UserTask 集合 141 * 获取当前任务的可回退的 UserTask 集合
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java
@@ -9,16 +9,18 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; @@ -9,16 +9,18 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
9 import cn.iocoder.yudao.framework.common.util.date.DateUtils; 9 import cn.iocoder.yudao.framework.common.util.date.DateUtils;
10 import cn.iocoder.yudao.framework.common.util.number.NumberUtils; 10 import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
11 import cn.iocoder.yudao.framework.common.util.object.PageUtils; 11 import cn.iocoder.yudao.framework.common.util.object.PageUtils;
12 -import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils;  
13 -import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils;  
14 import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; 12 import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
15 import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*; 13 import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*;
16 import cn.iocoder.yudao.module.bpm.convert.task.BpmTaskConvert; 14 import cn.iocoder.yudao.module.bpm.convert.task.BpmTaskConvert;
  15 +import cn.iocoder.yudao.module.bpm.enums.definition.BpmBoundaryEventType;
17 import cn.iocoder.yudao.module.bpm.enums.task.BpmCommentTypeEnum; 16 import cn.iocoder.yudao.module.bpm.enums.task.BpmCommentTypeEnum;
18 import cn.iocoder.yudao.module.bpm.enums.task.BpmDeleteReasonEnum; 17 import cn.iocoder.yudao.module.bpm.enums.task.BpmDeleteReasonEnum;
19 import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskSignTypeEnum; 18 import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskSignTypeEnum;
20 import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskStatusEnum; 19 import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskStatusEnum;
21 import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmConstants; 20 import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmConstants;
  21 +import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants;
  22 +import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils;
  23 +import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils;
22 import cn.iocoder.yudao.module.bpm.service.definition.BpmModelService; 24 import cn.iocoder.yudao.module.bpm.service.definition.BpmModelService;
23 import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; 25 import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService;
24 import cn.iocoder.yudao.module.system.api.user.AdminUserApi; 26 import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
@@ -26,6 +28,7 @@ import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; @@ -26,6 +28,7 @@ import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
26 import jakarta.annotation.Resource; 28 import jakarta.annotation.Resource;
27 import jakarta.validation.Valid; 29 import jakarta.validation.Valid;
28 import lombok.extern.slf4j.Slf4j; 30 import lombok.extern.slf4j.Slf4j;
  31 +import org.flowable.bpmn.model.BoundaryEvent;
29 import org.flowable.bpmn.model.BpmnModel; 32 import org.flowable.bpmn.model.BpmnModel;
30 import org.flowable.bpmn.model.FlowElement; 33 import org.flowable.bpmn.model.FlowElement;
31 import org.flowable.bpmn.model.UserTask; 34 import org.flowable.bpmn.model.UserTask;
@@ -33,6 +36,7 @@ import org.flowable.engine.HistoryService; @@ -33,6 +36,7 @@ import org.flowable.engine.HistoryService;
33 import org.flowable.engine.ManagementService; 36 import org.flowable.engine.ManagementService;
34 import org.flowable.engine.RuntimeService; 37 import org.flowable.engine.RuntimeService;
35 import org.flowable.engine.TaskService; 38 import org.flowable.engine.TaskService;
  39 +import org.flowable.engine.runtime.Execution;
36 import org.flowable.engine.runtime.ProcessInstance; 40 import org.flowable.engine.runtime.ProcessInstance;
37 import org.flowable.task.api.DelegationState; 41 import org.flowable.task.api.DelegationState;
38 import org.flowable.task.api.Task; 42 import org.flowable.task.api.Task;
@@ -245,7 +249,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { @@ -245,7 +249,7 @@ public class BpmTaskServiceImpl implements BpmTaskService {
245 249
246 /** 250 /**
247 * 如果父任务是有前后【加签】的任务,如果它【加签】出来的子任务都被处理,需要处理父任务: 251 * 如果父任务是有前后【加签】的任务,如果它【加签】出来的子任务都被处理,需要处理父任务:
248 - * 252 + * <p>
249 * 1. 如果是【向前】加签,则需要重新激活父任务,让它可以被审批 253 * 1. 如果是【向前】加签,则需要重新激活父任务,让它可以被审批
250 * 2. 如果是【向后】加签,则需要完成父任务,让它完成审批 254 * 2. 如果是【向后】加签,则需要完成父任务,让它完成审批
251 * 255 *
@@ -278,7 +282,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { @@ -278,7 +282,7 @@ public class BpmTaskServiceImpl implements BpmTaskService {
278 taskService.resolveTask(parentTaskId); 282 taskService.resolveTask(parentTaskId);
279 // 3.1.2 更新流程任务 status 283 // 3.1.2 更新流程任务 status
280 updateTaskStatus(parentTaskId, BpmTaskStatusEnum.RUNNING.getStatus()); 284 updateTaskStatus(parentTaskId, BpmTaskStatusEnum.RUNNING.getStatus());
281 - // 3.2 情况二:处理向【向后】加签 285 + // 3.2 情况二:处理向【向后】加签
282 } else if (BpmTaskSignTypeEnum.AFTER.getType().equals(scopeType)) { 286 } else if (BpmTaskSignTypeEnum.AFTER.getType().equals(scopeType)) {
283 // 只有 parentTask 处于 APPROVING 的情况下,才可以继续 complete 完成 287 // 只有 parentTask 处于 APPROVING 的情况下,才可以继续 complete 完成
284 // 否则,一个未审批的 parentTask 任务,在加签出来的任务都被减签的情况下,就直接完成审批,这样会存在问题 288 // 否则,一个未审批的 parentTask 任务,在加签出来的任务都被减签的情况下,就直接完成审批,这样会存在问题
@@ -333,14 +337,29 @@ public class BpmTaskServiceImpl implements BpmTaskService { @@ -333,14 +337,29 @@ public class BpmTaskServiceImpl implements BpmTaskService {
333 taskService.addComment(task.getId(), task.getProcessInstanceId(), BpmCommentTypeEnum.REJECT.getType(), 337 taskService.addComment(task.getId(), task.getProcessInstanceId(), BpmCommentTypeEnum.REJECT.getType(),
334 BpmCommentTypeEnum.REJECT.formatComment(reqVO.getReason())); 338 BpmCommentTypeEnum.REJECT.formatComment(reqVO.getReason()));
335 339
336 - // 3. 更新流程实例,审批不通过! 340 + BpmnModel bpmnModel = bpmModelService.getBpmnModelByDefinitionId(task.getProcessDefinitionId());
  341 + FlowElement flowElement = BpmnModelUtils.getFlowElementById(bpmnModel, task.getTaskDefinitionKey());
  342 + // 寻找用户任务的自定义拒绝后处理边界事件
  343 + BoundaryEvent rejectBoundaryEvent = BpmnModelUtils.findCustomBoundaryEventOfUserTask((UserTask) flowElement,
  344 + BpmBoundaryEventType.USER_TASK_REJECT_POST_PROCESS);
  345 +
  346 + if (rejectBoundaryEvent != null) {
  347 + Execution execution = runtimeService.createExecutionQuery().processInstanceId(task.getProcessInstanceId())
  348 + .activityId(rejectBoundaryEvent.getId()).singleResult();
  349 + if (execution != null) {
  350 + // 3.1 触发消息边界事件. 进一步的处理交给 BpmTaskEventListener
  351 + runtimeService.messageEventReceived(BpmnModelConstants.REJECT_POST_PROCESS_MESSAGE_NAME, execution.getId());
  352 + return;
  353 + }
  354 + }
  355 + // 3.2 没有找到拒绝后处理边界事件, 更新流程实例,审批不通过!
337 processInstanceService.updateProcessInstanceReject(instance.getProcessInstanceId(), reqVO.getReason()); 356 processInstanceService.updateProcessInstanceReject(instance.getProcessInstanceId(), reqVO.getReason());
338 } 357 }
339 358
340 /** 359 /**
341 * 更新流程任务的 status 状态 360 * 更新流程任务的 status 状态
342 * 361 *
343 - * @param id 任务编号 362 + * @param id 任务编号
344 * @param status 状态 363 * @param status 状态
345 */ 364 */
346 private void updateTaskStatus(String id, Integer status) { 365 private void updateTaskStatus(String id, Integer status) {
@@ -350,7 +369,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { @@ -350,7 +369,7 @@ public class BpmTaskServiceImpl implements BpmTaskService {
350 /** 369 /**
351 * 更新流程任务的 status 状态、reason 理由 370 * 更新流程任务的 status 状态、reason 理由
352 * 371 *
353 - * @param id 任务编号 372 + * @param id 任务编号
354 * @param status 状态 373 * @param status 状态
355 * @param reason 理由(审批通过、审批不通过的理由) 374 * @param reason 理由(审批通过、审批不通过的理由)
356 */ 375 */
@@ -434,9 +453,16 @@ public class BpmTaskServiceImpl implements BpmTaskService { @@ -434,9 +453,16 @@ public class BpmTaskServiceImpl implements BpmTaskService {
434 } 453 }
435 454
436 @Override 455 @Override
437 - public List<Task> getAssignedTaskListByConditions(String processInstanceId, String defineKey) {  
438 - TaskQuery taskQuery = taskService.createTaskQuery().processInstanceId(processInstanceId)  
439 - .taskDefinitionKey(defineKey).active().taskAssigned().includeTaskLocalVariables(); 456 + public List<Task> getAssignedTaskListByConditions(String processInstanceId, String executionId, String defineKey) {
  457 + Assert.notNull(processInstanceId, "processInstanceId 不能为空");
  458 + TaskQuery taskQuery = taskService.createTaskQuery().taskAssigned().processInstanceId(processInstanceId).active()
  459 + .includeTaskLocalVariables();
  460 + if (StrUtil.isNotEmpty(executionId)) {
  461 + taskQuery.executionId(executionId);
  462 + }
  463 + if (StrUtil.isNotEmpty(defineKey)) {
  464 + taskQuery.taskDefinitionKey(defineKey);
  465 + }
440 return taskQuery.list(); 466 return taskQuery.list();
441 } 467 }
442 468
@@ -664,7 +690,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { @@ -664,7 +690,7 @@ public class BpmTaskServiceImpl implements BpmTaskService {
664 List<Long> currentAssigneeList = convertListByFlatMap(taskList, task -> // 需要考虑 owner 的情况,因为向后加签时,它暂时没 assignee 而是 owner 690 List<Long> currentAssigneeList = convertListByFlatMap(taskList, task -> // 需要考虑 owner 的情况,因为向后加签时,它暂时没 assignee 而是 owner
665 Stream.of(NumberUtils.parseLong(task.getAssignee()), NumberUtils.parseLong(task.getOwner()))); 691 Stream.of(NumberUtils.parseLong(task.getAssignee()), NumberUtils.parseLong(task.getOwner())));
666 if (CollUtil.containsAny(currentAssigneeList, reqVO.getUserIds())) { 692 if (CollUtil.containsAny(currentAssigneeList, reqVO.getUserIds())) {
667 - List<AdminUserRespDTO> userList = adminUserApi.getUserList( CollUtil.intersection(currentAssigneeList, reqVO.getUserIds())); 693 + List<AdminUserRespDTO> userList = adminUserApi.getUserList(CollUtil.intersection(currentAssigneeList, reqVO.getUserIds()));
668 throw exception(TASK_SIGN_CREATE_USER_REPEAT, String.join(",", convertList(userList, AdminUserRespDTO::getNickname))); 694 throw exception(TASK_SIGN_CREATE_USER_REPEAT, String.join(",", convertList(userList, AdminUserRespDTO::getNickname)));
669 } 695 }
670 return taskEntity; 696 return taskEntity;
@@ -673,8 +699,8 @@ public class BpmTaskServiceImpl implements BpmTaskService { @@ -673,8 +699,8 @@ public class BpmTaskServiceImpl implements BpmTaskService {
673 /** 699 /**
674 * 创建加签子任务 700 * 创建加签子任务
675 * 701 *
676 - * @param userIds 被加签的用户 ID  
677 - * @param taskEntity 被加签的任务 702 + * @param userIds 被加签的用户 ID
  703 + * @param taskEntity 被加签的任务
678 */ 704 */
679 private void createSignTaskList(List<String> userIds, TaskEntityImpl taskEntity) { 705 private void createSignTaskList(List<String> userIds, TaskEntityImpl taskEntity) {
680 if (CollUtil.isEmpty(userIds)) { 706 if (CollUtil.isEmpty(userIds)) {
@@ -703,7 +729,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { @@ -703,7 +729,7 @@ public class BpmTaskServiceImpl implements BpmTaskService {
703 // 2.1 向前加签,设置审批人 729 // 2.1 向前加签,设置审批人
704 if (BpmTaskSignTypeEnum.BEFORE.getType().equals(parentTask.getScopeType())) { 730 if (BpmTaskSignTypeEnum.BEFORE.getType().equals(parentTask.getScopeType())) {
705 task.setAssignee(assignee); 731 task.setAssignee(assignee);
706 - // 2.2 向后加签,设置 owner 不设置 assignee 是因为不能同时审批,需要等父任务完成 732 + // 2.2 向后加签,设置 owner 不设置 assignee 是因为不能同时审批,需要等父任务完成
707 } else { 733 } else {
708 task.setOwner(assignee); 734 task.setOwner(assignee);
709 } 735 }