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-personnel/src/main/java/com/ruoyi/personnel/service/impl/PersonTrainingServiceImpl.java         |   39 ++++---
 cnas-manage/src/main/java/com/ruoyi/manage/service/impl/ManageDocumentControlledServiceImpl.java     |   20 +--
 cnas-personnel/src/main/java/com/ruoyi/personnel/pojo/PersonTrainingDetailed.java                    |    3 
 cnas-personnel/src/main/java/com/ruoyi/personnel/controller/PersonTrainingController.java            |   11 ++
 cnas-process/src/main/resources/static/quality-monitor-details-ratify.docx                           |    0 
 cnas-process/src/main/resources/static/quality-monitor.docx                                          |    0 
 cnas-personnel/src/main/java/com/ruoyi/personnel/service/impl/PersonTrainingDetailedServiceImpl.java |   21 ++-
 cnas-manage/src/main/java/com/ruoyi/manage/service/impl/ManageDocumentListServiceImpl.java           |   33 +++---
 cnas-process/src/main/resources/static/quality-monitor-evaluate.docx                                 |    0 
 cnas-manage/src/main/java/com/ruoyi/manage/util/DocumentPreviewUtils.java                            |   90 ++++++++++++++++++
 cnas-process/src/main/java/com/ruoyi/process/service/impl/QualityMonitorServiceImpl.java             |   19 +++
 cnas-personnel/src/main/resources/mapper/PersonTrainingDetailedMapper.xml                            |    8 
 cnas-manage/src/main/java/com/ruoyi/manage/service/impl/ManageDocumentAlterServiceImpl.java          |   20 +--
 13 files changed, 192 insertions(+), 72 deletions(-)

diff --git a/cnas-manage/src/main/java/com/ruoyi/manage/service/impl/ManageDocumentAlterServiceImpl.java b/cnas-manage/src/main/java/com/ruoyi/manage/service/impl/ManageDocumentAlterServiceImpl.java
index 6576d4b..6984e14 100644
--- a/cnas-manage/src/main/java/com/ruoyi/manage/service/impl/ManageDocumentAlterServiceImpl.java
+++ b/cnas-manage/src/main/java/com/ruoyi/manage/service/impl/ManageDocumentAlterServiceImpl.java
@@ -13,7 +13,9 @@
 import com.ruoyi.common.utils.QueryWrappers;
 import com.ruoyi.common.utils.SecurityUtils;
 import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.framework.exception.ErrorException;
 import com.ruoyi.system.mapper.UserMapper;
+import com.ruoyi.manage.util.DocumentPreviewUtils;
 
 
 import com.ruoyi.manage.mapper.*;
@@ -239,21 +241,11 @@
     @Override
     public void checkManageDocumentAlterPdf(Long id, HttpServletResponse response) throws Exception {
         ManageDocumentAlter manageDocumentAlter = manageDocumentAlterMapper.selectById(id);
-        File file = new File(wordUrl + "/" + manageDocumentAlter.getAlterAfterUrl());
-        FileInputStream fileInputStream = new FileInputStream(file);
-        response.setContentType("application/pdf");
-        response.setCharacterEncoding("UTF-8");
-        response.setHeader("Content-disposition", "inline;filename=" + file.getName());
-        response.setContentLength((int)file.length());
-        OutputStream os = response.getOutputStream();
-        // 灏嗘枃浠跺唴瀹瑰啓鍏ヨ緭鍑烘祦
-        byte[] buffer = new byte[4096];
-        int bytesRead;
-        while ((bytesRead = fileInputStream.read(buffer)) != -1) {
-            os.write(buffer, 0, bytesRead);
+        if (manageDocumentAlter == null || ObjectUtils.isEmpty(manageDocumentAlter.getAlterAfterUrl())) {
+            throw new ErrorException("鏂囦欢鏈笂浼�");
         }
-        os.flush();
-        os.close();
+        // PDF 鐩存帴杈撳嚭锛學ord/鍥剧墖鍦ㄧ嚎杞� PDF锛屼緵鍓嶇棰勮鐩栫珷
+        DocumentPreviewUtils.writeAsPdf(new File(wordUrl + "/" + manageDocumentAlter.getAlterAfterUrl()), response);
     }
 
     @Override
diff --git a/cnas-manage/src/main/java/com/ruoyi/manage/service/impl/ManageDocumentControlledServiceImpl.java b/cnas-manage/src/main/java/com/ruoyi/manage/service/impl/ManageDocumentControlledServiceImpl.java
index 06edf3c..29ed115 100644
--- a/cnas-manage/src/main/java/com/ruoyi/manage/service/impl/ManageDocumentControlledServiceImpl.java
+++ b/cnas-manage/src/main/java/com/ruoyi/manage/service/impl/ManageDocumentControlledServiceImpl.java
@@ -8,6 +8,7 @@
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.ruoyi.common.core.domain.entity.User;
 import com.ruoyi.common.utils.QueryWrappers;
+import com.ruoyi.framework.exception.ErrorException;
 import com.ruoyi.manage.mapper.ManageDocumentControlledMapper;
 import com.ruoyi.manage.mapper.ManageDocumentListMapper;
 import com.ruoyi.manage.mapper.ManageRecordCheckMapper;
@@ -15,6 +16,7 @@
 import com.ruoyi.manage.pojo.ManageDocumentList;
 import com.ruoyi.manage.pojo.ManageRecordCheck;
 import com.ruoyi.manage.service.ManageDocumentControlledService;
+import com.ruoyi.manage.util.DocumentPreviewUtils;
 import com.ruoyi.system.mapper.UserMapper;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
@@ -199,21 +201,11 @@
     @Override
     public void checkManageDocumentControlledPdf(Long id, HttpServletResponse response) throws Exception {
         ManageDocumentControlled manageDocumentControlled = manageDocumentControlledMapper.selectById(id);
-        File file = new File(wordUrl + "/" + manageDocumentControlled.getUrl());
-        FileInputStream fileInputStream = new FileInputStream(file);
-        response.setContentType("application/pdf");
-        response.setCharacterEncoding("UTF-8");
-        response.setHeader("Content-disposition", "inline;filename=" + file.getName());
-        response.setContentLength((int)file.length());
-        OutputStream os = response.getOutputStream();
-        // 灏嗘枃浠跺唴瀹瑰啓鍏ヨ緭鍑烘祦
-        byte[] buffer = new byte[4096];
-        int bytesRead;
-        while ((bytesRead = fileInputStream.read(buffer)) != -1) {
-            os.write(buffer, 0, bytesRead);
+        if (manageDocumentControlled == null || ObjectUtils.isEmpty(manageDocumentControlled.getUrl())) {
+            throw new ErrorException("鏂囦欢鏈笂浼�");
         }
-        os.flush();
-        os.close();
+        // PDF 鐩存帴杈撳嚭锛學ord/鍥剧墖鍦ㄧ嚎杞� PDF锛屼緵鍓嶇棰勮鐩栫珷
+        DocumentPreviewUtils.writeAsPdf(new File(wordUrl + "/" + manageDocumentControlled.getUrl()), response);
     }
 
 }
diff --git a/cnas-manage/src/main/java/com/ruoyi/manage/service/impl/ManageDocumentListServiceImpl.java b/cnas-manage/src/main/java/com/ruoyi/manage/service/impl/ManageDocumentListServiceImpl.java
index ef35755..6284493 100644
--- a/cnas-manage/src/main/java/com/ruoyi/manage/service/impl/ManageDocumentListServiceImpl.java
+++ b/cnas-manage/src/main/java/com/ruoyi/manage/service/impl/ManageDocumentListServiceImpl.java
@@ -11,6 +11,7 @@
 
 
 import com.ruoyi.common.utils.QueryWrappers;
+import com.ruoyi.framework.exception.ErrorException;
 import com.ruoyi.manage.mapper.ManageDocumentListMapper;
 import com.ruoyi.manage.pojo.ManageDocumentList;
 import com.ruoyi.manage.service.ManageDocumentListService;
@@ -25,6 +26,8 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.StandardCopyOption;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -58,29 +61,29 @@
 
     @Override
     public int uploadFile(Integer id, MultipartFile file) {
-        String urlString;
         String pathName;
-        String path;
         ManageDocumentList manageDocumentList = manageDocumentListMapper.selectById(id);
-        if (ObjectUtils.isNotEmpty(manageDocumentList.getUrl())){
-            // 鍒犻櫎鏃ф枃浠�
-            File oldFile = new File(wordUrl + "/" + manageDocumentList.getUrl());
-            oldFile.delete();
+        if (manageDocumentList == null) {
+            throw new ErrorException("鏂囦欢娓呭崟涓嶅瓨鍦�");
         }
-        //涓婁紶鏂版枃浠�
-        path = wordUrl;
+        if (file == null || file.isEmpty()) {
+            throw new ErrorException("璇烽�夋嫨瑕佷笂浼犵殑鏂囦欢");
+        }
+        File realpath = new File(wordUrl).getAbsoluteFile();
         try {
-            File realpath = new File(path);
-            if (!realpath.exists()) {
-                realpath.mkdirs();
+            if (!realpath.exists() && !realpath.mkdirs()) {
+                throw new IOException("鐩綍鍒涘缓澶辫触: " + realpath);
             }
             pathName = UUID.randomUUID() + "_" + file.getOriginalFilename();
-            urlString = realpath + "/" + pathName;
-            file.transferTo(new File(urlString));
+            // 鐢� Files.copy 鑰屼笉鏄� transferTo锛歵ransferTo 閬囧埌鐩稿璺緞浼氭寜 Tomcat 涓存椂鐩綍瑙f瀽
+            Files.copy(file.getInputStream(), new File(realpath, pathName).toPath(), StandardCopyOption.REPLACE_EXISTING);
         } catch (Exception e) {
             e.printStackTrace();
-            System.err.println("闄勪欢涓婁紶閿欒");
-            return 0;
+            throw new ErrorException("闄勪欢涓婁紶閿欒: " + e.getMessage());
+        }
+        if (ObjectUtils.isNotEmpty(manageDocumentList.getUrl())) {
+            // 鍒犻櫎鏃ф枃浠�
+            new File(realpath, manageDocumentList.getUrl()).delete();
         }
         manageDocumentList.setUrl(pathName);
         return manageDocumentListMapper.updateById(manageDocumentList);
diff --git a/cnas-manage/src/main/java/com/ruoyi/manage/util/DocumentPreviewUtils.java b/cnas-manage/src/main/java/com/ruoyi/manage/util/DocumentPreviewUtils.java
new file mode 100644
index 0000000..67d6824
--- /dev/null
+++ b/cnas-manage/src/main/java/com/ruoyi/manage/util/DocumentPreviewUtils.java
@@ -0,0 +1,90 @@
+package com.ruoyi.manage.util;
+
+import com.aspose.words.Document;
+import com.aspose.words.DocumentBuilder;
+import com.aspose.words.License;
+import com.aspose.words.SaveFormat;
+import com.ruoyi.framework.exception.ErrorException;
+import jakarta.servlet.http.HttpServletResponse;
+import org.springframework.core.io.ClassPathResource;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * 浣撶郴鏂囦欢闄勪欢棰勮宸ュ叿锛氭妸闄勪欢缁熶竴浠� PDF 娴佽緭鍑虹粰鍓嶇棰勮/鐩栫珷銆�
+ * PDF 鍘熸牱杈撳嚭锛沇ord銆佸浘鐗囩敤 Aspose.Words 鍦ㄧ嚎杞� PDF锛汦xcel/PPT 绛夋棤娉曡浆 PDF 鐨勬牸寮忕粰鍑烘槑纭彁绀恒��
+ */
+public final class DocumentPreviewUtils {
+
+    private static final String[] WORD_EXT = {".doc", ".docx", ".rtf", ".txt", ".wps"};
+    private static final String[] IMAGE_EXT = {".png", ".jpg", ".jpeg", ".bmp", ".gif"};
+
+    private DocumentPreviewUtils() {
+    }
+
+    public static void writeAsPdf(File file, HttpServletResponse response) throws Exception {
+        if (file == null || !file.exists()) {
+            throw new ErrorException("闄勪欢涓嶅瓨鍦ㄦ垨宸茶鍒犻櫎");
+        }
+        String name = file.getName().toLowerCase();
+        if (name.endsWith(".pdf")) {
+            prepare(response, file.getName(), file.length());
+            try (InputStream in = new FileInputStream(file);
+                 OutputStream os = response.getOutputStream()) {
+                in.transferTo(os);
+                os.flush();
+            }
+            return;
+        }
+
+        Document doc;
+        if (endsWithAny(name, WORD_EXT)) {
+            applyLicense();
+            doc = new Document(file.getPath());
+        } else if (endsWithAny(name, IMAGE_EXT)) {
+            applyLicense();
+            doc = new Document();
+            new DocumentBuilder(doc).insertImage(file.getPath());
+        } else {
+            throw new ErrorException("璇ユ枃浠舵牸寮忎笉鏀寔鍦ㄧ嚎鐩栫珷棰勮锛岃涓婁紶 PDF 鎴� Word 鏂囦欢");
+        }
+
+        // 鍏堣浆鎹㈠埌鍐呭瓨锛岃浆鎹㈠け璐ユ椂鍝嶅簲澶磋繕娌℃彁浜わ紝鍓嶇鎵嶈兘鏀跺埌閿欒淇℃伅
+        ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+        doc.save(buffer, SaveFormat.PDF);
+        byte[] bytes = buffer.toByteArray();
+        prepare(response, file.getName() + ".pdf", bytes.length);
+        try (OutputStream os = response.getOutputStream()) {
+            os.write(bytes);
+            os.flush();
+        }
+    }
+
+    private static void prepare(HttpServletResponse response, String fileName, long length) {
+        response.setContentType("application/pdf");
+        response.setCharacterEncoding("UTF-8");
+        response.setHeader("Content-disposition", "inline;filename=" + fileName);
+        response.setContentLength((int) length);
+    }
+
+    private static boolean endsWithAny(String name, String[] suffixes) {
+        for (String suffix : suffixes) {
+            if (name.endsWith(suffix)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static void applyLicense() throws Exception {
+        // 鍑瘉锛屽惁鍒欒浆鎹㈠悗甯︽按鍗�
+        try (InputStream is = new ClassPathResource("lib/license.xml").getInputStream()) {
+            License license = new License();
+            license.setLicense(is);
+        }
+    }
+}
diff --git a/cnas-personnel/src/main/java/com/ruoyi/personnel/controller/PersonTrainingController.java b/cnas-personnel/src/main/java/com/ruoyi/personnel/controller/PersonTrainingController.java
index e25a6e0..93d8a98 100644
--- a/cnas-personnel/src/main/java/com/ruoyi/personnel/controller/PersonTrainingController.java
+++ b/cnas-personnel/src/main/java/com/ruoyi/personnel/controller/PersonTrainingController.java
@@ -96,8 +96,17 @@
     public Result<?> addOrUpdatePersonTrainingDetailed(@RequestBody PersonTrainingDetailed personTrainingDetailed) {
         if (ObjectUtils.isEmpty(personTrainingDetailed.getId())) {
             personTrainingDetailed.setState(3);
+            personTrainingDetailedService.save(personTrainingDetailed);
+            return Result.success();
         }
-        personTrainingDetailedService.saveOrUpdate(personTrainingDetailed);
+        // 璁插笀鍙兘鍦ㄥ唴閮ㄤ汉鍛樺拰澶栬仒浜哄憳涔嬮棿鍒囨崲锛屽厛鏄惧紡瑕嗙洊涓ゅ垪锛岄伩鍏� updateById 璺宠繃 null 瀵艰嚧鏃у�兼畫鐣�
+        personTrainingDetailedService.update(null, Wrappers.<PersonTrainingDetailed>lambdaUpdate()
+                .eq(PersonTrainingDetailed::getId, personTrainingDetailed.getId())
+                .set(PersonTrainingDetailed::getTrainingLecturerId, personTrainingDetailed.getTrainingLecturerId())
+                .set(PersonTrainingDetailed::getTrainingLecturerName, personTrainingDetailed.getTrainingLecturerName()));
+        personTrainingDetailed.setTrainingLecturerId(null);
+        personTrainingDetailed.setTrainingLecturerName(null);
+        personTrainingDetailedService.updateById(personTrainingDetailed);
         return Result.success();
     }
 
diff --git a/cnas-personnel/src/main/java/com/ruoyi/personnel/pojo/PersonTrainingDetailed.java b/cnas-personnel/src/main/java/com/ruoyi/personnel/pojo/PersonTrainingDetailed.java
index aabc0b1..892dbe5 100644
--- a/cnas-personnel/src/main/java/com/ruoyi/personnel/pojo/PersonTrainingDetailed.java
+++ b/cnas-personnel/src/main/java/com/ruoyi/personnel/pojo/PersonTrainingDetailed.java
@@ -56,6 +56,9 @@
     @Schema(description = "鍩硅璁插笀_id")
     private Integer trainingLecturerId;
 
+    @Schema(description = "澶栬仒/闈炵郴缁熻甯堝鍚嶏紱鍐呴儴璁插笀浠嶅瓨 trainingLecturerId")
+    private String trainingLecturerName;
+
     @Schema(description = "璁″垝鍩硅鏃ユ湡")
     private String trainingDate;
 
diff --git a/cnas-personnel/src/main/java/com/ruoyi/personnel/service/impl/PersonTrainingDetailedServiceImpl.java b/cnas-personnel/src/main/java/com/ruoyi/personnel/service/impl/PersonTrainingDetailedServiceImpl.java
index eb6fa8a..39274d6 100644
--- a/cnas-personnel/src/main/java/com/ruoyi/personnel/service/impl/PersonTrainingDetailedServiceImpl.java
+++ b/cnas-personnel/src/main/java/com/ruoyi/personnel/service/impl/PersonTrainingDetailedServiceImpl.java
@@ -2,7 +2,7 @@
 
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
-import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
+import com.baomidou.mybatisplus.core.toolkit.StringUtils;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
@@ -47,13 +47,20 @@
             PersonTrainingDetailed personTrainingDetailed = new PersonTrainingDetailed();
             BeanUtils.copyProperties(i, personTrainingDetailed);
 
-            // 鍖归厤璁插笀
-            User user = userMapper.selectOne(Wrappers.<User>lambdaQuery()
-                    .eq(User::getName, i.getTrainingLecturerName()));
-            if (ObjectUtils.isEmpty(user)) {
-                throw new ErrorException("鏈壘鍒拌璁插笀锛�" + i.getTrainingLecturerName());
+            // 鍖归厤璁插笀锛氱郴缁熷唴鍞竴鍖归厤鐨勫瓨鐢ㄦ埛ID锛涘鑱�/闈炵郴缁熻甯堟寜濮撳悕鏂囨湰淇濆瓨
+            if (StringUtils.isBlank(i.getTrainingLecturerName())) {
+                throw new ErrorException("鍩硅璁插笀涓嶈兘涓虹┖");
             }
-            personTrainingDetailed.setTrainingLecturerId(user.getId());
+            String lecturerName = i.getTrainingLecturerName().trim();
+            List<User> lecturers = userMapper.selectList(Wrappers.<User>lambdaQuery()
+                    .eq(User::getName, lecturerName));
+            if (lecturers.size() == 1) {
+                personTrainingDetailed.setTrainingLecturerId(lecturers.get(0).getId());
+                personTrainingDetailed.setTrainingLecturerName(null);
+            } else {
+                personTrainingDetailed.setTrainingLecturerId(null);
+                personTrainingDetailed.setTrainingLecturerName(lecturerName);
+            }
             personTrainingDetailed.setPlanId(planId);
             personTrainingDetailed.setState(3);
 
diff --git a/cnas-personnel/src/main/java/com/ruoyi/personnel/service/impl/PersonTrainingServiceImpl.java b/cnas-personnel/src/main/java/com/ruoyi/personnel/service/impl/PersonTrainingServiceImpl.java
index e5d2c50..8a6bd95 100644
--- a/cnas-personnel/src/main/java/com/ruoyi/personnel/service/impl/PersonTrainingServiceImpl.java
+++ b/cnas-personnel/src/main/java/com/ruoyi/personnel/service/impl/PersonTrainingServiceImpl.java
@@ -19,6 +19,7 @@
 import com.ruoyi.common.utils.WxCpUtils;
 import com.ruoyi.framework.exception.ErrorException;
 import com.ruoyi.inspect.util.HackLoopTableRenderPolicy;
+import com.ruoyi.inspect.util.UserUtils;
 import com.ruoyi.personnel.dto.PersonTrainingDetailedDto;
 import com.ruoyi.personnel.dto.PersonTrainingDto;
 import com.ruoyi.personnel.dto.PersonTrainingRecordDto;
@@ -131,11 +132,14 @@
             message += "CNAS鍩硅璁″垝瀹℃牳閫氱煡";
             message += "\n璇峰幓璧勬簮绠$悊-浜哄憳-鍩硅璁″垝濉啓";
             message += "\n" + fileName + "鐨勫煿璁鍒掑緟瀹℃牳";
-            //鍙戦�佷紒涓氬井淇℃秷鎭�氱煡
+            //鍙戦�佷紒涓氬井淇℃秷鎭�氱煡锛堟帴鏀朵汉涓嶅瓨鍦ㄦ垨鍙戦�佸け璐ヤ笉褰卞搷瀵煎叆娴佺▼锛�
+            if (personnel == null || StringUtils.isBlank(personnel.getAccount())) {
+                return;
+            }
             try {
                 WxCpUtils.inform(personnel.getAccount(), message, null);
             } catch (Exception e) {
-                throw new RuntimeException(e);
+                e.printStackTrace();
             }
         });
 
@@ -306,9 +310,10 @@
         // 鏌ヨ浜哄憳鍩硅鏄庣粏
         PersonTrainingDetailedDto detailedDto = personTrainingDetailedMapper.selectTrainingDetail(id);
 
-        // 鐢熸垚鍩硅鑰佸笀绛惧悕
-        detailedDto.setTrainingLecturerRender(StringUtils.isNotBlank(detailedDto.getTrainingLecturerSignatureUrl())
-                    ? Pictures.ofLocal(imgUrl + "/" + detailedDto.getTrainingLecturerSignatureUrl()).create() : null);
+        // 鐢熸垚鍩硅鑰佸笀绛惧悕锛堟湭閰嶇疆绛惧悕鏃剁敤閫忔槑鍥剧墖鍏滃簳锛屾ā鏉块噷鐨勫浘鐗囧崰浣嶄笉鑳戒负 null锛�
+        detailedDto.setTrainingLecturerRender(UserUtils.orTransparentPicture(
+                StringUtils.isNotBlank(detailedDto.getTrainingLecturerSignatureUrl())
+                        ? Pictures.ofLocal(imgUrl + "/" + detailedDto.getTrainingLecturerSignatureUrl()).create() : null));
 
         // 鏌ヨ鍩硅鐨勪汉鍛�
         List<PersonTrainingRecordDto> recordDtos = personTrainingRecordMapper.selectListByTrainingDetailedId(id);
@@ -320,15 +325,15 @@
         for (PersonTrainingRecordDto recordDto : recordDtos) {
             switch (count) {
                 case 0:
-                    exportDto.setUserNameRender1(StringUtils.isNotBlank(recordDto.getSignatureUrl())
-                            ? Pictures.ofLocal(imgUrl + "/" + recordDto.getSignatureUrl()).create() : null);
+                    exportDto.setUserNameRender1(UserUtils.orTransparentPicture(StringUtils.isNotBlank(recordDto.getSignatureUrl())
+                            ? Pictures.ofLocal(imgUrl + "/" + recordDto.getSignatureUrl()).create() : null));
                     exportDto.setDepartment1(recordDto.getDepartment());
                     exportDto.setExaminationResults1(recordDto.getExaminationResults());
                     count ++;
                     break;
                 case 1:
-                    exportDto.setUserNameRender2(StringUtils.isNotBlank(recordDto.getSignatureUrl())
-                            ? Pictures.ofLocal(imgUrl + "/" + recordDto.getSignatureUrl()).create() : null);
+                    exportDto.setUserNameRender2(UserUtils.orTransparentPicture(StringUtils.isNotBlank(recordDto.getSignatureUrl())
+                            ? Pictures.ofLocal(imgUrl + "/" + recordDto.getSignatureUrl()).create() : null));
                     exportDto.setDepartment2(recordDto.getDepartment());
                     exportDto.setExaminationResults2(recordDto.getExaminationResults());
                     exportDtoList.add(exportDto);
@@ -337,14 +342,17 @@
                     break;
             }
         }
-        exportDtoList.add(exportDto);
+        // 鍙湁鍗曟暟鏉¤褰曟椂锛屾渶鍚庝竴琛屾墠鏈夋暟鎹紱鍋舵暟鏉℃椂 exportDto 鏄┖瀵硅薄锛屼笉鑳藉姞杩涜〃鏍�
+        if (count != 0) {
+            exportDtoList.add(exportDto);
+        }
 
-        // 璐ㄩ噺璐熻矗浜�
+        // 璐ㄩ噺璐熻矗浜猴紙鏈鍚嶆椂鐢ㄩ�忔槑鍥剧墖鍏滃簳锛�
         String assessmentUserUrl = null;
         if (detailedDto.getAssessmentUserId() != null) {
-            assessmentUserUrl = userMapper.selectById(detailedDto.getAssessmentUserId()).getSignatureUrl();
-            if (StringUtils.isBlank(assessmentUserUrl)) {
-                throw new ErrorException("鎵句笉鍒拌瘎浠蜂汉鐨勭鍚�");
+            User assessmentUser = userMapper.selectById(detailedDto.getAssessmentUserId());
+            if (assessmentUser != null) {
+                assessmentUserUrl = assessmentUser.getSignatureUrl();
             }
         }
 
@@ -359,7 +367,8 @@
                 new HashMap<String, Object>() {{
                     put("trainingDetail", detailedDto);
                     put("trainingRecordsList", exportDtoList);
-                    put("assessmentUserUrl", StringUtils.isNotBlank(finalAssessmentUserUrl) ? Pictures.ofLocal(imgUrl + "/" + finalAssessmentUserUrl).create() : null);
+                    put("assessmentUserUrl", UserUtils.orTransparentPicture(StringUtils.isNotBlank(finalAssessmentUserUrl)
+                            ? Pictures.ofLocal(imgUrl + "/" + finalAssessmentUserUrl).create() : null));
                 }});
         try {
             response.setContentType("application/msword");
diff --git a/cnas-personnel/src/main/resources/mapper/PersonTrainingDetailedMapper.xml b/cnas-personnel/src/main/resources/mapper/PersonTrainingDetailedMapper.xml
index e0013ed..307c8ed 100644
--- a/cnas-personnel/src/main/resources/mapper/PersonTrainingDetailedMapper.xml
+++ b/cnas-personnel/src/main/resources/mapper/PersonTrainingDetailedMapper.xml
@@ -4,7 +4,7 @@
 
     <select id="queryTheAnnualPlanDetailsTable" resultType="com.ruoyi.personnel.dto.PersonTrainingDetailedDto">
         SELECT cptd.*,
-        u1.name training_lecturer_name,
+        COALESCE(u1.name, cptd.training_lecturer_name) training_lecturer_name,
         dl.name holding_department_name, !isnull(cptr.training_record_id) whether_claim
         FROM cnas_person_training_detailed cptd
         left join user u1 on cptd.training_lecturer_id = u1.id
@@ -18,7 +18,7 @@
                 and u1.id = #{userId}
             </if>
             <if test="trainingLecturerName != null and trainingLecturerName != ''">
-                and u1.name like concat('%', #{trainingLecturerName}, '%')
+                and COALESCE(u1.name, cptd.training_lecturer_name) like concat('%', #{trainingLecturerName}, '%')
             </if>
             <if test="trainingDate != null and trainingDate != ''">
                 and date_format(cptd.training_date,'%Y-%m-%d') = #{trainingDate}
@@ -29,7 +29,7 @@
     <!-- 鏍规嵁涓昏〃id鏌ヨ璇︽儏 -->
     <select id="selectTrainingList" resultType="com.ruoyi.personnel.dto.PersonTrainingDetailedDto">
         SELECT cptd.*,
-               u1.name training_lecturer_name
+               COALESCE(u1.name, cptd.training_lecturer_name) training_lecturer_name
         FROM cnas_person_training_detailed cptd
                  left join user u1 on cptd.training_lecturer_id = u1.id
         where cptd.plan_id = #{trainingId}
@@ -38,7 +38,7 @@
     <!-- 鏌ヨ璇︾粏 -->
     <select id="selectTrainingDetail" resultType="com.ruoyi.personnel.dto.PersonTrainingDetailedDto">
         SELECT cptd.*,
-               u1.name training_lecturer_name,
+               COALESCE(u1.name, cptd.training_lecturer_name) training_lecturer_name,
                u1.signature_url training_lecturer_signature_url
         FROM cnas_person_training_detailed cptd
                  left join user u1 on cptd.training_lecturer_id = u1.id
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 e8f1d62..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
@@ -248,6 +248,7 @@
                         // 瀵硅薄澶嶅埗
                     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");
@@ -275,6 +276,20 @@
             throw new RuntimeException(e);
         }
         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("銆�"));
     }
 
     /**
@@ -628,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();
@@ -842,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();
diff --git a/cnas-process/src/main/resources/static/quality-monitor-details-ratify.docx b/cnas-process/src/main/resources/static/quality-monitor-details-ratify.docx
index 420d810..546e893 100644
--- a/cnas-process/src/main/resources/static/quality-monitor-details-ratify.docx
+++ b/cnas-process/src/main/resources/static/quality-monitor-details-ratify.docx
Binary files differ
diff --git a/cnas-process/src/main/resources/static/quality-monitor-evaluate.docx b/cnas-process/src/main/resources/static/quality-monitor-evaluate.docx
index c3e8a2e..9ab3edd 100644
--- a/cnas-process/src/main/resources/static/quality-monitor-evaluate.docx
+++ b/cnas-process/src/main/resources/static/quality-monitor-evaluate.docx
Binary files differ
diff --git a/cnas-process/src/main/resources/static/quality-monitor.docx b/cnas-process/src/main/resources/static/quality-monitor.docx
index 8ad9990..ad03438 100644
--- a/cnas-process/src/main/resources/static/quality-monitor.docx
+++ b/cnas-process/src/main/resources/static/quality-monitor.docx
Binary files differ

--
Gitblit v1.9.3