From abd339106ed3a6465293edccd33e5f87bd43bdde Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期二, 20 十月 2026 18:01:42 +0800
Subject: [PATCH] feat: 质量监控/人员培训对齐程序文件,体系文件控制附件格式放开

---
 cnas-process/src/main/java/com/ruoyi/process/service/impl/QualityMonitorServiceImpl.java |  218 +++++++++++++++++++++++++++++++++++++++++++-----------
 1 files changed, 174 insertions(+), 44 deletions(-)

diff --git a/cnas-process/src/main/java/com/ruoyi/process/service/impl/QualityMonitorServiceImpl.java b/cnas-process/src/main/java/com/ruoyi/process/service/impl/QualityMonitorServiceImpl.java
index a559f4b..b27630c 100644
--- a/cnas-process/src/main/java/com/ruoyi/process/service/impl/QualityMonitorServiceImpl.java
+++ b/cnas-process/src/main/java/com/ruoyi/process/service/impl/QualityMonitorServiceImpl.java
@@ -70,6 +70,9 @@
 @Transactional(rollbackFor = Exception.class)
 public class QualityMonitorServiceImpl extends ServiceImpl<QualityMonitorMapper, QualityMonitor> implements QualityMonitorService {
 
+    private static final Set<String> EDITABLE_PLAN_STATES = new HashSet<>(Arrays.asList(
+            "DRAFT", "REVIEW_REJECTED", "APPROVAL_REJECTED"));
+
     @Resource
     private QualityMonitorDetailsService qualityMonitorDetailsService;
     @Resource
@@ -96,6 +99,111 @@
     @Value("${wordUrl}")
     private String wordUrl;
 
+    @Override
+    public QualityMonitorDto createAnnualPlan(QualityMonitor input) {
+        if (input == null || StringUtils.isBlank(input.getMonitorYear())
+                || !input.getMonitorYear().matches("\\d{4}")) {
+            throw new ErrorException("璇烽�夋嫨姝g‘鐨勮鍒掑勾搴�");
+        }
+        if (input.getExamineUserId() == null || userMapper.selectById(input.getExamineUserId()) == null) {
+            throw new ErrorException("璇烽�夋嫨鏈夋晥鐨勫鏍镐汉");
+        }
+        if (StringUtils.isBlank(input.getMonitorName())) {
+            throw new ErrorException("璇峰~鍐欒鍒掑悕绉�");
+        }
+        int userId = SecurityUtils.getUserId().intValue();
+        QualityMonitor plan = new QualityMonitor();
+        plan.setMonitorYear(input.getMonitorYear());
+        plan.setMonitorName(input.getMonitorName().trim());
+        plan.setWriteUserId(userId);
+        plan.setWriteTime(LocalDateTime.now());
+        plan.setExamineUserId(input.getExamineUserId());
+        plan.setWorkflowStatus("DRAFT");
+        baseMapper.insert(plan);
+        return baseMapper.selectPlanDtoById(plan.getQualityMonitorId());
+    }
+
+    @Override
+    public QualityMonitorDto getAnnualPlan(String monitorYear, Integer qualityMonitorId) {
+        QualityMonitor plan;
+        if (qualityMonitorId != null) {
+            plan = baseMapper.selectById(qualityMonitorId);
+            if (plan == null || (StringUtils.isNotBlank(monitorYear)
+                    && !monitorYear.equals(plan.getMonitorYear()))) return null;
+        } else {
+            if (StringUtils.isBlank(monitorYear)) throw new ErrorException("璇烽�夋嫨璁″垝骞村害");
+            plan = baseMapper.selectOne(Wrappers.<QualityMonitor>lambdaQuery()
+                    .eq(QualityMonitor::getMonitorYear, monitorYear)
+                    .orderByDesc(QualityMonitor::getCreateTime, QualityMonitor::getQualityMonitorId)
+                    .last("limit 1"));
+        }
+        return plan == null ? null : baseMapper.selectPlanDtoById(plan.getQualityMonitorId());
+    }
+
+    @Override
+    public boolean submitAnnualPlan(Integer qualityMonitorId) {
+        QualityMonitor plan = requirePlan(qualityMonitorId);
+        int current = SecurityUtils.getUserId().intValue();
+        if (!Integer.valueOf(current).equals(plan.getWriteUserId())) {
+            throw new ErrorException("鍙湁璁″垝缂栧埗浜哄彲浠ユ彁浜ゅ鏍�");
+        }
+        String state = effectiveStatus(plan);
+        if (!EDITABLE_PLAN_STATES.contains(state)) throw new ErrorException("褰撳墠璁″垝鐘舵�佷笉鑳芥彁浜ゅ鏍�");
+        if (qualityMonitorDetailsMapper.selectCount(Wrappers.<QualityMonitorDetails>lambdaQuery()
+                .eq(QualityMonitorDetails::getQualityMonitorId, qualityMonitorId)) == 0) {
+            throw new ErrorException("璇疯嚦灏戞柊澧炰竴鏉¤川鎺ч」鐩悗鍐嶆彁浜ゅ鏍�");
+        }
+        baseMapper.update(null, Wrappers.<QualityMonitor>lambdaUpdate()
+                .eq(QualityMonitor::getQualityMonitorId, qualityMonitorId)
+                .set(QualityMonitor::getWorkflowStatus, "PENDING_REVIEW")
+                .set(QualityMonitor::getExamineStatus, null)
+                .set(QualityMonitor::getExamineRemark, null)
+                .set(QualityMonitor::getRatifyStatus, null));
+        sendPlanNotice(plan, plan.getExamineUserId(), "CNAS璐ㄩ噺鐩戞帶璁″垝瀹℃牳閫氱煡", "璐ㄩ噺鐩戞帶璁″垝寰呭鏍�");
+        return true;
+    }
+
+    @Override
+    public void validateDetailEditable(Integer qualityMonitorId) {
+        QualityMonitor plan = requirePlan(qualityMonitorId);
+        if (!Integer.valueOf(SecurityUtils.getUserId().intValue()).equals(plan.getWriteUserId())) {
+            throw new ErrorException("鍙湁璁″垝缂栧埗浜哄彲浠ョ淮鎶よ川鎺ч」鐩�");
+        }
+        if (!EDITABLE_PLAN_STATES.contains(effectiveStatus(plan))) {
+            throw new ErrorException("褰撳墠璁″垝宸叉彁浜わ紝涓嶈兘淇敼璐ㄦ帶椤圭洰");
+        }
+    }
+
+    private QualityMonitor requirePlan(Integer id) {
+        QualityMonitor plan = id == null ? null : baseMapper.selectById(id);
+        if (plan == null) throw new ErrorException("骞村害璐ㄩ噺鎺у埗璁″垝涓嶅瓨鍦�");
+        return plan;
+    }
+
+    private String effectiveStatus(QualityMonitor plan) {
+        if (StringUtils.isNotBlank(plan.getWorkflowStatus())) return plan.getWorkflowStatus();
+        if (Integer.valueOf(1).equals(plan.getRatifyStatus())) return "APPROVED";
+        if (Integer.valueOf(0).equals(plan.getRatifyStatus())) return "APPROVAL_REJECTED";
+        if (Integer.valueOf(1).equals(plan.getExamineStatus())) return "PENDING_APPROVAL";
+        if (Integer.valueOf(0).equals(plan.getExamineStatus())) return "REVIEW_REJECTED";
+        return "DRAFT";
+    }
+
+    private void sendPlanNotice(QualityMonitor plan, Integer receiverId, String theme, String suffix) {
+        if (receiverId == null) return;
+        int sender = SecurityUtils.getUserId().intValue();
+        User senderUser = userMapper.selectById(sender);
+        InformationNotification info = new InformationNotification();
+        info.setCreateUser(senderUser == null ? "" : senderUser.getName());
+        info.setMessageType("6");
+        info.setTheme(theme);
+        info.setContent(plan.getMonitorName() + suffix);
+        info.setSenderId(sender);
+        info.setConsigneeId(receiverId);
+        info.setJumpPath(MenuJumpPathConstants.QUALITY_MONITOR);
+        informationNotificationService.addInformationNotification(info);
+    }
+
 
     /**
      * 瀵煎叆鐩戞帶璁″垝
@@ -103,53 +211,25 @@
      * @return
      */
     @Override
-    public boolean importQualityMonitor(MultipartFile file, QualityMonitor monitor) {
+    public QualityMonitor importQualityMonitor(MultipartFile file, QualityMonitor monitor) {
         // 褰撳墠鐧诲綍鐢ㄦ埛
         Integer userId = SecurityUtils.getUserId().intValue();
         // 鏂囦欢鍚嶇О
         String fileName = file.getOriginalFilename().substring(0, file.getOriginalFilename().lastIndexOf("."));
+        if (monitor.getMonitorYear() == null || !monitor.getMonitorYear().matches("\\d{4}")) {
+            throw new ErrorException("璇烽�夋嫨姝g‘鐨勮鍒掑勾搴�");
+        }
+        if (monitor.getExamineUserId() == null) throw new ErrorException("缂哄皯瀹℃牳浜�");
         QualityMonitor qualityMonitor = new QualityMonitor();
         qualityMonitor.setMonitorName(fileName);
         qualityMonitor.setMonitorYear(monitor.getMonitorYear());
         qualityMonitor.setWriteUserId(userId);
         qualityMonitor.setExamineUserId(monitor.getExamineUserId());
         qualityMonitor.setWriteTime(LocalDateTime.now());
+        // 瀵煎叆鍙敓鎴愯崏绋匡紝瀵煎叆鐨勮川鎺ч」鐩繕闇�瑕佽ˉ鍏ㄦ娴嬫爣鍑嗐�佹娴嬪憳绛変俊鎭紱
+        // 瀹℃牳閫氱煡鍦ㄧ紪鍒朵汉鐐瑰嚮鈥滄彁浜ゅ鏍糕�濇椂缁熶竴鍙戦�併��
+        qualityMonitor.setWorkflowStatus("DRAFT");
         baseMapper.insert(qualityMonitor);
-
-        if (monitor.getExamineUserId() == null) {
-            throw new ErrorException("缂哄皯瀹℃牳浜�");
-        }
-
-        User user = userMapper.selectById(userId);
-        // 娑堟伅鍙戦��
-        InformationNotification info = new InformationNotification();
-        // 鍙戦�佷汉
-        info.setCreateUser(user.getName());
-        info.setMessageType("6");
-        info.setTheme("CNAS璐ㄩ噺鐩戞帶璁″垝瀹℃牳閫氱煡");
-        info.setContent(fileName + "璐ㄩ噺鐩戞帶璁″垝寰呭鏍�");
-        info.setSenderId(userId);
-        // 鎺ユ敹浜�
-        info.setConsigneeId(monitor.getExamineUserId());
-        info.setJumpPath(MenuJumpPathConstants.QUALITY_MONITOR);
-        informationNotificationService.addInformationNotification(info);
-
-        // 鍙戦�佷紒涓氬井淇¢�氱煡
-        threadPoolTaskExecutor.execute(() -> {
-            // 鏌ヨ鍙戦�佷汉
-            User people = userMapper.selectById(monitor.getExamineUserId());
-            String message = "";
-            message += "CNAS璐ㄩ噺鐩戞帶璁″垝瀹℃牳閫氱煡";
-            message += "\n璇峰幓杩囩▼瑕佹眰-璐ㄩ噺鐩戞帶璁″垝";
-            message += "\n" + fileName + "璐ㄩ噺鐩戞帶璁″垝寰呭鏍�";
-            //鍙戦�佷紒涓氬井淇℃秷鎭�氱煡
-            try {
-                WxCpUtils.inform(people.getAccount(), message, null);
-            } catch (Exception e) {
-                throw new RuntimeException(e);
-            }
-        });
-
 
         List<QualityMonitorDetails> detailsUploadList = new ArrayList<>();
 
@@ -159,14 +239,28 @@
             EasyExcel.read(file.getInputStream(), QualityMonitorDetailsUpload.class, new AnalysisEventListener<QualityMonitorDetailsUpload>() {
                 @Override
                 public void invoke(QualityMonitorDetailsUpload detailsUpload, AnalysisContext analysisContext) {
-                    // 鍒ゆ柇鏄惁涓虹┖
-                    if (StringUtils.isBlank(detailsUpload.getPlannedTime())) {
-                        throw new ErrorException("璁″垝寮�灞曟椂闂翠笉鑳戒负绌�");
+                    if (StringUtils.isBlank(detailsUpload.getMonitorProject())
+                            || StringUtils.isBlank(detailsUpload.getTechnicalStandardText())
+                            || StringUtils.isBlank(detailsUpload.getMonitorWay())
+                            || StringUtils.isBlank(detailsUpload.getCompletionMonth())) {
+                        throw new ErrorException("璐ㄦ帶椤圭洰銆佹妧鏈爣鍑嗐�佽川鎺ф柟寮忓拰瀹屾垚鏃堕檺涓嶈兘涓虹┖");
                     }
                         // 瀵硅薄澶嶅埗
                     QualityMonitorDetails monitorDetails = new QualityMonitorDetails();
                     BeanUtils.copyProperties(detailsUpload, monitorDetails);
+                    monitorDetails.setMonitorWay(normalizeMonitorWay(detailsUpload.getMonitorWay()));
                     monitorDetails.setQualityMonitorId(qualityMonitor.getQualityMonitorId());
+                    if (!detailsUpload.getCompletionMonth().matches("\\d{4}-\\d{2}")) {
+                        throw new ErrorException("瀹屾垚鏃堕檺鏍煎紡搴斾负yyyy-MM");
+                    }
+                    if (StringUtils.isBlank(detailsUpload.getResponsibleName())) {
+                        throw new ErrorException("璐熻矗浜轰笉鑳戒负绌�");
+                    }
+                    List<User> users = userMapper.selectList(Wrappers.<User>lambdaQuery()
+                            .eq(User::getName, detailsUpload.getResponsibleName()));
+                    if (users.size() != 1) throw new ErrorException("璐熻矗浜哄鍚嶄笉瀛樺湪鎴栦笉鍞竴锛�" + detailsUpload.getResponsibleName());
+                    monitorDetails.setResponsibleUserId(users.get(0).getId());
+                    monitorDetails.setItemKind("OTHER");
 
                     detailsUploadList.add(monitorDetails);
                 }
@@ -181,7 +275,21 @@
         } catch (IOException e) {
             throw new RuntimeException(e);
         }
-        return true;
+        return qualityMonitor;
+    }
+
+    /**
+     * 璐ㄦ帶鏂瑰紡缁熶竴鐢ㄢ�溿�佲�濆垎闅旓紝鍏煎瀵煎叆妯℃澘閲屽父瑙佺殑閫楀彿/鍒嗗彿鍐欐硶銆�
+     */
+    private String normalizeMonitorWay(String value) {
+        if (StringUtils.isBlank(value)) {
+            return value;
+        }
+        return java.util.Arrays.stream(value.split("[銆�,锛�;锛沒"))
+                .map(String::trim)
+                .filter(StringUtils::isNotBlank)
+                .distinct()
+                .collect(Collectors.joining("銆�"));
     }
 
     /**
@@ -191,8 +299,16 @@
      */
     @Override
     public boolean examineQualityMonitor(QualityMonitor qualityMonitor) {
-        if (qualityMonitor.getRatifyUserId() == null) {
-            throw new ErrorException("缂哄皯鎵瑰噯浜�");
+        QualityMonitor stored = requirePlan(qualityMonitor.getQualityMonitorId());
+        int current = SecurityUtils.getUserId().intValue();
+        if (!Integer.valueOf(current).equals(stored.getExamineUserId())) {
+            throw new ErrorException("鍙湁鎸囧畾瀹℃牳浜哄彲浠ュ鏍歌鍒�");
+        }
+        if (!"PENDING_REVIEW".equals(effectiveStatus(stored))) {
+            throw new ErrorException("褰撳墠璁″垝涓嶅湪寰呭鏍哥姸鎬�");
+        }
+        if (Integer.valueOf(1).equals(qualityMonitor.getExamineStatus()) && qualityMonitor.getRatifyUserId() == null) {
+            throw new ErrorException("瀹℃牳閫氳繃鏃跺繀椤绘寚瀹氭壒鍑嗕汉");
         }
 
         // 褰撳墠鐧诲綍鐢ㄦ埛
@@ -202,7 +318,11 @@
                 .set(QualityMonitor::getExamineRemark, qualityMonitor.getExamineRemark())
                 .set(QualityMonitor::getExamineStatus, qualityMonitor.getExamineStatus())
                 .set(QualityMonitor::getExamineTime, LocalDateTime.now())
+                .set(QualityMonitor::getWorkflowStatus,
+                        Integer.valueOf(1).equals(qualityMonitor.getExamineStatus()) ? "PENDING_APPROVAL" : "REVIEW_REJECTED")
         );
+
+        if (!Integer.valueOf(1).equals(qualityMonitor.getExamineStatus())) return true;
 
         QualityMonitor monitor = baseMapper.selectById(qualityMonitor.getQualityMonitorId());
 
@@ -247,12 +367,22 @@
      */
     @Override
     public boolean ratifyQualityMonitor(QualityMonitor qualityMonitor) {
+        QualityMonitor stored = requirePlan(qualityMonitor.getQualityMonitorId());
+        int current = SecurityUtils.getUserId().intValue();
+        if (!Integer.valueOf(current).equals(stored.getRatifyUserId())) {
+            throw new ErrorException("鍙湁鎸囧畾鎵瑰噯浜哄彲浠ユ壒鍑嗚鍒�");
+        }
+        if (!"PENDING_APPROVAL".equals(effectiveStatus(stored))) {
+            throw new ErrorException("褰撳墠璁″垝涓嶅湪寰呮壒鍑嗙姸鎬�");
+        }
         // 褰撳墠鐧诲綍鐢ㄦ埛
         baseMapper.update(null, Wrappers.<QualityMonitor>lambdaUpdate()
                 .eq(QualityMonitor::getQualityMonitorId, qualityMonitor.getQualityMonitorId())
                 .set(QualityMonitor::getRatifyRemark, qualityMonitor.getRatifyRemark())
                 .set(QualityMonitor::getRatifyStatus, qualityMonitor.getRatifyStatus())
                 .set(QualityMonitor::getRatifyTime, LocalDateTime.now())
+                .set(QualityMonitor::getWorkflowStatus,
+                        Integer.valueOf(1).equals(qualityMonitor.getRatifyStatus()) ? "APPROVED" : "APPROVAL_REJECTED")
         );
         return true;
     }
@@ -513,7 +643,7 @@
         try {
             response.setContentType("application/msword");
             String fileName = URLEncoder.encode(
-                    "璐ㄩ噺鐩戞帶瀹炴柦璁″垝", "UTF-8");
+                    "璐ㄩ噺鎺у埗鎺柦", "UTF-8");
             response.setHeader("Content-disposition",
                     "attachment;filename=" + fileName + ".docx");
             OutputStream os = response.getOutputStream();
@@ -727,7 +857,7 @@
         try {
             response.setContentType("application/msword");
             String fileName = URLEncoder.encode(
-                    "鐩戞帶璇勪环", "UTF-8");
+                    "璐ㄩ噺鎺у埗璇勪环璁板綍", "UTF-8");
             response.setHeader("Content-disposition",
                     "attachment;filename=" + fileName + ".docx");
             OutputStream os = response.getOutputStream();

--
Gitblit v1.9.3