diff --git a/backend/crm/src/main/java/cn/cordys/crm/approval/controller/ApprovalActionController.java b/backend/crm/src/main/java/cn/cordys/crm/approval/controller/ApprovalActionController.java index aab9d513d..1bf342a4c 100644 --- a/backend/crm/src/main/java/cn/cordys/crm/approval/controller/ApprovalActionController.java +++ b/backend/crm/src/main/java/cn/cordys/crm/approval/controller/ApprovalActionController.java @@ -51,15 +51,15 @@ public void reject(@Validated @RequestBody ApprovalActionRequest request) { approvalActionService.reject(request, SessionUtils.getUserId(), OrganizationContext.getOrganizationId()); } + @PostMapping("/batch-approve") + @Operation(summary = "批量同意") + public void batchApprove(@Validated @RequestBody ApprovalActionBatchRequest request) { + approvalActionService.batchApprove(request, SessionUtils.getUserId(), OrganizationContext.getOrganizationId()); + } + @PostMapping("/batch-reject") @Operation(summary = "批量驳回") public void batchReject(@Validated @RequestBody ApprovalActionBatchRequest request) { approvalActionService.batchReject(request, SessionUtils.getUserId(), OrganizationContext.getOrganizationId()); } - - @PostMapping("/batch-approve") - @Operation(summary = "批量同意") - public void batchApprove(@Validated @RequestBody ApprovalActionBatchRequest request) { - approvalActionService.batchApprove(request, SessionUtils.getUserId(), OrganizationContext.getOrganizationId()); - } } diff --git a/backend/crm/src/main/java/cn/cordys/crm/approval/dto/ApprovalRecordNode.java b/backend/crm/src/main/java/cn/cordys/crm/approval/dto/ApprovalRecordNode.java index be5ec8712..03cfff40c 100644 --- a/backend/crm/src/main/java/cn/cordys/crm/approval/dto/ApprovalRecordNode.java +++ b/backend/crm/src/main/java/cn/cordys/crm/approval/dto/ApprovalRecordNode.java @@ -18,9 +18,15 @@ public class ApprovalRecordNode { @Schema(description = "节点ID") private String nodeId; + @Schema(description = "节点名称") + private String nodeName; + @Schema(description = "节点轮次") private Integer nodeRound; + @Schema(description = "序号") + private Integer sort; + @Schema(description = "审批状态") private String approvalStatus; diff --git a/backend/crm/src/main/java/cn/cordys/crm/approval/dto/request/ApprovalActionBatchRequest.java b/backend/crm/src/main/java/cn/cordys/crm/approval/dto/request/ApprovalActionBatchRequest.java index 0f4994743..b69012794 100644 --- a/backend/crm/src/main/java/cn/cordys/crm/approval/dto/request/ApprovalActionBatchRequest.java +++ b/backend/crm/src/main/java/cn/cordys/crm/approval/dto/request/ApprovalActionBatchRequest.java @@ -1,6 +1,7 @@ package cn.cordys.crm.approval.dto.request; import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotEmpty; import lombok.Data; @@ -9,16 +10,13 @@ @Data public class ApprovalActionBatchRequest { - @NotEmpty + @NotEmpty(message = "当前任务节点ID集合不能为空") @Schema(description = "ids", requiredMode = Schema.RequiredMode.REQUIRED) private List ids; - @Schema(description = "驳回原因") - private String rejectReason; + @Schema(description = "意见, 评论") + private String comment; - @Schema(description = "驳回附件集合") + @Schema(description = "附件ID集合") private List attachmentIds; - - @Schema(description="操作模块:首页/具体模块详情页") - private String module; } \ No newline at end of file diff --git a/backend/crm/src/main/java/cn/cordys/crm/approval/dto/request/ApprovalActionRequest.java b/backend/crm/src/main/java/cn/cordys/crm/approval/dto/request/ApprovalActionRequest.java index bf1cc6d81..1b0e04fb7 100644 --- a/backend/crm/src/main/java/cn/cordys/crm/approval/dto/request/ApprovalActionRequest.java +++ b/backend/crm/src/main/java/cn/cordys/crm/approval/dto/request/ApprovalActionRequest.java @@ -2,34 +2,38 @@ import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; +import lombok.NoArgsConstructor; import java.util.List; @Data +@AllArgsConstructor +@NoArgsConstructor +@Builder public class ApprovalActionRequest { - @NotBlank(message = "当前task任务ID不能为空") - @Schema(description = "task任务id") + @NotBlank(message = "当前任务节点ID不能为空") + @Schema(description = "当前任务节点ID") private String id; - @NotBlank(message = "当前node节点id不能为空") - @Schema(description = "node节点id") + @NotBlank(message = "当前节点ID不能为空") + @Schema(description = "节点ID") private String nodeId; @NotBlank(message = "审批实例ID不能为空") @Schema(description = "审批实例ID") private String instanceId; + @NotBlank(message = "审批人ID不能为空") @Schema(description = "审批人ID") private String approverId; - @Schema(description = "意见") + @Schema(description = "意见, 评论") private String comment; - @Schema(description = "意见的附件集合") + @Schema(description = "附件ID集合") private List attachmentIds; - - @Schema(description="操作模块:首页/具体模块详情页") - private String module; } diff --git a/backend/crm/src/main/java/cn/cordys/crm/approval/service/ApprovalActionService.java b/backend/crm/src/main/java/cn/cordys/crm/approval/service/ApprovalActionService.java index 71d7f51fc..945aa4ef3 100644 --- a/backend/crm/src/main/java/cn/cordys/crm/approval/service/ApprovalActionService.java +++ b/backend/crm/src/main/java/cn/cordys/crm/approval/service/ApprovalActionService.java @@ -1,7 +1,5 @@ package cn.cordys.crm.approval.service; -import cn.cordys.aspectj.constants.LogType; -import cn.cordys.aspectj.dto.LogDTO; import cn.cordys.common.constants.FormKey; import cn.cordys.common.exception.GenericException; import cn.cordys.common.uid.IDGenerator; @@ -15,11 +13,9 @@ import cn.cordys.crm.approval.dto.response.ApprovalNodeApproverResponse; import cn.cordys.crm.approval.dto.response.ApprovalNodeResponse; import cn.cordys.crm.approval.mapper.ExtApprovalInstanceMapper; -import cn.cordys.crm.approval.mapper.ExtApprovalTaskMapper; import cn.cordys.crm.system.domain.User; import cn.cordys.crm.system.dto.request.UploadTransferRequest; import cn.cordys.crm.system.service.AttachmentService; -import cn.cordys.crm.system.service.LogService; import cn.cordys.mybatis.BaseMapper; import cn.cordys.mybatis.lambda.LambdaQueryWrapper; import jakarta.annotation.Resource; @@ -27,20 +23,11 @@ import org.apache.commons.collections4.ListUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.Strings; -import org.apache.ibatis.session.ExecutorType; -import org.apache.ibatis.session.SqlSession; -import org.apache.ibatis.session.SqlSessionFactory; -import org.mybatis.spring.SqlSessionUtils; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.ArrayList; import java.util.List; -import java.util.Map; -import java.util.function.Function; -import java.util.stream.Collectors; - -import static cn.cordys.crm.approval.service.ApprovalResourceService.FORM_APPROVAL_TABLE; @Service @Transactional(rollbackFor = Exception.class) @@ -69,10 +56,6 @@ public class ApprovalActionService { @Resource private BaseMapper approvalInstanceAttachmentMapper; @Resource - private LogService logService; - @Resource - private SqlSessionFactory sqlSessionFactory; - @Resource private ExtApprovalInstanceMapper extApprovalInstanceMapper; public static final Long DEFAULT_SIGN_SORT_STEP = 100L; @@ -168,6 +151,33 @@ public void reject(ApprovalActionRequest request, String currentUserId, String c rejectProcess(currentTask, currentUserId, currentOrgId); } + /** + * 批量同意 + * @param request 请求参数 + * @param userId 用户ID + * @param organizationId 组织ID + */ + public void batchApprove(ApprovalActionBatchRequest request, String userId, String organizationId) { + List approvalTasks = approvalTaskMapper.selectByIds(request.getIds()); + approvalTasks.forEach(approvalTask -> approve(ApprovalActionRequest.builder().id(approvalTask.getId()).instanceId(approvalTask.getInstanceId()) + .nodeId(approvalTask.getNodeId()).approverId(approvalTask.getApproverId()) + .comment(request.getComment()).attachmentIds(request.getAttachmentIds()) + .build(), userId, organizationId)); + } + + /** + * 批量驳回 + * @param request 请求参数 + * @param userId 当前用户ID + * @param orgId 当前组织ID + */ + public void batchReject(ApprovalActionBatchRequest request, String userId, String orgId) { + List approvalTasks = approvalTaskMapper.selectByIds(request.getIds()); + approvalTasks.forEach(approvalTask -> reject(ApprovalActionRequest.builder().id(approvalTask.getId()).nodeId(approvalTask.getNodeId()).instanceId(approvalTask.getInstanceId()) + .approverId(approvalTask.getApproverId()).comment(request.getComment()).attachmentIds(request.getAttachmentIds()).build(), + userId, orgId)); + } + /** * 保存加签任务的信息 * @@ -336,7 +346,7 @@ private void approvedProcess(ApprovalTask currentTask, String currentUserId, Str nextTask.setStatus(ApprovalStatus.AUTO_APPROVED.name()); approvalFlowService.saveAutoRecord(currentTask.getInstanceId(), currentTask.getNodeId(), ApprovalStatus.AUTO_APPROVED, "审批人与提交人为同一人时, 自动同意跳过", nextTask.getId()); // 依次审批下一位自动同意跳过, 发送下下一个位次的待办 - User nextPlusUser = getMultiSeqNextPlusOne(currentTask.getNodeId(), currentTask.getInstanceId(), currentOrgId); + User nextPlusUser = getMultiSeqNextNextOne(currentTask.getNodeId(), currentTask.getInstanceId(), currentOrgId); if (nextPlusUser != null) { ApprovalTask nextNextTask = buildTask(currentTask.getNodeId(), currentTask.getInstanceId(), nextPlusUser.getId(), ApprovalTaskType.NL.name(), currentUserId, currentTask.getNodeRound()); multiSeqApprovalTasks.add(nextNextTask); @@ -389,6 +399,10 @@ private void rejectProcess(ApprovalTask currentTask, String currentUserId, Strin } } + /** + * 加签操作导致的后续待办任务 + * @param currentTask 当前节点任务 + */ private void appendProcessSignTask(ApprovalTask currentTask) { if (Strings.CI.equals(currentTask.getType(), ApprovalTaskType.SN.name())) { // 加签任务执行, 需要获取同一加签链路的下一个待办任务 @@ -412,21 +426,21 @@ private ApprovalTask saveActionTask(ApprovalActionRequest request, ApprovalActio // 保存执行的任务及记录 ApprovalTask currentTask = getTaskById(request.getId()); switch (action) { - case ApprovalAction.APPROVE: { + case APPROVE: { currentTask.setAction(ApprovalAction.APPROVE.name()); currentTask.setStatus(ApprovalStatus.APPROVED.name()); break; } - case ApprovalAction.REJECT: { + case REJECT: { currentTask.setAction(ApprovalAction.REJECT.name()); currentTask.setStatus(ApprovalStatus.UNAPPROVED.name()); break; } - case ApprovalAction.BACK: { + case BACK: { currentTask.setAction(ApprovalAction.BACK.name()); break; } - case ApprovalAction.SIGN: { + case SIGN: { if (signType == ApprovalAddSignType.BEFORE) { currentTask.setStatus(ApprovalStatus.PENDING.name()); currentTask.setAction(ApprovalAction.SIGN.name()); @@ -590,19 +604,7 @@ private ApprovalTask copyEmptyTask(ApprovalTask old) { * @return 下一个审批人 */ private User getMultiSeqNextOne(String nodeId, String instanceId, String currentOrgId) { - ApprovalInstance instance = approvalInstanceMapper.selectByPrimaryKey(instanceId); - List approvers = approvalFlowService.getCurrentNodeApproverList(nodeId, instance.getSubmitterId(), currentOrgId); - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.eq(ApprovalTask::getNodeId, nodeId) - .eq(ApprovalTask::getInstanceId, instanceId) - .eq(ApprovalTask::getType, ApprovalTaskType.NL.name()) - .eq(ApprovalTask::getStatus, ApprovalStatus.APPROVED.name()); - List approvedTask = approvalTaskMapper.selectListByLambda(queryWrapper); - if (approvedTask.size() < approvers.size()) { - // 依次审批, 返回下一个审批人 - return approvers.get(approvedTask.size()); - } - return null; + return getMultiSeqAfterOne(nodeId, instanceId, currentOrgId, 0); } /** @@ -612,7 +614,19 @@ private User getMultiSeqNextOne(String nodeId, String instanceId, String current * @param currentOrgId 组织ID * @return 下一个审批人 */ - private User getMultiSeqNextPlusOne(String nodeId, String instanceId, String currentOrgId) { + private User getMultiSeqNextNextOne(String nodeId, String instanceId, String currentOrgId) { + return getMultiSeqAfterOne(nodeId, instanceId, currentOrgId, 1); + } + + /** + * 获取多人依次审批后续审批人 + * @param nodeId 节点ID + * @param instanceId 实例ID + * @param currentOrgId 组织ID + * @param next 后续位次 (从0开始, 0为下一个) + * @return 后续审批人 + */ + private User getMultiSeqAfterOne(String nodeId, String instanceId, String currentOrgId, Integer next) { ApprovalInstance instance = approvalInstanceMapper.selectByPrimaryKey(instanceId); List approvers = approvalFlowService.getCurrentNodeApproverList(nodeId, instance.getSubmitterId(), currentOrgId); LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); @@ -623,7 +637,7 @@ private User getMultiSeqNextPlusOne(String nodeId, String instanceId, String cur List approvedTask = approvalTaskMapper.selectListByLambda(queryWrapper); if (approvedTask.size() < approvers.size()) { // 依次审批, 返回下下一个审批人 - return approvers.get(approvedTask.size() + 1); + return approvers.get(approvedTask.size() + next); } return null; } @@ -803,50 +817,6 @@ private void refreshRevokeTask(ApprovalTask approvalTask, ApprovalInstance insta approvalInstanceMapper.updateById(instance); } - /** - * 批量驳回 - * @param request 请求参数 - * @param userId 当前用户ID - * @param orgId 当前组织ID - */ - public void batchReject(ApprovalActionBatchRequest request, String userId, String orgId) { - List approvalTasks = approvalTaskMapper.selectByIds(request.getIds()); - if (CollectionUtils.isEmpty(approvalTasks)) { - throw new GenericException("审批任务不存在!"); - } - /* - * 驳回: 当前任务所属节点最终执行状态为驳回, 中断审批流程 - * TODO: 特殊场景: 节点多人审批, 会签及依次审批时直接整体走驳回逻辑; 反过来如果是或签, 则需要节点下审批任务都为驳回状态才整体走驳回逻辑 - */ - List instanceIds = approvalTasks.stream().map(ApprovalTask::getInstanceId).toList(); - List approvalInstances = approvalInstanceMapper.selectByIds(instanceIds); - Map instanceMaps = approvalInstances.stream().collect(Collectors.toMap(ApprovalInstance::getId, Function.identity())); - List logs = new ArrayList<>(); - SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH); - ExtApprovalTaskMapper taskMapper = sqlSession.getMapper(ExtApprovalTaskMapper.class); - approvalTasks.forEach(approvalTask -> { - approvalTask.setAction(ApprovalAction.REJECT.name()); - approvalTask.setStatus(ApprovalStatus.UNAPPROVED.name()); - approvalTask.setUpdateUser(userId); - approvalTask.setUpdateTime(System.currentTimeMillis()); - taskMapper.updateTaskById(approvalTask); - - saveApprovalRecord(approvalTask, request.getRejectReason(), request.getAttachmentIds(), userId, orgId); - if (instanceMaps.containsKey(approvalTask.getInstanceId())) { - ApprovalInstance approvalInstance = instanceMaps.get(approvalTask.getInstanceId()); - approvalInstanceService.rejectApprovalInstance(approvalInstance, userId); - - String resourceName = selectBusinessName(FormKey.valueOf(approvalInstance.getType()), approvalInstance.getResourceId()); - LogDTO logDTO = new LogDTO(orgId, approvalInstance.getResourceId(), userId, LogType.APPROVAL, request.getModule(), resourceName); - logDTO.setModifiedValue(Translator.get("reject_approval")); - logs.add(logDTO); - } - }); - sqlSession.flushStatements(); - SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory); - logService.batchAdd(logs); - } - /** * 处理下一个节点 * @param node 下一个节点 @@ -882,32 +852,6 @@ private void handleNextApprovalNode(ApprovalNodeResponse node, ApprovalInstance } } - - /** - * 批量同意 - * @param request - * @param userId - * @param organizationId - */ - public void batchApprove(ApprovalActionBatchRequest request, String userId, String organizationId) { - - } - - /** - * 查询对应业务表的业务名 - * - * @param formKey 表单类型 - * @param resourceId 资源ID - */ - public String selectBusinessName(FormKey formKey, String resourceId) { - String tableName = FORM_APPROVAL_TABLE.get(formKey.getKey()); - if (StringUtils.isBlank(tableName)) { - throw new GenericException(Translator.get("module.form.illegal")); - } - return extApprovalInstanceMapper.selectBusinessName(tableName, resourceId); - } - - /** * 获取审批节点待办任务 * @param approverNode 审批节点 @@ -946,7 +890,7 @@ public List getNodeApproverTasks(ApprovalNodeApproverResponse appr } approvalTasks.add(firstTask); } - case ALL -> { + case ALL -> // 如果是会签, 需要发送所有审批人的待办 approverNode.getApproverList().forEach(approver -> { ApprovalTask approvalTask = buildTask(approverNode.getId(), instanceId, approver, taskType, userId, nextRound); @@ -958,7 +902,6 @@ public List getNodeApproverTasks(ApprovalNodeApproverResponse appr } approvalTasks.add(approvalTask); }); - } default -> { } @@ -997,6 +940,16 @@ public List getNodeCcTasks(ApprovalNodeApproverResponse approverNo return approvalTasks; } + /** + * 生成待办任务 + * @param nodeId 节点ID + * @param instanceId 实例ID + * @param approverId 审批人ID + * @param taskType 任务类型 + * @param currentUserId 当前用户ID + * @param round 任务轮次 + * @return 待办任务 + */ public ApprovalTask buildTask(String nodeId, String instanceId, String approverId, String taskType, String currentUserId, Integer round) { ApprovalTask approvalTask = new ApprovalTask(); approvalTask.setId(IDGenerator.nextStr()); diff --git a/backend/crm/src/main/java/cn/cordys/crm/approval/service/ApprovalFlowService.java b/backend/crm/src/main/java/cn/cordys/crm/approval/service/ApprovalFlowService.java index 2f74f7bb4..953662ee2 100644 --- a/backend/crm/src/main/java/cn/cordys/crm/approval/service/ApprovalFlowService.java +++ b/backend/crm/src/main/java/cn/cordys/crm/approval/service/ApprovalFlowService.java @@ -56,7 +56,6 @@ import java.util.*; import java.util.stream.Collectors; -import java.util.stream.Stream; @Service @Transactional(rollbackFor = Exception.class) @@ -745,7 +744,7 @@ private Map> buildConditionOptionMap(List combinedConditions = new ArrayList<>(allConditions); @@ -756,23 +755,22 @@ private Map> buildConditionOptionMap(List getNodePostConfigFieldValues(List nodes) { // 收集审批人节点中的 passPostConfig 和 rejectPostConfig 中的字段值 - List postConfigFieldValues = nodes.stream() - .filter(node -> node instanceof ApprovalNodeApproverResponse) - .map(node -> (ApprovalNodeApproverResponse) node) - .flatMap(approverNode -> { - List fieldValues = new ArrayList<>(); - if (approverNode.getPassPostConfig() != null - && CollectionUtils.isNotEmpty(approverNode.getPassPostConfig().getFieldUpdateConfigs())) { - fieldValues.addAll(approverNode.getPassPostConfig().getFieldUpdateConfigs()); - } - if (approverNode.getRejectPostConfig() != null - && CollectionUtils.isNotEmpty(approverNode.getRejectPostConfig().getFieldUpdateConfigs())) { - fieldValues.addAll(approverNode.getRejectPostConfig().getFieldUpdateConfigs()); - } - return fieldValues.stream(); - }) - .collect(Collectors.toList()); - return postConfigFieldValues; + return nodes.stream() + .filter(node -> node instanceof ApprovalNodeApproverResponse) + .map(node -> (ApprovalNodeApproverResponse) node) + .flatMap(approverNode -> { + List fieldValues = new ArrayList<>(); + if (approverNode.getPassPostConfig() != null + && CollectionUtils.isNotEmpty(approverNode.getPassPostConfig().getFieldUpdateConfigs())) { + fieldValues.addAll(approverNode.getPassPostConfig().getFieldUpdateConfigs()); + } + if (approverNode.getRejectPostConfig() != null + && CollectionUtils.isNotEmpty(approverNode.getRejectPostConfig().getFieldUpdateConfigs())) { + fieldValues.addAll(approverNode.getRejectPostConfig().getFieldUpdateConfigs()); + } + return fieldValues.stream(); + }) + .collect(Collectors.toList()); } /** @@ -1046,10 +1044,10 @@ private boolean matchCondition(CombineSearch combineSearch, List matchSingleCondition(condition, fieldValueMap)); } else { - // OR 模式:任一条件满足即可 + // OR 模式:任一满足即可 return conditions.stream().anyMatch(condition -> matchSingleCondition(condition, fieldValueMap)); } } @@ -1295,7 +1293,7 @@ public ApprovalFlow getEnabledFlow(String formKey, String organizationId) { } /** - * 根据审批人类型解析具体的审批人用户列表 + * 根据审批人类型解析具体审批人用户列表 * * @param userId 当前用户ID * @param approverType 审批人类型枚举 @@ -1323,8 +1321,7 @@ private OrganizationUser getOrganizationUser(String userId, String orgId) { OrganizationUser criteria = new OrganizationUser(); criteria.setUserId(userId); criteria.setOrganizationId(orgId); - OrganizationUser currentUser = organizationUserMapper.selectOne(criteria); - return currentUser; + return organizationUserMapper.selectOne(criteria); } /** @@ -1392,7 +1389,7 @@ private List resolveMultipleSuperiorApprovers(String orgId, OrganizationUs return List.of(); } // 值是单选 - Integer approvalLevel = getValidLevel(approverList); + int approvalLevel = getValidLevel(approverList); List userIds = new ArrayList<>(); String currentSupervisorId = currentUser.getSupervisorId(); @@ -1433,7 +1430,7 @@ private Integer getValidLevel(List approverList) { } /** - * 解析部门负责人审批人 + * 解析部门的负责人审批人 */ private List resolveDeptHeadApprovers(String orgId, OrganizationUser currentUser, List approverList) { if (currentUser == null) { @@ -1476,7 +1473,7 @@ private String getDeptCommander(String orgId, String departmentId) { } /** - * 解析多级部门负责人审批人 + * 解析多级部门的负责人审批人 */ private List resolveMultipleDeptHeadApprovers(String orgId, OrganizationUser currentUser, List approverList) { if (currentUser == null) { @@ -1488,7 +1485,7 @@ private List resolveMultipleDeptHeadApprovers(String orgId, OrganizationUs } // 值是单选 - Integer approvalLevel = getValidLevel(approverList); + int approvalLevel = getValidLevel(approverList); List userIds = new ArrayList<>(); String currentDepartmentId = departmentId; @@ -1557,18 +1554,6 @@ public List getCurrentNodeApproverList(String approverType, List a return resolveApprovers(userId, currentOrgId, ApproverTypeEnum.valueOf(approverType), approverList); } - /** - * 获取当前实例节点抄送人 - * @param currentNodeId 当前节点ID - * @param userId 用户ID - * @param currentOrgId 当前组织ID - * @return 抄送人ID集合 - */ - public List getCurrentNodeCcList(String currentNodeId, String userId, String currentOrgId) { - ApprovalNodeApprover nodeApprover = approvalNodeApproverMapper.selectByPrimaryKey(currentNodeId); - return resolveApprovers(userId, currentOrgId, ApproverTypeEnum.valueOf(nodeApprover.getCcType()), JSON.parseArray(nodeApprover.getCcList(), String.class)); - } - /** * 获取当前实例节点抄送人 * @param ccType 抄送类型 @@ -1709,13 +1694,13 @@ private ApprovalNodeResponse handleNextApproverNodeWithExceptionHandler(Approval // 自动跳过 if (nextApproverNode.getApproverList().size() == 1) { // 如果刚好为单人审批, 直接插入待办任务和记录, 流转到下一个节点 - ApprovalTask autoTask = saveAutoTask(instance.getId(), nextApproverNode.getId(), findSame.get(), ApprovalStatus.APPROVED); + ApprovalTask autoTask = saveAutoSkipTask(instance.getId(), nextApproverNode.getId(), findSame.get()); saveAutoRecord(instance.getId(), nextApproverNode.getId(), ApprovalStatus.AUTO_APPROVED, "审批人与提交人为同一人时, 自动同意跳过", autoTask.getId()); return getNextNodeWithExceptionHandler(instance, nextApproverNode.getId(), fieldValues, currentOrgId); } if (MultiApproverModeEnum.valueOf(nextApproverNode.getMultiApproverMode()) == MultiApproverModeEnum.ANY) { // 如果为多人或签, 插入待办任务和记录, 且需要流转到下一个节点 - ApprovalTask autoTask = saveAutoTask(instance.getId(), nextApproverNode.getId(), findSame.get(), ApprovalStatus.APPROVED); + ApprovalTask autoTask = saveAutoSkipTask(instance.getId(), nextApproverNode.getId(), findSame.get()); saveAutoRecord(instance.getId(), nextApproverNode.getId(), ApprovalStatus.AUTO_APPROVED, "审批人与提交人为同一人时, 自动同意跳过", autoTask.getId()); return getNextNodeWithExceptionHandler(instance, nextApproverNode.getId(), fieldValues, currentOrgId); } @@ -1729,13 +1714,12 @@ private ApprovalNodeResponse handleNextApproverNodeWithExceptionHandler(Approval } /** - * 自动审批的记录 + * 自动跳过的待办任务 * * @param instanceId 实例ID * @param nodeId 节点ID - * @param approvalStatus 审批状态 */ - private ApprovalTask saveAutoTask(String instanceId, String nodeId, String approver, ApprovalStatus approvalStatus) { + private ApprovalTask saveAutoSkipTask(String instanceId, String nodeId, String approver) { Integer nextRound = extApprovalInstanceMapper.getNextNodeRound(instanceId, nodeId); ApprovalTask task = new ApprovalTask(); task.setId(IDGenerator.nextStr()); @@ -1744,12 +1728,8 @@ private ApprovalTask saveAutoTask(String instanceId, String nodeId, String appro task.setNodeRound(nextRound); task.setApproverId(approver); task.setType(ApprovalTaskType.NL.name()); - task.setStatus(approvalStatus.name()); - if (approvalStatus == ApprovalStatus.AUTO_APPROVED) { - task.setAction(ApprovalAction.APPROVE.name()); - } else { - task.setAction(ApprovalAction.REJECT.name()); - } + task.setStatus(ApprovalStatus.APPROVED.name()); + task.setAction(ApprovalAction.APPROVE.name()); task.setCreateTime(System.currentTimeMillis()); task.setCreateUser(InternalUser.ADMIN.getValue()); task.setUpdateTime(System.currentTimeMillis()); diff --git a/backend/crm/src/main/java/cn/cordys/crm/approval/service/ApprovalInstanceService.java b/backend/crm/src/main/java/cn/cordys/crm/approval/service/ApprovalInstanceService.java index fcb94ed86..869e6e9dd 100644 --- a/backend/crm/src/main/java/cn/cordys/crm/approval/service/ApprovalInstanceService.java +++ b/backend/crm/src/main/java/cn/cordys/crm/approval/service/ApprovalInstanceService.java @@ -54,6 +54,8 @@ public class ApprovalInstanceService { private UserExtendService userExtendService; @Resource private BaseMapper approvalNodeApproverMapper; + @Resource + private BaseMapper approvalNodeMapper; /** * 获取资源最新审批实例详情 @@ -76,7 +78,7 @@ public ApprovalInstanceDetail getLatestApprovalInstanceDetail(String resourceId) Map> addSignMap = getAddSignMap(tasks.stream().filter(task -> ApprovalTaskType.valueOf(task.getType()) == ApprovalTaskType.NL || ApprovalTaskType.valueOf(task.getType()) == ApprovalTaskType.BK).map(ApprovalTask::getId).toList()); Map> elementAttachmentsMap = queryAttachments(records); - instanceDetail.setNodes(buildApprovalRecordNodeList(tasks, records, elementAttachmentsMap, simpleUserMap, addSignMap, instanceDetail.getCurrentNodeId())); + instanceDetail.setNodes(buildApprovalRecordNodeList(tasks, records, elementAttachmentsMap, simpleUserMap, addSignMap)); return instanceDetail; } @@ -153,7 +155,7 @@ private Map> queryAttachments(List reco */ private List buildApprovalRecordNodeList(List tasks, List records, Map> attachmentsMap, Map simpleUserMap, - Map> addSignTaskMap, String currentNodeId) { + Map> addSignTaskMap) { List nodes = new ArrayList<>(); Map autoNodeRecordMap = records.stream().filter(record -> StringUtils.isBlank(record.getTaskId())).collect(Collectors.toMap(ApprovalRecord::getNodeId, r -> r)); Map taskRecordMap = records.stream().filter(record -> StringUtils.isNotBlank(record.getTaskId())).collect(Collectors.toMap(ApprovalRecord::getTaskId, r -> r)); @@ -213,8 +215,10 @@ private List buildApprovalRecordNodeList(List }); Map approverNodeMap = getApproverNodeMapByIds(sortHisNodes); + Map approvalNodeMap = getApprovalNodeMapByIds(sortHisNodes); nodes.forEach(node -> { ApprovalNodeApprover approverNode = approverNodeMap.get(node.getNodeId()); + ApprovalNode approvalNode = approvalNodeMap.get(node.getNodeId()); if (approverNode != null) { node.setMultiApproverMode(MultiApproverModeEnum.valueOf(approverNode.getMultiApproverMode())); if (node.getTaskNodes().size() > 1) { @@ -222,8 +226,11 @@ private List buildApprovalRecordNodeList(List node.setApprovalStatus(approvalStatusOfMultiNode == null ? null : approvalStatusOfMultiNode.name()); } } - + node.setNodeName(approvalNode.getName()); + node.setSort(approvalNode.getSort()); }); + // 节点流程配置顺序 + nodes.sort(Comparator.comparing(ApprovalRecordNode::getSort)); return nodes; } @@ -283,6 +290,19 @@ private Map getApproverNodeMapByIds(List n return approvalNodeApprovers.stream().collect(Collectors.toMap(ApprovalNodeApprover::getId, n -> n)); } + /** + * 获取所有审批节点集合 + * @param nodeIds 节点ID集合 + * @return 审批节点集合 + */ + private Map getApprovalNodeMapByIds(List nodeIds) { + if (CollectionUtils.isEmpty(nodeIds)) { + return Map.of(); + } + List approvalNodes = approvalNodeMapper.selectByIds(nodeIds); + return approvalNodes.stream().collect(Collectors.toMap(ApprovalNode::getId, n -> n)); + } + private List flatSignTask(ApprovalTask currentTask, Map> addSignTaskMap, Map signTaskMap) { if (!signTaskMap.containsKey(currentTask.getId())) { // 不存在加签链 @@ -321,9 +341,7 @@ private Map mergeNodeMaxRound(List tasks, List recordNodeMaxRoundMap = records.stream().collect(Collectors.toMap(ApprovalRecord::getNodeId, ApprovalRecord::getNodeRound, Math::max)); // 合并节点集合, 按照最大轮次保留 Map mergedMap = new HashMap<>(recordNodeMaxRoundMap); - taskNodeMaxRoundMap.forEach((nodeId, nodeRound) -> { - mergedMap.merge(nodeId, nodeRound, Math::max); - }); + taskNodeMaxRoundMap.forEach((nodeId, nodeRound) -> mergedMap.merge(nodeId, nodeRound, Math::max)); return mergedMap; }