From 1c518e10a50050d383e714b581c94dea58ec4d67 Mon Sep 17 00:00:00 2001
From: liyong <18434998025@163.com>
Date: 星期五, 22 五月 2026 18:01:34 +0800
Subject: [PATCH] fix(approve): 修复审批实例查询条件及流程控制问题

---
 src/main/java/com/ruoyi/approve/service/impl/ApprovalInstanceServiceImpl.java |  276 ++++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 261 insertions(+), 15 deletions(-)

diff --git a/src/main/java/com/ruoyi/approve/service/impl/ApprovalInstanceServiceImpl.java b/src/main/java/com/ruoyi/approve/service/impl/ApprovalInstanceServiceImpl.java
index 1d7f217..1fb2333 100644
--- a/src/main/java/com/ruoyi/approve/service/impl/ApprovalInstanceServiceImpl.java
+++ b/src/main/java/com/ruoyi/approve/service/impl/ApprovalInstanceServiceImpl.java
@@ -10,23 +10,35 @@
 import com.ruoyi.approve.bean.dto.ApprovalInstanceDto;
 import com.ruoyi.approve.bean.vo.ApprovalInstanceVo;
 import com.ruoyi.approve.mapper.ApprovalInstanceMapper;
-import com.ruoyi.approve.mapper.ApprovalTemplateMapper;
+import com.ruoyi.approve.mapper.ApprovalTemplateNodeApproverMapper;
+import com.ruoyi.approve.mapper.FinReimbursementMapper;
 import com.ruoyi.approve.pojo.*;
 import com.ruoyi.approve.service.*;
 import com.ruoyi.approve.utils.ApproveProcessConfigNodeUtils;
+import com.ruoyi.basic.enums.ApplicationTypeEnum;
+import com.ruoyi.basic.enums.RecordTypeEnum;
+import com.ruoyi.basic.utils.FileUtil;
+import com.ruoyi.collaborativeApproval.mapper.EnterpriseNewsMapper;
+import com.ruoyi.collaborativeApproval.mapper.EnterpriseNewsScopeDeptMapper;
+import com.ruoyi.collaborativeApproval.mapper.EnterpriseNewsScopeUserMapper;
+import com.ruoyi.collaborativeApproval.pojo.EnterpriseNews;
+import com.ruoyi.collaborativeApproval.pojo.EnterpriseNewsScopeDept;
+import com.ruoyi.collaborativeApproval.pojo.EnterpriseNewsScopeUser;
 import com.ruoyi.common.enums.*;
+import com.ruoyi.common.exception.ServiceException;
 import com.ruoyi.common.utils.OrderUtils;
 import com.ruoyi.common.utils.SecurityUtils;
 import com.ruoyi.framework.security.LoginUser;
 import com.ruoyi.framework.web.domain.R;
 import com.ruoyi.procurementrecord.utils.StockUtils;
+import com.ruoyi.project.system.domain.SysDept;
+import com.ruoyi.project.system.domain.SysUser;
+import com.ruoyi.project.system.mapper.SysDeptMapper;
+import com.ruoyi.project.system.mapper.SysUserDeptMapper;
+import com.ruoyi.project.system.mapper.SysUserMapper;
 import com.ruoyi.project.system.service.ISysNoticeService;
 import com.ruoyi.purchase.mapper.PurchaseLedgerMapper;
 import com.ruoyi.purchase.pojo.PurchaseLedger;
-import com.ruoyi.quality.mapper.QualityInspectMapper;
-import com.ruoyi.quality.mapper.QualityInspectParamMapper;
-import com.ruoyi.quality.mapper.QualityTestStandardMapper;
-import com.ruoyi.quality.mapper.QualityTestStandardParamMapper;
 import com.ruoyi.quality.utils.QualityInspectHelper;
 import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
 import com.ruoyi.sales.mapper.SalesQuotationMapper;
@@ -34,6 +46,8 @@
 import com.ruoyi.sales.pojo.SalesLedgerProduct;
 import com.ruoyi.sales.pojo.SalesQuotation;
 import com.ruoyi.sales.pojo.ShippingInfo;
+import com.ruoyi.staff.mapper.HolidayApplicationMapper;
+import com.ruoyi.staff.pojo.HolidayApplication;
 import lombok.RequiredArgsConstructor;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
@@ -54,25 +68,32 @@
 @RequiredArgsConstructor
 public class ApprovalInstanceServiceImpl extends ServiceImpl<ApprovalInstanceMapper, ApprovalInstance> implements ApprovalInstanceService {
 
+    private static final String ENTERPRISE_NEWS_STATUS_PUBLISHED = "PUBLISHED";
+    private static final String ENTERPRISE_NEWS_STATUS_REJECTED = "REJECTED";
+
     private final ApprovalInstanceMapper approvalInstanceMapper;
     private final ApproveProcessConfigNodeUtils approveProcessConfigNodeUtils;
     private final ApprovalInstanceNodeService approvalInstanceNodeService;
     private final ApprovalTaskService approvalTaskService;
     private final ApprovalRecordService approvalRecordService;
     private final ApprovalTemplateNodeService approvalTemplateNodeService;
-    private final ApprovalTemplateNodeApproverService approvalTemplateNodeApproverService;
+    private final FinReimbursementMapper finReimbursementMapper;
+    private final FileUtil fileUtil;
     private final ISysNoticeService sysNoticeService;
     private final PurchaseLedgerMapper purchaseLedgerMapper;
     private final SalesLedgerProductMapper salesLedgerProductMapper;
     private final StockUtils stockUtils;
-    private final QualityInspectMapper qualityInspectMapper;
-    private final QualityTestStandardMapper qualityTestStandardMapper;
-    private final QualityTestStandardParamMapper qualityTestStandardParamMapper;
-    private final QualityInspectParamMapper qualityInspectParamMapper;
     private final SalesQuotationMapper salesQuotationMapper;
     private final ShippingInfoMapper shippingInfoMapper;
-    private final ApprovalTemplateMapper approvalTemplateMapper;
     private final QualityInspectHelper qualityInspectHelper;
+    private final EnterpriseNewsScopeUserMapper enterpriseNewsScopeUserMapper;
+    private final SysUserMapper sysUserMapper;
+    private final SysUserDeptMapper sysUserDeptMapper;
+    private final SysDeptMapper sysDeptMapper;
+    private final HolidayApplicationMapper holidayApplicationMapper;
+    private final EnterpriseNewsMapper enterpriseNewsMapper;
+    private final EnterpriseNewsScopeDeptMapper enterpriseNewsScopeDeptMapper;
+    private final ApprovalTemplateNodeApproverMapper approvalTemplateNodeApproverMapper;
 
     @Override
     public R listPage(Page<ApprovalInstanceVo> page, ApprovalInstanceDto approvalInstanceDto) {
@@ -109,6 +130,7 @@
                 vo.setIsApprove(approveProcessConfigNodeUtils.isCurrentApprover(vo.getId(), currentUserId));
                 vo.setRecords(recordMap.getOrDefault(vo.getId(), new ArrayList<>()));
                 vo.setTasks(taskMap.getOrDefault(vo.getId(), new ArrayList<>()));
+                vo.setStorageBlobVOList(fileUtil.getStorageBlobVOsByRecordTypeAndRecordId(RecordTypeEnum.APPROVAL_INSTANCE, vo.getId()));
             }
 
         }
@@ -127,7 +149,32 @@
             return false;
         }
         approveProcessConfigNodeUtils.createCurrentNodeAndTasks(approvalInstanceDto);
+        fileUtil.saveStorageAttachment(ApplicationTypeEnum.FILE, RecordTypeEnum.APPROVAL_INSTANCE, approvalInstanceDto.getId(), approvalInstanceDto.getStorageBlobDTOs());
         sendApproveNotice(approvalInstanceDto, approveProcessConfigNodeUtils.getCurrentPendingTasks(approvalInstanceDto.getId()));
+        return true;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean update(ApprovalInstanceDto approvalInstanceDto) {
+        if (approvalInstanceDto == null || approvalInstanceDto.getId() == null) {
+            return false;
+        }
+        // 鍒ゆ柇鏄惁鏈夋鍦ㄨ繘琛岀殑瀹℃壒浠诲姟锛屾湁鍒欎笉鍏佽淇敼
+        long pendingTaskCount = approvalTaskService.count(
+                Wrappers.<ApprovalTask>lambdaQuery()
+                        .eq(ApprovalTask::getInstanceId, approvalInstanceDto.getId())
+                        .eq(ApprovalTask::getTaskStatus, "PENDING")
+                        .eq(ApprovalTask::getDeleted, 0)
+        );
+        if (pendingTaskCount > 0) {
+            throw new ServiceException("璇ュ鎵瑰崟鏈夋鍦ㄨ繘琛岀殑瀹℃壒浠诲姟锛屼笉鍏佽淇敼");
+        }
+        boolean updated = this.updateById(approvalInstanceDto);
+        if (!updated) {
+            return false;
+        }
+        fileUtil.saveStorageAttachment(ApplicationTypeEnum.FILE, RecordTypeEnum.APPROVAL_INSTANCE, approvalInstanceDto.getId(), approvalInstanceDto.getStorageBlobDTOs());
         return true;
     }
 
@@ -137,6 +184,7 @@
         if (ids == null || ids.isEmpty()) {
             return false;
         }
+        fileUtil.deleteStorageAttachmentsByApplicationAndRecordTypeAndRecordIds(ApplicationTypeEnum.FILE, RecordTypeEnum.APPROVAL_INSTANCE, ids);
 
         int instanceRows = approvalInstanceMapper.update(
                 null,
@@ -211,11 +259,10 @@
                 approveAction,
                 approvalInstanceDto.getApproveComment()
         );
-
+        //瀹℃壒鎷掔粷鐨勫鐞�
         if ("REJECTED".equals(approveAction)) {
             return rejectCurrentNode(instance, currentNode, now);
         }
-
         if (!approveProcessConfigNodeUtils.canProceedToNextLevel(instance.getId(), currentNode.getApproveType())) {
             return R.ok("瀹℃壒鎴愬姛锛岀瓑寰呭叾浠栧鎵逛汉澶勭悊");
         }
@@ -268,6 +315,20 @@
         instance.setStatus("REJECTED");
         instance.setFinishTime(now);
         this.updateById(instance);
+        // 椹冲洖瀵瑰簲鐨勪紒涓氭柊闂伙紝 宸梾鎶ラ攢
+        if (instance.getBusinessType().equals(TypeEnums.ENTERPRISE_NEWS_APPROVAL.getCode())) {
+            enterpriseNewsMapper.update(
+                    new LambdaUpdateWrapper<EnterpriseNews>()
+                            .eq(EnterpriseNews::getId, instance.getBusinessId())
+                            .set(EnterpriseNews::getStatus, "REJECTED")
+            );
+        }else if (instance.getBusinessType().equals(TypeEnums.TRAVEL_REIMBURSEMENT_APPROVAL.getCode())||instance.getBusinessType().equals(TypeEnums.EXPENSE_APPROVAL.getCode())) {
+            finReimbursementMapper.update(
+                    new LambdaUpdateWrapper<FinReimbursement>()
+                            .eq(FinReimbursement::getId, instance.getBusinessId())
+                            .set(FinReimbursement::getBillStatus, "REJECTED")
+            );
+        }
         return R.ok("瀹℃壒宸查┏鍥�");
     }
 
@@ -282,6 +343,33 @@
         closePendingTasks(instance.getId(), currentNode.getId());
 
         int nextLevel = currentNode.getLevelNo() + 1;
+        ApprovalInstanceNode nextInstanceNode = approvalInstanceNodeService.getOne(
+                new LambdaQueryWrapper<ApprovalInstanceNode>()
+                        .eq(ApprovalInstanceNode::getInstanceId, instance.getId())
+                        .eq(ApprovalInstanceNode::getLevelNo, nextLevel)
+                        .eq(ApprovalInstanceNode::getDeleted, 0)
+                        .orderByAsc(ApprovalInstanceNode::getId)
+                        .last("LIMIT 1")
+        );
+
+        if (nextInstanceNode != null) {
+            if (!activateNextInstanceNode(nextInstanceNode.getId(), now)) {
+                return R.ok("涓嬩竴瀹℃壒鑺傜偣宸茶婵�娲伙紝璇峰埛鏂板悗閲嶈瘯");
+            }
+            instance.setCurrentLevel(nextLevel);
+            instance.setStatus("PENDING");
+            this.updateById(instance);
+            List<ApprovalTask> nextTasks = approvalTaskService.list(
+                    Wrappers.<ApprovalTask>lambdaQuery()
+                            .eq(ApprovalTask::getInstanceId, instance.getId())
+                            .eq(ApprovalTask::getNodeId, nextInstanceNode.getId())
+                            .eq(ApprovalTask::getTaskStatus, "PENDING")
+                            .eq(ApprovalTask::getDeleted, 0)
+            );
+            sendApproveNotice(instance, nextTasks);
+            return R.ok("瀹℃壒鎴愬姛锛屽凡娴佽浆鍒颁笅涓�鑺傜偣");
+        }
+
         ApprovalTemplateNode nextTemplateNode = approvalTemplateNodeService.getOne(
                 new LambdaQueryWrapper<ApprovalTemplateNode>()
                         .eq(ApprovalTemplateNode::getTemplateId, instance.getTemplateId())
@@ -304,6 +392,17 @@
         approveProcessConfigNodeUtils.createCurrentNodeAndTasks(instance, false);
         sendApproveNotice(instance, approveProcessConfigNodeUtils.getCurrentPendingTasks(approvalInstanceDto.getId()));
         return R.ok("瀹℃壒鎴愬姛锛屽凡娴佽浆鍒颁笅涓�鑺傜偣");
+    }
+
+    private boolean activateNextInstanceNode(Long nodeId, LocalDateTime now) {
+        return approvalInstanceNodeService.update(
+                Wrappers.<ApprovalInstanceNode>lambdaUpdate()
+                        .eq(ApprovalInstanceNode::getId, nodeId)
+                        .eq(ApprovalInstanceNode::getStatus, "WAITING")
+                        .eq(ApprovalInstanceNode::getDeleted, 0)
+                        .set(ApprovalInstanceNode::getStatus, "PENDING")
+                        .set(ApprovalInstanceNode::getStartTime, now)
+        );
     }
 
     private boolean updateCurrentNodeStatus(Long nodeId, String targetStatus, LocalDateTime now) {
@@ -331,7 +430,78 @@
         }
         if (TypeEnums.SHIPPING_APPROVAL.getCode().equals(businessType)) {
             handleShippingApprovalFinished(instance, status);
+            return;
         }
+        if (TypeEnums.TRAVEL_REIMBURSEMENT_APPROVAL.getCode().equals(businessType)
+                || TypeEnums.EXPENSE_APPROVAL.getCode().equals(businessType)) {
+            handleReimbursementApprovalFinished(instance, status);
+            return;
+        }
+        // 椹冲洖瀵瑰簲鐨勪紒涓氭柊闂汇�佸姞鐝敵璇枫�佽鍋囩敵璇峰彲浠ラ噸鏂板啀鎻愪氦
+        if (TypeEnums.LEAVE_APPROVAL.getCode().equals(businessType)
+                || TypeEnums.OVERTIME_APPROVAL.getCode().equals(businessType)) {
+            handleHolidayApplicationApprovalFinished(instance, status);
+            return;
+        }
+        if (TypeEnums.ENTERPRISE_NEWS_APPROVAL.getCode().equals(businessType)) {
+            handleNewsApprovalFinished(instance, status);
+        }
+    }
+
+    private void handleReimbursementApprovalFinished(ApprovalInstance instance, String status) {
+        if (instance == null || instance.getBusinessId() == null) {
+            return;
+        }
+
+        FinReimbursement reimbursement = new FinReimbursement();
+        reimbursement.setId(instance.getBusinessId());
+        if ("APPROVED".equals(status)) {
+            reimbursement.setBillStatus("APPROVED");
+            reimbursement.setApprovedTime(instance.getFinishTime());
+        } else if ("REJECTED".equals(status)) {
+            reimbursement.setBillStatus("REJECTED");
+        } else if ("PENDING".equals(status)) {
+            reimbursement.setBillStatus("IN_APPROVAL");
+        } else {
+            return;
+        }
+        finReimbursementMapper.updateById(reimbursement);
+    }
+
+    private void handleNewsApprovalFinished(ApprovalInstance instance, String status) {
+        if (instance == null || instance.getBusinessId() == null) {
+            return;
+        }
+        EnterpriseNews enterpriseNews = new EnterpriseNews();
+        enterpriseNews.setId(instance.getBusinessId());
+        if ("APPROVED".equals(status)) {
+            enterpriseNews.setStatus(ENTERPRISE_NEWS_STATUS_PUBLISHED);
+            enterpriseNewsMapper.updateById(enterpriseNews);
+            sendEnterpriseNewsNotice(instance.getBusinessId());
+            return;
+        }
+        if ("REJECTED".equals(status)) {
+            enterpriseNews.setStatus(ENTERPRISE_NEWS_STATUS_REJECTED);
+            enterpriseNewsMapper.updateById(enterpriseNews);
+        }
+    }
+
+    private void handleHolidayApplicationApprovalFinished(ApprovalInstance instance, String status) {
+        if (instance == null || instance.getBusinessId() == null) {
+            return;
+        }
+        HolidayApplication holidayApplication = new HolidayApplication();
+        holidayApplication.setId(instance.getBusinessId());
+        if ("APPROVED".equals(status)) {
+            holidayApplication.setStatus("APPROVED");
+        } else if ("REJECTED".equals(status)) {
+            holidayApplication.setStatus("REJECTED");
+        } else if ("PENDING".equals(status)) {
+            holidayApplication.setStatus("PENDING");
+        } else {
+            return;
+        }
+        holidayApplicationMapper.updateById(holidayApplication);
     }
 
     private void handlePurchaseApprovalFinished(ApprovalInstance instance, String status) {
@@ -417,7 +587,7 @@
     }
 
     private List<ApprovalTask> createNodeAndTasks(ApprovalInstance instance, ApprovalTemplateNode templateNode) {
-        List<ApprovalTemplateNodeApprover> approvers = approvalTemplateNodeApproverService.list(
+        List<ApprovalTemplateNodeApprover> approvers = approvalTemplateNodeApproverMapper.selectList(
                 new LambdaQueryWrapper<ApprovalTemplateNodeApprover>()
                         .eq(ApprovalTemplateNodeApprover::getTemplateId, instance.getTemplateId())
                         .eq(ApprovalTemplateNodeApprover::getNodeId, templateNode.getId())
@@ -470,10 +640,86 @@
 
         String title = StringUtils.hasText(instance.getTemplateName()) ? instance.getTemplateName() : "瀹℃壒鎻愰啋";
         String message = "瀹℃壒鍗曞彿 " + instance.getInstanceNo() + " 闇�瑕佹偍瀹℃壒";
-        String jumpPath = "/approvalInstance?id=" + instance.getId();
+        String jumpPath = "/officeProcessAutomation/ApproveManage/approve-list?id=" + instance.getId();
         sysNoticeService.simpleNoticeByUser(title, message, approverIds, jumpPath);
     }
 
+    private void sendEnterpriseNewsNotice(Long newsId) {
+        EnterpriseNews enterpriseNews = enterpriseNewsMapper.selectById(newsId);
+        if (enterpriseNews == null) {
+            return;
+        }
+        List<Long> userIds = getEnterpriseNewsNoticeUserIds(enterpriseNews);
+        if (userIds == null || userIds.isEmpty()) {
+            return;
+        }
+        String title = "浼佷笟鏂伴椈";
+        String message = "鎮ㄦ湁鏂扮殑浼佷笟鏂伴椈銆�" + enterpriseNews.getTitle() + "銆嬭鍙婃椂鏌ラ槄";
+        String jumpPath = "/officeProcessAutomation/EnterpriseNews?id=" + newsId;
+        sysNoticeService.simpleNoticeByUser(title, message, userIds, jumpPath);
+    }
+
+    private List<Long> getEnterpriseNewsNoticeUserIds(EnterpriseNews enterpriseNews) {
+        if (enterpriseNews == null || !org.springframework.util.StringUtils.hasText(enterpriseNews.getReadScope())) {
+            return Collections.emptyList();
+        }
+        String readScope = enterpriseNews.getReadScope().trim();
+        if ("all".equals(readScope)) {
+            return sysUserMapper.selectList(new LambdaQueryWrapper<SysUser>()
+                            .select(SysUser::getUserId)
+                            .eq(SysUser::getDelFlag, "0"))
+                    .stream()
+                    .map(SysUser::getUserId)
+                    .filter(id -> id != null && id > 0)
+                    .distinct()
+                    .collect(Collectors.toList());
+        }
+        if ("dept".equals(readScope)) {
+            List<Long> deptIds = enterpriseNewsScopeDeptMapper.selectList(
+                            new LambdaQueryWrapper<EnterpriseNewsScopeDept>()
+                                    .eq(EnterpriseNewsScopeDept::getNewsId, enterpriseNews.getId()))
+                    .stream()
+                    .map(EnterpriseNewsScopeDept::getDeptId)
+                    .filter(id -> id != null && id > 0)
+                    .distinct()
+                    .collect(Collectors.toList());
+            if (deptIds.isEmpty()) {
+                return Collections.emptyList();
+            }
+            return sysUserDeptMapper.selectDistinctUserIdsByDeptIds(collectDeptIdsWithChildren(deptIds));
+        }
+        if ("custom".equals(readScope)) {
+            return enterpriseNewsScopeUserMapper.selectList(
+                            new LambdaQueryWrapper<EnterpriseNewsScopeUser>()
+                                    .eq(EnterpriseNewsScopeUser::getNewsId, enterpriseNews.getId()))
+                    .stream()
+                    .map(EnterpriseNewsScopeUser::getUserId)
+                    .filter(id -> id != null && id > 0)
+                    .distinct()
+                    .collect(Collectors.toList());
+        }
+        return Collections.emptyList();
+    }
+
+    private List<Long> collectDeptIdsWithChildren(List<Long> deptIds) {
+        Set<Long> allDeptIds = new LinkedHashSet<>();
+        for (Long deptId : deptIds) {
+            if (deptId == null) {
+                continue;
+            }
+            allDeptIds.add(deptId);
+            List<SysDept> children = sysDeptMapper.selectChildrenDeptById(deptId);
+            if (children != null && !children.isEmpty()) {
+                for (SysDept child : children) {
+                    if (child != null && child.getDeptId() != null) {
+                        allDeptIds.add(child.getDeptId());
+                    }
+                }
+            }
+        }
+        return new ArrayList<>(allDeptIds);
+    }
+
     private void closePendingTasks(Long instanceId, Long nodeId) {
         LambdaUpdateWrapper<ApprovalTask> updateWrapper = Wrappers.lambdaUpdate();
         updateWrapper.eq(ApprovalTask::getInstanceId, instanceId)

--
Gitblit v1.9.3