Pārlūkot izejas kodu

feat: 【工作流】--委派

kehaiyou 1 gadu atpakaļ
vecāks
revīzija
4efa93b03b

+ 2 - 0
yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/ErrorCodeConstants.java

@@ -50,6 +50,8 @@ public interface ErrorCodeConstants {
     ErrorCode TASK_SOURCE_TARGET_ERROR = new ErrorCode(1_009_005_004, "目标节点是在并行网关上或非同一路线上,不可跳转");
     ErrorCode TASK_TARGET_NODE_NOT_EXISTS = new ErrorCode(1_009_005_005, " 目标节点不存在");
     ErrorCode TASK_RETURN_FAIL = new ErrorCode(1_009_005_006, "回退任务失败,选择回退的节点没有需要回滚的任务!请重新选择其他任务节点");
+    ErrorCode TASK_DELEGATE_APPROVE_FAIL = new ErrorCode(1_009_005_007, "任务审批失败:委派任务找不到原审批人");
+    ErrorCode TASK_DELEGATE_USER_REPEAT = new ErrorCode(1_009_005_008, "任务委派失败,委派人和当前审批人为同一人");
     // ========== 流程任务分配规则 1-009-006-000 ==========
     ErrorCode TASK_ASSIGN_RULE_EXISTS = new ErrorCode(1_009_006_000, "流程({}) 的任务({}) 已经存在分配规则");
     ErrorCode TASK_ASSIGN_RULE_NOT_EXISTS = new ErrorCode(1_009_006_001, "流程任务分配规则不存在");

+ 3 - 1
yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmProcessInstanceResultEnum.java

@@ -20,7 +20,9 @@ public enum BpmProcessInstanceResultEnum {
 
     // ========== 流程任务独有的状态 ==========
 
-    BACK(5, "退回/驳回");
+    BACK(5, "退回/驳回"),
+
+    DELEGATE(6, "委派");
 
     /**
      * 结果

+ 8 - 0
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java

@@ -91,4 +91,12 @@ public class BpmTaskController {
         return success(true);
     }
 
+    @PutMapping("/delegate")
+    @Operation(summary = "委派任务", description = "用于【流程详情】的【委派】按钮,和向前加签有点像,和向前加签的唯一的区别是没有单独创立任务")
+    @PreAuthorize("@ss.hasPermission('bpm:task:delegate')")
+    public CommonResult<Boolean> delegateTask(@Valid @RequestBody BpmTaskDelegateReqVO reqVO) {
+        taskService.delegateTask(reqVO);
+        return success(true);
+    }
+
 }

+ 24 - 0
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskDelegateReqVO.java

@@ -0,0 +1,24 @@
+package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+
+@Schema(description = "管理后台 - 委派流程任务的 Request VO")
+@Data
+public class BpmTaskDelegateReqVO {
+
+    @Schema(description = "任务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+    @NotEmpty(message = "任务编号不能为空")
+    private String id;
+
+    @Schema(description = "接收人ID", requiredMode = Schema.RequiredMode.REQUIRED,example = "1")
+    @NotNull(message = "接收人ID不能为空")
+    private Long receiveId;
+
+    @Schema(description = "委派原因", requiredMode = Schema.RequiredMode.REQUIRED,example = "做不了决定,需要你先帮忙瞅瞅")
+    @NotEmpty(message = "委派原因不能为空")
+    private String reason;
+}

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

@@ -137,4 +137,10 @@ public interface BpmTaskService {
      */
     void returnTask(BpmTaskReturnReqVO reqVO);
 
+    /**
+     * 将指定任务委派给其他人处理,等接收人处理后再回到原审批人手中审批
+     *
+     * @param reqVO 接收人和被委派的任务编号理由参数
+     */
+    void delegateTask(BpmTaskDelegateReqVO reqVO);
 }

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

@@ -2,16 +2,19 @@ package cn.iocoder.yudao.module.bpm.service.task;
 
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.ArrayUtil;
+import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.util.date.DateUtils;
 import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
 import cn.iocoder.yudao.framework.common.util.object.PageUtils;
 import cn.iocoder.yudao.framework.flowable.core.util.ModelUtils;
+import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
 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.dal.dataobject.task.BpmTaskExtDO;
 import cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmTaskExtMapper;
+import cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants;
 import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceDeleteReasonEnum;
 import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum;
 import cn.iocoder.yudao.module.bpm.service.definition.BpmModelService;
@@ -29,6 +32,7 @@ import org.flowable.engine.RuntimeService;
 import org.flowable.engine.TaskService;
 import org.flowable.engine.history.HistoricProcessInstance;
 import org.flowable.engine.runtime.ProcessInstance;
+import org.flowable.task.api.DelegationState;
 import org.flowable.task.api.Task;
 import org.flowable.task.api.TaskQuery;
 import org.flowable.task.api.history.HistoricTaskInstance;
@@ -192,13 +196,43 @@ public class BpmTaskServiceImpl implements BpmTaskService {
         if (instance == null) {
             throw exception(PROCESS_INSTANCE_NOT_EXISTS);
         }
+        //被委派的任务,不调用 complete 去完成任务
+        if (DelegationState.PENDING.equals(task.getDelegationState())) {
+            this.approveDelegateTask(reqVO, task);
+        } else {
+            // 完成任务,审批通过
+            taskService.complete(task.getId(), instance.getProcessVariables());
+
+            // 更新任务拓展表为通过
+            taskExtMapper.updateByTaskId(
+                    new BpmTaskExtDO().setTaskId(task.getId()).setResult(BpmProcessInstanceResultEnum.APPROVE.getResult())
+                            .setReason(reqVO.getReason()));
+        }
+    }
 
-        // 完成任务,审批通过
-        taskService.complete(task.getId(), instance.getProcessVariables());
-
-        // 更新任务拓展表为通过
+    /**
+     * 审批被委派的任务
+     *
+     * @param reqVO 前端请求参数,包含当前任务ID,审批意见等
+     * @param task  当前被审批的任务
+     */
+    private void approveDelegateTask(BpmTaskApproveReqVO reqVO, Task task) {
+        // 添加审批意见
+        AdminUserRespDTO currentUser = adminUserApi.getUser(WebFrameworkUtils.getLoginUserId());
+        //原审批人
+        AdminUserRespDTO sourceApproveUser = adminUserApi.getUser(NumberUtils.parseLong(task.getOwner()));
+        if (sourceApproveUser == null) {
+            throw exception(TASK_DELEGATE_APPROVE_FAIL);
+        }
+        String comment = String.format("[%s]完成委派任务,任务重新回到[%s]手中,审批意见为:%s", currentUser.getNickname(),
+                sourceApproveUser.getNickname(), reqVO.getReason());
+        taskService.addComment(reqVO.getId(), task.getProcessInstanceId(), BpmProcessInstanceResultEnum.DELEGATE.getResult().toString(), comment);
+        //调用 resolveTask 完成任务,底层调用 TaskHelper.changeTaskAssignee(task, task.getOwner());
+        //将 owner 设置为 assignee
+        taskService.resolveTask(task.getId());
+        // 更新任务拓展表为【处理中】
         taskExtMapper.updateByTaskId(
-                new BpmTaskExtDO().setTaskId(task.getId()).setResult(BpmProcessInstanceResultEnum.APPROVE.getResult())
+                new BpmTaskExtDO().setTaskId(task.getId()).setResult(BpmProcessInstanceResultEnum.PROCESS.getResult())
                         .setReason(reqVO.getReason()));
     }
 
@@ -318,7 +352,11 @@ public class BpmTaskServiceImpl implements BpmTaskService {
     }
 
     private Task getTask(String id) {
-        return taskService.createTaskQuery().taskId(id).singleResult();
+        Task task = taskService.createTaskQuery().taskId(id).singleResult();
+        if (null == task) {
+            throw exception(TASK_NOT_EXISTS);
+        }
+        return task;
     }
 
     private HistoricTaskInstance getHistoricTask(String id) {
@@ -329,9 +367,6 @@ public class BpmTaskServiceImpl implements BpmTaskService {
     public List<BpmTaskSimpleRespVO> getReturnTaskList(String taskId) {
         // 当前任务 task
         Task task = getTask(taskId);
-        if (null == task) {
-            throw exception(TASK_NOT_EXISTS);
-        }
         // 根据流程定义获取流程模型信息
         BpmnModel bpmnModel = bpmModelService.getBpmnModelByDefinitionId(task.getProcessDefinitionId());
         // 查询该任务的前置任务节点的key集合
@@ -372,8 +407,8 @@ public class BpmTaskServiceImpl implements BpmTaskService {
         return Collections.emptySet();
     }
 
-    @Transactional(rollbackFor = Exception.class)
     @Override
+    @Transactional(rollbackFor = Exception.class)
     public void returnTask(BpmTaskReturnReqVO reqVO) {
         // 当前任务 task
         Task task = validateReturnTask(reqVO.getId());
@@ -396,9 +431,6 @@ public class BpmTaskServiceImpl implements BpmTaskService {
     private Task validateReturnTask(String taskId) {
         // 当前任务 task
         Task task = getTask(taskId);
-        if (null == task) {
-            throw exception(TASK_NOT_EXISTS);
-        }
         if (task.isSuspended()) {
             throw exception(TASK_IS_PENDING);
         }
@@ -468,4 +500,41 @@ public class BpmTaskServiceImpl implements BpmTaskService {
                 .changeState();
     }
 
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void delegateTask(BpmTaskDelegateReqVO reqVO) {
+        // 校验任务
+        Task task = this.validateTaskDelegate(reqVO);
+        // 添加审批意见
+        AdminUserRespDTO currentUser = adminUserApi.getUser(WebFrameworkUtils.getLoginUserId());
+        AdminUserRespDTO receiveUser = adminUserApi.getUser(reqVO.getReceiveId());
+        String comment = String.format("[%s]将任务委派给[%s],委派理由为:%s", currentUser.getNickname(),
+                receiveUser.getNickname(), reqVO.getReason());
+        String taskId = reqVO.getId();
+        taskService.addComment(taskId, task.getProcessInstanceId(), BpmProcessInstanceResultEnum.DELEGATE.getResult().toString(), comment);
+        // 设置任务所有人 (owner) 为原任务的处理人 (assignee)
+        taskService.setOwner(taskId, task.getAssignee());
+        // 执行委派,将任务委派给  receiveId
+        taskService.delegateTask(taskId, reqVO.getReceiveId().toString());
+        // 更新任务拓展表为【委派】
+        taskExtMapper.updateByTaskId(
+                new BpmTaskExtDO().setTaskId(task.getId()).setResult(BpmProcessInstanceResultEnum.DELEGATE.getResult())
+                        .setReason(reqVO.getReason()));
+    }
+
+    /**
+     * 校验任务委派参数
+     *
+     * @param reqVO 任务编号,接收人ID
+     * @return 当前任务信息
+     */
+    private Task validateTaskDelegate(BpmTaskDelegateReqVO reqVO) {
+        // 校验任务
+        Task task = checkTask(WebFrameworkUtils.getLoginUserId(), reqVO.getId());
+        //校验当前审批人和被委派人不是同一人
+        if (task.getAssignee().equals(reqVO.getReceiveId().toString())) {
+            throw exception(TASK_DELEGATE_USER_REPEAT);
+        }
+        return task;
+    }
 }