Browse Source

【功能重构】工作流:重构流程不通过、取消的处理逻辑,完全转向 flowable 的 moveActivityIdsToSingleActivityId API

YunaiV 11 months ago
parent
commit
32804d3e0b

+ 2 - 8
yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmDeleteReasonEnum.java → yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmReasonEnum.java

@@ -5,13 +5,13 @@ import lombok.AllArgsConstructor;
 import lombok.Getter;
 
 /**
- * 流程实例/任务的删除原因枚举
+ * 流程实例/任务的的处理原因枚举
  *
  * @author 芋道源码
  */
 @Getter
 @AllArgsConstructor
-public enum BpmDeleteReasonEnum {
+public enum BpmReasonEnum {
 
     // ========== 流程实例的独有原因 ==========
 
@@ -36,10 +36,4 @@ public enum BpmDeleteReasonEnum {
         return StrUtil.format(reason, args);
     }
 
-    // ========== 逻辑 ==========
-
-    public static boolean isRejectReason(String reason) {
-        return StrUtil.startWith(reason, "审批不通过任务,原因:");
-    }
-
 }

+ 0 - 5
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java

@@ -89,11 +89,6 @@ public interface BpmProcessInstanceConvert {
     @Mapping(source = "from.id", target = "to.id", ignore = true)
     void copyTo(BpmProcessDefinitionInfoDO from, @MappingTarget BpmProcessDefinitionRespVO to);
 
-    default BpmProcessInstanceStatusEvent buildProcessInstanceStatusEvent(Object source, HistoricProcessInstance instance, Integer status) {
-        return new BpmProcessInstanceStatusEvent(source).setId(instance.getId()).setStatus(status)
-                .setProcessDefinitionKey(instance.getProcessDefinitionKey()).setBusinessKey(instance.getBusinessKey());
-    }
-
     default BpmProcessInstanceStatusEvent buildProcessInstanceStatusEvent(Object source, ProcessInstance instance, Integer status) {;
         return new BpmProcessInstanceStatusEvent(source).setId(instance.getId()).setStatus(status)
                 .setProcessDefinitionKey(instance.getProcessDefinitionKey()).setBusinessKey(instance.getBusinessKey());

+ 8 - 0
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmConstants.java

@@ -15,6 +15,14 @@ public class BpmConstants {
      * @see ProcessInstance#getProcessVariables()
      */
     public static final String PROCESS_INSTANCE_VARIABLE_STATUS = "PROCESS_STATUS";
+    /**
+     * 流程实例的变量 - 理由
+     *
+     * 例如说:审批不通过的理由(目前审核通过暂时不会记录)
+     *
+     * @see ProcessInstance#getProcessVariables()
+     */
+    public static final String PROCESS_INSTANCE_VARIABLE_REASON = "PROCESS_REASON";
     /**
      * 流程实例的变量 - 发起用户选择的审批人 Map
      *

+ 5 - 12
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/BpmProcessInstanceEventListener.java

@@ -6,7 +6,6 @@ import jakarta.annotation.Resource;
 import org.flowable.common.engine.api.delegate.event.FlowableEngineEntityEvent;
 import org.flowable.common.engine.api.delegate.event.FlowableEngineEventType;
 import org.flowable.engine.delegate.event.AbstractFlowableEngineEventListener;
-import org.flowable.engine.delegate.event.FlowableCancelledEvent;
 import org.flowable.engine.runtime.ProcessInstance;
 import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Component;
@@ -21,24 +20,18 @@ import java.util.Set;
 @Component
 public class BpmProcessInstanceEventListener extends AbstractFlowableEngineEventListener {
 
+    public static final Set<FlowableEngineEventType> PROCESS_INSTANCE_EVENTS = ImmutableSet.<FlowableEngineEventType>builder()
+            .add(FlowableEngineEventType.PROCESS_COMPLETED)
+            .build();
+
     @Resource
-    @Lazy
+    @Lazy // 延迟加载,避免循环依赖
     private BpmProcessInstanceService processInstanceService;
 
-    public static final Set<FlowableEngineEventType> PROCESS_INSTANCE_EVENTS = ImmutableSet.<FlowableEngineEventType>builder()
-                     .add(FlowableEngineEventType.PROCESS_CANCELLED)
-                     .add(FlowableEngineEventType.PROCESS_COMPLETED)
-                     .build();
-
     public BpmProcessInstanceEventListener(){
         super(PROCESS_INSTANCE_EVENTS);
     }
 
-    @Override
-    protected void processCancelled(FlowableCancelledEvent event) {
-        processInstanceService.updateProcessInstanceWhenCancel(event);
-    }
-
     @Override
     protected void processCompleted(FlowableEngineEntityEvent event) {
         processInstanceService.updateProcessInstanceWhenCompleted((ProcessInstance)event.getEntity());

+ 2 - 20
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceService.java

@@ -6,11 +6,9 @@ import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessI
 import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCreateReqVO;
 import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstancePageReqVO;
 import jakarta.validation.Valid;
-import org.flowable.engine.delegate.event.FlowableCancelledEvent;
 import org.flowable.engine.history.HistoricProcessInstance;
 import org.flowable.engine.runtime.ProcessInstance;
 
-import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -120,32 +118,16 @@ public interface BpmProcessInstanceService {
      */
     void cancelProcessInstanceByAdmin(Long userId, BpmProcessInstanceCancelReqVO cancelReqVO);
 
-    /**
-     * 更新 ProcessInstance 拓展记录为取消
-     *
-     * @param event 流程取消事件
-     */
-    void updateProcessInstanceWhenCancel(FlowableCancelledEvent event);
-
-    /**
-     * 更新 ProcessInstance 为完成
-     *
-     * @param instance 流程任务
-     */
-    void updateProcessInstanceWhenApprove(ProcessInstance instance);
-
     /**
      * 更新 ProcessInstance 为不通过
      *
      * @param processInstance   流程实例
-     * @param activityIds  当前未完成活动节点 Id
-     * @param endId  结束节点 Id
      * @param reason 理由。例如说,审批不通过时,需要传递该值
      */
-    void updateProcessInstanceReject(ProcessInstance processInstance, Collection<String> activityIds, String endId, String reason);
+    void updateProcessInstanceReject(ProcessInstance processInstance, String reason);
 
     /**
-     * 当流程结束时候,更新 ProcessInstance 为通过
+     * 处理 ProcessInstance 完成(审批通过、不通过、取消)
      *
      * @param instance 流程任务
      */

File diff suppressed because it is too large
+ 0 - 0
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java


+ 7 - 2
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskService.java

@@ -90,8 +90,6 @@ public interface BpmTaskService {
      */
     void rejectTask(Long userId, @Valid BpmTaskRejectReqVO reqVO);
 
-
-
     /**
      * 将流程任务分配给指定用户
      *
@@ -100,6 +98,13 @@ public interface BpmTaskService {
      */
     void transferTask(Long userId, BpmTaskTransferReqVO reqVO);
 
+    /**
+     * 将指定流程实例的、进行中的流程任务,移动到结束节点
+     *
+     * @param processInstanceId 流程编号
+     */
+    void moveTaskToEnd(String processInstanceId);
+
     /**
      * 更新 Task 状态,在创建时
      *

+ 40 - 33
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java

@@ -11,7 +11,7 @@ import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*;
 import cn.iocoder.yudao.module.bpm.convert.task.BpmTaskConvert;
 import cn.iocoder.yudao.module.bpm.enums.definition.BpmUserTaskRejectHandlerType;
 import cn.iocoder.yudao.module.bpm.enums.task.BpmCommentTypeEnum;
-import cn.iocoder.yudao.module.bpm.enums.task.BpmDeleteReasonEnum;
+import cn.iocoder.yudao.module.bpm.enums.task.BpmReasonEnum;
 import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskSignTypeEnum;
 import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskStatusEnum;
 import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmConstants;
@@ -327,15 +327,12 @@ public class BpmTaskServiceImpl implements BpmTaskService {
             throw exception(PROCESS_INSTANCE_NOT_EXISTS);
         }
 
-        // 2. 处理当前任务
         // 2.1 更新流程任务为不通过
         updateTaskStatusAndReason(task.getId(), BpmTaskStatusEnum.REJECT.getStatus(), reqVO.getReason());
-        // 2.2 添加评论
+        // 2.2 添加流程评论
         taskService.addComment(task.getId(), task.getProcessInstanceId(), BpmCommentTypeEnum.REJECT.getType(),
                 BpmCommentTypeEnum.REJECT.formatComment(reqVO.getReason()));
-
-        // 3. 处理其他进行中的任务
-        // 3.1 如果当前任务时被加签的,则加它的根任务也标记成未通过
+        // 2.3 如果当前任务时被加签的,则加它的根任务也标记成未通过
         // 疑问:为什么要标记未通过呢?
         // 回答:例如说 A 任务被向前加签除 B 任务时,B 任务被审批不通过,此时 A 会被取消。而 yudao-ui-admin-vue3 不展示“已取消”的任务,导致展示不出审批不通过的细节。
         if (task.getParentTaskId() != null) {
@@ -345,41 +342,22 @@ public class BpmTaskServiceImpl implements BpmTaskService {
             taskService.addComment(rootParentId, task.getProcessInstanceId(), BpmCommentTypeEnum.REJECT.getType(),
                     BpmCommentTypeEnum.REJECT.formatComment("加签任务不通过"));
         }
-        // 3.2 其它未结束的任务,直接取消
-        // 疑问:为什么不通过 updateTaskStatusWhenCanceled 监听取消,而是直接提前调用呢?
-        // 回答:详细见 updateTaskStatusWhenCanceled 的方法,加签的场景
-        List<Task> taskList = getRunningTaskListByProcessInstanceId(instance.getProcessInstanceId(), null, null, null);
-        taskList.forEach(otherTask -> {
-            if (!otherTask.getId().equals(task.getId())) { // 不需要处理当前任务
-                return;
-            }
-            Integer otherTaskStatus = (Integer) task.getTaskLocalVariables().get(BpmConstants.TASK_VARIABLE_STATUS);
-            if (BpmTaskStatusEnum.isEndStatus(otherTaskStatus)) {
-                return;
-            }
-            updateTaskStatusWhenCanceled(otherTask.getId());
-        });
-        taskList.stream().filter(otherTask -> !otherTask.getId().equals(task.getId())) // 需要排除当前任务
-                .forEach(otherTask -> updateTaskStatusWhenCanceled(otherTask.getId()));
 
-        // 4.1 驳回到指定的任务节点
+        // 3. 根据不同的 RejectHandler 处理策略
         BpmnModel bpmnModel = bpmModelService.getBpmnModelByDefinitionId(task.getProcessDefinitionId());
         FlowElement flowElement = BpmnModelUtils.getFlowElementById(bpmnModel, task.getTaskDefinitionKey());
+        // 3.1 情况一:驳回到指定的任务节点
         BpmUserTaskRejectHandlerType userTaskRejectHandlerType = BpmnModelUtils.parseRejectHandlerType(flowElement);
         if (userTaskRejectHandlerType == BpmUserTaskRejectHandlerType.RETURN_USER_TASK) {
             String returnTaskId = BpmnModelUtils.parseReturnTaskId(flowElement);
             Assert.notNull(returnTaskId, "回退的节点不能为空");
-            BpmTaskReturnReqVO returnReq = new BpmTaskReturnReqVO().setId(task.getId()).setTargetTaskDefinitionKey(returnTaskId)
-                    .setReason(reqVO.getReason());
-            returnTask(userId, returnReq);
+            returnTask(userId, new BpmTaskReturnReqVO().setId(task.getId())
+                    .setTargetTaskDefinitionKey(returnTaskId).setReason(reqVO.getReason()));
             return;
         }
-
-        // 4.2 终止流程
-        Set<String> activityIds = convertSet(taskList, Task::getTaskDefinitionKey);
-        EndEvent endEvent = BpmnModelUtils.getEndEvent(bpmnModel);
-        Assert.notNull(endEvent, "结束节点不能未空");
-        processInstanceService.updateProcessInstanceReject(instance, activityIds, endEvent.getId(), reqVO.getReason());
+        // 3.2 情况二:直接结束,审批不通过
+        processInstanceService.updateProcessInstanceReject(instance, reqVO.getReason()); // 标记不通过
+        moveTaskToEnd(task.getProcessInstanceId()); // 结束流程
     }
 
     /**
@@ -449,7 +427,7 @@ public class BpmTaskServiceImpl implements BpmTaskService {
             log.error("[updateTaskStatusWhenCanceled][taskId({}) 处于结果({}),无需进行更新]", taskId, status);
             return;
         }
-        updateTaskStatusAndReason(taskId, BpmTaskStatusEnum.CANCEL.getStatus(), BpmDeleteReasonEnum.CANCEL_BY_SYSTEM.getReason());
+        updateTaskStatusAndReason(taskId, BpmTaskStatusEnum.CANCEL.getStatus(), BpmReasonEnum.CANCEL_BY_SYSTEM.getReason());
         // 补充说明:由于 Task 被删除成 HistoricTask 后,无法通过 taskService.addComment 添加理由,所以无法存储具体的取消理由
     }
 
@@ -665,6 +643,35 @@ public class BpmTaskServiceImpl implements BpmTaskService {
         taskService.setAssignee(taskId, reqVO.getAssigneeUserId().toString());
     }
 
+    @Override
+    public void moveTaskToEnd(String processInstanceId) {
+        List<Task> taskList = getRunningTaskListByProcessInstanceId(processInstanceId, null, null, null);
+        if (CollUtil.isEmpty(taskList)) {
+            return;
+        }
+
+        // 1. 其它未结束的任务,直接取消
+        // 疑问:为什么不通过 updateTaskStatusWhenCanceled 监听取消,而是直接提前调用呢?
+        // 回答:详细见 updateTaskStatusWhenCanceled 的方法,加签的场景
+        taskList.forEach(task -> {
+            Integer otherTaskStatus = (Integer) task.getTaskLocalVariables().get(BpmConstants.TASK_VARIABLE_STATUS);
+            if (BpmTaskStatusEnum.isEndStatus(otherTaskStatus)) {
+                return;
+            }
+            updateTaskStatusWhenCanceled(task.getId());
+        });
+
+        // 2. 终止流程
+        BpmnModel bpmnModel = bpmModelService.getBpmnModelByDefinitionId(taskList.get(0).getProcessDefinitionId());
+        List<String> activityIds = CollUtil.newArrayList(convertSet(taskList, Task::getTaskDefinitionKey));
+        EndEvent endEvent = BpmnModelUtils.getEndEvent(bpmnModel);
+        Assert.notNull(endEvent, "结束节点不能未空");
+        runtimeService.createChangeActivityStateBuilder()
+                .processInstanceId(processInstanceId)
+                .moveActivityIdsToSingleActivityId(activityIds, endEvent.getId())
+                .changeState();
+    }
+
     @Override
     @Transactional(rollbackFor = Exception.class)
     public void createSignTask(Long userId, BpmTaskSignCreateReqVO reqVO) {

Some files were not shown because too many files changed in this diff