Commit 4efa93b03b48b75e41b4c922cb3b9e2d96d977df

Authored by kehaiyou
1 parent 921f99d3

feat: 【工作流】--委派

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 { @@ -50,6 +50,8 @@ public interface ErrorCodeConstants {
50 ErrorCode TASK_SOURCE_TARGET_ERROR = new ErrorCode(1_009_005_004, "目标节点是在并行网关上或非同一路线上,不可跳转"); 50 ErrorCode TASK_SOURCE_TARGET_ERROR = new ErrorCode(1_009_005_004, "目标节点是在并行网关上或非同一路线上,不可跳转");
51 ErrorCode TASK_TARGET_NODE_NOT_EXISTS = new ErrorCode(1_009_005_005, " 目标节点不存在"); 51 ErrorCode TASK_TARGET_NODE_NOT_EXISTS = new ErrorCode(1_009_005_005, " 目标节点不存在");
52 ErrorCode TASK_RETURN_FAIL = new ErrorCode(1_009_005_006, "回退任务失败,选择回退的节点没有需要回滚的任务!请重新选择其他任务节点"); 52 ErrorCode TASK_RETURN_FAIL = new ErrorCode(1_009_005_006, "回退任务失败,选择回退的节点没有需要回滚的任务!请重新选择其他任务节点");
  53 + ErrorCode TASK_DELEGATE_APPROVE_FAIL = new ErrorCode(1_009_005_007, "任务审批失败:委派任务找不到原审批人");
  54 + ErrorCode TASK_DELEGATE_USER_REPEAT = new ErrorCode(1_009_005_008, "任务委派失败,委派人和当前审批人为同一人");
53 // ========== 流程任务分配规则 1-009-006-000 ========== 55 // ========== 流程任务分配规则 1-009-006-000 ==========
54 ErrorCode TASK_ASSIGN_RULE_EXISTS = new ErrorCode(1_009_006_000, "流程({}) 的任务({}) 已经存在分配规则"); 56 ErrorCode TASK_ASSIGN_RULE_EXISTS = new ErrorCode(1_009_006_000, "流程({}) 的任务({}) 已经存在分配规则");
55 ErrorCode TASK_ASSIGN_RULE_NOT_EXISTS = new ErrorCode(1_009_006_001, "流程任务分配规则不存在"); 57 ErrorCode TASK_ASSIGN_RULE_NOT_EXISTS = new ErrorCode(1_009_006_001, "流程任务分配规则不存在");
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 { @@ -20,7 +20,9 @@ public enum BpmProcessInstanceResultEnum {
20 20
21 // ========== 流程任务独有的状态 ========== 21 // ========== 流程任务独有的状态 ==========
22 22
23 - BACK(5, "退回/驳回"); 23 + BACK(5, "退回/驳回"),
  24 +
  25 + DELEGATE(6, "委派");
24 26
25 /** 27 /**
26 * 结果 28 * 结果
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 { @@ -91,4 +91,12 @@ public class BpmTaskController {
91 return success(true); 91 return success(true);
92 } 92 }
93 93
  94 + @PutMapping("/delegate")
  95 + @Operation(summary = "委派任务", description = "用于【流程详情】的【委派】按钮,和向前加签有点像,和向前加签的唯一的区别是没有单独创立任务")
  96 + @PreAuthorize("@ss.hasPermission('bpm:task:delegate')")
  97 + public CommonResult<Boolean> delegateTask(@Valid @RequestBody BpmTaskDelegateReqVO reqVO) {
  98 + taskService.delegateTask(reqVO);
  99 + return success(true);
  100 + }
  101 +
94 } 102 }
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskDelegateReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +
  6 +import javax.validation.constraints.NotEmpty;
  7 +import javax.validation.constraints.NotNull;
  8 +
  9 +@Schema(description = "管理后台 - 委派流程任务的 Request VO")
  10 +@Data
  11 +public class BpmTaskDelegateReqVO {
  12 +
  13 + @Schema(description = "任务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  14 + @NotEmpty(message = "任务编号不能为空")
  15 + private String id;
  16 +
  17 + @Schema(description = "接收人ID", requiredMode = Schema.RequiredMode.REQUIRED,example = "1")
  18 + @NotNull(message = "接收人ID不能为空")
  19 + private Long receiveId;
  20 +
  21 + @Schema(description = "委派原因", requiredMode = Schema.RequiredMode.REQUIRED,example = "做不了决定,需要你先帮忙瞅瞅")
  22 + @NotEmpty(message = "委派原因不能为空")
  23 + private String reason;
  24 +}
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 { @@ -137,4 +137,10 @@ public interface BpmTaskService {
137 */ 137 */
138 void returnTask(BpmTaskReturnReqVO reqVO); 138 void returnTask(BpmTaskReturnReqVO reqVO);
139 139
  140 + /**
  141 + * 将指定任务委派给其他人处理,等接收人处理后再回到原审批人手中审批
  142 + *
  143 + * @param reqVO 接收人和被委派的任务编号理由参数
  144 + */
  145 + void delegateTask(BpmTaskDelegateReqVO reqVO);
140 } 146 }
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; @@ -2,16 +2,19 @@ package cn.iocoder.yudao.module.bpm.service.task;
2 2
3 import cn.hutool.core.collection.CollUtil; 3 import cn.hutool.core.collection.CollUtil;
4 import cn.hutool.core.util.ArrayUtil; 4 import cn.hutool.core.util.ArrayUtil;
  5 +import cn.hutool.core.util.ObjectUtil;
5 import cn.hutool.core.util.StrUtil; 6 import cn.hutool.core.util.StrUtil;
6 import cn.iocoder.yudao.framework.common.pojo.PageResult; 7 import cn.iocoder.yudao.framework.common.pojo.PageResult;
7 import cn.iocoder.yudao.framework.common.util.date.DateUtils; 8 import cn.iocoder.yudao.framework.common.util.date.DateUtils;
8 import cn.iocoder.yudao.framework.common.util.number.NumberUtils; 9 import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
9 import cn.iocoder.yudao.framework.common.util.object.PageUtils; 10 import cn.iocoder.yudao.framework.common.util.object.PageUtils;
10 import cn.iocoder.yudao.framework.flowable.core.util.ModelUtils; 11 import cn.iocoder.yudao.framework.flowable.core.util.ModelUtils;
  12 +import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
11 import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*; 13 import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*;
12 import cn.iocoder.yudao.module.bpm.convert.task.BpmTaskConvert; 14 import cn.iocoder.yudao.module.bpm.convert.task.BpmTaskConvert;
13 import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmTaskExtDO; 15 import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmTaskExtDO;
14 import cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmTaskExtMapper; 16 import cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmTaskExtMapper;
  17 +import cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants;
15 import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceDeleteReasonEnum; 18 import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceDeleteReasonEnum;
16 import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; 19 import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum;
17 import cn.iocoder.yudao.module.bpm.service.definition.BpmModelService; 20 import cn.iocoder.yudao.module.bpm.service.definition.BpmModelService;
@@ -29,6 +32,7 @@ import org.flowable.engine.RuntimeService; @@ -29,6 +32,7 @@ import org.flowable.engine.RuntimeService;
29 import org.flowable.engine.TaskService; 32 import org.flowable.engine.TaskService;
30 import org.flowable.engine.history.HistoricProcessInstance; 33 import org.flowable.engine.history.HistoricProcessInstance;
31 import org.flowable.engine.runtime.ProcessInstance; 34 import org.flowable.engine.runtime.ProcessInstance;
  35 +import org.flowable.task.api.DelegationState;
32 import org.flowable.task.api.Task; 36 import org.flowable.task.api.Task;
33 import org.flowable.task.api.TaskQuery; 37 import org.flowable.task.api.TaskQuery;
34 import org.flowable.task.api.history.HistoricTaskInstance; 38 import org.flowable.task.api.history.HistoricTaskInstance;
@@ -192,13 +196,43 @@ public class BpmTaskServiceImpl implements BpmTaskService { @@ -192,13 +196,43 @@ public class BpmTaskServiceImpl implements BpmTaskService {
192 if (instance == null) { 196 if (instance == null) {
193 throw exception(PROCESS_INSTANCE_NOT_EXISTS); 197 throw exception(PROCESS_INSTANCE_NOT_EXISTS);
194 } 198 }
  199 + //被委派的任务,不调用 complete 去完成任务
  200 + if (DelegationState.PENDING.equals(task.getDelegationState())) {
  201 + this.approveDelegateTask(reqVO, task);
  202 + } else {
  203 + // 完成任务,审批通过
  204 + taskService.complete(task.getId(), instance.getProcessVariables());
  205 +
  206 + // 更新任务拓展表为通过
  207 + taskExtMapper.updateByTaskId(
  208 + new BpmTaskExtDO().setTaskId(task.getId()).setResult(BpmProcessInstanceResultEnum.APPROVE.getResult())
  209 + .setReason(reqVO.getReason()));
  210 + }
  211 + }
195 212
196 - // 完成任务,审批通过  
197 - taskService.complete(task.getId(), instance.getProcessVariables());  
198 -  
199 - // 更新任务拓展表为通过 213 + /**
  214 + * 审批被委派的任务
  215 + *
  216 + * @param reqVO 前端请求参数,包含当前任务ID,审批意见等
  217 + * @param task 当前被审批的任务
  218 + */
  219 + private void approveDelegateTask(BpmTaskApproveReqVO reqVO, Task task) {
  220 + // 添加审批意见
  221 + AdminUserRespDTO currentUser = adminUserApi.getUser(WebFrameworkUtils.getLoginUserId());
  222 + //原审批人
  223 + AdminUserRespDTO sourceApproveUser = adminUserApi.getUser(NumberUtils.parseLong(task.getOwner()));
  224 + if (sourceApproveUser == null) {
  225 + throw exception(TASK_DELEGATE_APPROVE_FAIL);
  226 + }
  227 + String comment = String.format("[%s]完成委派任务,任务重新回到[%s]手中,审批意见为:%s", currentUser.getNickname(),
  228 + sourceApproveUser.getNickname(), reqVO.getReason());
  229 + taskService.addComment(reqVO.getId(), task.getProcessInstanceId(), BpmProcessInstanceResultEnum.DELEGATE.getResult().toString(), comment);
  230 + //调用 resolveTask 完成任务,底层调用 TaskHelper.changeTaskAssignee(task, task.getOwner());
  231 + //将 owner 设置为 assignee
  232 + taskService.resolveTask(task.getId());
  233 + // 更新任务拓展表为【处理中】
200 taskExtMapper.updateByTaskId( 234 taskExtMapper.updateByTaskId(
201 - new BpmTaskExtDO().setTaskId(task.getId()).setResult(BpmProcessInstanceResultEnum.APPROVE.getResult()) 235 + new BpmTaskExtDO().setTaskId(task.getId()).setResult(BpmProcessInstanceResultEnum.PROCESS.getResult())
202 .setReason(reqVO.getReason())); 236 .setReason(reqVO.getReason()));
203 } 237 }
204 238
@@ -318,7 +352,11 @@ public class BpmTaskServiceImpl implements BpmTaskService { @@ -318,7 +352,11 @@ public class BpmTaskServiceImpl implements BpmTaskService {
318 } 352 }
319 353
320 private Task getTask(String id) { 354 private Task getTask(String id) {
321 - return taskService.createTaskQuery().taskId(id).singleResult(); 355 + Task task = taskService.createTaskQuery().taskId(id).singleResult();
  356 + if (null == task) {
  357 + throw exception(TASK_NOT_EXISTS);
  358 + }
  359 + return task;
322 } 360 }
323 361
324 private HistoricTaskInstance getHistoricTask(String id) { 362 private HistoricTaskInstance getHistoricTask(String id) {
@@ -329,9 +367,6 @@ public class BpmTaskServiceImpl implements BpmTaskService { @@ -329,9 +367,6 @@ public class BpmTaskServiceImpl implements BpmTaskService {
329 public List<BpmTaskSimpleRespVO> getReturnTaskList(String taskId) { 367 public List<BpmTaskSimpleRespVO> getReturnTaskList(String taskId) {
330 // 当前任务 task 368 // 当前任务 task
331 Task task = getTask(taskId); 369 Task task = getTask(taskId);
332 - if (null == task) {  
333 - throw exception(TASK_NOT_EXISTS);  
334 - }  
335 // 根据流程定义获取流程模型信息 370 // 根据流程定义获取流程模型信息
336 BpmnModel bpmnModel = bpmModelService.getBpmnModelByDefinitionId(task.getProcessDefinitionId()); 371 BpmnModel bpmnModel = bpmModelService.getBpmnModelByDefinitionId(task.getProcessDefinitionId());
337 // 查询该任务的前置任务节点的key集合 372 // 查询该任务的前置任务节点的key集合
@@ -372,8 +407,8 @@ public class BpmTaskServiceImpl implements BpmTaskService { @@ -372,8 +407,8 @@ public class BpmTaskServiceImpl implements BpmTaskService {
372 return Collections.emptySet(); 407 return Collections.emptySet();
373 } 408 }
374 409
375 - @Transactional(rollbackFor = Exception.class)  
376 @Override 410 @Override
  411 + @Transactional(rollbackFor = Exception.class)
377 public void returnTask(BpmTaskReturnReqVO reqVO) { 412 public void returnTask(BpmTaskReturnReqVO reqVO) {
378 // 当前任务 task 413 // 当前任务 task
379 Task task = validateReturnTask(reqVO.getId()); 414 Task task = validateReturnTask(reqVO.getId());
@@ -396,9 +431,6 @@ public class BpmTaskServiceImpl implements BpmTaskService { @@ -396,9 +431,6 @@ public class BpmTaskServiceImpl implements BpmTaskService {
396 private Task validateReturnTask(String taskId) { 431 private Task validateReturnTask(String taskId) {
397 // 当前任务 task 432 // 当前任务 task
398 Task task = getTask(taskId); 433 Task task = getTask(taskId);
399 - if (null == task) {  
400 - throw exception(TASK_NOT_EXISTS);  
401 - }  
402 if (task.isSuspended()) { 434 if (task.isSuspended()) {
403 throw exception(TASK_IS_PENDING); 435 throw exception(TASK_IS_PENDING);
404 } 436 }
@@ -468,4 +500,41 @@ public class BpmTaskServiceImpl implements BpmTaskService { @@ -468,4 +500,41 @@ public class BpmTaskServiceImpl implements BpmTaskService {
468 .changeState(); 500 .changeState();
469 } 501 }
470 502
  503 + @Override
  504 + @Transactional(rollbackFor = Exception.class)
  505 + public void delegateTask(BpmTaskDelegateReqVO reqVO) {
  506 + // 校验任务
  507 + Task task = this.validateTaskDelegate(reqVO);
  508 + // 添加审批意见
  509 + AdminUserRespDTO currentUser = adminUserApi.getUser(WebFrameworkUtils.getLoginUserId());
  510 + AdminUserRespDTO receiveUser = adminUserApi.getUser(reqVO.getReceiveId());
  511 + String comment = String.format("[%s]将任务委派给[%s],委派理由为:%s", currentUser.getNickname(),
  512 + receiveUser.getNickname(), reqVO.getReason());
  513 + String taskId = reqVO.getId();
  514 + taskService.addComment(taskId, task.getProcessInstanceId(), BpmProcessInstanceResultEnum.DELEGATE.getResult().toString(), comment);
  515 + // 设置任务所有人 (owner) 为原任务的处理人 (assignee)
  516 + taskService.setOwner(taskId, task.getAssignee());
  517 + // 执行委派,将任务委派给 receiveId
  518 + taskService.delegateTask(taskId, reqVO.getReceiveId().toString());
  519 + // 更新任务拓展表为【委派】
  520 + taskExtMapper.updateByTaskId(
  521 + new BpmTaskExtDO().setTaskId(task.getId()).setResult(BpmProcessInstanceResultEnum.DELEGATE.getResult())
  522 + .setReason(reqVO.getReason()));
  523 + }
  524 +
  525 + /**
  526 + * 校验任务委派参数
  527 + *
  528 + * @param reqVO 任务编号,接收人ID
  529 + * @return 当前任务信息
  530 + */
  531 + private Task validateTaskDelegate(BpmTaskDelegateReqVO reqVO) {
  532 + // 校验任务
  533 + Task task = checkTask(WebFrameworkUtils.getLoginUserId(), reqVO.getId());
  534 + //校验当前审批人和被委派人不是同一人
  535 + if (task.getAssignee().equals(reqVO.getReceiveId().toString())) {
  536 + throw exception(TASK_DELEGATE_USER_REPEAT);
  537 + }
  538 + return task;
  539 + }
471 } 540 }