mirror of
				https://gitee.com/hhyykk/ipms-sjy.git
				synced 2025-10-31 10:18:42 +08:00 
			
		
		
		
	feat: 【工作流】--减签
This commit is contained in:
		| @@ -53,6 +53,7 @@ public interface ErrorCodeConstants { | ||||
|     ErrorCode TASK_ADD_SIGN_USER_NOT_EXIST = new ErrorCode(1_009_005_009, "任务加签:选择的用户不存在"); | ||||
|     ErrorCode TASK_ADD_SIGN_TYPE_ERROR = new ErrorCode(1_009_005_010, "任务加签:当前任务已经{},不能{}"); | ||||
|     ErrorCode TASK_ADD_SIGN_USER_REPEAT = new ErrorCode(1_009_005_011, "任务加签失败,加签人与现有审批人[{}]重复"); | ||||
|     ErrorCode TASK_SUB_SIGN_NO_PARENT = new ErrorCode(1_009_005_011, "任务减签失败,被减签的任务必须是通过加签生成的任务"); | ||||
|     // ========== 流程任务分配规则 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, "流程任务分配规则不存在"); | ||||
|   | ||||
| @@ -103,8 +103,23 @@ public class BpmTaskController { | ||||
|     @PutMapping("/add-sign") | ||||
|     @Operation(summary = "加签", description = "before, after为前加签后加签") | ||||
|     @PreAuthorize("@ss.hasPermission('bpm:task:add-sign')") | ||||
|     public CommonResult<Boolean> addSign(@RequestBody @Valid BpmTaskAddSignReqVO reqVO) { | ||||
|     public CommonResult<Boolean> addSign(@Valid @RequestBody BpmTaskAddSignReqVO reqVO) { | ||||
|         taskService.addSign(reqVO,getLoginUserId()); | ||||
|         return success(true); | ||||
|     } | ||||
|  | ||||
|     @PutMapping("/sub-sign") | ||||
|     @Operation(summary = "减签", description = "") | ||||
|     @PreAuthorize("@ss.hasPermission('bpm:task:sub-sign')") | ||||
|     public CommonResult<Boolean> subSign(@Valid @RequestBody  BpmTaskSubSignReqVO bpmTaskSubSignReqVO) { | ||||
|         taskService.subSign(bpmTaskSubSignReqVO,getLoginUserId()); | ||||
|         return success(true); | ||||
|     } | ||||
|     @GetMapping("/get-sub-sign") | ||||
|     @Operation(summary = "获取能被减签的任务", description = "") | ||||
|     @PreAuthorize("@ss.hasPermission('bpm:task:sub-sign')") | ||||
|     public CommonResult<List<BpmTaskSubSignRespVO>> getChildrenTaskList(@RequestParam("taskId") String taskId) { | ||||
|         return success(taskService.getChildrenTaskList(taskId)); | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -19,6 +19,11 @@ public class BpmTaskRespVO extends BpmTaskDonePageItemRespVO { | ||||
|      */ | ||||
|     private User assigneeUser; | ||||
|  | ||||
|     /** | ||||
|      * 父任务ID | ||||
|      */ | ||||
|     private String parentTaskId; | ||||
|  | ||||
|     @Schema(description = "用户信息") | ||||
|     @Data | ||||
|     public static class User { | ||||
|   | ||||
| @@ -0,0 +1,19 @@ | ||||
| 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; | ||||
|  | ||||
| @Schema(description = "管理后台 - 减签流程任务的 Request VO") | ||||
| @Data | ||||
| public class BpmTaskSubSignReqVO { | ||||
|  | ||||
|     @Schema(description = "被减签的任务 ID") | ||||
|     @NotEmpty(message = "任务编号不能为空") | ||||
|     private String id; | ||||
|  | ||||
|     @Schema(description = "加签原因") | ||||
|     @NotEmpty(message = "加签原因不能为空") | ||||
|     private String reason; | ||||
| } | ||||
| @@ -0,0 +1,15 @@ | ||||
| package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task; | ||||
|  | ||||
| import io.swagger.v3.oas.annotations.media.Schema; | ||||
| import lombok.Data; | ||||
|  | ||||
| @Schema(description = "管理后台 - 减签流程任务的 Response VO") | ||||
| @Data | ||||
| public class BpmTaskSubSignRespVO { | ||||
|     @Schema(description = "审核的用户信息", requiredMode = Schema.RequiredMode.REQUIRED, example = "小李") | ||||
|     private BpmTaskRespVO.User assigneeUser; | ||||
|     @Schema(description = "任务 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "12312") | ||||
|     private String id; | ||||
|     @Schema(description = "任务名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "经理审批") | ||||
|     private String name; | ||||
| } | ||||
| @@ -4,10 +4,7 @@ import cn.hutool.core.date.LocalDateTimeUtil; | ||||
| import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | ||||
| import cn.iocoder.yudao.framework.common.util.date.DateUtils; | ||||
| import cn.iocoder.yudao.framework.common.util.number.NumberUtils; | ||||
| import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskDonePageItemRespVO; | ||||
| import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRespVO; | ||||
| import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskSimpleRespVO; | ||||
| import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskTodoPageItemRespVO; | ||||
| import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*; | ||||
| import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmTaskExtDO; | ||||
| import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenTaskCreatedReqDTO; | ||||
| import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; | ||||
| @@ -162,4 +159,17 @@ public interface BpmTaskConvert { | ||||
|         task.setCreateTime(new Date()); | ||||
|         return task; | ||||
|     } | ||||
|  | ||||
|     default List<BpmTaskSubSignRespVO> convertList(List<BpmTaskExtDO> bpmTaskExtDOList, Map<Long, AdminUserRespDTO> userMap){ | ||||
|         return CollectionUtils.convertList(bpmTaskExtDOList, task->{ | ||||
|             BpmTaskSubSignRespVO bpmTaskSubSignRespVO = new BpmTaskSubSignRespVO(); | ||||
|             bpmTaskSubSignRespVO.setName(task.getName()); | ||||
|             bpmTaskSubSignRespVO.setId(task.getTaskId()); | ||||
|             AdminUserRespDTO assignUser = userMap.get(task.getAssigneeUserId()); | ||||
|             if (assignUser != null) { | ||||
|                 bpmTaskSubSignRespVO.setAssigneeUser(convert3(assignUser)); | ||||
|             } | ||||
|             return bpmTaskSubSignRespVO; | ||||
|         }); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -163,4 +163,17 @@ public interface BpmTaskService { | ||||
|      */ | ||||
|     void addSign(BpmTaskAddSignReqVO reqVO, Long userId); | ||||
|  | ||||
|     /** | ||||
|      * 减签 | ||||
|      * @param bpmTaskSubSignReqVO 被减签的任务ID,理由 | ||||
|      * @param loginUserId 当前用户ID | ||||
|      */ | ||||
|     void subSign(BpmTaskSubSignReqVO bpmTaskSubSignReqVO, Long loginUserId); | ||||
|  | ||||
|     /** | ||||
|      * 获取指定任务的子任务和审批人信息 | ||||
|      * @param taskId 指定任务ID | ||||
|      * @return 子任务列表 | ||||
|      */ | ||||
|     List<BpmTaskSubSignRespVO> getChildrenTaskList(String taskId); | ||||
| } | ||||
|   | ||||
| @@ -15,6 +15,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.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.*; | ||||
| import cn.iocoder.yudao.module.bpm.service.definition.BpmModelService; | ||||
| import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; | ||||
| @@ -264,7 +265,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { | ||||
|             long subTaskCount = getSubTaskCount(parentTaskId); | ||||
|             if (subTaskCount == 0) { | ||||
|                 //2. 获取父任务 | ||||
|                 Task parentTask = getTask(parentTaskId); | ||||
|                 Task parentTask = validateTaskExist(parentTaskId); | ||||
|                 String scopeType = parentTask.getScopeType(); | ||||
|                 //3. 处理向前加签 | ||||
|                 if (BpmTaskAddSignTypeEnum.BEFORE.getType().equals(scopeType)) { | ||||
| @@ -319,7 +320,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { | ||||
|             //此时,D 任务完成,要一直往上找到祖先任务 A ,调用 complete 方法完成 A 任务 | ||||
|             boolean allChildrenTaskFinish = true; | ||||
|             while (StrUtil.isNotBlank(parentTask.getParentTaskId())) { | ||||
|                 parentTask = getTask(parentTask.getParentTaskId()); | ||||
|                 parentTask = validateTaskExist(parentTask.getParentTaskId()); | ||||
|                 BpmTaskExtDO bpmTaskExtDO = taskExtMapper.selectByTaskId(parentTask.getId()); | ||||
|                 if (bpmTaskExtDO == null) { | ||||
|                     break; | ||||
| @@ -375,7 +376,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { | ||||
|         String comment = StrUtil.format("[{}]完成委派任务,任务重新回到[{}]手中,审批意见为:{}", currentUser.getNickname(), | ||||
|                 sourceApproveUser.getNickname(), reqVO.getReason()); | ||||
|         taskService.addComment(reqVO.getId(), task.getProcessInstanceId(), | ||||
|                 BpmCommentTypeEnum.DELEGATE.getDesc(), comment); | ||||
|                 BpmCommentTypeEnum.DELEGATE.getResult().toString(), comment); | ||||
|  | ||||
|         // 2.1 调用 resolveTask 完成任务。 | ||||
|         // 底层调用 TaskHelper.changeTaskAssignee(task, task.getOwner()):将 owner 设置为 assignee | ||||
| @@ -425,10 +426,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { | ||||
|      * @param taskId task id | ||||
|      */ | ||||
|     private Task validateTask(Long userId, String taskId) { | ||||
|         Task task = getTask(taskId); | ||||
|         if (task == null) { | ||||
|             throw exception(TASK_NOT_EXISTS); | ||||
|         } | ||||
|         Task task = validateTaskExist(taskId); | ||||
|         if (!Objects.equals(userId, NumberUtils.parseLong(task.getAssignee()))) { | ||||
|             throw exception(TASK_OPERATE_FAIL_ASSIGN_NOT_SELF); | ||||
|         } | ||||
| @@ -507,6 +505,14 @@ public class BpmTaskServiceImpl implements BpmTaskService { | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     private Task validateTaskExist(String id){ | ||||
|         Task task = taskService.createTaskQuery().taskId(id).singleResult(); | ||||
|         if(task == null){ | ||||
|             throw exception(TASK_NOT_EXISTS); | ||||
|         } | ||||
|         return task; | ||||
|     } | ||||
|  | ||||
|     private Task getTask(String id) { | ||||
|         return taskService.createTaskQuery().taskId(id).singleResult(); | ||||
|     } | ||||
| @@ -518,10 +524,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { | ||||
|     @Override | ||||
|     public List<BpmTaskSimpleRespVO> getReturnTaskList(String taskId) { | ||||
|         // 1. 校验当前任务 task 存在 | ||||
|         Task task = getTask(taskId); | ||||
|         if (task == null) { | ||||
|             throw exception(TASK_NOT_EXISTS); | ||||
|         } | ||||
|         Task task = validateTaskExist(taskId); | ||||
|         // 根据流程定义获取流程模型信息 | ||||
|         BpmnModel bpmnModel = bpmModelService.getBpmnModelByDefinitionId(task.getProcessDefinitionId()); | ||||
|         FlowElement source = BpmnModelUtils.getFlowElementById(bpmnModel, task.getTaskDefinitionKey()); | ||||
| @@ -609,7 +612,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { | ||||
|                 return; | ||||
|             } | ||||
|             taskService.addComment(task.getId(), currentTask.getProcessInstanceId(), | ||||
|                     BpmCommentTypeEnum.BACK.getDesc(), reqVO.getReason()); | ||||
|                     BpmCommentTypeEnum.BACK.getResult().toString(), reqVO.getReason()); | ||||
|         }); | ||||
|  | ||||
|         // 3. 执行驳回 | ||||
| @@ -637,7 +640,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { | ||||
|                 delegateUser.getNickname(), reqVO.getReason()); | ||||
|         String taskId = reqVO.getId(); | ||||
|         taskService.addComment(taskId, task.getProcessInstanceId(), | ||||
|                 BpmCommentTypeEnum.DELEGATE.getDesc(), comment); | ||||
|                 BpmCommentTypeEnum.DELEGATE.getResult().toString(), comment); | ||||
|  | ||||
|         // 3.1 设置任务所有人 (owner) 为原任务的处理人 (assignee) | ||||
|         taskService.setOwner(taskId, task.getAssignee()); | ||||
| @@ -702,7 +705,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { | ||||
|         String comment = StrUtil.format("[{}]{}给了[{}],理由为:{}", currentUser.getNickname(), BpmTaskAddSignTypeEnum.formatDesc(reqVO.getType()), | ||||
|                 String.join(SymbolConstant.D, convertList(userList, AdminUserRespDTO::getNickname)), reqVO.getReason()); | ||||
|         taskService.addComment(reqVO.getId(), taskEntity.getProcessInstanceId(), | ||||
|                 BpmCommentTypeEnum.ADD_SIGN.getDesc(), comment); | ||||
|                 BpmCommentTypeEnum.ADD_SIGN.getResult().toString(), comment); | ||||
|     } | ||||
|  | ||||
|  | ||||
| @@ -776,6 +779,86 @@ public class BpmTaskServiceImpl implements BpmTaskService { | ||||
|         taskService.saveTask(task); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     @Transactional(rollbackFor = Exception.class) | ||||
|     public void subSign(BpmTaskSubSignReqVO reqVO,Long userId) { | ||||
|         Task task = validateSubSign(reqVO.getId()); | ||||
|         AdminUserRespDTO user = adminUserApi.getUser(userId); | ||||
|         AdminUserRespDTO cancelUser = null; | ||||
|         if(StrUtil.isNotBlank(task.getAssignee())){ | ||||
|             cancelUser = adminUserApi.getUser(NumberUtils.parseLong(task.getAssignee())); | ||||
|         } | ||||
|         if(cancelUser == null && StrUtil.isNotBlank(task.getOwner())){ | ||||
|             cancelUser = adminUserApi.getUser(NumberUtils.parseLong(task.getOwner())); | ||||
|         } | ||||
|         Assert.notNull(cancelUser,"任务中没有所有者和审批人,数据错误"); | ||||
|         //1. 获取所有需要删除的任务 ID ,包含当前任务和所有子任务 | ||||
|         List<String> allTaskIdList = getAllChildTaskIds(task.getId()); | ||||
|         //2. 删除任务和所有子任务 | ||||
|         taskService.deleteTasks(allTaskIdList); | ||||
|         //3. 修改扩展表状态为取消 | ||||
|         taskExtMapper.updateBatchByTaskIdList(allTaskIdList,new BpmTaskExtDO().setResult(BpmProcessInstanceResultEnum.CANCEL.getResult()) | ||||
|                 .setReason(StrUtil.format("由于{}操作[减签],任务被取消",user.getNickname()))); | ||||
|         //4. 判断当前任务的父任务是否还有子任务 | ||||
|         Task parentTask = validateTaskExist(task.getParentTaskId()); | ||||
|         Long subTaskCount = getSubTaskCount(task.getParentTaskId()); | ||||
|         if(subTaskCount == 0){ | ||||
|             if(BpmTaskAddSignTypeEnum.BEFORE.getType().equals(parentTask.getScopeType())){ | ||||
|                 //4.1 父任务是往前加签的,则进入判断,将当前任务的状态设置为进行中,并将 owner 设置回 assignee | ||||
|                 taskExtMapper.updateByTaskId(new BpmTaskExtDO().setResult(BpmProcessInstanceResultEnum.PROCESS.getResult()).setTaskId(task.getParentTaskId())); | ||||
|                 parentTask.setAssignee(parentTask.getOwner()); | ||||
|                 parentTask.setOwner(null); | ||||
|             } | ||||
|             //4.2 清空 scopeType 字段,修改task | ||||
|             clearTaskScopeTypeAndSave(parentTask); | ||||
|         } | ||||
|         //5.记录日志到父任务中 | ||||
|         String comment = StrUtil.format("{}操作了【减签】,审批人{}的任务被取消",user.getNickname(),cancelUser.getNickname()); | ||||
|         taskService.addComment(parentTask.getId(),parentTask.getProcessInstanceId(), | ||||
|                 BpmCommentTypeEnum.SUB_SIGN.getResult().toString(),comment); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 校验任务是否能被减签 | ||||
|      * @param id 任务ID | ||||
|      * @return 任务信息 | ||||
|      */ | ||||
|     private Task validateSubSign(String id) { | ||||
|         Task task = validateTaskExist(id); | ||||
|         //必须有parentId | ||||
|         if(StrUtil.isEmpty(task.getParentTaskId())){ | ||||
|             throw exception(TASK_SUB_SIGN_NO_PARENT); | ||||
|         } | ||||
|         return task; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取所有要被取消的删除的任务 ID 集合 | ||||
|      * @param parentTaskId 父级任务ID | ||||
|      * @return 所有任务ID | ||||
|      */ | ||||
|     public List<String> getAllChildTaskIds(String parentTaskId) { | ||||
|         List<String> allChildTaskIds = new ArrayList<>(); | ||||
|         //1. 先将自己放入 | ||||
|         allChildTaskIds.add(parentTaskId); | ||||
|         //2. 递归获取子级 | ||||
|         recursiveGetChildTaskIds(parentTaskId, allChildTaskIds); | ||||
|         return allChildTaskIds; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 递归处理子级任务 | ||||
|      * @param taskId 当前任务ID | ||||
|      * @param taskIds 结果 | ||||
|      */ | ||||
|     private void recursiveGetChildTaskIds(String taskId, List<String> taskIds) { | ||||
|         List<String> childrenTaskIdList = getChildrenTaskIdList(taskId); | ||||
|         for (String childTaskId : childrenTaskIdList) { | ||||
|             taskIds.add(childTaskId); // 将子任务的ID添加到集合中 | ||||
|             recursiveGetChildTaskIds(childTaskId, taskIds); // 递归获取子任务的子任务 | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取指定父级任务的所有子任务 ID 集合 | ||||
|      * @param parentTaskId 父任务 ID | ||||
| @@ -787,4 +870,16 @@ public class BpmTaskServiceImpl implements BpmTaskService { | ||||
|         List<Task> childrenTaskList = taskService.createNativeTaskQuery().sql(sql).parameter("parentTaskId", parentTaskId).list(); | ||||
|         return convertList(childrenTaskList, Task::getId); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public List<BpmTaskSubSignRespVO> getChildrenTaskList(String taskId){ | ||||
|         List<String> childrenTaskIdList = getChildrenTaskIdList(taskId); | ||||
|         if(CollUtil.isEmpty(childrenTaskIdList)){ | ||||
|             return Collections.emptyList(); | ||||
|         } | ||||
|         List<BpmTaskExtDO> bpmTaskExtDOList = taskExtMapper.selectListByTaskIds(childrenTaskIdList); | ||||
|         Set<Long> assigneeUserIdSet = convertSet(bpmTaskExtDOList, BpmTaskExtDO::getAssigneeUserId); | ||||
|         Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(assigneeUserIdSet); | ||||
|         return BpmTaskConvert.INSTANCE.convertList(bpmTaskExtDOList,userMap); | ||||
|     } | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 kehaiyou
					kehaiyou