From 68b49efb4da346edb42a5d8ebb39af47207402bd Mon Sep 17 00:00:00 2001
From: yxh <172933527@qq.com>
Date: 星期一, 12 十月 2026 11:14:13 +0800
Subject: [PATCH] 修改了报销校验

---
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/project/ServiceReimbursementController.java          |   51 +
 ruoyi-project/src/main/java/com/ruoyi/project/service/impl/DingTalkServiceImpl.java                     |  290 ++++++---
 ruoyi-project/src/main/resources/mapper/project/ServiceDonationwitnessMapper.xml                        |   17 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/project/ServiceDonatecompletioninfoController.java   |   20 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/project/ServiceExternalpersonController.java         |   22 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/project/ServiceDonationwitnessController.java        |   20 
 ruoyi-project/src/main/java/com/ruoyi/project/service/impl/ServiceFunddetailServiceImpl.java            |   46 +
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/project/ServiceDonorpaymentController.java           |   19 
 ruoyi-project/src/main/java/com/ruoyi/project/service/impl/ServiceDonatebaseinfoServiceImpl.java        |   42 
 ruoyi-project/src/main/java/com/ruoyi/project/service/IServiceFundService.java                          |   10 
 ruoyi-project/src/main/java/com/ruoyi/project/service/impl/ServiceDonatecompletioninfoServiceImpl.java  |   45 +
 ruoyi-project/src/main/java/com/ruoyi/project/service/impl/ServiceFundServiceImpl.java                  |  226 ++++++-
 ruoyi-project/src/main/resources/mapper/project/ServiceExternalpersonMapper.xml                         |    4 
 ruoyi-project/src/main/java/com/ruoyi/project/service/impl/ServiceEthicalreviewopinionsServiceImpl.java |   42 
 ruoyi-project/src/main/java/com/ruoyi/project/mapper/ServiceDonationwitnessMapper.java                  |   13 
 ruoyi-project/src/main/java/com/ruoyi/project/service/impl/ServiceRelativesconfirmationServiceImpl.java |   43 +
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/project/ServiceRelativesconfirmationController.java  |   13 
 ruoyi-common/src/main/java/com/ruoyi/common/utils/MergeFilesToPDFUtils.java                             |   40 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/project/ServiceFundController.java                   |  161 ++--
 ruoyi-project/src/main/java/com/ruoyi/project/service/impl/ServiceReimbursementServiceImpl.java         |  120 +++
 ruoyi-admin/src/main/resources/application.yml                                                          |    5 
 ruoyi-project/src/main/java/com/ruoyi/project/service/impl/ServiceDonationwitnessServiceImpl.java       |   45 +
 ruoyi-project/src/main/java/com/ruoyi/project/domain/ServiceFunddetail.java                             |    7 
 ruoyi-project/src/main/resources/mapper/project/ServiceFunddetailMapper.xml                             |    3 
 ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/RyTask.java                                            |   11 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/project/ServiceDonatebaseinfoController.java         |  305 +++++-----
 ruoyi-project/src/main/java/com/ruoyi/project/service/impl/ServiceExternalpersonServiceImpl.java        |    3 
 27 files changed, 1,068 insertions(+), 555 deletions(-)

diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/project/ServiceDonatebaseinfoController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/project/ServiceDonatebaseinfoController.java
index b30772c..879f517 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/project/ServiceDonatebaseinfoController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/project/ServiceDonatebaseinfoController.java
@@ -262,18 +262,16 @@
 
         //杈撳嚭鏂囨。璺緞鍙婂悕绉�
         File outFile = new File(RuoYiConfig.getProfile() + "/download/wordtemplate/" + name + ".doc");
-        Writer out = null;
-
-        try {
-            out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "utf-8"));
-
-        } catch (FileNotFoundException e1) {
-            e1.printStackTrace();
+        if (t == null) {
+            throw new ServiceException("妯℃澘鍔犺浇澶辫触锛岃妫�鏌ユā鏉挎枃浠舵槸鍚﹀瓨鍦�", HttpStatus.NO_CONTENT);
         }
-        try {
+
+        // Writer 蹇呴』鍏抽棴/鍒锋柊锛欱ufferedWriter 甯︾紦鍐诧紝涓嶅叧闂細瀵艰嚧鐢熸垚鐨� doc 鍐呭涓嶅畬鏁�
+        try (Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "utf-8"))) {
             t.process(dataMap, out);
-        } catch (TemplateException e) {
-            e.printStackTrace();
+        } catch (TemplateException | IOException e) {
+            log.error("鐢熸垚妯℃澘鏂囨。澶辫触, name={}", name, e);
+            throw new ServiceException("鐢熸垚鏂囨。澶辫触", HttpStatus.ERROR);
         }
         Map<String, Object> map = new HashMap<>();
         map.put("downloadUrl", "/profile/download/wordtemplate/" + name + ".doc");
@@ -292,44 +290,56 @@
             throw new ServiceException("涓嬭浇澶辫触锛岀敤鎴蜂俊鎭嚭閿�", HttpStatus.NO_CONTENT);
         }
 
+        // 浠ヤ笅瀛楁鍦ㄦ暟鎹簱涓潎鍙负绌猴紝缁熶竴鍙栫┖涓插厹搴曪紝閬垮厤鎷艰妯℃澘鏃舵姏绌烘寚閽堝紓甯�
+        String diseasetype = serviceDonatebaseinfo.getDiseasetype() == null ? "" : serviceDonatebaseinfo.getDiseasetype();
+        String infectious = serviceDonatebaseinfo.getInfectious() == null ? "" : serviceDonatebaseinfo.getInfectious();
+        String infosources = serviceDonatebaseinfo.getInfosources() == null ? "" : serviceDonatebaseinfo.getInfosources();
+        String selfwill = serviceDonatebaseinfo.getSelfwill() == null ? "" : serviceDonatebaseinfo.getSelfwill();
+        String othercases = serviceDonatebaseinfo.getOthercases() == null ? "" : serviceDonatebaseinfo.getOthercases();
+        String kinship = serviceDonatebaseinfo.getKinship() == null ? "" : serviceDonatebaseinfo.getKinship();
+        String patientstate = serviceDonatebaseinfo.getPatientstate() == null ? "" : serviceDonatebaseinfo.getPatientstate();
+
         dataMap.put("JXBH", serviceDonatebaseinfo.getDonorno() == null ? "" : serviceDonatebaseinfo.getDonorno());
         dataMap.put("SZYLJG", serviceDonatebaseinfo.getTreatmenthospitalname() == null ? "" : serviceDonatebaseinfo.getTreatmenthospitalname());
         dataMap.put("KS", serviceDonatebaseinfo.getTreatmentdeptname() == null ? "" : serviceDonatebaseinfo.getTreatmentdeptname());
         dataMap.put("XM", serviceDonatebaseinfo.getName() == null ? "" : serviceDonatebaseinfo.getName());
-        if (serviceDonatebaseinfo.getSex().equals("0")) {
+        if ("0".equals(serviceDonatebaseinfo.getSex())) {
             dataMap.put("XB", "鏈煡鐨勬�у埆");
-        } else if (serviceDonatebaseinfo.getSex().equals("1")) {
+        } else if ("1".equals(serviceDonatebaseinfo.getSex())) {
             dataMap.put("XB", "鐢�");
-        } else if (serviceDonatebaseinfo.getSex().equals("2")) {
+        } else if ("2".equals(serviceDonatebaseinfo.getSex())) {
             dataMap.put("XB", "濂�");
         }
-        Date dt = serviceDonatebaseinfo.getBirthday();
         SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
-        String date = formatter.format(dt);
-        String time = date.substring(0, 10);
-        dataMap.put("CSRQ", serviceDonatebaseinfo.getBirthday() == null ? "" : time);
+        String csrq = "";
+        if (serviceDonatebaseinfo.getBirthday() != null) {
+            csrq = formatter.format(serviceDonatebaseinfo.getBirthday()).substring(0, 10);
+        }
+        dataMap.put("CSRQ", csrq);
         dataMap.put("GJ", serviceDonatebaseinfo.getNationality() == null ? "" : serviceDonatebaseinfo.getNationality());
-        if (serviceDonatebaseinfo.getIdcardtype() == 1) {
+        // idcardtype 涓哄寘瑁呯被鍨� Long锛屾暟鎹簱涓彲涓� NULL锛涘厛鍙栧�煎啀鍒ゆ柇锛岄伩鍏嶈嚜鍔ㄦ媶绠辨姏绌烘寚閽�
+        Long idcardtype = serviceDonatebaseinfo.getIdcardtype();
+        if (idcardtype != null && idcardtype == 1) {
             dataMap.put("ZJLX", "韬唤璇�");
-        } else if (serviceDonatebaseinfo.getIdcardtype() == 2) {
+        } else if (idcardtype != null && idcardtype == 2) {
             dataMap.put("ZJLX", "鍐涗汉璇�");
-        } else if (serviceDonatebaseinfo.getIdcardtype() == 3) {
+        } else if (idcardtype != null && idcardtype == 3) {
             dataMap.put("ZJLX", "鎶ょ収");
-        } else if (serviceDonatebaseinfo.getIdcardtype() == 4) {
+        } else if (idcardtype != null && idcardtype == 4) {
             dataMap.put("ZJLX", "鎴峰彛鏈�");
-        } else if (serviceDonatebaseinfo.getIdcardtype() == 5) {
+        } else if (idcardtype != null && idcardtype == 5) {
             dataMap.put("ZJLX", "澶栧浗浜烘案涔呭眳浣忚瘉");
-        } else if (serviceDonatebaseinfo.getIdcardtype() == 6) {
+        } else if (idcardtype != null && idcardtype == 6) {
             dataMap.put("ZJLX", "姝﹁璇�");
-        } else if (serviceDonatebaseinfo.getIdcardtype() == 10) {
+        } else if (idcardtype != null && idcardtype == 10) {
             dataMap.put("ZJLX", "瀛︾敓璇�");
-        } else if (serviceDonatebaseinfo.getIdcardtype() == 11) {
+        } else if (idcardtype != null && idcardtype == 11) {
             dataMap.put("ZJLX", "澹叺璇�");
-        } else if (serviceDonatebaseinfo.getIdcardtype() == 16) {
+        } else if (idcardtype != null && idcardtype == 16) {
             dataMap.put("ZJLX", "娓境灞呮皯鏉ュ線鍐呭湴閫氳璇�");
-        } else if (serviceDonatebaseinfo.getIdcardtype() == 17) {
+        } else if (idcardtype != null && idcardtype == 17) {
             dataMap.put("ZJLX", "鍙版咕灞呮皯鏉ュ線澶ч檰閫氳璇�");
-        } else if (serviceDonatebaseinfo.getIdcardtype() == 18) {
+        } else if (idcardtype != null && idcardtype == 18) {
             dataMap.put("ZJLX", "鍏朵粬璇佷欢绫诲瀷");
         }
         dataMap.put("ZJHM", serviceDonatebaseinfo.getIdcardno() == null ? "" : serviceDonatebaseinfo.getIdcardno());
@@ -346,28 +356,28 @@
 
         dataMap.put("ZYH", serviceDonatebaseinfo.getInpatientno() == null ? "" : serviceDonatebaseinfo.getInpatientno());
 
-        if (serviceDonatebaseinfo.getBloodtype().equals("1")) {
+        if ("1".equals(serviceDonatebaseinfo.getBloodtype())) {
             dataMap.put("XXA", (char) 8730);
             dataMap.put("XXB", "鈻�");
             dataMap.put("XXO", "鈻�");
             dataMap.put("XXAB", "鈻�");
-        } else if (serviceDonatebaseinfo.getBloodtype().equals("2")) {
+        } else if ("2".equals(serviceDonatebaseinfo.getBloodtype())) {
             dataMap.put("XXA", "鈻�");
             dataMap.put("XXB", (char) 8730);
             dataMap.put("XXO", "鈻�");
             dataMap.put("XXAB", "鈻�");
-        } else if (serviceDonatebaseinfo.getBloodtype().equals("3")) {
+        } else if ("3".equals(serviceDonatebaseinfo.getBloodtype())) {
             dataMap.put("XXA", "鈻�");
             dataMap.put("XXB", "鈻�");
             dataMap.put("XXO", (char) 8730);
             dataMap.put("XXAB", "鈻�");
-        } else if (serviceDonatebaseinfo.getBloodtype().equals("4")) {
+        } else if ("4".equals(serviceDonatebaseinfo.getBloodtype())) {
             dataMap.put("XXA", "鈻�");
             dataMap.put("XXB", "鈻�");
             dataMap.put("XXO", "鈻�");
             dataMap.put("XXAB", (char) 8730);
         }
-        if (serviceDonatebaseinfo.getRhyin().equals("1")) {
+        if ("1".equals(serviceDonatebaseinfo.getRhyin())) {
             dataMap.put("YX", (char) 8730);
         } else {
             dataMap.put("YX", "鈻�");
@@ -376,22 +386,22 @@
         dataMap.put("JBZD", serviceDonatebaseinfo.getDiagnosisname() == null ? "" : serviceDonatebaseinfo.getDiagnosisname());
 
         //鐤剧梾绫诲瀷
-        if (serviceDonatebaseinfo.getDiseasetype().contains("0")) {
+        if (diseasetype.contains("0")) {
             dataMap.put("NXGYW", (char) 8730);
-            if (serviceDonatebaseinfo.getDiseasetype().contains("1")) {
+            if (diseasetype.contains("1")) {
                 dataMap.put("NWS", (char) 8730);
-                if (serviceDonatebaseinfo.getDiseasetype().contains("2")) {
+                if (diseasetype.contains("2")) {
                     dataMap.put("QXQY", (char) 8730);
-                    if (serviceDonatebaseinfo.getDiseasetype().contains("3")) {
+                    if (diseasetype.contains("3")) {
                         dataMap.put("NZL", (char) 8730);
-                        if (serviceDonatebaseinfo.getDiseasetype().contains("4")) {
+                        if (diseasetype.contains("4")) {
                             dataMap.put("XXGJB", (char) 8730);
                         } else {
                             dataMap.put("XXGJB", "鈻�");
                         }
                     } else {
                         dataMap.put("NZL", "鈻�");
-                        if (serviceDonatebaseinfo.getDiseasetype().contains("4")) {
+                        if (diseasetype.contains("4")) {
                             dataMap.put("XXGJB", (char) 8730);
                         } else {
                             dataMap.put("XXGJB", "鈻�");
@@ -399,16 +409,16 @@
                     }
                 } else {
                     dataMap.put("QXQY", "鈻�");
-                    if (serviceDonatebaseinfo.getDiseasetype().contains("3")) {
+                    if (diseasetype.contains("3")) {
                         dataMap.put("NZL", (char) 8730);
-                        if (serviceDonatebaseinfo.getDiseasetype().contains("4")) {
+                        if (diseasetype.contains("4")) {
                             dataMap.put("XXGJB", (char) 8730);
                         } else {
                             dataMap.put("XXGJB", "鈻�");
                         }
                     } else {
                         dataMap.put("NZL", "鈻�");
-                        if (serviceDonatebaseinfo.getDiseasetype().contains("4")) {
+                        if (diseasetype.contains("4")) {
                             dataMap.put("XXGJB", (char) 8730);
                         } else {
                             dataMap.put("XXGJB", "鈻�");
@@ -417,18 +427,18 @@
                 }
             } else {
                 dataMap.put("NWS", "鈻�");
-                if (serviceDonatebaseinfo.getDiseasetype().contains("2")) {
+                if (diseasetype.contains("2")) {
                     dataMap.put("QXQY", (char) 8730);
-                    if (serviceDonatebaseinfo.getDiseasetype().contains("3")) {
+                    if (diseasetype.contains("3")) {
                         dataMap.put("NZL", (char) 8730);
-                        if (serviceDonatebaseinfo.getDiseasetype().contains("4")) {
+                        if (diseasetype.contains("4")) {
                             dataMap.put("XXGJB", (char) 8730);
                         } else {
                             dataMap.put("XXGJB", "鈻�");
                         }
                     } else {
                         dataMap.put("NZL", "鈻�");
-                        if (serviceDonatebaseinfo.getDiseasetype().contains("4")) {
+                        if (diseasetype.contains("4")) {
                             dataMap.put("XXGJB", (char) 8730);
                         } else {
                             dataMap.put("XXGJB", "鈻�");
@@ -436,16 +446,16 @@
                     }
                 } else {
                     dataMap.put("QXQY", "鈻�");
-                    if (serviceDonatebaseinfo.getDiseasetype().contains("3")) {
+                    if (diseasetype.contains("3")) {
                         dataMap.put("NZL", (char) 8730);
-                        if (serviceDonatebaseinfo.getDiseasetype().contains("4")) {
+                        if (diseasetype.contains("4")) {
                             dataMap.put("XXGJB", (char) 8730);
                         } else {
                             dataMap.put("XXGJB", "鈻�");
                         }
                     } else {
                         dataMap.put("NZL", "鈻�");
-                        if (serviceDonatebaseinfo.getDiseasetype().contains("4")) {
+                        if (diseasetype.contains("4")) {
                             dataMap.put("XXGJB", (char) 8730);
                         } else {
                             dataMap.put("XXGJB", "鈻�");
@@ -455,20 +465,20 @@
             }
         } else {
             dataMap.put("NXGYW", "鈻�");
-            if (serviceDonatebaseinfo.getDiseasetype().contains("1")) {
+            if (diseasetype.contains("1")) {
                 dataMap.put("NWS", (char) 8730);
-                if (serviceDonatebaseinfo.getDiseasetype().contains("2")) {
+                if (diseasetype.contains("2")) {
                     dataMap.put("QXQY", (char) 8730);
-                    if (serviceDonatebaseinfo.getDiseasetype().contains("3")) {
+                    if (diseasetype.contains("3")) {
                         dataMap.put("NZL", (char) 8730);
-                        if (serviceDonatebaseinfo.getDiseasetype().contains("4")) {
+                        if (diseasetype.contains("4")) {
                             dataMap.put("XXGJB", (char) 8730);
                         } else {
                             dataMap.put("XXGJB", "鈻�");
                         }
                     } else {
                         dataMap.put("NZL", "鈻�");
-                        if (serviceDonatebaseinfo.getDiseasetype().contains("4")) {
+                        if (diseasetype.contains("4")) {
                             dataMap.put("XXGJB", (char) 8730);
                         } else {
                             dataMap.put("XXGJB", "鈻�");
@@ -476,16 +486,16 @@
                     }
                 } else {
                     dataMap.put("QXQY", "鈻�");
-                    if (serviceDonatebaseinfo.getDiseasetype().contains("3")) {
+                    if (diseasetype.contains("3")) {
                         dataMap.put("NZL", (char) 8730);
-                        if (serviceDonatebaseinfo.getDiseasetype().contains("4")) {
+                        if (diseasetype.contains("4")) {
                             dataMap.put("XXGJB", (char) 8730);
                         } else {
                             dataMap.put("XXGJB", "鈻�");
                         }
                     } else {
                         dataMap.put("NZL", "鈻�");
-                        if (serviceDonatebaseinfo.getDiseasetype().contains("4")) {
+                        if (diseasetype.contains("4")) {
                             dataMap.put("XXGJB", (char) 8730);
                         } else {
                             dataMap.put("XXGJB", "鈻�");
@@ -494,18 +504,18 @@
                 }
             } else {
                 dataMap.put("NWS", "鈻�");
-                if (serviceDonatebaseinfo.getDiseasetype().contains("2")) {
+                if (diseasetype.contains("2")) {
                     dataMap.put("QXQY", (char) 8730);
-                    if (serviceDonatebaseinfo.getDiseasetype().contains("3")) {
+                    if (diseasetype.contains("3")) {
                         dataMap.put("NZL", (char) 8730);
-                        if (serviceDonatebaseinfo.getDiseasetype().contains("4")) {
+                        if (diseasetype.contains("4")) {
                             dataMap.put("XXGJB", (char) 8730);
                         } else {
                             dataMap.put("XXGJB", "鈻�");
                         }
                     } else {
                         dataMap.put("NZL", "鈻�");
-                        if (serviceDonatebaseinfo.getDiseasetype().contains("4")) {
+                        if (diseasetype.contains("4")) {
                             dataMap.put("XXGJB", (char) 8730);
                         } else {
                             dataMap.put("XXGJB", "鈻�");
@@ -513,16 +523,16 @@
                     }
                 } else {
                     dataMap.put("QXQY", "鈻�");
-                    if (serviceDonatebaseinfo.getDiseasetype().contains("3")) {
+                    if (diseasetype.contains("3")) {
                         dataMap.put("NZL", (char) 8730);
-                        if (serviceDonatebaseinfo.getDiseasetype().contains("4")) {
+                        if (diseasetype.contains("4")) {
                             dataMap.put("XXGJB", (char) 8730);
                         } else {
                             dataMap.put("XXGJB", "鈻�");
                         }
                     } else {
                         dataMap.put("NZL", "鈻�");
-                        if (serviceDonatebaseinfo.getDiseasetype().contains("4")) {
+                        if (diseasetype.contains("4")) {
                             dataMap.put("XXGJB", (char) 8730);
                         } else {
                             dataMap.put("XXGJB", "鈻�");
@@ -536,20 +546,20 @@
 
 
         //浼犳煋鐥呮儏鍐�
-        if (serviceDonatebaseinfo.getInfectious().contains("1")) {
+        if (infectious.contains("1")) {
             dataMap.put("YG", (char) 8730);
-            if (serviceDonatebaseinfo.getInfectious().contains("2")) {
+            if (infectious.contains("2")) {
                 dataMap.put("BG", (char) 8730);
-                if (serviceDonatebaseinfo.getInfectious().contains("3")) {
+                if (infectious.contains("3")) {
                     dataMap.put("MD", (char) 8730);
-                    if (serviceDonatebaseinfo.getInfectious().contains("4")) {
+                    if (infectious.contains("4")) {
                         dataMap.put("AZB", (char) 8730);
                     } else {
                         dataMap.put("AZB", "鈻�");
                     }
                 } else {
                     dataMap.put("MD", "鈻�");
-                    if (serviceDonatebaseinfo.getInfectious().contains("4")) {
+                    if (infectious.contains("4")) {
                         dataMap.put("AZB", (char) 8730);
                     } else {
                         dataMap.put("AZB", "鈻�");
@@ -557,16 +567,16 @@
                 }
             } else {
                 dataMap.put("BG", "鈻�");
-                if (serviceDonatebaseinfo.getInfectious().contains("3")) {
+                if (infectious.contains("3")) {
                     dataMap.put("MD", (char) 8730);
-                    if (serviceDonatebaseinfo.getInfectious().contains("4")) {
+                    if (infectious.contains("4")) {
                         dataMap.put("AZB", (char) 8730);
                     } else {
                         dataMap.put("AZB", "鈻�");
                     }
                 } else {
                     dataMap.put("MD", "鈻�");
-                    if (serviceDonatebaseinfo.getInfectious().contains("4")) {
+                    if (infectious.contains("4")) {
                         dataMap.put("AZB", (char) 8730);
                     } else {
                         dataMap.put("AZB", "鈻�");
@@ -575,18 +585,18 @@
             }
         } else {
             dataMap.put("YG", "鈻�");
-            if (serviceDonatebaseinfo.getInfectious().contains("2")) {
+            if (infectious.contains("2")) {
                 dataMap.put("BG", (char) 8730);
-                if (serviceDonatebaseinfo.getInfectious().contains("3")) {
+                if (infectious.contains("3")) {
                     dataMap.put("MD", (char) 8730);
-                    if (serviceDonatebaseinfo.getInfectious().contains("4")) {
+                    if (infectious.contains("4")) {
                         dataMap.put("AZB", (char) 8730);
                     } else {
                         dataMap.put("AZB", "鈻�");
                     }
                 } else {
                     dataMap.put("MD", "鈻�");
-                    if (serviceDonatebaseinfo.getInfectious().contains("4")) {
+                    if (infectious.contains("4")) {
                         dataMap.put("AZB", (char) 8730);
                     } else {
                         dataMap.put("AZB", "鈻�");
@@ -594,16 +604,16 @@
                 }
             } else {
                 dataMap.put("BG", "鈻�");
-                if (serviceDonatebaseinfo.getInfectious().contains("3")) {
+                if (infectious.contains("3")) {
                     dataMap.put("MD", (char) 8730);
-                    if (serviceDonatebaseinfo.getInfectious().contains("4")) {
+                    if (infectious.contains("4")) {
                         dataMap.put("AZB", (char) 8730);
                     } else {
                         dataMap.put("AZB", "鈻�");
                     }
                 } else {
                     dataMap.put("MD", "鈻�");
-                    if (serviceDonatebaseinfo.getInfectious().contains("4")) {
+                    if (infectious.contains("4")) {
                         dataMap.put("AZB", (char) 8730);
                     } else {
                         dataMap.put("AZB", "鈻�");
@@ -613,16 +623,16 @@
         }
         dataMap.put("CRBQT", serviceDonatebaseinfo.getInfectiousOther() == null ? "" : serviceDonatebaseinfo.getInfectiousOther());
         //鐥呬汉鐘跺喌
-        if (serviceDonatebaseinfo.getPatientstate().contains("0")) {
+        if (patientstate.contains("0")) {
             dataMap.put("SDHM", (char) 8730);
-            if (serviceDonatebaseinfo.getPatientstate().contains("1")) {
+            if (patientstate.contains("1")) {
                 dataMap.put("WZZHX", (char) 8730);
             } else {
                 dataMap.put("WZZHX", "鈻�");
             }
         } else {
             dataMap.put("SDHM", "鈻�");
-            if (serviceDonatebaseinfo.getPatientstate().contains("1")) {
+            if (patientstate.contains("1")) {
                 dataMap.put("WZZHX", (char) 8730);
             } else {
                 dataMap.put("WZZHX", "鈻�");
@@ -630,20 +640,20 @@
         }
 
         //鍏朵粬鎯呭喌
-        if (serviceDonatebaseinfo.getOthercases().contains("0")) {
+        if (othercases.contains("0")) {
             dataMap.put("JTSG", (char) 8730);
-            if (serviceDonatebaseinfo.getOthercases().contains("1")) {
+            if (othercases.contains("1")) {
                 dataMap.put("XSAJ", (char) 8730);
-                if (serviceDonatebaseinfo.getOthercases().contains("2")) {
+                if (othercases.contains("2")) {
                     dataMap.put("GSSG", (char) 8730);
-                    if (serviceDonatebaseinfo.getOthercases().contains("3")) {
+                    if (othercases.contains("3")) {
                         dataMap.put("QTYWSG", (char) 8730);
                     } else {
                         dataMap.put("QTYWSG", "鈻�");
                     }
                 } else {
                     dataMap.put("GSSG", "鈻�");
-                    if (serviceDonatebaseinfo.getOthercases().contains("3")) {
+                    if (othercases.contains("3")) {
                         dataMap.put("QTYWSG", (char) 8730);
                     } else {
                         dataMap.put("QTYWSG", "鈻�");
@@ -651,16 +661,16 @@
                 }
             } else {
                 dataMap.put("XSAJ", "鈻�");
-                if (serviceDonatebaseinfo.getOthercases().contains("2")) {
+                if (othercases.contains("2")) {
                     dataMap.put("GSSG", (char) 8730);
-                    if (serviceDonatebaseinfo.getOthercases().contains("3")) {
+                    if (othercases.contains("3")) {
                         dataMap.put("QTYWSG", (char) 8730);
                     } else {
                         dataMap.put("QTYWSG", "鈻�");
                     }
                 } else {
                     dataMap.put("GSSG", "鈻�");
-                    if (serviceDonatebaseinfo.getOthercases().contains("3")) {
+                    if (othercases.contains("3")) {
                         dataMap.put("QTYWSG", (char) 8730);
                     } else {
                         dataMap.put("QTYWSG", "鈻�");
@@ -669,18 +679,18 @@
             }
         } else {
             dataMap.put("JTSG", "鈻�");
-            if (serviceDonatebaseinfo.getOthercases().contains("1")) {
+            if (othercases.contains("1")) {
                 dataMap.put("XSAJ", (char) 8730);
-                if (serviceDonatebaseinfo.getOthercases().contains("2")) {
+                if (othercases.contains("2")) {
                     dataMap.put("GSSG", (char) 8730);
-                    if (serviceDonatebaseinfo.getOthercases().contains("3")) {
+                    if (othercases.contains("3")) {
                         dataMap.put("QTYWSG", (char) 8730);
                     } else {
                         dataMap.put("QTYWSG", "鈻�");
                     }
                 } else {
                     dataMap.put("GSSG", "鈻�");
-                    if (serviceDonatebaseinfo.getOthercases().contains("3")) {
+                    if (othercases.contains("3")) {
                         dataMap.put("QTYWSG", (char) 8730);
                     } else {
                         dataMap.put("QTYWSG", "鈻�");
@@ -688,16 +698,16 @@
                 }
             } else {
                 dataMap.put("XSAJ", "鈻�");
-                if (serviceDonatebaseinfo.getOthercases().contains("2")) {
+                if (othercases.contains("2")) {
                     dataMap.put("GSSG", (char) 8730);
-                    if (serviceDonatebaseinfo.getOthercases().contains("3")) {
+                    if (othercases.contains("3")) {
                         dataMap.put("QTYWSG", (char) 8730);
                     } else {
                         dataMap.put("QTYWSG", "鈻�");
                     }
                 } else {
                     dataMap.put("GSSG", "鈻�");
-                    if (serviceDonatebaseinfo.getOthercases().contains("3")) {
+                    if (othercases.contains("3")) {
                         dataMap.put("QTYWSG", (char) 8730);
                     } else {
                         dataMap.put("QTYWSG", "鈻�");
@@ -707,20 +717,20 @@
         }
 
         //鎯呬翰灞炲叧绯绘儏鍐�
-        if (serviceDonatebaseinfo.getKinship().contains("0")) {
+        if (kinship.contains("0")) {
             dataMap.put("PE", (char) 8730);
-            if (serviceDonatebaseinfo.getKinship().contains("1")) {
+            if (kinship.contains("1")) {
                 dataMap.put("ZN", (char) 8730);
-                if (serviceDonatebaseinfo.getKinship().contains("2")) {
+                if (kinship.contains("2")) {
                     dataMap.put("FQ", (char) 8730);
-                    if (serviceDonatebaseinfo.getKinship().contains("3")) {
+                    if (kinship.contains("3")) {
                         dataMap.put("MQ", (char) 8730);
                     } else {
                         dataMap.put("MQ", "鈻�");
                     }
                 } else {
                     dataMap.put("FQ", "鈻�");
-                    if (serviceDonatebaseinfo.getKinship().contains("3")) {
+                    if (kinship.contains("3")) {
                         dataMap.put("MQ", (char) 8730);
                     } else {
                         dataMap.put("MQ", "鈻�");
@@ -728,16 +738,16 @@
                 }
             } else {
                 dataMap.put("ZN", "鈻�");
-                if (serviceDonatebaseinfo.getKinship().contains("2")) {
+                if (kinship.contains("2")) {
                     dataMap.put("FQ", (char) 8730);
-                    if (serviceDonatebaseinfo.getKinship().contains("3")) {
+                    if (kinship.contains("3")) {
                         dataMap.put("MQ", (char) 8730);
                     } else {
                         dataMap.put("MQ", "鈻�");
                     }
                 } else {
                     dataMap.put("FQ", "鈻�");
-                    if (serviceDonatebaseinfo.getKinship().contains("3")) {
+                    if (kinship.contains("3")) {
                         dataMap.put("MQ", (char) 8730);
                     } else {
                         dataMap.put("MQ", "鈻�");
@@ -746,18 +756,18 @@
             }
         } else {
             dataMap.put("PE", "鈻�");
-            if (serviceDonatebaseinfo.getKinship().contains("1")) {
+            if (kinship.contains("1")) {
                 dataMap.put("ZN", (char) 8730);
-                if (serviceDonatebaseinfo.getKinship().contains("2")) {
+                if (kinship.contains("2")) {
                     dataMap.put("FQ", (char) 8730);
-                    if (serviceDonatebaseinfo.getKinship().contains("3")) {
+                    if (kinship.contains("3")) {
                         dataMap.put("MQ", (char) 8730);
                     } else {
                         dataMap.put("MQ", "鈻�");
                     }
                 } else {
                     dataMap.put("FQ", "鈻�");
-                    if (serviceDonatebaseinfo.getKinship().contains("3")) {
+                    if (kinship.contains("3")) {
                         dataMap.put("MQ", (char) 8730);
                     } else {
                         dataMap.put("MQ", "鈻�");
@@ -765,16 +775,16 @@
                 }
             } else {
                 dataMap.put("ZN", "鈻�");
-                if (serviceDonatebaseinfo.getKinship().contains("2")) {
+                if (kinship.contains("2")) {
                     dataMap.put("FQ", (char) 8730);
-                    if (serviceDonatebaseinfo.getKinship().contains("3")) {
+                    if (kinship.contains("3")) {
                         dataMap.put("MQ", (char) 8730);
                     } else {
                         dataMap.put("MQ", "鈻�");
                     }
                 } else {
                     dataMap.put("FQ", "鈻�");
-                    if (serviceDonatebaseinfo.getKinship().contains("3")) {
+                    if (kinship.contains("3")) {
                         dataMap.put("MQ", (char) 8730);
                     } else {
                         dataMap.put("MQ", "鈻�");
@@ -785,20 +795,20 @@
         dataMap.put("QSQT", serviceDonatebaseinfo.getKinshipOther() == null ? "" : serviceDonatebaseinfo.getKinshipOther());
 
         //鏈汉鎹愮尞
-        if (serviceDonatebaseinfo.getSelfwill().contains("0")) {
+        if (selfwill.contains("0")) {
             dataMap.put("ZYDJ", (char) 8730);
-            if (serviceDonatebaseinfo.getSelfwill().contains("1")) {
+            if (selfwill.contains("1")) {
                 dataMap.put("SMTY", (char) 8730);
-                if (serviceDonatebaseinfo.getSelfwill().contains("2")) {
+                if (selfwill.contains("2")) {
                     dataMap.put("KTTY", (char) 8730);
-                    if (serviceDonatebaseinfo.getSelfwill().contains("3")) {
+                    if (selfwill.contains("3")) {
                         dataMap.put("WBSBTY", (char) 8730);
                     } else {
                         dataMap.put("WBSBTY", "鈻�");
                     }
                 } else {
                     dataMap.put("KTTY", "鈻�");
-                    if (serviceDonatebaseinfo.getSelfwill().contains("3")) {
+                    if (selfwill.contains("3")) {
                         dataMap.put("WBSBTY", (char) 8730);
                     } else {
                         dataMap.put("WBSBTY", "鈻�");
@@ -806,16 +816,16 @@
                 }
             } else {
                 dataMap.put("SMTY", "鈻�");
-                if (serviceDonatebaseinfo.getSelfwill().contains("2")) {
+                if (selfwill.contains("2")) {
                     dataMap.put("KTTY", (char) 8730);
-                    if (serviceDonatebaseinfo.getSelfwill().contains("3")) {
+                    if (selfwill.contains("3")) {
                         dataMap.put("WBSBTY", (char) 8730);
                     } else {
                         dataMap.put("WBSBTY", "鈻�");
                     }
                 } else {
                     dataMap.put("KTTY", "鈻�");
-                    if (serviceDonatebaseinfo.getSelfwill().contains("3")) {
+                    if (selfwill.contains("3")) {
                         dataMap.put("WBSBTY", (char) 8730);
                     } else {
                         dataMap.put("WBSBTY", "鈻�");
@@ -824,18 +834,18 @@
             }
         } else {
             dataMap.put("ZYDJ", "鈻�");
-            if (serviceDonatebaseinfo.getSelfwill().contains("1")) {
+            if (selfwill.contains("1")) {
                 dataMap.put("SMTY", (char) 8730);
-                if (serviceDonatebaseinfo.getSelfwill().contains("2")) {
+                if (selfwill.contains("2")) {
                     dataMap.put("KTTY", (char) 8730);
-                    if (serviceDonatebaseinfo.getSelfwill().contains("3")) {
+                    if (selfwill.contains("3")) {
                         dataMap.put("WBSBTY", (char) 8730);
                     } else {
                         dataMap.put("WBSBTY", "鈻�");
                     }
                 } else {
                     dataMap.put("KTTY", "鈻�");
-                    if (serviceDonatebaseinfo.getSelfwill().contains("3")) {
+                    if (selfwill.contains("3")) {
                         dataMap.put("WBSBTY", (char) 8730);
                     } else {
                         dataMap.put("WBSBTY", "鈻�");
@@ -843,16 +853,16 @@
                 }
             } else {
                 dataMap.put("SMTY", "鈻�");
-                if (serviceDonatebaseinfo.getSelfwill().contains("2")) {
+                if (selfwill.contains("2")) {
                     dataMap.put("KTTY", (char) 8730);
-                    if (serviceDonatebaseinfo.getSelfwill().contains("3")) {
+                    if (selfwill.contains("3")) {
                         dataMap.put("WBSBTY", (char) 8730);
                     } else {
                         dataMap.put("WBSBTY", "鈻�");
                     }
                 } else {
                     dataMap.put("KTTY", "鈻�");
-                    if (serviceDonatebaseinfo.getSelfwill().contains("3")) {
+                    if (selfwill.contains("3")) {
                         dataMap.put("WBSBTY", (char) 8730);
                     } else {
                         dataMap.put("WBSBTY", "鈻�");
@@ -883,25 +893,25 @@
             dataMap.put("YJXZGX", "鍙楀鎵樹汉");
         }
         //淇℃伅鏉ユ簮
-        if (serviceDonatebaseinfo.getInfosources().contains("绾㈠崄瀛椾細")) {
+        if (infosources.contains("绾㈠崄瀛椾細")) {
             dataMap.put("HSZH2", (char) 8730);  // 鍕鹃�夌鍙�
         } else {
             dataMap.put("HSZH2", "鈻�");  // 鏂规绗﹀彿
         }
-        if (serviceDonatebaseinfo.getInfosources().contains("鍖荤枟鏈烘瀯")) {
+        if (infosources.contains("鍖荤枟鏈烘瀯")) {
             dataMap.put("YLJG", (char) 8730);
-            if (serviceDonatebaseinfo.getInfosources().contains("瀹跺睘")) {
+            if (infosources.contains("瀹跺睘")) {
                 dataMap.put("QS", (char) 8730);
-                if (serviceDonatebaseinfo.getInfosources().contains("浜ら��")) {
+                if (infosources.contains("浜ら��")) {
                     dataMap.put("JT", (char) 8730);
-                    if (serviceDonatebaseinfo.getInfosources().contains("鍏畨")) {
+                    if (infosources.contains("鍏畨")) {
                         dataMap.put("GA", (char) 8730);
                     } else {
                         dataMap.put("GA", "鈻�");
                     }
                 } else {
                     dataMap.put("JT", "鈻�");
-                    if (serviceDonatebaseinfo.getInfosources().contains("鍏畨")) {
+                    if (infosources.contains("鍏畨")) {
                         dataMap.put("GA", (char) 8730);
                     } else {
                         dataMap.put("GA", "鈻�");
@@ -909,16 +919,16 @@
                 }
             } else {
                 dataMap.put("QS", "鈻�");
-                if (serviceDonatebaseinfo.getInfosources().contains("浜ら��")) {
+                if (infosources.contains("浜ら��")) {
                     dataMap.put("JT", (char) 8730);
-                    if (serviceDonatebaseinfo.getInfosources().contains("鍏畨")) {
+                    if (infosources.contains("鍏畨")) {
                         dataMap.put("GA", (char) 8730);
                     } else {
                         dataMap.put("GA", "鈻�");
                     }
                 } else {
                     dataMap.put("JT", "鈻�");
-                    if (serviceDonatebaseinfo.getInfosources().contains("鍏畨")) {
+                    if (infosources.contains("鍏畨")) {
                         dataMap.put("GA", (char) 8730);
                     } else {
                         dataMap.put("GA", "鈻�");
@@ -927,18 +937,18 @@
             }
         } else {
             dataMap.put("YLJG", "鈻�");
-            if (serviceDonatebaseinfo.getInfosources().contains("瀹跺睘")) {
+            if (infosources.contains("瀹跺睘")) {
                 dataMap.put("QS", (char) 8730);
-                if (serviceDonatebaseinfo.getInfosources().contains("浜ら��")) {
+                if (infosources.contains("浜ら��")) {
                     dataMap.put("JT", (char) 8730);
-                    if (serviceDonatebaseinfo.getInfosources().contains("鍏畨")) {
+                    if (infosources.contains("鍏畨")) {
                         dataMap.put("GA", (char) 8730);
                     } else {
                         dataMap.put("GA", "鈻�");
                     }
                 } else {
                     dataMap.put("JT", "鈻�");
-                    if (serviceDonatebaseinfo.getInfosources().contains("鍏畨")) {
+                    if (infosources.contains("鍏畨")) {
                         dataMap.put("GA", (char) 8730);
                     } else {
                         dataMap.put("GA", "鈻�");
@@ -946,16 +956,16 @@
                 }
             } else {
                 dataMap.put("QS", "鈻�");
-                if (serviceDonatebaseinfo.getInfosources().contains("浜ら��")) {
+                if (infosources.contains("浜ら��")) {
                     dataMap.put("JT", (char) 8730);
-                    if (serviceDonatebaseinfo.getInfosources().contains("鍏畨")) {
+                    if (infosources.contains("鍏畨")) {
                         dataMap.put("GA", (char) 8730);
                     } else {
                         dataMap.put("GA", "鈻�");
                     }
                 } else {
                     dataMap.put("JT", "鈻�");
-                    if (serviceDonatebaseinfo.getInfosources().contains("鍏畨")) {
+                    if (infosources.contains("鍏畨")) {
                         dataMap.put("GA", (char) 8730);
                     } else {
                         dataMap.put("GA", "鈻�");
@@ -967,10 +977,11 @@
         dataMap.put("HSZH", serviceDonatebaseinfo.getRedorganname() == null ? "" : serviceDonatebaseinfo.getRedorganname());
         dataMap.put("LXR", serviceDonatebaseinfo.getContactperson() == null ? "" : serviceDonatebaseinfo.getContactperson());
 
-        Date dt1 = serviceDonatebaseinfo.getContacttime();
-        String date1 = formatter.format(dt1);
-        String time1 = date1.substring(0, 16);
-        dataMap.put("LXSJ", serviceDonatebaseinfo.getContacttime() == null ? "" : time1);
+        String lxsj = "";
+        if (serviceDonatebaseinfo.getContacttime() != null) {
+            lxsj = formatter.format(serviceDonatebaseinfo.getContacttime()).substring(0, 16);
+        }
+        dataMap.put("LXSJ", lxsj);
         dataMap.put("HQZZ", serviceDonatebaseinfo.getAcquisitiontissuename() == null ? "" : serviceDonatebaseinfo.getAcquisitiontissuename());
         dataMap.put("BGR", serviceDonatebaseinfo.getReportername() == null ? "" : serviceDonatebaseinfo.getReportername());
         dataMap.put("BGRDH", serviceDonatebaseinfo.getReporterphone() == null ? "" : serviceDonatebaseinfo.getReporterphone());
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/project/ServiceDonatecompletioninfoController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/project/ServiceDonatecompletioninfoController.java
index 0c05ca2..e5f8163 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/project/ServiceDonatecompletioninfoController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/project/ServiceDonatecompletioninfoController.java
@@ -3,11 +3,13 @@
 import com.ruoyi.common.annotation.Log;
 import com.ruoyi.common.annotation.RepeatSubmit;
 import com.ruoyi.common.config.RuoYiConfig;
+import com.ruoyi.common.constant.HttpStatus;
 import com.ruoyi.common.core.controller.BaseController;
 import com.ruoyi.common.core.domain.AjaxResult;
 import com.ruoyi.common.core.page.TableDataInfo;
 import com.ruoyi.common.enums.BusinessType;
 import com.ruoyi.common.enums.OrganEnum;
+import com.ruoyi.common.exception.ServiceException;
 import com.ruoyi.common.exception.base.BaseException;
 import com.ruoyi.common.utils.bean.DtoConversionUtils;
 import com.ruoyi.common.utils.poi.ExcelUtil;
@@ -221,18 +223,16 @@
         String name = "浜轰綋鍣ㄥ畼鎹愮尞瀹屾垚缁撴灉鐧昏琛╛" + dataMap.get("XM") + "_" + newTime;
         //杈撳嚭鏂囨。璺緞鍙婂悕绉�
         File outFile = new File(RuoYiConfig.getProfile() + "/download/wordtemplate/" + name + ".doc");
-        Writer out = null;
-
-        try {
-            out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "utf-8"));
-
-        } catch (FileNotFoundException e1) {
-            e1.printStackTrace();
+        if (t == null) {
+            throw new ServiceException("妯℃澘鍔犺浇澶辫触锛岃妫�鏌ユā鏉挎枃浠舵槸鍚﹀瓨鍦�", HttpStatus.NO_CONTENT);
         }
-        try {
+
+        // Writer 蹇呴』鍏抽棴/鍒锋柊锛欱ufferedWriter 甯︾紦鍐诧紝涓嶅叧闂細閫犳垚鏂囦欢鍙ユ焺娉勬紡涓斿唴瀹瑰彲鑳戒笉瀹屾暣
+        try (Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "utf-8"))) {
             t.process(dataMap, out);
-        } catch (TemplateException e) {
-            e.printStackTrace();
+        } catch (TemplateException | IOException e) {
+            log.error("鐢熸垚妯℃澘鏂囨。澶辫触, name={}", name, e);
+            throw new ServiceException("鐢熸垚鏂囨。澶辫触", HttpStatus.ERROR);
         }
         Map<String, Object> map = new HashMap<>();
         map.put("downloadUrl", "/profile/download/wordtemplate/" + name + ".doc");
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/project/ServiceDonationwitnessController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/project/ServiceDonationwitnessController.java
index 5559c14..c1f68fd 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/project/ServiceDonationwitnessController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/project/ServiceDonationwitnessController.java
@@ -6,7 +6,9 @@
 
 import com.ruoyi.common.annotation.NotRepeatCommit;
 import com.ruoyi.common.config.RuoYiConfig;
+import com.ruoyi.common.constant.HttpStatus;
 import com.ruoyi.common.enums.OrganEnum;
+import com.ruoyi.common.exception.ServiceException;
 import com.ruoyi.common.exception.base.BaseException;
 import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.common.utils.bean.DtoConversionUtils;
@@ -210,18 +212,16 @@
         String name = "浜轰綋鍣ㄥ畼鎹愮尞鑾峰彇瑙佽瘉鐧昏琛╛" + dataMap.get("XM") + "_" + newTime;
         //杈撳嚭鏂囨。璺緞鍙婂悕绉�
         File outFile = new File(RuoYiConfig.getProfile() + "/download/wordtemplate/" + name + ".doc");
-        Writer out = null;
-
-        try {
-            out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "utf-8"));
-
-        } catch (FileNotFoundException e1) {
-            e1.printStackTrace();
+        if (t == null) {
+            throw new ServiceException("妯℃澘鍔犺浇澶辫触锛岃妫�鏌ユā鏉挎枃浠舵槸鍚﹀瓨鍦�", HttpStatus.NO_CONTENT);
         }
-        try {
+
+        // Writer 蹇呴』鍏抽棴/鍒锋柊锛欱ufferedWriter 甯︾紦鍐诧紝涓嶅叧闂細閫犳垚鏂囦欢鍙ユ焺娉勬紡涓斿唴瀹瑰彲鑳戒笉瀹屾暣
+        try (Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "utf-8"))) {
             t.process(dataMap, out);
-        } catch (TemplateException e) {
-            e.printStackTrace();
+        } catch (TemplateException | IOException e) {
+            log.error("鐢熸垚妯℃澘鏂囨。澶辫触, name={}", name, e);
+            throw new ServiceException("鐢熸垚鏂囨。澶辫触", HttpStatus.ERROR);
         }
         Map<String, Object> map = new HashMap<>();
         map.put("downloadUrl", "/profile/download/wordtemplate/" + name + ".doc");
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/project/ServiceDonorpaymentController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/project/ServiceDonorpaymentController.java
index 16e01e9..28a08b5 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/project/ServiceDonorpaymentController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/project/ServiceDonorpaymentController.java
@@ -3,10 +3,12 @@
 import com.ruoyi.common.annotation.Log;
 import com.ruoyi.common.annotation.RepeatSubmit;
 import com.ruoyi.common.config.RuoYiConfig;
+import com.ruoyi.common.constant.HttpStatus;
 import com.ruoyi.common.core.controller.BaseController;
 import com.ruoyi.common.core.domain.AjaxResult;
 import com.ruoyi.common.core.page.TableDataInfo;
 import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.common.exception.ServiceException;
 import com.ruoyi.common.utils.poi.ExcelUtil;
 import com.ruoyi.project.domain.ServiceDonorpayment;
 import com.ruoyi.project.service.IServiceDonorpaymentService;
@@ -131,19 +133,16 @@
         String name = "娴欐睙鐪佹帴鏀跺櫒瀹樼粨绠楄〃_"+ newTime;
         //杈撳嚭鏂囨。璺緞鍙婂悕绉�
         File outFile = new File(RuoYiConfig.getProfile() + "/download/wordtemplate/" + name + ".doc");
-        Writer out = null;
-
-        try {
-            out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "utf-8"));
-
-        } catch (FileNotFoundException e1) {
-            e1.printStackTrace();
+        if (t == null) {
+            throw new ServiceException("妯℃澘鍔犺浇澶辫触锛岃妫�鏌ユā鏉挎枃浠舵槸鍚﹀瓨鍦�", HttpStatus.NO_CONTENT);
         }
-        try {
 
+        // Writer 蹇呴』鍏抽棴/鍒锋柊锛欱ufferedWriter 甯︾紦鍐诧紝涓嶅叧闂細閫犳垚鏂囦欢鍙ユ焺娉勬紡涓斿唴瀹瑰彲鑳戒笉瀹屾暣
+        try (Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "utf-8"))) {
             t.process(dataMap, out);
-        } catch (TemplateException e) {
-            e.printStackTrace();
+        } catch (TemplateException | IOException e) {
+            logger.error("鐢熸垚妯℃澘鏂囨。澶辫触, name={}", name, e);
+            throw new ServiceException("鐢熸垚鏂囨。澶辫触", HttpStatus.ERROR);
         }
         Map<String, Object> map = new HashMap<>();
         map.put("downloadUrl", "/profile/download/wordtemplate/" + name + ".doc");
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/project/ServiceExternalpersonController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/project/ServiceExternalpersonController.java
index 30d25e9..b3f73bb 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/project/ServiceExternalpersonController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/project/ServiceExternalpersonController.java
@@ -96,7 +96,8 @@
         {
             return AjaxResult.error("鏂板浜哄憳闇�瑕佺‘瀹氫汉鍛樼被鍨�!");
         }
-        if (!"org".equals(usertype)){
+        // UserType 鑷� 2026-09-27 璧蜂负澶氬�煎瓧娈碉紙閫楀彿鍒嗛殧锛夛紝鍗曚綅鍒ゆ柇鏀逛负"鍖呭惈 org"
+        if (!hasUserType(usertype, "org")){
             String idcardno = serviceExternalperson.getIdcardno();
             List<ServiceExternalperson> existpsersons = serviceExternalpersonService.getInfoByIDCardNo(idcardno);
             if (existpsersons.size() > 0) {
@@ -148,4 +149,23 @@
     public AjaxResult getInfoByIDCardNo(@PathVariable("idcardno") String idcardno) {
         return AjaxResult.success(serviceExternalpersonService.getInfoByIDCardNo(idcardno));
     }
+
+    /**
+     * 鍒ゆ柇浜哄憳绫诲瀷锛堝鍊硷紝閫楀彿鍒嗛殧锛変腑鏄惁鍖呭惈鎸囧畾绫诲瀷
+     *
+     * @param usertype 浜哄憳绫诲瀷锛屽 "zzry,performance"锛涘吋瀹规敼閫犲墠鐨勫崟鍊�
+     * @param code     瀛楀吀 sys_UserType 鐨勫彇鍊硷紝濡� "org"
+     * @return 鏄惁鍖呭惈
+     */
+    private static boolean hasUserType(String usertype, String code) {
+        if (usertype == null || usertype.isEmpty()) {
+            return false;
+        }
+        for (String item : usertype.split(",")) {
+            if (code.equals(item.trim())) {
+                return true;
+            }
+        }
+        return false;
+    }
 }
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/project/ServiceFundController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/project/ServiceFundController.java
index 67edad5..b846a92 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/project/ServiceFundController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/project/ServiceFundController.java
@@ -322,6 +322,23 @@
         return AjaxResult.success(serviceFundService.addOrUpdateNew(serviceFundVO));
     }
 
+    /**
+     * 涓撳鍔冲姟璐癸細淇濆瓨鍓嶇殑璐圭敤鎺у埗鏍¢獙锛堝共璺戯紝涓嶈惤搴擄級
+     *
+     * <p>渚涗笓瀹跺姵鍔¤垂濉姤椤靛湪鐐光�滀繚瀛樷�濆墠璋冪敤锛屾妸 9 鏉¤鍒欑殑鏍¢獙缁撴灉
+     * 锛坋rrors 闃绘柇 / warnings 鎻愮ず锛夎繑鍥炲墠绔睍绀猴紱鐪熸鐨勮惤搴撴嫤鎴湪 addOrUpdateNew 涓��
+     */
+    @ApiOperation("涓撳鍔冲姟璐逛繚瀛樺墠鏍¢獙")
+    @PostMapping("/validateExpertFee")
+    public AjaxResult validateExpertFee(@RequestBody ServiceFundVO serviceFundVO) {
+        ExpertFeeCheckResult result = serviceFundService.validateExpertFee(serviceFundVO);
+        AjaxResult ajaxResult = AjaxResult.success();
+        ajaxResult.put("errors", result.getErrors());
+        ajaxResult.put("warnings", result.getWarnings());
+        ajaxResult.put("blocked", result.hasError());
+        return ajaxResult;
+    }
+
 
     /**
      * 瀹℃牳璐圭敤
@@ -475,18 +492,16 @@
 
         //杈撳嚭鏂囨。璺緞鍙婂悕绉�
         File outFile = new File(RuoYiConfig.getProfile() + "/download/wordtemplate/" + name + ".doc");
-        Writer out = null;
-
-        try {
-            out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "utf-8"));
-
-        } catch (FileNotFoundException e1) {
-            e1.printStackTrace();
+        if (t == null) {
+            throw new ServiceException("妯℃澘鍔犺浇澶辫触锛岃妫�鏌ユā鏉挎枃浠舵槸鍚﹀瓨鍦�", HttpStatus.NO_CONTENT);
         }
-        try {
+
+        // Writer 蹇呴』鍏抽棴/鍒锋柊锛欱ufferedWriter 甯︾紦鍐诧紝涓嶅叧闂細閫犳垚鏂囦欢鍙ユ焺娉勬紡涓斿唴瀹瑰彲鑳戒笉瀹屾暣
+        try (Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "utf-8"))) {
             t.process(dataMap, out);
-        } catch (TemplateException e) {
-            e.printStackTrace();
+        } catch (TemplateException | IOException e) {
+            log.error("鐢熸垚妯℃澘鏂囨。澶辫触, name={}", name, e);
+            throw new ServiceException("鐢熸垚鏂囨。澶辫触", HttpStatus.ERROR);
         }
         Map<String, Object> map = new HashMap<>();
         map.put("downloadUrl", "/profile/download/wordtemplate/" + name + ".doc");
@@ -659,18 +674,16 @@
 
         //杈撳嚭鏂囨。璺緞鍙婂悕绉�
         File outFile = new File(RuoYiConfig.getProfile() + "/download/wordtemplate/" + name + ".doc");
-        Writer out = null;
-
-        try {
-            out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "utf-8"));
-
-        } catch (FileNotFoundException e1) {
-            e1.printStackTrace();
+        if (t == null) {
+            throw new ServiceException("妯℃澘鍔犺浇澶辫触锛岃妫�鏌ユā鏉挎枃浠舵槸鍚﹀瓨鍦�", HttpStatus.NO_CONTENT);
         }
-        try {
+
+        // Writer 蹇呴』鍏抽棴/鍒锋柊锛欱ufferedWriter 甯︾紦鍐诧紝涓嶅叧闂細閫犳垚鏂囦欢鍙ユ焺娉勬紡涓斿唴瀹瑰彲鑳戒笉瀹屾暣
+        try (Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "utf-8"))) {
             t.process(dataMap, out);
-        } catch (TemplateException e) {
-            e.printStackTrace();
+        } catch (TemplateException | IOException e) {
+            log.error("鐢熸垚妯℃澘鏂囨。澶辫触, name={}", name, e);
+            throw new ServiceException("鐢熸垚鏂囨。澶辫触", HttpStatus.ERROR);
         }
         Map<String, Object> map = new HashMap<>();
         map.put("downloadUrl", "/profile/download/wordtemplate/" + name + ".doc");
@@ -756,18 +769,16 @@
 
         //杈撳嚭鏂囨。璺緞鍙婂悕绉�
         File outFile = new File(RuoYiConfig.getProfile() + "/download/wordtemplate/" + name + ".doc");
-        Writer out = null;
-
-        try {
-            out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "utf-8"));
-
-        } catch (FileNotFoundException e1) {
-            e1.printStackTrace();
+        if (t == null) {
+            throw new ServiceException("妯℃澘鍔犺浇澶辫触锛岃妫�鏌ユā鏉挎枃浠舵槸鍚﹀瓨鍦�", HttpStatus.NO_CONTENT);
         }
-        try {
+
+        // Writer 蹇呴』鍏抽棴/鍒锋柊锛欱ufferedWriter 甯︾紦鍐诧紝涓嶅叧闂細閫犳垚鏂囦欢鍙ユ焺娉勬紡涓斿唴瀹瑰彲鑳戒笉瀹屾暣
+        try (Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "utf-8"))) {
             t.process(dataMap, out);
-        } catch (TemplateException e) {
-            e.printStackTrace();
+        } catch (TemplateException | IOException e) {
+            log.error("鐢熸垚妯℃澘鏂囨。澶辫触, name={}", name, e);
+            throw new ServiceException("鐢熸垚鏂囨。澶辫触", HttpStatus.ERROR);
         }
         Map<String, Object> map = new HashMap<>();
         map.put("downloadUrl", "/profile/download/wordtemplate/" + name + ".doc");
@@ -858,20 +869,16 @@
         }
         //杈撳嚭鏂囨。璺緞鍙婂悕绉�
         File outFile = new File(RuoYiConfig.getProfile() + "/download/wordtemplate/" + name + ".doc");
-        Writer out = null;
-        try {
-            out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "utf-8"));
-
-        } catch (FileNotFoundException e1) {
-            log.error("FileNotFoundException鎶ラ敊淇℃伅鏄細{}", e1.getMessage());
-//            e1.printStackTrace();
+        if (t == null) {
+            throw new ServiceException("妯℃澘鍔犺浇澶辫触锛岃妫�鏌ユā鏉挎枃浠舵槸鍚﹀瓨鍦�", HttpStatus.NO_CONTENT);
         }
-        try {
 
+        // Writer 蹇呴』鍏抽棴/鍒锋柊锛欱ufferedWriter 甯︾紦鍐诧紝涓嶅叧闂細閫犳垚鏂囦欢鍙ユ焺娉勬紡涓斿唴瀹瑰彲鑳戒笉瀹屾暣
+        try (Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "utf-8"))) {
             t.process(dataMap, out);
-        } catch (TemplateException e) {
-            log.error("TemplateException鎶ラ敊淇¤嚜鏄細{}", e.getMessage());
-            e.getMessage();
+        } catch (TemplateException | IOException e) {
+            log.error("鐢熸垚妯℃澘鏂囨。澶辫触, name={}", name, e);
+            throw new ServiceException("鐢熸垚鏂囨。澶辫触", HttpStatus.ERROR);
         }
         Map<String, Object> map = new HashMap<>();
         map.put("downloadUrl", "/profile/download/wordtemplate/" + name + ".doc");
@@ -1083,18 +1090,16 @@
 
         //杈撳嚭鏂囨。璺緞鍙婂悕绉�
         File outFile = new File(RuoYiConfig.getProfile() + "/download/wordtemplate/" + name + ".doc");
-        Writer out = null;
-
-        try {
-            out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "utf-8"));
-
-        } catch (FileNotFoundException e1) {
-            e1.printStackTrace();
+        if (t == null) {
+            throw new ServiceException("妯℃澘鍔犺浇澶辫触锛岃妫�鏌ユā鏉挎枃浠舵槸鍚﹀瓨鍦�", HttpStatus.NO_CONTENT);
         }
-        try {
+
+        // Writer 蹇呴』鍏抽棴/鍒锋柊锛欱ufferedWriter 甯︾紦鍐诧紝涓嶅叧闂細閫犳垚鏂囦欢鍙ユ焺娉勬紡涓斿唴瀹瑰彲鑳戒笉瀹屾暣
+        try (Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "utf-8"))) {
             t.process(dataMap, out);
-        } catch (TemplateException e) {
-            e.printStackTrace();
+        } catch (TemplateException | IOException e) {
+            log.error("鐢熸垚妯℃澘鏂囨。澶辫触, name={}", name, e);
+            throw new ServiceException("鐢熸垚鏂囨。澶辫触", HttpStatus.ERROR);
         }
         Map<String, Object> map = new HashMap<>();
         map.put("downloadUrl", "/profile/download/wordtemplate/" + name + ".doc");
@@ -1152,18 +1157,16 @@
 
         //杈撳嚭鏂囨。璺緞鍙婂悕绉�
         File outFile = new File(RuoYiConfig.getProfile() + "/download/wordtemplate/" + name + ".doc");
-        Writer out = null;
-
-        try {
-            out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "utf-8"));
-
-        } catch (FileNotFoundException e1) {
-            e1.printStackTrace();
+        if (t == null) {
+            throw new ServiceException("妯℃澘鍔犺浇澶辫触锛岃妫�鏌ユā鏉挎枃浠舵槸鍚﹀瓨鍦�", HttpStatus.NO_CONTENT);
         }
-        try {
+
+        // Writer 蹇呴』鍏抽棴/鍒锋柊锛欱ufferedWriter 甯︾紦鍐诧紝涓嶅叧闂細閫犳垚鏂囦欢鍙ユ焺娉勬紡涓斿唴瀹瑰彲鑳戒笉瀹屾暣
+        try (Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "utf-8"))) {
             t.process(dataMap, out);
-        } catch (TemplateException e) {
-            e.printStackTrace();
+        } catch (TemplateException | IOException e) {
+            log.error("鐢熸垚妯℃澘鏂囨。澶辫触, name={}", name, e);
+            throw new ServiceException("鐢熸垚鏂囨。澶辫触", HttpStatus.ERROR);
         }
         Map<String, Object> map = new HashMap<>();
         map.put("downloadUrl", "/profile/download/wordtemplate/" + name + ".doc");
@@ -1652,18 +1655,16 @@
 
         //杈撳嚭鏂囨。璺緞鍙婂悕绉�
         File outFile = new File(RuoYiConfig.getProfile() + "/download/wordtemplate/" + name + ".doc");
-        Writer out = null;
-
-        try {
-            out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "utf-8"));
-
-        } catch (FileNotFoundException e1) {
-            e1.printStackTrace();
+        if (t == null) {
+            throw new ServiceException("妯℃澘鍔犺浇澶辫触锛岃妫�鏌ユā鏉挎枃浠舵槸鍚﹀瓨鍦�", HttpStatus.NO_CONTENT);
         }
-        try {
+
+        // Writer 蹇呴』鍏抽棴/鍒锋柊锛欱ufferedWriter 甯︾紦鍐诧紝涓嶅叧闂細閫犳垚鏂囦欢鍙ユ焺娉勬紡涓斿唴瀹瑰彲鑳戒笉瀹屾暣
+        try (Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "utf-8"))) {
             t.process(dataMap, out);
-        } catch (TemplateException e) {
-            e.printStackTrace();
+        } catch (TemplateException | IOException e) {
+            log.error("鐢熸垚妯℃澘鏂囨。澶辫触, name={}", name, e);
+            throw new ServiceException("鐢熸垚鏂囨。澶辫触", HttpStatus.ERROR);
         }
         Map<String, Object> map = new HashMap<>();
         map.put("downloadUrl", "/profile/download/wordtemplate/" + name + ".doc");
@@ -1741,18 +1742,16 @@
 
         //杈撳嚭鏂囨。璺緞鍙婂悕绉�
         File outFile = new File(RuoYiConfig.getProfile() + "/download/wordtemplate/" + name + ".doc");
-        Writer out = null;
-
-        try {
-            out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "utf-8"));
-
-        } catch (FileNotFoundException e1) {
-            e1.printStackTrace();
+        if (t == null) {
+            throw new ServiceException("妯℃澘鍔犺浇澶辫触锛岃妫�鏌ユā鏉挎枃浠舵槸鍚﹀瓨鍦�", HttpStatus.NO_CONTENT);
         }
-        try {
+
+        // Writer 蹇呴』鍏抽棴/鍒锋柊锛欱ufferedWriter 甯︾紦鍐诧紝涓嶅叧闂細閫犳垚鏂囦欢鍙ユ焺娉勬紡涓斿唴瀹瑰彲鑳戒笉瀹屾暣
+        try (Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "utf-8"))) {
             t.process(dataMap, out);
-        } catch (TemplateException e) {
-            e.printStackTrace();
+        } catch (TemplateException | IOException e) {
+            log.error("鐢熸垚妯℃澘鏂囨。澶辫触, name={}", name, e);
+            throw new ServiceException("鐢熸垚鏂囨。澶辫触", HttpStatus.ERROR);
         }
         Map<String, Object> map = new HashMap<>();
         map.put("downloadUrl", "/profile/download/wordtemplate/" + name + ".doc");
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/project/ServiceReimbursementController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/project/ServiceReimbursementController.java
index 2f47faa..96d05de 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/project/ServiceReimbursementController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/project/ServiceReimbursementController.java
@@ -14,6 +14,7 @@
 import com.ruoyi.common.utils.SecurityUtils;
 import com.ruoyi.common.utils.poi.ExcelUtil;
 import com.ruoyi.project.domain.*;
+import com.ruoyi.project.common.FundNotifyMessageBuilder;
 import com.ruoyi.project.domain.dto.ServiceReimbursementDto;
 import com.ruoyi.project.domain.vo.CheckFundVO;
 import com.ruoyi.project.domain.vo.DingTalkReqVo;
@@ -346,17 +347,27 @@
                     //闄堟厱鍗庝俊鎭�
                     sysUser = sysUserService.selectUserByUserName("047");
                 }
-                ConcurrentHashMap map = new ConcurrentHashMap();
-                ArrayList<ConcurrentHashMap<String, Object>> contentList = new ArrayList<>();
-                map.put("鎻愪氦浜猴細", loginUser.getUser().getUserName());
-                map.put("鎻愪氦鏃堕棿锛�", new Date());
-                map.put("鍐呭锛�", serviceReimbursement.getReason());
-                contentList.add(map);
-                DingTalkReqVo dingTalkReqVo = new DingTalkReqVo();
-                dingTalkReqVo.setTitle("宸梾瀹℃壒淇℃伅");
-                dingTalkReqVo.setNumber(sysUser != null ? sysUser.getPhonenumber() : "");
-                dingTalkReqVo.setContents(contentList);
-                dingTalkService.sendNotification(dingTalkReqVo);
+                //宸梾璐逛笂鎶ユ彁浜わ細鍗曟嵁淇℃伅 + 鎻愪氦浜�/鎻愪氦鏃堕棿/鍐呭
+                //閽夐拤灞炰簬鏃佽矾閫氱煡锛屼换浣曞け璐ラ兘涓嶅緱褰卞搷"涓婃姤"涓绘祦绋嬶紙鍚﹀垯鍓嶇浼氭彁绀哄け璐ヤ絾鏁版嵁宸叉洿鏂帮級
+                try {
+                    List<ConcurrentHashMap<String, Object>> contentList = FundNotifyMessageBuilder.newRows();
+                    FundNotifyMessageBuilder.addBillInfo(contentList, "0", serviceReimbursement.getUsername(),
+                            serviceReimbursement.getAmountrequested(), null,
+                            FundNotifyMessageBuilder.billNo(serviceReimbursement.getBh(),
+                                    serviceReimbursement.getId()));
+                    FundNotifyMessageBuilder.addTravelInfo(contentList, serviceReimbursement.getTravelers(),
+                            serviceReimbursement.getReason());
+                    FundNotifyMessageBuilder.addSubmitInfo(contentList, loginUser.getUser().getNickName(),
+                            new Date(), serviceReimbursement.getReason());
+                    DingTalkReqVo dingTalkReqVo = new DingTalkReqVo();
+                    dingTalkReqVo.setTitle(FundNotifyMessageBuilder.TITLE);
+                    dingTalkReqVo.setNumber(sysUser != null ? sysUser.getPhonenumber() : "");
+                    dingTalkReqVo.setContents(contentList);
+                    dingTalkService.sendNotification(dingTalkReqVo);
+                } catch (Throwable t) {
+                    log.error("宸梾涓婃姤閽夐拤閫氱煡澶辫触锛屽凡蹇界暐锛堜笉褰卞搷涓婃姤涓绘祦绋嬶級锛宨d={}",
+                            serviceReimbursement.getId(), t);
+                }
             }
 
             serviceReimbursementService.updateById(serviceReimbursement);
@@ -467,18 +478,16 @@
             System.out.println("鐩綍宸插瓨鍦�");
         }
 
-        Writer out = null;
-
-        try {
-            out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "utf-8"));
-
-        } catch (FileNotFoundException e1) {
-            e1.printStackTrace();
+        if (t == null) {
+            throw new ServiceException("妯℃澘鍔犺浇澶辫触锛岃妫�鏌ユā鏉挎枃浠舵槸鍚﹀瓨鍦�", HttpStatus.NO_CONTENT);
         }
-        try {
+
+        // Writer 蹇呴』鍏抽棴/鍒锋柊锛欱ufferedWriter 甯︾紦鍐诧紝涓嶅叧闂細閫犳垚鏂囦欢鍙ユ焺娉勬紡涓斿唴瀹瑰彲鑳戒笉瀹屾暣
+        try (Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "utf-8"))) {
             t.process(dataMap, out);
-        } catch (TemplateException e) {
-            e.printStackTrace();
+        } catch (TemplateException | IOException e) {
+            log.error("鐢熸垚妯℃澘鏂囨。澶辫触, name={}", name, e);
+            throw new ServiceException("鐢熸垚鏂囨。澶辫触", HttpStatus.ERROR);
         }
         Map<String, Object> map = new HashMap<>();
         map.put("downloadUrl", "/profile/download/wordtemplate/" + name + ".doc");
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/project/ServiceRelativesconfirmationController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/project/ServiceRelativesconfirmationController.java
index 72938a7..71bfc70 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/project/ServiceRelativesconfirmationController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/project/ServiceRelativesconfirmationController.java
@@ -189,13 +189,16 @@
         String name = "浜轰綋鍣ㄥ畼鎹愮尞浜插睘纭鐧昏琛╛" + dataMap.get("XM") + "_" + newTime;
         //杈撳嚭鏂囨。璺緞鍙婂悕绉�
         File outFile = new File(RuoYiConfig.getProfile() + "/download/wordtemplate/" + name + ".doc");
-        Writer out = null;
+        if (t == null) {
+            throw new ServiceException("妯℃澘鍔犺浇澶辫触锛岃妫�鏌ユā鏉挎枃浠舵槸鍚﹀瓨鍦�", HttpStatus.NO_CONTENT);
+        }
 
-        try {
-            out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "utf-8"));
+        // Writer 蹇呴』鍏抽棴/鍒锋柊锛欱ufferedWriter 甯︾紦鍐诧紝涓嶅叧闂細閫犳垚鏂囦欢鍙ユ焺娉勬紡涓斿唴瀹瑰彲鑳戒笉瀹屾暣
+        try (Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "utf-8"))) {
             t.process(dataMap, out);
-        } catch (TemplateException e) {
-            e.printStackTrace();
+        } catch (TemplateException | IOException e) {
+            log.error("鐢熸垚妯℃澘鏂囨。澶辫触, name={}", name, e);
+            throw new ServiceException("鐢熸垚鏂囨。澶辫触", HttpStatus.ERROR);
         }
         Map<String, Object> map = new HashMap<>();
         map.put("downloadUrl", "/profile/download/wordtemplate/" + name + ".doc");
diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml
index 48bc13e..a27b896 100644
--- a/ruoyi-admin/src/main/resources/application.yml
+++ b/ruoyi-admin/src/main/resources/application.yml
@@ -53,8 +53,9 @@
     # 鍥介檯鍖栬祫婧愭枃浠惰矾寰�
     basename: i18n/messages
   profiles:
-#    active: srm
-    active: druid
+    active: srm
+#    active: druid
+
   # 鏂囦欢涓婁紶
   servlet:
     multipart:
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/MergeFilesToPDFUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/MergeFilesToPDFUtils.java
index ac164ca..ba13ac9 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/MergeFilesToPDFUtils.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/MergeFilesToPDFUtils.java
@@ -76,11 +76,16 @@
      * @param outputPath
      */
     public Boolean wordtoPdf(String inputPath, String outputPath) {
+        // Spire.Doc 鐨� Document 鎸佹湁鏂囦欢鍙ユ焺锛屽繀椤绘樉寮忓叧闂紝鍚﹀垯鍙ユ焺瑕佺瓑 finalize 鎵嶉噴鏀撅紝涓斾細鍗犵敤婧愭枃浠�
         Document doc = new Document();
-        //鍔犺浇Word
-        doc.loadFromFile(inputPath);
-        //淇濆瓨涓篜DF鏍煎紡
-        doc.saveToFile(outputPath, FileFormat.PDF);
+        try {
+            //鍔犺浇Word
+            doc.loadFromFile(inputPath);
+            //淇濆瓨涓篜DF鏍煎紡
+            doc.saveToFile(outputPath, FileFormat.PDF);
+        } finally {
+            doc.close();
+        }
         return true;
     }
 
@@ -91,18 +96,25 @@
         com.itextpdf.text.Document document = new com.itextpdf.text.Document();
         log.info("fileName鐨勫叏璺緞锛歿}", archived + "/" + fileName);
         PdfCopy copy = new PdfCopy(document, new FileOutputStream(archived + "/" + fileName));
-        document.open();
-
-        for (String pdfFile : pdfFiles) {
-            PdfReader reader = new PdfReader(pdfFile);
-            int totalPages = reader.getNumberOfPages();
-            for (int page = 1; page <= totalPages; page++) {
-                PdfImportedPage importedPage = copy.getImportedPage(reader, page);
-                copy.addPage(importedPage);
+        // 鍚堝苟杩囩▼涓换浣曚竴姝ユ姏寮傚父閮藉繀椤诲叧闂� document锛歞ocument.close() 浼氱骇鑱斿叧闂� PdfWriter 鍙婂叾杈撳嚭娴侊紝
+        // 鍚﹀垯杈撳嚭娴佸彞鏌勪細琚暱鏃堕棿鍗犵敤锛堜緷璧� finalize 鎵嶈兘閲婃斁锛夛紝涓斿紓甯告椂鏂囦欢鍐呭涓嶅畬鏁�
+        try {
+            document.open();
+            for (String pdfFile : pdfFiles) {
+                PdfReader reader = new PdfReader(pdfFile);
+                try {
+                    int totalPages = reader.getNumberOfPages();
+                    for (int page = 1; page <= totalPages; page++) {
+                        PdfImportedPage importedPage = copy.getImportedPage(reader, page);
+                        copy.addPage(importedPage);
+                    }
+                } finally {
+                    reader.close();
+                }
             }
-            reader.close();
+        } finally {
+            document.close();
         }
-        document.close();
     }
 
 }
diff --git a/ruoyi-project/src/main/java/com/ruoyi/project/domain/ServiceFunddetail.java b/ruoyi-project/src/main/java/com/ruoyi/project/domain/ServiceFunddetail.java
index f12073d..437f4cb 100644
--- a/ruoyi-project/src/main/java/com/ruoyi/project/domain/ServiceFunddetail.java
+++ b/ruoyi-project/src/main/java/com/ruoyi/project/domain/ServiceFunddetail.java
@@ -77,6 +77,13 @@
     private String unituserno;
 
     /**
+     * 鍗曚綅鏍囪瘑锛�1=鍗曚綅锛堝彈鐩婁汉閫夋嫨鍗曚綅鏃朵笉闇�瑕佽韩浠借瘉鍙凤級锛�0=涓汉
+     */
+    @ApiModelProperty("鍗曚綅鏍囪瘑锛�1=鍗曚綅锛�0=涓汉")
+    @Excel(name = "鍗曚綅鏍囪瘑", readConverterExp = "1=鍗曚綅,0=涓汉")
+    private Integer isunit;
+
+    /**
      * 鑱岀О,瑙佸瓧鍏竤ys_professionaltitle
      */
     @ApiModelProperty("鑱岀О")
diff --git a/ruoyi-project/src/main/java/com/ruoyi/project/mapper/ServiceDonationwitnessMapper.java b/ruoyi-project/src/main/java/com/ruoyi/project/mapper/ServiceDonationwitnessMapper.java
index 88e8927..c9ed063 100644
--- a/ruoyi-project/src/main/java/com/ruoyi/project/mapper/ServiceDonationwitnessMapper.java
+++ b/ruoyi-project/src/main/java/com/ruoyi/project/mapper/ServiceDonationwitnessMapper.java
@@ -12,6 +12,7 @@
 import com.ruoyi.project.domain.vo.DonationWitnessVO;
 import com.ruoyi.project.domain.vo.TimeVO;
 import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
 
 /**
  * 鎹愮尞瑙佽瘉Mapper鎺ュ彛
@@ -30,6 +31,18 @@
      */
     public List<ServiceDonationwitness> selectServiceDonationwitnessList(ServiceDonationwitness serviceDonationwitness);
 
+    /**
+     * 涓�娆℃�ф煡鍑哄叏閮ㄣ�屾崘鐚熀纭�ID -> 姝讳骸鏃堕棿銆嶅搴斿叧绯汇��
+     *
+     * 鐢ㄤ簬鍒楄〃椤佃绠楀勾榫勶細鍘熷疄鐜板湪璁板綍寰幆閲屾寜 InfoID 閫愭潯鏌ヨ瑙佽瘉琛紙N+1锛夛紝
+     * 棣栭〉/鍒楄〃鏈夊灏戞潯璁板綍灏变細鍙戝灏戞 SQL銆傛敼涓轰竴娆℃煡璇㈠悗鍦ㄥ唴瀛樹腑鍖归厤銆�
+     * 鍙彇 InfoID 涓� DeathTime 涓ゅ垪锛岄伩鍏嶆媺鍙栨暣琛屽琛ㄦ暟鎹��
+     *
+     * @param infoIds 闇�瑕佹煡璇㈢殑鎹愮尞鍩虹ID闆嗗悎锛涗负绌烘椂鏌ュ叏閮�
+     * @return 浠呭惈 infoid 涓� deathtime 鐨勫垪琛�
+     */
+    List<ServiceDonationwitness> selectDeathTimeByInfoIds(@Param("infoIds") Collection<Long> infoIds);
+
     List<ServiceDonationwitness> getWitnessList();
 
     List<DonationWitnessVO> selectVOList(DonationWitnessVO donationWitnessVO);
diff --git a/ruoyi-project/src/main/java/com/ruoyi/project/service/IServiceFundService.java b/ruoyi-project/src/main/java/com/ruoyi/project/service/IServiceFundService.java
index 686e6dd..0c59e30 100644
--- a/ruoyi-project/src/main/java/com/ruoyi/project/service/IServiceFundService.java
+++ b/ruoyi-project/src/main/java/com/ruoyi/project/service/IServiceFundService.java
@@ -89,5 +89,15 @@
 
     public Boolean updateFundTaxIdById(Long id, Long fundTaxIds);
 
+    /**
+     * 涓撳鍔冲姟璐癸細9 鏉¤垂鐢ㄦ帶鍒惰鍒欑殑琛ㄥ崟鏍¢獙锛堜笉钀藉簱锛夈��
+     *
+     * <p>渚涘~鎶ヤ繚瀛樺墠璋冪敤锛岃繑鍥� errors锛堥樆鏂�э紝涓嶈兘淇濆瓨锛変笌 warnings锛堜粎鎻愮ず锛夛紱
+     * 鐪熸鐨勮惤搴撴嫤鎴湪 {@link #addOrUpdateNew} 鍐呫��
+     *
+     * @param serviceFundVO 鏈鎻愪氦鐨勮〃鍗�
+     * @return 鏍¢獙缁撴灉
+     */
+    ExpertFeeCheckResult validateExpertFee(ServiceFundVO serviceFundVO);
 
 }
diff --git a/ruoyi-project/src/main/java/com/ruoyi/project/service/impl/DingTalkServiceImpl.java b/ruoyi-project/src/main/java/com/ruoyi/project/service/impl/DingTalkServiceImpl.java
index 99fb158..45375be 100644
--- a/ruoyi-project/src/main/java/com/ruoyi/project/service/impl/DingTalkServiceImpl.java
+++ b/ruoyi-project/src/main/java/com/ruoyi/project/service/impl/DingTalkServiceImpl.java
@@ -18,7 +18,7 @@
 import com.ruoyi.project.service.DingTalkService;
 import com.ruoyi.system.mapper.SysUserMapper;
 import com.taobao.api.ApiException;
-import lombok.extern.log4j.Log4j;
+import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.collections4.CollectionUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
@@ -38,7 +38,7 @@
  * @date 2023-05-23
  */
 @Service
-@Log4j
+@Slf4j
 public class DingTalkServiceImpl implements DingTalkService {
 
 
@@ -51,119 +51,195 @@
     @Value("${agentId}")
     private Long agentId;
 
+    /**
+     * access_token 缂撳瓨銆�
+     * 閽夐拤 token 鏈夋晥鏈� 7200 绉掞紝杩欓噷鎸� 6000 绉掍繚瀹堝埛鏂帮紱
+     * 鍘熷疄鐜版瘡娆″彂娑堟伅閮借皟涓�娆� /gettoken锛岄拤閽夊鍙� token 鏈夐娆¢檺鍒讹紝瀹℃牳楂樺嘲鏈熷鏄撴暣浣撳け璐ャ��
+     */
+    private volatile String cachedAccessToken;
+    /** access_token 杩囨湡鏃堕棿锛坋poch millis锛� */
+    private volatile long accessTokenExpireAt;
+    private static final long ACCESS_TOKEN_TTL_MILLIS = 6000L * 1000L;
+
+    /**
+     * 閽夐拤鎺ュ彛瓒呮椂锛堟绉掞級銆�
+     * SDK 鏈樉寮忚缃秴鏃舵椂浼氭棤闄愮瓑寰咃紝閽夐拤缃戠粶涓嶉�氬皢鍗犳弧瀹瑰櫒绾跨▼銆佹嫋姝诲鎵圭瓑璋冪敤鏂癸紝
+     * 鍥犳杩欓噷瀵规墍鏈夊嚭绔欒姹傜粺涓�璁剧疆杩炴帴/璇诲彇瓒呮椂銆�
+     */
+    private static final int CONNECT_TIMEOUT_MS = 3000;
+    private static final int READ_TIMEOUT_MS = 5000;
+
     @Autowired
     private SysUserMapper sysUserMapper;
 
+    /**
+     * 鍒涘缓甯﹁秴鏃剁殑閽夐拤瀹㈡埛绔�
+     */
+    private DefaultDingTalkClient newClient(String url) {
+        DefaultDingTalkClient client = new DefaultDingTalkClient(url);
+        client.setConnectTimeout(CONNECT_TIMEOUT_MS);
+        client.setReadTimeout(READ_TIMEOUT_MS);
+        return client;
+    }
+
+    /**
+     * 鍙戦�侀拤閽夐�氱煡锛堝澶栧敮涓�鍏ュ彛锛夈��
+     *
+     * <p><b>鏈柟娉曚繚璇佷笉鍚戝鎶涗换浣曞紓甯�</b>锛氶拤閽夊睘浜庢梺璺�氱煡锛屼换浣曞け璐ラ兘鍙鏃ュ織骞惰繑鍥� false锛�
+     * 缁濅笉鑳藉奖鍝嶅鎵广�佷笂鎶ョ瓑涓氬姟涓绘祦绋嬨��
+     */
     @Override
     public Boolean sendNotification(DingTalkReqVo dingTalkReqVo) {
-        String body = null;
+        try {
+            return doSendNotification(dingTalkReqVo);
+        } catch (Throwable t) {
+            log.error("閽夐拤閫氱煡鍙戦�佸彂鐢熸湭棰勬湡寮傚父锛屽凡蹇界暐锛堜笉褰卞搷涓氬姟涓绘祦绋嬶級", t);
+            return false;
+        }
+    }
+
+    private Boolean doSendNotification(DingTalkReqVo dingTalkReqVo) {
         List<String> userIdlist = new ArrayList();
-        Boolean result = false;
-        log.info("鍙戦�侀拤閽夐�氱煡");
+        if (dingTalkReqVo == null) {
+            log.warn("閽夐拤閫氱煡鍏ュ弬涓虹┖锛岃烦杩囧彂閫�");
+            return false;
+        }
+        log.info("鍙戦�侀拤閽夐�氱煡锛宼itle={}", dingTalkReqVo.getTitle());
 
         String accessToken = null;
         try {
             accessToken = getAccessToken();
-        } catch (ApiException e) {
-            e.printStackTrace();
+        } catch (Exception e) {
+            log.error("閽夐拤鑾峰彇 access_token 澶辫触锛屾棤娉曞彂閫侀�氱煡", e);
         }
-        if (StringUtils.isNotEmpty(dingTalkReqVo.getNumber())) {
-            DingTalkClient clientT = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/user/getbymobile");
-            OapiV2UserGetbymobileRequest req = new OapiV2UserGetbymobileRequest();
-            req.setMobile(dingTalkReqVo.getNumber());
-            OapiV2UserGetbymobileResponse rsp = null;
-            try {
-                rsp = clientT.execute(req, accessToken);
-                body = rsp.getBody();
-                String jsonObject = JSONObject.parseObject(body).getJSONObject("result").get("userid").toString();
-                userIdlist.add(jsonObject);
+        if (StringUtils.isEmpty(accessToken)) {
+            log.error("閽夐拤 access_token 涓虹┖锛屾棤娉曞彂閫侀�氱煡");
+            return false;
+        }
 
-            } catch (ApiException e) {
-                e.printStackTrace();
+        // ---- 瑙f瀽鏀朵欢浜猴細浼樺厛鎵嬫満鍙凤紝鍏舵閮ㄩ棬 ----
+        if (StringUtils.isNotEmpty(dingTalkReqVo.getNumber())) {
+            try {
+                DingTalkClient clientT = newClient("https://oapi.dingtalk.com/topapi/v2/user/getbymobile");
+                OapiV2UserGetbymobileRequest req = new OapiV2UserGetbymobileRequest();
+                req.setMobile(dingTalkReqVo.getNumber());
+                OapiV2UserGetbymobileResponse rsp = clientT.execute(req, accessToken);
+                String body = rsp == null ? null : rsp.getBody();
+                if (StringUtils.isEmpty(body)) {
+                    log.error("閽夐拤鎸夋墜鏈哄彿鏌ョ敤鎴峰け璐ワ紝mobile={}锛屽搷搴斾负绌�", dingTalkReqVo.getNumber());
+                    return false;
+                }
+                JSONObject resultObj = JSONObject.parseObject(body).getJSONObject("result");
+                if (resultObj == null || resultObj.get("userid") == null) {
+                    log.error("閽夐拤鎸夋墜鏈哄彿鏌ョ敤鎴峰け璐ワ紝mobile={}锛屽搷搴�={}", dingTalkReqVo.getNumber(), body);
+                    return false;
+                }
+                userIdlist.add(resultObj.get("userid").toString());
+            } catch (Exception e) {
+                log.error("閽夐拤鎸夋墜鏈哄彿鏌ョ敤鎴峰紓甯革紝mobile={}", dingTalkReqVo.getNumber(), e);
+                return false;
+            }
+        } else if (dingTalkReqVo.getDeptId() != null) {
+            try {
+                DingTalkClient client3 = newClient("https://oapi.dingtalk.com/topapi/user/listid");
+
+                OapiUserListidRequest request2 = new OapiUserListidRequest();
+                request2.setDeptId(dingTalkReqVo.getDeptId()); // 璁剧疆瑕佽幏鍙栫殑閮ㄩ棬 ID锛岃繖閲屼互鏍归儴闂ㄤ负渚�675909059L
+                // 璁剧疆閮ㄩ棬 ID锛屽鏋滆幏鍙栨墍鏈夊憳宸ユ墜鏈哄彿锛屽彲浠ヨ缃负鏍归儴闂ㄧ殑 ID
+                OapiUserListidResponse response2 = client3.execute(request2, accessToken);
+                String body = response2 == null ? null : response2.getBody();
+                if (StringUtils.isNotEmpty(body)) {
+                    // 瑙f瀽涓篔SONObject
+                    JSONObject jsonObject = JSONObject.parseObject(body);
+                    // 鎻愬彇鍑篔SONArray
+                    JSONArray jsonArray = new JSONArray(jsonObject.getJSONObject("result").getJSONArray("userid_list"));
+                    // 灏咼SONArray杞负List鍒楄〃
+                    String str = JSONObject.toJSONString(jsonArray);
+                    userIdlist = JSONObject.parseObject(str, List.class);
+                }
+            } catch (Exception e) {
+                log.error("閽夐拤鎸夐儴闂ㄦ煡鐢ㄦ埛寮傚父锛宒eptId={}", dingTalkReqVo.getDeptId(), e);
+                return false;
             }
         } else {
-            DingTalkClient client3 = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/user/listid");
+            // 鏃㈡棤鎵嬫満鍙蜂篃鏃犻儴闂細鍘熷疄鐜颁細璧� listid(null) 琚拤閽夋嫆缁濅笖寮傚父琚悶鎺夛紝琛ㄧ幇涓�"闈欓粯鍙戜笉鍑哄幓"
+            log.warn("閽夐拤閫氱煡鏈彁渚涙敹浠朵汉锛堟墜鏈哄彿涓庨儴闂ㄥ潎涓虹┖锛夛紝璺宠繃鍙戦��");
+            return false;
+        }
 
-            OapiUserListidRequest request2 = new OapiUserListidRequest();
-            request2.setDeptId(dingTalkReqVo.getDeptId()); // 璁剧疆瑕佽幏鍙栫殑閮ㄩ棬 ID锛岃繖閲屼互鏍归儴闂ㄤ负渚�675909059L
-            // 璁剧疆閮ㄩ棬 ID锛屽鏋滆幏鍙栨墍鏈夊憳宸ユ墜鏈哄彿锛屽彲浠ヨ缃负鏍归儴闂ㄧ殑 ID
-            OapiUserListidResponse response2 = null;
-            try {
-                response2 = client3.execute(request2, accessToken);
-            } catch (ApiException e) {
-                e.printStackTrace();
-            }
-            body = response2.getBody();
-            // 瑙f瀽涓篔SONObject
-            JSONObject jsonObject = JSONObject.parseObject(body);
-            if (jsonObject != null) {
-                // 鎻愬彇鍑篔SONArray
-                JSONArray jsonArray = new JSONArray(jsonObject.getJSONObject("result").getJSONArray("userid_list"));
-                // 灏咼SONArray杞负List鍒楄〃
-                String str = JSONObject.toJSONString(jsonArray);
-                userIdlist = JSONObject.parseObject(str, List.class);
-            }
+        if (CollectionUtils.isEmpty(userIdlist)) {
+            log.warn("閽夐拤閫氱煡鏈В鏋愬埌浠讳綍鏀朵欢浜猴紝璺宠繃鍙戦��");
+            return false;
         }
 
 
-        //userid鏁扮粍
-        for (String urid : userIdlist) {
-            DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2");
-            OapiMessageCorpconversationAsyncsendV2Request request = new OapiMessageCorpconversationAsyncsendV2Request();
-            request.setUseridList(urid);
-            request.setAgentId(agentId);
-            request.setToAllUser(false);
-
-            //鍙戦�佸唴瀹瑰鐞�
-            List<ConcurrentHashMap<String, Object>> contents = dingTalkReqVo.getContents();
-            ArrayList<OapiMessageCorpconversationAsyncsendV2Request.Form> objects = new ArrayList<>();
-            for (int i = 0; i < contents.size(); i++) {
-                ConcurrentHashMap<String, Object> map = contents.get(i);
+        // ---- 缁勮娑堟伅浣擄紙鎵�鏈夋敹浠朵汉鍏辩敤锛� ----
+        // contents 涓瘡琛屼竴涓崟閿� map锛岀敤 List 椤哄簭淇濊瘉閽夐拤琛ㄥ崟琛屽簭
+        List<OapiMessageCorpconversationAsyncsendV2Request.Form> objects = new ArrayList<>();
+        List<ConcurrentHashMap<String, Object>> contents = dingTalkReqVo.getContents();
+        if (contents != null) {
+            for (ConcurrentHashMap<String, Object> map : contents) {
+                if (map == null) {
+                    continue;
+                }
                 for (Map.Entry<String, Object> entry : map.entrySet()) {
+                    Object value = entry.getValue();
+                    if (value == null) {
+                        continue;
+                    }
                     OapiMessageCorpconversationAsyncsendV2Request.Form formSeverityDesc = new OapiMessageCorpconversationAsyncsendV2Request.Form();
                     formSeverityDesc.setKey(entry.getKey());
-                    if (entry.getKey().contains("瀹℃壒鏃堕棿")) {
-                        Date date = (Date) entry.getValue();
-                        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
-                        String format = simpleDateFormat.format(date);
-                        formSeverityDesc.setValue(format);
+                    if (entry.getKey().contains("瀹℃壒鏃堕棿") && value instanceof Date) {
+                        // 24 灏忔椂鍒讹細鍘熷疄鐜扮敤 hh锛�12 灏忔椂鍒朵笖鏃� AM/PM锛夛紝涓嬪崍鐨勬椂闂翠細鏄剧ず鎴� 01:xx
+                        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+                        formSeverityDesc.setValue(simpleDateFormat.format((Date) value));
                     } else {
-                        if (entry.getValue() != null) {
-                            formSeverityDesc.setValue(entry.getValue().toString());
-                        }
+                        formSeverityDesc.setValue(value.toString());
                     }
                     objects.add(formSeverityDesc);
                 }
             }
+        }
 
-            OapiMessageCorpconversationAsyncsendV2Request.Msg msg = new OapiMessageCorpconversationAsyncsendV2Request.Msg();
-            msg.setOa(new OapiMessageCorpconversationAsyncsendV2Request.OA());
-            msg.getOa().setMessageUrl(dingTalkReqVo.getUrl());
-            msg.getOa().setPcMessageUrl(dingTalkReqVo.getUrl());
-            msg.getOa().setHead(new OapiMessageCorpconversationAsyncsendV2Request.Head());
-            //   msg.getOa().getHead().setText("浣犲湪璇村暐鍛㈢粧椤舵浛鑻涘ず闃挎柉钂傝姮闃挎柉钂傝姮");
-            msg.getOa().getHead().setBgcolor("00409eff");
-            msg.getOa().setBody(new OapiMessageCorpconversationAsyncsendV2Request.Body());
-            msg.getOa().getBody().setTitle(dingTalkReqVo.getTitle());
-            // msg.getOa().getBody().setContent("寰呭鐞�:" + "123" + "鏉�");
-
-            msg.getOa().getBody().setForm(objects);
-            msg.setMsgtype("oa");
-            request.setMsg(msg);
-            //  log.info("鑾峰彇鍙戦�侀�氱煡娑堟伅浣撳拰鑾峰彇鍙戦�侀�氱煡浜哄畬鎴�");
+        // ---- 閫愪汉鍙戦�侊紱鍏ㄩ儴鎴愬姛鎵嶇畻鎴愬姛锛堝師瀹炵幇 result 鍐欏湪寰幆鍐咃紝鍙弽鏄犳渶鍚庝竴涓敹浠朵汉锛� ----
+        boolean allSuccess = true;
+        for (String urid : userIdlist) {
             OapiMessageCorpconversationAsyncsendV2Response response = null;
             try {
+                DingTalkClient client = newClient("https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2");
+                OapiMessageCorpconversationAsyncsendV2Request request = new OapiMessageCorpconversationAsyncsendV2Request();
+                request.setUseridList(urid);
+                request.setAgentId(agentId);
+                request.setToAllUser(false);
+
+                OapiMessageCorpconversationAsyncsendV2Request.Msg msg = new OapiMessageCorpconversationAsyncsendV2Request.Msg();
+                msg.setOa(new OapiMessageCorpconversationAsyncsendV2Request.OA());
+                msg.getOa().setMessageUrl(dingTalkReqVo.getUrl());
+                msg.getOa().setPcMessageUrl(dingTalkReqVo.getUrl());
+                msg.getOa().setHead(new OapiMessageCorpconversationAsyncsendV2Request.Head());
+                msg.getOa().getHead().setBgcolor("00409eff");
+                msg.getOa().setBody(new OapiMessageCorpconversationAsyncsendV2Request.Body());
+                msg.getOa().getBody().setTitle(dingTalkReqVo.getTitle());
+                msg.getOa().getBody().setForm(objects);
+                msg.setMsgtype("oa");
+                request.setMsg(msg);
+
                 response = client.execute(request, accessToken);
-            } catch (ApiException e) {
-                e.getErrMsg();
+            } catch (Exception e) {
+                log.error("閽夐拤娑堟伅鍙戦�佸紓甯革紝鏀朵欢浜�={}", urid, e);
             }
 
-            //  log.info("娑堟伅浠诲姟ID"+response.getTaskId());
-            System.out.println(response.getTaskId());
-
-            result = response.isSuccess();
+            if (response == null || !response.isSuccess()) {
+                allSuccess = false;
+                log.error("閽夐拤娑堟伅鍙戦�佸け璐ワ紝鏀朵欢浜�={}锛屽搷搴�={}", urid,
+                        response == null ? "null" : response.getBody());
+                // 澶辫触鍙兘鏄� access_token 澶辨晥锛屾竻鎺夌紦瀛樿涓嬫閲嶆柊鑾峰彇
+                clearAccessToken();
+            } else {
+                log.info("閽夐拤娑堟伅鍙戦�佹垚鍔燂紝鏀朵欢浜�={}锛宼askId={}", urid, response.getTaskId());
+            }
         }
-        return result;
+        return allSuccess;
     }
 
     /**
@@ -193,7 +269,7 @@
             //鏍规嵁浼犺繃鏉ョ殑閮ㄩ棬ID锛屽幓鑾峰彇璇ラ儴闂ㄤ笅鐨勭敤鎴蜂俊鎭�
             if (begin != 1) DingUserInfoList(deptID);
             //鑾峰彇瀛愰儴闂ㄧ殑dept_id
-            DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/department/listsub");
+            DingTalkClient client = newClient("https://oapi.dingtalk.com/topapi/v2/department/listsub");
             OapiV2DepartmentListsubRequest req = new OapiV2DepartmentListsubRequest();
             req.setDeptId(deptID);
             req.setLanguage("zh_CN");
@@ -218,7 +294,7 @@
     public void DingUserInfoList(Long deptId) {
         DingTalkClient client = null;
         try {
-            client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/user/list?access_token=" + getAccessToken());
+            client = newClient("https://oapi.dingtalk.com/topapi/v2/user/list?access_token=" + getAccessToken());
             OapiV2UserListRequest req = new OapiV2UserListRequest();
             req.setDeptId(deptId);
             req.setCursor(0L);
@@ -248,19 +324,43 @@
 
 
     /**
-     * 鑾峰彇 access_token
+     * 鑾峰彇 access_token锛堝甫缂撳瓨锛屽け鏁堣嚜鍔ㄩ噸鍙栵級
      */
     private String getAccessToken() throws ApiException {
-        DefaultDingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/gettoken");
-        OapiGettokenRequest request = new OapiGettokenRequest();
-        //Appkey
-        request.setAppkey(dingAppid);
-        //Appsecret
-        request.setAppsecret(dingAppSecret);
-        /*璇锋眰鏂瑰紡*/
-        request.setHttpMethod("GET");
-        OapiGettokenResponse response = client.execute(request);
-        return response.getAccessToken();
+        String token = cachedAccessToken;
+        if (StringUtils.isNotEmpty(token) && System.currentTimeMillis() < accessTokenExpireAt) {
+            return token;
+        }
+        synchronized (this) {
+            if (StringUtils.isNotEmpty(cachedAccessToken)
+                    && System.currentTimeMillis() < accessTokenExpireAt) {
+                return cachedAccessToken;
+            }
+            DefaultDingTalkClient client = newClient("https://oapi.dingtalk.com/gettoken");
+            OapiGettokenRequest request = new OapiGettokenRequest();
+            //Appkey
+            request.setAppkey(dingAppid);
+            //Appsecret
+            request.setAppsecret(dingAppSecret);
+            /*璇锋眰鏂瑰紡*/
+            request.setHttpMethod("GET");
+            OapiGettokenResponse response = client.execute(request);
+            String newToken = response == null ? null : response.getAccessToken();
+            if (StringUtils.isNotEmpty(newToken)) {
+                cachedAccessToken = newToken;
+                accessTokenExpireAt = System.currentTimeMillis() + ACCESS_TOKEN_TTL_MILLIS;
+            }
+            return newToken;
+        }
+    }
+
+    /**
+     * 娓呯┖ access_token 缂撳瓨銆�
+     * 鍙戦�佸け璐ユ湁鍙兘鏄� token 澶辨晥锛堥拤閽� errcode 40014/42001锛夛紝娓呮帀鍚庝笅娆″彂閫佷細閲嶆柊鑾峰彇銆�
+     */
+    private void clearAccessToken() {
+        cachedAccessToken = null;
+        accessTokenExpireAt = 0L;
     }
 
 }
diff --git a/ruoyi-project/src/main/java/com/ruoyi/project/service/impl/ServiceDonatebaseinfoServiceImpl.java b/ruoyi-project/src/main/java/com/ruoyi/project/service/impl/ServiceDonatebaseinfoServiceImpl.java
index cd42b9f..a89a649 100644
--- a/ruoyi-project/src/main/java/com/ruoyi/project/service/impl/ServiceDonatebaseinfoServiceImpl.java
+++ b/ruoyi-project/src/main/java/com/ruoyi/project/service/impl/ServiceDonatebaseinfoServiceImpl.java
@@ -236,6 +236,23 @@
             serviceDonatebaseinfo.setDeptid(user.getDeptId());
         }
         List<ServiceDonatebaseinfo> serviceDonatebaseinfos = serviceDonatebaseinfoMapper.selectServiceDonatebaseinfoList(serviceDonatebaseinfo);
+
+        // 涓�娆℃�у彇鍑哄悇鎹愮尞鍩虹瀵瑰簲鐨勬浜℃椂闂达紝閬垮厤鍦ㄥ惊鐜噷鎸� InfoID 閫愭潯鏌ヨ璇佽〃锛圢+1锛�
+        List<Long> infoIds = new ArrayList<>();
+        for (ServiceDonatebaseinfo item : serviceDonatebaseinfos) {
+            if (item.getId() != null) {
+                infoIds.add(item.getId());
+            }
+        }
+        Map<Long, Date> deathTimeMap = new HashMap<>();
+        if (!infoIds.isEmpty()) {
+            for (ServiceDonationwitness witness : serviceDonationwitnessMapper.selectDeathTimeByInfoIds(infoIds)) {
+                if (witness.getInfoid() != null && !deathTimeMap.containsKey(witness.getInfoid())) {
+                    deathTimeMap.put(witness.getInfoid(), witness.getDeathtime());
+                }
+            }
+        }
+
         for (ServiceDonatebaseinfo serviceDonatebaseinfo1 : serviceDonatebaseinfos) {
             //鍏堢粰涓勾榫勯粯璁ゅ�硷紙鍥犱负age鏄暟瀛楃被鍨嬶紝涓嶈兘鏀炬í鏉狅紝鎵�浠ュ氨鎵�妯墰鏀惧埌鍗曚綅涓婏級
             serviceDonatebaseinfo1.setAgeunit("-");
@@ -243,22 +260,17 @@
             serviceDonatebaseinfo1.setAge2(null);
 
             //鑾峰彇姝讳骸鏃堕棿锛屽鏋滆幏鍙栬璇侀噷鏈夋浜℃椂闂达紝鍒欒繘琛岃绠椾粬鐨勫勾榫�
-            ServiceDonationwitness sdw = new ServiceDonationwitness();
-            sdw.setInfoid(serviceDonatebaseinfo1.getId());
-            List<ServiceDonationwitness> serviceDonationwitnessList = serviceDonationwitnessMapper.selectServiceDonationwitnessList(sdw);
-            if (!CollectionUtils.isEmpty(serviceDonationwitnessList) && serviceDonatebaseinfo1.getBirthday() != null) {
-                Date deathtime = serviceDonationwitnessList.get(0).getDeathtime();
-                if (ObjectUtils.isNotEmpty(deathtime)) {
-                    Map<String, String> map = CalculateDateUtils.calculateAge(serviceDonatebaseinfo1.getBirthday().toInstant().atZone(ZoneId.systemDefault()).toLocalDate(), deathtime.toInstant().atZone(ZoneId.systemDefault()).toLocalDate());
-                    if (Objects.isNull(map)) {
-                        log.error("ServiceDonationwitness鍑虹敓鏃ユ湡锛歿},ServiceDonationwitness姝讳骸鏃ユ湡锛歿}", serviceDonatebaseinfo1.getBirthday(), deathtime);
-                        continue;
-                    }
-                    serviceDonatebaseinfo1.setAge(org.apache.commons.lang3.ObjectUtils.isNotEmpty(map.get("age")) ? Long.valueOf(map.get("age")) : null);
-                    serviceDonatebaseinfo1.setAgeunit(map.get("ageUnit"));
-                    serviceDonatebaseinfo1.setAge2(org.apache.commons.lang3.ObjectUtils.isNotEmpty(map.get("age2")) ? Long.valueOf(map.get("age2")) : null);
-                    serviceDonatebaseinfo1.setAgeunit2(map.get("ageUnit2"));
+            Date deathtime = deathTimeMap.get(serviceDonatebaseinfo1.getId());
+            if (ObjectUtils.isNotEmpty(deathtime) && serviceDonatebaseinfo1.getBirthday() != null) {
+                Map<String, String> map = CalculateDateUtils.calculateAge(serviceDonatebaseinfo1.getBirthday().toInstant().atZone(ZoneId.systemDefault()).toLocalDate(), deathtime.toInstant().atZone(ZoneId.systemDefault()).toLocalDate());
+                if (Objects.isNull(map)) {
+                    log.error("ServiceDonationwitness鍑虹敓鏃ユ湡锛歿},ServiceDonationwitness姝讳骸鏃ユ湡锛歿}", serviceDonatebaseinfo1.getBirthday(), deathtime);
+                    continue;
                 }
+                serviceDonatebaseinfo1.setAge(org.apache.commons.lang3.ObjectUtils.isNotEmpty(map.get("age")) ? Long.valueOf(map.get("age")) : null);
+                serviceDonatebaseinfo1.setAgeunit(map.get("ageUnit"));
+                serviceDonatebaseinfo1.setAge2(org.apache.commons.lang3.ObjectUtils.isNotEmpty(map.get("age2")) ? Long.valueOf(map.get("age2")) : null);
+                serviceDonatebaseinfo1.setAgeunit2(map.get("ageUnit2"));
             }
 
         }
diff --git a/ruoyi-project/src/main/java/com/ruoyi/project/service/impl/ServiceDonatecompletioninfoServiceImpl.java b/ruoyi-project/src/main/java/com/ruoyi/project/service/impl/ServiceDonatecompletioninfoServiceImpl.java
index 453f215..42176f1 100644
--- a/ruoyi-project/src/main/java/com/ruoyi/project/service/impl/ServiceDonatecompletioninfoServiceImpl.java
+++ b/ruoyi-project/src/main/java/com/ruoyi/project/service/impl/ServiceDonatecompletioninfoServiceImpl.java
@@ -25,7 +25,9 @@
 
 import java.time.LocalDate;
 import java.time.ZoneId;
+import java.util.ArrayList;
 import java.util.Date;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
@@ -132,6 +134,22 @@
         }
         List<DonationCompletionVO> donationCompletionVOS = serviceDonatecompletioninfoMapper.selectVOList(donationCompletionVO);
 
+        // 涓�娆℃�у彇鍑哄悇鎹愮尞鍩虹瀵瑰簲鐨勬浜℃椂闂达紝閬垮厤鍦ㄥ惊鐜噷鎸� InfoID 閫愭潯鏌ヨ璇佽〃锛圢+1锛�
+        List<Long> infoIds = new ArrayList<>();
+        for (DonationCompletionVO item : donationCompletionVOS) {
+            if (item.getInfoid() != null) {
+                infoIds.add(item.getInfoid());
+            }
+        }
+        Map<Long, Date> deathTimeMap = new HashMap<>();
+        if (!infoIds.isEmpty()) {
+            for (ServiceDonationwitness witness : serviceDonationwitnessMapper.selectDeathTimeByInfoIds(infoIds)) {
+                if (witness.getInfoid() != null && !deathTimeMap.containsKey(witness.getInfoid())) {
+                    deathTimeMap.put(witness.getInfoid(), witness.getDeathtime());
+                }
+            }
+        }
+
         for (DonationCompletionVO donationCompletionVO1 : donationCompletionVOS) {
 //            if (donationCompletionVO1.getBirthday() != null) {
 //                Map<String, String> map = CalculateDateUtils.calculateAge(donationCompletionVO1.getBirthday().toInstant().atZone(ZoneId.systemDefault()).toLocalDate(), LocalDate.now());
@@ -146,23 +164,18 @@
             donationCompletionVO1.setAge(null);
             donationCompletionVO1.setAge2(null);
             //鑾峰彇姝讳骸鏃堕棿锛屽鏋滆幏鍙栬璇侀噷鏈夋浜℃椂闂达紝鍒欒繘琛岃绠椾粬鐨勫勾榫�
-            ServiceDonationwitness sdw = new ServiceDonationwitness();
-            sdw.setInfoid(donationCompletionVO1.getInfoid());
-            List<ServiceDonationwitness> serviceDonationwitnessList = serviceDonationwitnessMapper.selectServiceDonationwitnessList(sdw);
-            if (!org.springframework.util.CollectionUtils.isEmpty(serviceDonationwitnessList) && donationCompletionVO1.getBirthday() != null) {
-                Date deathtime = serviceDonationwitnessList.get(0).getDeathtime();
-                if (ObjectUtils.isNotEmpty(deathtime)) {
-                    Map<String, String> map = CalculateDateUtils.calculateAge(donationCompletionVO1.getBirthday().toInstant().atZone(ZoneId.systemDefault()).toLocalDate(), deathtime.toInstant().atZone(ZoneId.systemDefault()).toLocalDate());
-                    if (ObjectUtils.isEmpty(map)) {
-                        log.error("DonationCompletionVO鍑虹敓鏃ユ湡锛歿},DonationCompletionVO姝讳骸鏃ユ湡锛歿}", donationCompletionVO1.getBirthday(), deathtime);
-                        continue;
-                    }
-
-                    donationCompletionVO1.setAge(org.apache.commons.lang3.ObjectUtils.isNotEmpty(map.get("age")) ? Long.valueOf(map.get("age")) : null);
-                    donationCompletionVO1.setAgeunit(map.get("ageUnit"));
-                    donationCompletionVO1.setAge2(org.apache.commons.lang3.ObjectUtils.isNotEmpty(map.get("age2")) ? Long.valueOf(map.get("age2")) : null);
-                    donationCompletionVO1.setAgeunit2(map.get("ageUnit2"));
+            Date deathtime = deathTimeMap.get(donationCompletionVO1.getInfoid());
+            if (ObjectUtils.isNotEmpty(deathtime) && donationCompletionVO1.getBirthday() != null) {
+                Map<String, String> map = CalculateDateUtils.calculateAge(donationCompletionVO1.getBirthday().toInstant().atZone(ZoneId.systemDefault()).toLocalDate(), deathtime.toInstant().atZone(ZoneId.systemDefault()).toLocalDate());
+                if (ObjectUtils.isEmpty(map)) {
+                    log.error("DonationCompletionVO鍑虹敓鏃ユ湡锛歿},DonationCompletionVO姝讳骸鏃ユ湡锛歿}", donationCompletionVO1.getBirthday(), deathtime);
+                    continue;
                 }
+
+                donationCompletionVO1.setAge(org.apache.commons.lang3.ObjectUtils.isNotEmpty(map.get("age")) ? Long.valueOf(map.get("age")) : null);
+                donationCompletionVO1.setAgeunit(map.get("ageUnit"));
+                donationCompletionVO1.setAge2(org.apache.commons.lang3.ObjectUtils.isNotEmpty(map.get("age2")) ? Long.valueOf(map.get("age2")) : null);
+                donationCompletionVO1.setAgeunit2(map.get("ageUnit2"));
             }
         }
 
diff --git a/ruoyi-project/src/main/java/com/ruoyi/project/service/impl/ServiceDonationwitnessServiceImpl.java b/ruoyi-project/src/main/java/com/ruoyi/project/service/impl/ServiceDonationwitnessServiceImpl.java
index 7259405..53f6c13 100644
--- a/ruoyi-project/src/main/java/com/ruoyi/project/service/impl/ServiceDonationwitnessServiceImpl.java
+++ b/ruoyi-project/src/main/java/com/ruoyi/project/service/impl/ServiceDonationwitnessServiceImpl.java
@@ -26,6 +26,7 @@
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.Map;
 
 import com.ruoyi.common.utils.StringUtils;
@@ -95,28 +96,40 @@
             donationWitnessVO.setReporterno(user.getUserName());
         }
         List<DonationWitnessVO> donationWitnessVOS = serviceDonationwitnessMapper.selectVOList(donationWitnessVO);
+
+        // 涓�娆℃�у彇鍑哄悇鎹愮尞鍩虹瀵瑰簲鐨勬浜℃椂闂达紝閬垮厤鍦ㄥ惊鐜噷鎸� InfoID 閫愭潯鏌ヨ璇佽〃锛圢+1锛�
+        List<Long> infoIds = new ArrayList<>();
+        for (DonationWitnessVO item : donationWitnessVOS) {
+            if (item.getInfoid() != null) {
+                infoIds.add(item.getInfoid());
+            }
+        }
+        Map<Long, Date> deathTimeMap = new HashMap<>();
+        if (!infoIds.isEmpty()) {
+            for (ServiceDonationwitness witness : serviceDonationwitnessMapper.selectDeathTimeByInfoIds(infoIds)) {
+                if (witness.getInfoid() != null && !deathTimeMap.containsKey(witness.getInfoid())) {
+                    deathTimeMap.put(witness.getInfoid(), witness.getDeathtime());
+                }
+            }
+        }
+
         for (DonationWitnessVO donationWitnessVO1 : donationWitnessVOS) {
             //鍏堢粰涓勾榫勯粯璁ゅ�硷紙鍥犱负age鏄暟瀛楃被鍨嬶紝涓嶈兘鏀炬í鏉狅紝鎵�浠ュ氨鎵�妯墰鏀惧埌鍗曚綅涓婏級
             donationWitnessVO1.setAgeunit("-");
 
             //鑾峰彇姝讳骸鏃堕棿锛屽鏋滆幏鍙栬璇侀噷鏈夋浜℃椂闂达紝鍒欒繘琛岃绠椾粬鐨勫勾榫�
-            ServiceDonationwitness sdw = new ServiceDonationwitness();
-            sdw.setInfoid(donationWitnessVO1.getInfoid());
-            List<ServiceDonationwitness> serviceDonationwitnessList = serviceDonationwitnessMapper.selectServiceDonationwitnessList(sdw);
-            if (!CollectionUtils.isEmpty(serviceDonationwitnessList) && donationWitnessVO1.getBirthday() != null) {
-                Date deathtime = serviceDonationwitnessList.get(0).getDeathtime();
-                if (ObjectUtils.isNotEmpty(deathtime)) {
-                    Map<String, String> map = CalculateDateUtils.calculateAge(donationWitnessVO1.getBirthday().toInstant().atZone(ZoneId.systemDefault()).toLocalDate(), deathtime.toInstant().atZone(ZoneId.systemDefault()).toLocalDate());
-                    if (ObjectUtils.isEmpty(map)) {
-                        log.error("DonationWitnessVO鍑虹敓鏃ユ湡锛歿},DonationWitnessVO姝讳骸鏃ユ湡锛歿}", donationWitnessVO1.getBirthday(), deathtime);
-                        continue;
-                    }
-
-                    donationWitnessVO1.setAge(org.apache.commons.lang3.ObjectUtils.isNotEmpty(map.get("age")) ? Long.valueOf(map.get("age")) : null);
-                    donationWitnessVO1.setAgeunit(map.get("ageUnit"));
-                    donationWitnessVO1.setAge2(org.apache.commons.lang3.ObjectUtils.isNotEmpty(map.get("age2")) ? Long.valueOf(map.get("age2")) : null);
-                    donationWitnessVO1.setAgeunit2(map.get("ageUnit2"));
+            Date deathtime = deathTimeMap.get(donationWitnessVO1.getInfoid());
+            if (ObjectUtils.isNotEmpty(deathtime) && donationWitnessVO1.getBirthday() != null) {
+                Map<String, String> map = CalculateDateUtils.calculateAge(donationWitnessVO1.getBirthday().toInstant().atZone(ZoneId.systemDefault()).toLocalDate(), deathtime.toInstant().atZone(ZoneId.systemDefault()).toLocalDate());
+                if (ObjectUtils.isEmpty(map)) {
+                    log.error("DonationWitnessVO鍑虹敓鏃ユ湡锛歿},DonationWitnessVO姝讳骸鏃ユ湡锛歿}", donationWitnessVO1.getBirthday(), deathtime);
+                    continue;
                 }
+
+                donationWitnessVO1.setAge(org.apache.commons.lang3.ObjectUtils.isNotEmpty(map.get("age")) ? Long.valueOf(map.get("age")) : null);
+                donationWitnessVO1.setAgeunit(map.get("ageUnit"));
+                donationWitnessVO1.setAge2(org.apache.commons.lang3.ObjectUtils.isNotEmpty(map.get("age2")) ? Long.valueOf(map.get("age2")) : null);
+                donationWitnessVO1.setAgeunit2(map.get("ageUnit2"));
             }
         }
         return donationWitnessVOS;
diff --git a/ruoyi-project/src/main/java/com/ruoyi/project/service/impl/ServiceEthicalreviewopinionsServiceImpl.java b/ruoyi-project/src/main/java/com/ruoyi/project/service/impl/ServiceEthicalreviewopinionsServiceImpl.java
index 1d5aaab..1d974e5 100644
--- a/ruoyi-project/src/main/java/com/ruoyi/project/service/impl/ServiceEthicalreviewopinionsServiceImpl.java
+++ b/ruoyi-project/src/main/java/com/ruoyi/project/service/impl/ServiceEthicalreviewopinionsServiceImpl.java
@@ -23,6 +23,7 @@
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.Map;
 
 import com.ruoyi.common.utils.StringUtils;
@@ -99,28 +100,39 @@
         }
         List<EthicalReviewVO> ethicalReviewVOS = serviceEthicalreviewopinionsMapper.selectVOList(ethicalReviewVO);
 
+        // 涓�娆℃�у彇鍑哄悇鎹愮尞鍩虹瀵瑰簲鐨勬浜℃椂闂达紝閬垮厤鍦ㄥ惊鐜噷鎸夋崘鐚熀纭�ID閫愭潯鏌ヨ璇佽〃锛圢+1锛�
+        List<Long> infoIds = new ArrayList<>();
+        for (EthicalReviewVO item : ethicalReviewVOS) {
+            if (item.getId() != null) {
+                infoIds.add(item.getId());
+            }
+        }
+        Map<Long, Date> deathTimeMap = new HashMap<>();
+        if (!infoIds.isEmpty()) {
+            for (ServiceDonationwitness witness : serviceDonationwitnessMapper.selectDeathTimeByInfoIds(infoIds)) {
+                if (witness.getInfoid() != null && !deathTimeMap.containsKey(witness.getInfoid())) {
+                    deathTimeMap.put(witness.getInfoid(), witness.getDeathtime());
+                }
+            }
+        }
+
         for (EthicalReviewVO ethicalReviewVO1 : ethicalReviewVOS) {
             //鍏堢粰涓勾榫勯粯璁ゅ�硷紙鍥犱负age鏄暟瀛楃被鍨嬶紝涓嶈兘鏀炬í鏉狅紝鎵�浠ュ氨鎵�妯墰鏀惧埌鍗曚綅涓婏級
             ethicalReviewVO1.setAgeunit("-");
             ethicalReviewVO1.setAge(null);
             ethicalReviewVO1.setAge2(null);
             //鑾峰彇姝讳骸鏃堕棿锛屽鏋滆幏鍙栬璇侀噷鏈夋浜℃椂闂达紝鍒欒繘琛岃绠椾粬鐨勫勾榫�
-            ServiceDonationwitness sdw = new ServiceDonationwitness();
-            sdw.setInfoid(ethicalReviewVO1.getId());
-            List<ServiceDonationwitness> serviceDonationwitnessList = serviceDonationwitnessMapper.selectServiceDonationwitnessList(sdw);
-            if (!CollectionUtils.isEmpty(serviceDonationwitnessList) && ethicalReviewVO1.getBirthday() != null) {
-                Date deathtime = serviceDonationwitnessList.get(0).getDeathtime();
-                if (ObjectUtils.isNotEmpty(deathtime)) {
-                    Map<String, String> map = CalculateDateUtils.calculateAge(ethicalReviewVO1.getBirthday().toInstant().atZone(ZoneId.systemDefault()).toLocalDate(), deathtime.toInstant().atZone(ZoneId.systemDefault()).toLocalDate());
-                    if (ObjectUtils.isEmpty(map)) {
-                        log.error("EthicalReviewVO鍑虹敓鏃ユ湡锛歿},EthicalReviewVO姝讳骸鏃ユ湡锛歿}", ethicalReviewVO1.getBirthday(), deathtime);
-                        continue;
-                    }
-                    ethicalReviewVO1.setAge(org.apache.commons.lang3.ObjectUtils.isNotEmpty(map.get("age")) ? Long.valueOf(map.get("age")) : null);
-                    ethicalReviewVO1.setAgeunit(map.get("ageUnit"));
-                    ethicalReviewVO1.setAge2(org.apache.commons.lang3.ObjectUtils.isNotEmpty(map.get("age2")) ? Long.valueOf(map.get("age2")) : null);
-                    ethicalReviewVO1.setAgeunit2(map.get("ageUnit2"));
+            Date deathtime = deathTimeMap.get(ethicalReviewVO1.getId());
+            if (ObjectUtils.isNotEmpty(deathtime) && ethicalReviewVO1.getBirthday() != null) {
+                Map<String, String> map = CalculateDateUtils.calculateAge(ethicalReviewVO1.getBirthday().toInstant().atZone(ZoneId.systemDefault()).toLocalDate(), deathtime.toInstant().atZone(ZoneId.systemDefault()).toLocalDate());
+                if (ObjectUtils.isEmpty(map)) {
+                    log.error("EthicalReviewVO鍑虹敓鏃ユ湡锛歿},EthicalReviewVO姝讳骸鏃ユ湡锛歿}", ethicalReviewVO1.getBirthday(), deathtime);
+                    continue;
                 }
+                ethicalReviewVO1.setAge(org.apache.commons.lang3.ObjectUtils.isNotEmpty(map.get("age")) ? Long.valueOf(map.get("age")) : null);
+                ethicalReviewVO1.setAgeunit(map.get("ageUnit"));
+                ethicalReviewVO1.setAge2(org.apache.commons.lang3.ObjectUtils.isNotEmpty(map.get("age2")) ? Long.valueOf(map.get("age2")) : null);
+                ethicalReviewVO1.setAgeunit2(map.get("ageUnit2"));
             }
 
         }
diff --git a/ruoyi-project/src/main/java/com/ruoyi/project/service/impl/ServiceExternalpersonServiceImpl.java b/ruoyi-project/src/main/java/com/ruoyi/project/service/impl/ServiceExternalpersonServiceImpl.java
index d9f13a0..326fcea 100644
--- a/ruoyi-project/src/main/java/com/ruoyi/project/service/impl/ServiceExternalpersonServiceImpl.java
+++ b/ruoyi-project/src/main/java/com/ruoyi/project/service/impl/ServiceExternalpersonServiceImpl.java
@@ -49,7 +49,8 @@
             wrappers.like(ServiceExternalperson::getUsername, serviceExternalperson.getUsername());
         }
         if (StringUtils.isNotBlank(serviceExternalperson.getUsertype())) {
-            wrappers.eq(ServiceExternalperson::getUsertype, serviceExternalperson.getUsertype());
+            // UserType 鑷� 2026-09-27 璧蜂负澶氬�煎瓧娈碉紙閫楀彿鍒嗛殧锛夛紝鎸�"鍖呭惈"鍖归厤
+            wrappers.apply("FIND_IN_SET({0}, UserType)", serviceExternalperson.getUsertype());
         }
         if (StringUtils.isNotBlank(serviceExternalperson.getUnitname())) {
             wrappers.like(ServiceExternalperson::getUnitname, serviceExternalperson.getUnitname());
diff --git a/ruoyi-project/src/main/java/com/ruoyi/project/service/impl/ServiceFundServiceImpl.java b/ruoyi-project/src/main/java/com/ruoyi/project/service/impl/ServiceFundServiceImpl.java
index a2cfd8d..296e3ec 100644
--- a/ruoyi-project/src/main/java/com/ruoyi/project/service/impl/ServiceFundServiceImpl.java
+++ b/ruoyi-project/src/main/java/com/ruoyi/project/service/impl/ServiceFundServiceImpl.java
@@ -16,11 +16,13 @@
 import com.ruoyi.common.core.domain.entity.SysUser;
 import com.ruoyi.common.core.domain.model.LoginUser;
 import com.ruoyi.common.enums.ApplyTypeEnum;
+import com.ruoyi.common.exception.ServiceException;
 import com.ruoyi.common.exception.base.BaseException;
 import com.ruoyi.common.utils.HttpClientKit;
 import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.common.utils.bean.DtoConversionUtils;
 import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.project.common.FundNotifyMessageBuilder;
 import com.ruoyi.project.common.IdGeneratorUtils;
 import com.ruoyi.project.domain.*;
 import com.ruoyi.project.domain.vo.*;
@@ -28,6 +30,7 @@
 import com.ruoyi.project.service.*;
 import com.ruoyi.system.mapper.SysUserMapper;
 import com.ruoyi.system.mapper.SysUserRoleMapper;
+import com.ruoyi.system.service.ISysConfigService;
 import com.ruoyi.system.service.ISysUserService;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.ObjectUtils;
@@ -61,6 +64,10 @@
 public class ServiceFundServiceImpl extends ServiceImpl<ServiceFundMapper, ServiceFund> implements IServiceFundService {
     @Autowired
     ServiceFundMapper serviceFundMapper;
+
+    /** 涓撳鍔冲姟璐� 9 鏉¤垂鐢ㄦ帶鍒惰鍒欐牎楠岋紙鍚屼竴妗堜緥绱锛� */
+    @Autowired
+    private ExpertFeeValidateService expertFeeValidateService;
 
     @Autowired
     private DingTalkService dingTalkService;
@@ -137,6 +144,35 @@
     @Value("${spring.profiles.active}")
     private String active;
 
+    @Autowired
+    private ISysConfigService sysConfigService;
+
+    /**
+     * 瀹℃壒鍗曟槸鍚︿笂浼犲尰闄㈠崗鍙嬶紙鑷磋繙锛夌郴缁燂細0=涓嶄笂浼狅紙娴嬭瘯鐜锛夛紝1=涓婁紶锛堟寮忕幆澧冿級銆�
+     *
+     * <p>2026-10-09 鏂板锛氬師鏉ョ敤 {@code spring.profiles.active == druid} 鍒ゆ柇鏄惁鎺ㄩ�侊紝
+     * 娴嬭瘯鐜涓庢寮忕幆澧冩棤娉曢�氳繃鍙傛暟鍖哄垎銆傛敼涓虹郴缁熷弬鏁版帶鍒躲��
+     */
+    private static final String CFG_UPLOAD_OA = "sys.approval.upload.oa";
+
+    /** 鍙傛暟缂虹渷鍊硷細涓婁紶锛堜繚鎸佹寮忕幆澧冨師鏈夎涓猴級 */
+    private static final boolean DEFAULT_UPLOAD_OA = true;
+
+    /** 瀹℃壒鍗曟槸鍚﹂渶瑕佷笂浼犲尰闄㈠崗鍙嬶紙鑷磋繙锛夌郴缁� */
+    private boolean isUploadOaEnabled() {
+        String value = null;
+        try {
+            value = sysConfigService.selectConfigByKey(CFG_UPLOAD_OA);
+        } catch (Exception e) {
+            log.warn("璇诲彇鍙傛暟 {} 澶辫触锛屾寜榛樿鍊� {} 澶勭悊", CFG_UPLOAD_OA, DEFAULT_UPLOAD_OA, e);
+        }
+        if (value == null || value.trim().isEmpty()) {
+            return DEFAULT_UPLOAD_OA;
+        }
+        String v = value.trim();
+        return "1".equals(v) || "true".equalsIgnoreCase(v) || "y".equalsIgnoreCase(v) || "on".equalsIgnoreCase(v);
+    }
+
     /**
      * 鑷磋繙绯荤粺娴佺▼閫�鍥�
      *
@@ -199,6 +235,12 @@
         String phone = null;
         String applytype = null;
         Long flowlevel = null;
+        //閽夐拤閫氱煡鐢ㄧ殑鍗曟嵁淇℃伅
+        Double amount = null;
+        String donorName = null;
+        String billNo = null;
+        String travelers = null;
+        String reason = null;
         if (serviceProcessVO.getApplytype().equals("0")) {
             ServiceReimbursement serviceReimbursement = new ServiceReimbursement();
             serviceReimbursement.setId(StringUtils.isNotEmpty(serviceProcessVO.getBackCode()) ? Long.valueOf(serviceProcessVO.getBackCode()) : null);
@@ -213,6 +255,11 @@
             phone = serviceReimbursementList.get(0).getPhone();
             flowlevel = serviceReimbursementList.get(0).getFlowlevel();
             applytype = "0";
+            amount = serviceReimbursementList.get(0).getAmountrequested();
+            billNo = FundNotifyMessageBuilder.billNo(serviceReimbursementList.get(0).getBh(),
+                    serviceReimbursementList.get(0).getId());
+            travelers = serviceReimbursementList.get(0).getTravelers();
+            reason = serviceReimbursementList.get(0).getReason();
         } else {
             ServiceFund serviceFund = new ServiceFund();
             serviceFund.setId(StringUtils.isNotEmpty(serviceProcessVO.getBackCode()) ? Long.valueOf(serviceProcessVO.getBackCode()) : null);
@@ -226,6 +273,10 @@
             phone = serviceFunds.get(0).getPhone();
             flowlevel = serviceFunds.get(0).getFlowlevel();
             applytype = serviceFunds.get(0).getApplytype();
+            amount = serviceFunds.get(0).getPretaxcost();
+            donorName = serviceFunds.get(0).getDonorname();
+            billNo = FundNotifyMessageBuilder.billNo(serviceFunds.get(0).getBh(),
+                    serviceFunds.get(0).getId());
         }
 
 //        //灏嗘搷浣滀繚瀛樺埌fundflow琛ㄤ腑
@@ -248,7 +299,16 @@
 
 
         SysUser sysUser = sysUserService.selectUserByUserName(userNo);
-        sendMeg(serviceProcessVO, phone);
+
+        //閽夐拤閫氱煡鍐呭锛氬崟鎹俊鎭紙绫诲瀷/鎶ラ攢浜�/閲戦/妗堜緥/缂栧彿锛�+ 瀹℃壒浜�/瀹℃壒鏃堕棿/鎰忚
+        List<ConcurrentHashMap<String, Object>> notifyRows = FundNotifyMessageBuilder.newRows();
+        FundNotifyMessageBuilder.addBillInfo(notifyRows, applytype, userName, amount, donorName, billNo);
+        FundNotifyMessageBuilder.addTravelInfo(notifyRows, travelers, reason);
+        FundNotifyMessageBuilder.addAuditResult(notifyRows, serviceProcessVO.getCheckusername(),
+                serviceProcessVO.getCheckTime(),
+                FundNotifyMessageBuilder.opinion(serviceProcessVO.getFlowconclusion(),
+                        serviceProcessVO.getFlowcontent()));
+        sendMeg(serviceProcessVO, phone, notifyRows);
         //鍙戦�佷俊鎭繚瀛�
         ServiceSystemmessage serviceSystemmessage = new ServiceSystemmessage();
         serviceSystemmessage.setFundtype(1);
@@ -260,7 +320,7 @@
         serviceSystemmessage.setUpdateBy(sysUser.getNickName());
         serviceSystemmessage.setIsread(0);
         serviceSystemmessage.setMessagetype(1);
-        serviceSystemmessage.setMessagetitle("璐㈠姟绯荤粺淇℃伅");
+        serviceSystemmessage.setMessagetitle("OPO绯荤粺瀹℃壒");
         serviceSystemmessage.setMessagecontent(serviceProcessVO.getFlowcontent());
         iServiceSystemmessageService.save(serviceSystemmessage);
 
@@ -374,6 +434,7 @@
     }
 
     @Override
+    @Transactional(rollbackFor = Exception.class)
     public Map<String, String> checkFund(CheckFundVO checkFundVO, LoginUser loginUser) {
         ServiceFund serviceFund = getById(checkFundVO.getFundid());
         Map<String, String> map = new HashMap<>();
@@ -381,6 +442,19 @@
         if (serviceFund == null) {
             map.put(HttpStatus.NO_CONTENT + "", "璐圭敤缂栧彿涓嶆纭�");
             return map;
+        }
+
+        // 涓撳鍔冲姟璐癸細瀹℃牳鈥滈�氳繃鈥濆墠鏍¢獙 9 鏉¤垂鐢ㄦ帶鍒惰鍒欙紙鍚屼竴妗堜緥绱锛夛紱涓嶉�氳繃鍒欎笉闃绘柇
+        if (checkFundVO.getFlowconclusion() != null && checkFundVO.getFlowconclusion() == 1) {
+            ExpertFeeCheckResult expertFeeResult = expertFeeValidateService.validateBeforeCheck(checkFundVO.getFundid());
+            if (expertFeeResult.hasError()) {
+                map.put(HttpStatus.ERROR + "", expertFeeResult.errorMessage());
+                return map;
+            }
+            if (expertFeeResult.hasWarning()) {
+                // 瑙勫垯 5銆�6 浠呮彁绀猴紝涓嶉樆鏂鏍�
+                log.warn("涓撳鍔冲姟璐瑰鏍告牎楠屾彁绀猴細fundId={}锛寋}", checkFundVO.getFundid(), expertFeeResult.warningMessage());
+            }
         }
 
         Integer TotalLevel = 0;
@@ -409,6 +483,11 @@
         Integer RecordStatus = serviceFund.getRecordstatus();
         Integer FlowLevel = serviceFund.getFlowlevel().intValue();
         Integer OriginalFlowLevel = FlowLevel;
+        //瀹℃壒缁撹蹇呭~锛氬師瀹炵幇鐩存帴 == 1 鎷嗙锛屾帴鍙h鐩磋皟浼� null 浼� NPE 500
+        if (checkFundVO.getFlowconclusion() == null) {
+            map.put(HttpStatus.ERROR + "", "瀹℃壒缁撹涓嶈兘涓虹┖");
+            return map;
+        }
         if (checkFundVO.getFlowconclusion() == 1) {
             CheckFlag = 1;
             if (TotalLevel == 0) {
@@ -437,8 +516,9 @@
                 if (newSwitch == 1) {
                     aBoolean1 = sendData(serviceFund);
                     if (!aBoolean1) {
-                        map.put("500", "鍙戦�佸け璐�");
-                        return map;
+                        // 鎺ㄩ�佸尰闄㈠崗鍙嬬郴缁熷け璐ワ細鏁翠釜瀹℃壒涓嶇敓鏁堬紙浜嬪姟鍥炴粴锛夛紝鍏佽涓嬫閲嶆柊瀹℃壒
+                        log.error("璐圭敤瀹℃壒鍗曚笂浼犲尰闄㈠崗鍙嬬郴缁熷け璐ワ紝瀹℃壒涓嶇敓鏁堬紝fundId={}锛岃閲嶆柊瀹℃壒", serviceFund.getId());
+                        throw new ServiceException("鍖婚櫌鍗忓弸绯荤粺鎺ユ敹澶辫触锛屾湰娆″鎵规湭鐢熸晥锛岃绋嶅悗閲嶆柊瀹℃壒");
                     }
                 }
                 //淇濆瓨瀹℃壒娴佺▼琛�
@@ -481,21 +561,22 @@
             }
 
             SysUser sysUser = sysUserService.selectUserByUserName(serviceFund.getUserno());
-            ArrayList<ConcurrentHashMap<String, Object>> contentList = new ArrayList<>();
-            ConcurrentHashMap cmap = new ConcurrentHashMap();
-            cmap.put("瀹℃壒浜猴細", loginUser.getUser().getUserName());
-            cmap.put("瀹℃壒鏃堕棿锛�", new Date());
-            cmap.put("鎰忚锛�", "涓嶉�氳繃");
-            if (StringUtils.isNotBlank(checkFundVO.getFlowcontent())) cmap.put("鎰忚锛�", checkFundVO.getFlowcontent());
-            contentList.add(cmap);
-            try{
-            DingTalkReqVo dingTalkReqVo = new DingTalkReqVo();
-            dingTalkReqVo.setTitle("璐㈠姟绯荤粺椹冲洖淇℃伅");
-            dingTalkReqVo.setNumber(sysUser.getPhonenumber());
-            dingTalkReqVo.setContents(contentList);
-            dingTalkService.sendNotification(dingTalkReqVo);
-            }catch (Exception e){
-                log.error("璐圭敤---璐㈠姟绯荤粺椹冲洖淇℃伅鎶ラ敊浜�", e);
+            //瀹℃壒鏈�氳繃锛氬崟鎹俊鎭� + 瀹℃壒浜�/瀹℃壒鏃堕棿/鎰忚锛堟剰瑙� = "瀹℃壒鏈�氳繃銆�" + 椹冲洖鎰忚锛�
+            List<ConcurrentHashMap<String, Object>> contentList = FundNotifyMessageBuilder.newRows();
+            FundNotifyMessageBuilder.addBillInfo(contentList, serviceFund.getApplytype(),
+                    serviceFund.getUsername(), serviceFund.getPretaxcost(), serviceFund.getDonorname(),
+                    FundNotifyMessageBuilder.billNo(serviceFund.getBh(), serviceFund.getId()));
+            FundNotifyMessageBuilder.addAuditResult(contentList, loginUser.getUser().getNickName(), new Date(),
+                    FundNotifyMessageBuilder.opinion(FundNotifyMessageBuilder.CONCLUSION_REJECT,
+                            checkFundVO.getFlowcontent()));
+            try {
+                DingTalkReqVo dingTalkReqVo = new DingTalkReqVo();
+                dingTalkReqVo.setTitle(FundNotifyMessageBuilder.TITLE);
+                dingTalkReqVo.setNumber(sysUser.getPhonenumber());
+                dingTalkReqVo.setContents(contentList);
+                dingTalkService.sendNotification(dingTalkReqVo);
+            } catch (Exception e) {
+                log.error("璐圭敤---瀹℃壒鏈�氳繃閽夐拤閫氱煡澶辫触锛宖undId={}", serviceFund.getId(), e);
             }
         }
 
@@ -538,8 +619,9 @@
                 //鎼炰竴涓紑鍏筹紝鍒奖鍝嶈�佹祦绋�
                 aBoolean1 = sendData(serviceFund);
                 if (!aBoolean1) {
-                    map.put("500", "鍙戦�佸け璐�");
-                    return map;
+                    // 鎺ㄩ�佸尰闄㈠崗鍙嬬郴缁熷け璐ワ細鏁翠釜瀹℃壒涓嶇敓鏁堬紙浜嬪姟鍥炴粴锛夛紝鍏佽涓嬫閲嶆柊瀹℃壒
+                    log.error("璐圭敤瀹℃壒鍗曚笂浼犲尰闄㈠崗鍙嬬郴缁熷け璐ワ紝瀹℃壒涓嶇敓鏁堬紝fundId={}锛岃閲嶆柊瀹℃壒", serviceFund.getId());
+                    throw new ServiceException("鍖婚櫌鍗忓弸绯荤粺鎺ユ敹澶辫触锛屾湰娆″鎵规湭鐢熸晥锛岃绋嶅悗閲嶆柊瀹℃壒");
                 }
             }
         }
@@ -603,7 +685,30 @@
 
     }
 
+    /**
+     * 瀹℃壒鍗曚笂浼犲尰闄㈠崗鍙嬶紙鑷磋繙锛夌郴缁熴��
+     *
+     * <p>2026-10-09锛氬灞傚寘涓�灞傚厹搴曪紝淇濊瘉**浠讳綍寮傚父閮戒笉浼氬悜澶栨姏**锛堝師鏉� strRes 涓� null 鏃�
+     * 浼氬湪 parseObject 鍚庡彇 code 瑙﹀彂 NPE锛屾妸鏁翠釜瀹℃壒璇锋眰鎵撴垚 500锛夈��
+     * 杩斿洖 false 琛ㄧず鎺ㄩ�佸け璐ワ紝璋冪敤鏂规寜"瀹℃壒涓嶇敓鏁堛�佸厑璁镐笅娆¢噸鏂板鎵�"澶勭悊銆�
+     */
     public Boolean sendData(ServiceFund serviceFund) {
+        if (!isUploadOaEnabled()) {
+            // 涓婁紶寮�鍏冲叧闂紙濡傛祴璇曠幆澧冿級锛氳烦杩囦笂浼犲苟瑙嗕负鎴愬姛锛岀粷涓嶈兘鍥犳闃绘柇瀹℃壒
+            log.info("瀹℃壒鍗曚笂浼犲尰闄㈠崗鍙嬬郴缁熷凡鍏抽棴锛坰ys.approval.upload.oa != 1锛夛紝璺宠繃涓婁紶骞惰涓烘垚鍔燂紝fundId={}",
+                    serviceFund == null ? null : serviceFund.getId());
+            return true;
+        }
+        try {
+            return doSendData(serviceFund);
+        } catch (Throwable t) {
+            log.error("璐圭敤瀹℃壒鍗曚笂浼犲尰闄㈠崗鍙嬬郴缁熷紓甯革紝瀹℃壒涓嶇敓鏁堬紝fundId={}",
+                    serviceFund == null ? null : serviceFund.getId(), t);
+            return false;
+        }
+    }
+
+    private Boolean doSendData(ServiceFund serviceFund) {
         // fund鍜宖unddetail鐨勬暟鎹幏鍙�
         addFundSharedInfo(serviceFund.getId());
         List<ServiceFundShared> fundShareInfos = serviceFundSharedMapper.getFundShareInfoById(serviceFund.getId());
@@ -644,7 +749,7 @@
 
         map.put("data", data);
         String strRes = null;
-        if (!active.equals("druid")) {
+        if (isUploadOaEnabled()) {
             //濡傛灉鏄湰鍦扮幆澧冿紝灏变笉璋冭繖涓簡
             String token = getToken();
             JSONObject json1 = JSONObject.parseObject(token);
@@ -684,9 +789,28 @@
             }
         }
         log.error("------------------strRes鐨勫�间负锛歿}", strRes);
-        JSONObject jsonObject = JSONObject.parseObject(strRes);
+        if (strRes == null || strRes.trim().isEmpty()) {
+            // 鍖婚櫌鍗忓弸绯荤粺鏃犺繑鍥烇紙瓒呮椂/寮傚父/鏈厤缃級锛氭帹閫佸け璐ワ紝鐢辫皟鐢ㄦ柟鍥炴粴鏁翠釜瀹℃壒
+            log.error("璐圭敤瀹℃壒鍗曚笂浼犲尰闄㈠崗鍙嬬郴缁熷け璐ワ細鎺ュ彛鏃犺繑鍥炲唴瀹癸紝fundId={}", serviceFund.getId());
+            return false;
+        }
+        JSONObject jsonObject = null;
+        try {
+            jsonObject = JSONObject.parseObject(strRes);
+        } catch (Exception e) {
+            log.error("璐圭敤瀹℃壒鍗曚笂浼犲尰闄㈠崗鍙嬬郴缁熷け璐ワ細杩斿洖鍐呭鏃犳硶瑙f瀽锛宖undId={}锛宻trRes={}",
+                    serviceFund.getId(), strRes, e);
+            return false;
+        }
+        if (jsonObject == null) {
+            log.error("璐圭敤瀹℃壒鍗曚笂浼犲尰闄㈠崗鍙嬬郴缁熷け璐ワ細杩斿洖鍐呭涓虹┖锛宖undId={}锛宻trRes={}",
+                    serviceFund.getId(), strRes);
+            return false;
+        }
         String code = jsonObject.getString("code");
-        if (!code.equals("0")) {
+        if (code == null || !"0".equals(code)) {
+            log.error("璐圭敤瀹℃壒鍗曚笂浼犲尰闄㈠崗鍙嬬郴缁熷け璐ワ細code={}锛宖undId={}锛宻trRes={}",
+                    code, serviceFund.getId(), strRes);
             return false;
         }
 
@@ -885,7 +1009,7 @@
             serviceFunddetailShareds.get(i).setId(null);
             //鏁版嵁鍙戦�佺粰璐㈠姟
             try {
-                if (!active.equals("druid")) uploadOAFileAndUpdateDb(serviceFunddetailShareds.get(i));
+                if (isUploadOaEnabled()) uploadOAFileAndUpdateDb(serviceFunddetailShareds.get(i));
             } catch (Exception e) {
                 e.printStackTrace();
                 log.error("Exception涓叆鍙傜殑ID涓猴細{},寮傚父淇℃伅涓� 锛� {}", id, e.getMessage());
@@ -1421,8 +1545,23 @@
     }
 
     @Override
+    public ExpertFeeCheckResult validateExpertFee(ServiceFundVO serviceFundVO) {
+        return expertFeeValidateService.validateBeforeSave(serviceFundVO);
+    }
+
+    @Override
     @Transactional(rollbackFor = Exception.class)
     public Long addOrUpdateNew(ServiceFundVO serviceFundVO) {
+        // 涓撳鍔冲姟璐癸細淇濆瓨鍓嶆牎楠� 9 鏉¤垂鐢ㄦ帶鍒惰鍒欙紙鍚屼竴妗堜緥绱锛�
+        ExpertFeeCheckResult expertFeeResult = expertFeeValidateService.validateBeforeSave(serviceFundVO);
+        if (expertFeeResult.hasError()) {
+            throw new BaseException(expertFeeResult.errorMessage());
+        }
+        if (expertFeeResult.hasWarning()) {
+            // 瑙勫垯 5銆�6 浠呮彁绀猴紝涓嶉樆鏂繚瀛橈紱鍓嶇鍗曠嫭鍙栫敤鎻愮ず鏂囨
+            log.warn("涓撳鍔冲姟璐逛繚瀛樻牎楠屾彁绀猴細{}", expertFeeResult.warningMessage());
+        }
+
         Long id = null;
         //灏嗘暟鎹繚瀛樺埌fund琛�
         serviceFundVO.setUploadStates(0);
@@ -1484,10 +1623,9 @@
             return null;
         }
 
-        //鎬荤◣鍓�
-        Double pretaxcosts = 0.00;
-        //鎬荤◣鍚�
-        Double taxedcosts = 0.00;
+        //鎬荤◣鍓嶃�佹�荤◣鍚庯紙閲戦绱姞鐢� BigDecimal锛岄伩鍏嶆诞鐐瑰熬宸級
+        BigDecimal pretaxcosts = BigDecimal.ZERO;
+        BigDecimal taxedcosts = BigDecimal.ZERO;
         for (ServiceFunddetailVO serviceFunddetailVO : serviceFunddetails) {
             serviceFunddetailVO.setFundid(id);
 
@@ -1496,13 +1634,18 @@
             if (!performance.isEmpty()) {
                 Double amount = performance.get("amount");
                 Double taxedamount = performance.get("taxedamount");
-                pretaxcosts = pretaxcosts + amount;
-                taxedcosts = taxedcosts + taxedamount;
+                if (amount != null) {
+                    pretaxcosts = pretaxcosts.add(BigDecimal.valueOf(amount));
+                }
+                if (taxedamount != null) {
+                    taxedcosts = taxedcosts.add(BigDecimal.valueOf(taxedamount));
+                }
             }
-            serviceFundVO.setPretaxcost(pretaxcosts);
-            serviceFundVO.setTaxedcost(taxedcosts);
-            updateById(serviceFundVO);
         }
+        // 鍚堣鍦ㄥ惊鐜粨鏉熷悗缁熶竴鍥炲啓锛屽師鏉ュ啓鍦ㄥ惊鐜唴浼氭瘡琛岄兘 UPDATE 涓�娆★紝涓斾腑闂村�艰鍙嶅瑕嗙洊
+        serviceFundVO.setPretaxcost(pretaxcosts.doubleValue());
+        serviceFundVO.setTaxedcost(taxedcosts.doubleValue());
+        updateById(serviceFundVO);
         Map map = new HashMap();
         map.put("fundId", id);
         return map;
@@ -1700,7 +1843,7 @@
         Map<String, Object> map = new HashMap<String, Object>();
         map.put("userName", "opo");
         map.put("password", "4126407a-9821-4874-be41-6568abd6dbe5");
-        map.put("loginName", "OPO绯荤粺");
+        map.put("loginName", "OPO绯荤粺瀹℃壒");
 
         JSONObject jsonObj = new JSONObject(map);
 
@@ -1819,7 +1962,8 @@
     }
 
 
-    public void sendMeg(ServiceProcessVO serviceProcessVO, String phone) {
+    public void sendMeg(ServiceProcessVO serviceProcessVO, String phone,
+                        List<ConcurrentHashMap<String, Object>> contentList) {
         //璁板綍鎿嶄綔璁板綍
         ServiceFundflow serviceFundflow = new ServiceFundflow();
 
@@ -1838,20 +1982,14 @@
         serviceFundflow.setFundid(StringUtils.isNotEmpty(serviceProcessVO.getBackCode()) ? Long.valueOf(serviceProcessVO.getBackCode()) : null);
         fundflowService.save(serviceFundflow);
         try {
-            ArrayList<ConcurrentHashMap<String, Object>> contentList = new ArrayList<>();
-            ConcurrentHashMap map = new ConcurrentHashMap();
-            map.put("瀹℃壒浜猴細", serviceProcessVO.getCheckusername());
-            map.put("瀹℃壒鏃堕棿锛�", serviceProcessVO.getCheckTime());
-            map.put("鎰忚锛�", serviceProcessVO.getFlowcontent());
-            contentList.add(map);
             DingTalkReqVo dingTalkReqVo = new DingTalkReqVo();
-            dingTalkReqVo.setTitle("璐㈠姟绯荤粺淇℃伅");
+            dingTalkReqVo.setTitle(FundNotifyMessageBuilder.TITLE);
             dingTalkReqVo.setNumber(phone);
             dingTalkReqVo.setContents(contentList);
             log.info("閽夐拤鍙戦�佹秷鎭�:{}", dingTalkReqVo);
             dingTalkService.sendNotification(dingTalkReqVo);
         } catch (Exception e) {
-            log.error("璐㈠姟绯荤粺淇℃伅---閽夐拤娑堟伅鍙戦�佸け璐ワ紝涓嶅奖鍝嶄富娴佺▼", e);
+            log.error("鎶ラ攢瀹℃壒閽夐拤娑堟伅鍙戦�佸け璐ワ紝涓嶅奖鍝嶄富娴佺▼", e);
         }
     }
 }
diff --git a/ruoyi-project/src/main/java/com/ruoyi/project/service/impl/ServiceFunddetailServiceImpl.java b/ruoyi-project/src/main/java/com/ruoyi/project/service/impl/ServiceFunddetailServiceImpl.java
index 251704e..7488e4b 100644
--- a/ruoyi-project/src/main/java/com/ruoyi/project/service/impl/ServiceFunddetailServiceImpl.java
+++ b/ruoyi-project/src/main/java/com/ruoyi/project/service/impl/ServiceFunddetailServiceImpl.java
@@ -136,21 +136,30 @@
      */
     @Override
     public Double getTaxByBeneFiciaryNo(TaxMoneyVO taxMoneyVo) {
-        Double sum = 0.00;
-        Double totalScore = 0.00;
+        // 閲戦绱姞蹇呴』鐢� BigDecimal锛歞ouble 绱姞浼氬紩鍏ユ诞鐐瑰熬宸紝瀵艰嚧绠楀嚭鐨勪釜绋庡嚭鐜板垎浠ヤ笅璇樊
+        BigDecimal sum = BigDecimal.ZERO;
+        BigDecimal totalScore = BigDecimal.ZERO;
         List<ServiceFunddetail> taxationByBeneFiciaryNo = serviceFunddetailMapper.getTaxBeforeByBeneFiciaryNo(taxMoneyVo);
         if (CollectionUtils.isNotEmpty(taxationByBeneFiciaryNo)) {
             //璁$畻鐢宠閲戦鎬诲拰锛屼笉鍖呮嫭褰撳墠浼犺繘鏉ョ殑
-            sum = taxationByBeneFiciaryNo.stream().mapToDouble(ServiceFunddetail::getAmount).sum();
+            sum = taxationByBeneFiciaryNo.stream()
+                    .map(ServiceFunddetail::getAmount)
+                    .filter(java.util.Objects::nonNull)
+                    .map(BigDecimal::valueOf)
+                    .reduce(BigDecimal.ZERO, BigDecimal::add);
             //涓嶅姞鏈钖叕鐨勪釜绋�
-            totalScore = taxationByBeneFiciaryNo.stream().mapToDouble(ServiceFunddetail::getTaxamount).sum();
+            totalScore = taxationByBeneFiciaryNo.stream()
+                    .map(ServiceFunddetail::getTaxamount)
+                    .filter(java.util.Objects::nonNull)
+                    .map(BigDecimal::valueOf)
+                    .reduce(BigDecimal.ZERO, BigDecimal::add);
         }
 
-        sum = sum + new Double(taxMoneyVo.getMoney());
+        sum = sum.add(new BigDecimal(taxMoneyVo.getMoney()));
         //鍔犱笂鏈钖叕鐨勬�讳釜绋�
-        String taxation = TaxtUtils.getTaxation(new BigDecimal(sum));
+        String taxation = TaxtUtils.getTaxation(sum);
 
-        Double tax = Double.valueOf(taxation) - totalScore;
+        Double tax = new BigDecimal(taxation).subtract(totalScore).doubleValue();
         return tax;
     }
 
@@ -163,21 +172,30 @@
     @Override
     public TaxedMoneyVO getTaxBeforeByAfterMoney(TaxMoneyVO taxMoneyVo) {
         TaxedMoneyVO taxedMoneyVO = new TaxedMoneyVO();
-        Double sum = 0.00;
-        Double totalScore = 0.00;
+        // 閲戦绱姞蹇呴』鐢� BigDecimal锛岄伩鍏嶆诞鐐瑰熬宸奖鍝嶇◣鍓�/绋庨缁撴灉
+        BigDecimal sum = BigDecimal.ZERO;
+        BigDecimal totalScore = BigDecimal.ZERO;
         List<ServiceFunddetail> taxationByBeneFiciaryNo = serviceFunddetailMapper.getTaxBeforeByBeneFiciaryNo(taxMoneyVo);
         if (CollectionUtils.isNotEmpty(taxationByBeneFiciaryNo)) {
             //璁$畻鍑虹◣鍚庢�婚噾棰濓紙涓嶅寘鍚湰娆★級
-            sum = taxationByBeneFiciaryNo.stream().mapToDouble(ServiceFunddetail::getTaxedamount).sum();
+            sum = taxationByBeneFiciaryNo.stream()
+                    .map(ServiceFunddetail::getTaxedamount)
+                    .filter(java.util.Objects::nonNull)
+                    .map(BigDecimal::valueOf)
+                    .reduce(BigDecimal.ZERO, BigDecimal::add);
             //姹傚嚭涔嬪墠鐨勬�荤殑涓◣
-            totalScore = taxationByBeneFiciaryNo.stream().mapToDouble(ServiceFunddetail::getTaxamount).sum();
+            totalScore = taxationByBeneFiciaryNo.stream()
+                    .map(ServiceFunddetail::getTaxamount)
+                    .filter(java.util.Objects::nonNull)
+                    .map(BigDecimal::valueOf)
+                    .reduce(BigDecimal.ZERO, BigDecimal::add);
         }
         //璁$畻鍑烘�荤殑绋庡悗钖叕锛堝寘鍚湰娆★級
-        sum = sum + Double.valueOf(taxMoneyVo.getMoney());
+        sum = sum.add(new BigDecimal(taxMoneyVo.getMoney()));
         //绋庡墠鎬婚噾棰�
-        String taxationBefore = TaxtUtils.getTaxationBefore(new BigDecimal(sum));
+        String taxationBefore = TaxtUtils.getTaxationBefore(sum);
         //鎬讳釜绋�
-        BigDecimal tax = new BigDecimal(taxationBefore).subtract(new BigDecimal(sum));
+        BigDecimal tax = new BigDecimal(taxationBefore).subtract(sum);
 
         //鏈鐨勭◣鍓嶉噾棰�
         String nowTaxMoney = TaxtUtils.getTaxationBefore(new BigDecimal(taxMoneyVo.getMoney()));
diff --git a/ruoyi-project/src/main/java/com/ruoyi/project/service/impl/ServiceReimbursementServiceImpl.java b/ruoyi-project/src/main/java/com/ruoyi/project/service/impl/ServiceReimbursementServiceImpl.java
index f566881..bbb0cb4 100644
--- a/ruoyi-project/src/main/java/com/ruoyi/project/service/impl/ServiceReimbursementServiceImpl.java
+++ b/ruoyi-project/src/main/java/com/ruoyi/project/service/impl/ServiceReimbursementServiceImpl.java
@@ -17,6 +17,8 @@
 import com.ruoyi.common.utils.HttpClientKit;
 import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.common.utils.bean.DtoConversionUtils;
+import com.ruoyi.common.exception.ServiceException;
+import com.ruoyi.project.common.FundNotifyMessageBuilder;
 import com.ruoyi.project.common.IdGeneratorUtils;
 import com.ruoyi.project.domain.*;
 import com.ruoyi.project.domain.dto.ServiceReimbursementDto;
@@ -27,6 +29,7 @@
 import com.ruoyi.project.service.*;
 import com.ruoyi.system.mapper.SysUserMapper;
 import com.ruoyi.system.mapper.SysUserRoleMapper;
+import com.ruoyi.system.service.ISysConfigService;
 import com.ruoyi.system.service.ISysPostService;
 import com.ruoyi.system.service.ISysUserService;
 import lombok.extern.slf4j.Slf4j;
@@ -116,6 +119,35 @@
 
     @Value("${spring.profiles.active}")
     private String active;
+
+    @Autowired
+    private ISysConfigService sysConfigService;
+
+    /**
+     * 瀹℃壒鍗曟槸鍚︿笂浼犲尰闄㈠崗鍙嬶紙鑷磋繙锛夌郴缁燂細0=涓嶄笂浼狅紙娴嬭瘯鐜锛夛紝1=涓婁紶锛堟寮忕幆澧冿級銆�
+     *
+     * <p>2026-10-09 鏂板锛氬師鏉ョ敤 {@code spring.profiles.active == druid} 鏉ュ垽鏂槸鍚︽帹閫侊紝
+     * 瀵艰嚧娴嬭瘯鐜涓庢寮忕幆澧冩棤娉曢�氳繃鍙傛暟鍖哄垎銆傛敼涓虹郴缁熷弬鏁版帶鍒讹紝鐜鍚勮嚜閰嶇疆銆�
+     */
+    private static final String CFG_UPLOAD_OA = "sys.approval.upload.oa";
+
+    /** 鍙傛暟缂虹渷鍊硷細涓婁紶锛堜繚鎸佹寮忕幆澧冨師鏈夎涓猴級 */
+    private static final boolean DEFAULT_UPLOAD_OA = true;
+
+    /** 瀹℃壒鍗曟槸鍚﹂渶瑕佷笂浼犲尰闄㈠崗鍙嬶紙鑷磋繙锛夌郴缁� */
+    private boolean isUploadOaEnabled() {
+        String value = null;
+        try {
+            value = sysConfigService.selectConfigByKey(CFG_UPLOAD_OA);
+        } catch (Exception e) {
+            log.warn("璇诲彇鍙傛暟 {} 澶辫触锛屾寜榛樿鍊� {} 澶勭悊", CFG_UPLOAD_OA, DEFAULT_UPLOAD_OA, e);
+        }
+        if (value == null || value.trim().isEmpty()) {
+            return DEFAULT_UPLOAD_OA;
+        }
+        String v = value.trim();
+        return "1".equals(v) || "true".equalsIgnoreCase(v) || "y".equalsIgnoreCase(v) || "on".equalsIgnoreCase(v);
+    }
 
 
     /**
@@ -259,7 +291,7 @@
             log.info("涓婁紶OA鏂囦欢鏂规硶鐨勫叆鍙�:{}", serviceReimbursementdetailShareds.get(i));
             try {
                 //濡傛灉鏄湰鍦扮幆澧冿紝灏变笉璋冭繖涓簡
-                if (!active.equals("druid")) uploadOAFileAndUpdateDb(serviceReimbursementdetailShareds.get(i));
+                if (isUploadOaEnabled()) uploadOAFileAndUpdateDb(serviceReimbursementdetailShareds.get(i));
             } catch (Exception e) {
                 log.error("Exception涓璻eimShare鐨勫叆鍙俰d涓猴細{}", serviceReimbursementShared.getId());
                 if (serviceReimbursementShared.getId() != null) {
@@ -333,6 +365,7 @@
     }
 
     @Override
+    @Transactional(rollbackFor = Exception.class)
     public Map<String, String> checkFund(LoginUser loginUser, CheckFundVO checkFundVO) {
         Map<String, String> allMap = new HashMap<>();
 
@@ -397,8 +430,9 @@
                     if (newSwitch == 1) {
                         aBoolean1 = sendData(serviceReimbursement);
                         if (!aBoolean1) {
-                            allMap.put("500", "鍙戦�佸け璐�");
-                            return allMap;
+                            // 鎺ㄩ�佸尰闄㈠崗鍙嬬郴缁熷け璐ワ細鏁翠釜瀹℃壒涓嶇敓鏁堬紙浜嬪姟鍥炴粴锛夛紝鍏佽涓嬫閲嶆柊瀹℃壒
+                            log.error("宸梾瀹℃壒鍗曚笂浼犲尰闄㈠崗鍙嬬郴缁熷け璐ワ紝瀹℃壒涓嶇敓鏁堬紝id={}锛岃閲嶆柊瀹℃壒", serviceReimbursement.getId());
+                            throw new ServiceException("鍖婚櫌鍗忓弸绯荤粺鎺ユ敹澶辫触锛屾湰娆″鎵规湭鐢熸晥锛岃绋嶅悗閲嶆柊瀹℃壒");
                         }
                     }
                     //淇濆瓨瀹℃壒娴佺▼琛�
@@ -443,22 +477,25 @@
                     }
                 }
                 SysUser sysUser = sysUserService.selectUserByUserName(serviceReimbursement.getUserno());
-                ArrayList<ConcurrentHashMap<String, Object>> contentList = new ArrayList<>();
-                ConcurrentHashMap map = new ConcurrentHashMap();
-                map.put("瀹℃壒浜猴細", loginUser.getUser().getUserName());
-                map.put("瀹℃壒鏃堕棿锛�", new Date());
-                map.put("鎰忚锛�", "涓嶉�氳繃");
-                if (StringUtils.isNotBlank(checkFundVO.getFlowcontent()))
-                    map.put("鎰忚锛�", checkFundVO.getFlowcontent());
-                contentList.add(map);
+                //瀹℃壒鏈�氳繃锛氬崟鎹俊鎭� + 鍑哄樊淇℃伅 + 瀹℃壒浜�/瀹℃壒鏃堕棿/鎰忚锛堟剰瑙� = "瀹℃壒鏈�氳繃銆�" + 椹冲洖鎰忚锛�
+                List<ConcurrentHashMap<String, Object>> contentList = FundNotifyMessageBuilder.newRows();
+                FundNotifyMessageBuilder.addBillInfo(contentList, "0", serviceReimbursement.getUsername(),
+                        serviceReimbursement.getAmountrequested(), null,
+                        FundNotifyMessageBuilder.billNo(serviceReimbursement.getBh(),
+                                serviceReimbursement.getId()));
+                FundNotifyMessageBuilder.addTravelInfo(contentList, serviceReimbursement.getTravelers(),
+                        serviceReimbursement.getReason());
+                FundNotifyMessageBuilder.addAuditResult(contentList, loginUser.getUser().getNickName(), new Date(),
+                        FundNotifyMessageBuilder.opinion(FundNotifyMessageBuilder.CONCLUSION_REJECT,
+                                checkFundVO.getFlowcontent()));
                 try {
                     DingTalkReqVo dingTalkReqVo = new DingTalkReqVo();
-                    dingTalkReqVo.setTitle("璐㈠姟绯荤粺椹冲洖淇℃伅");
+                    dingTalkReqVo.setTitle(FundNotifyMessageBuilder.TITLE);
                     dingTalkReqVo.setNumber(sysUser.getPhonenumber());
                     dingTalkReqVo.setContents(contentList);
                     dingTalkService.sendNotification(dingTalkReqVo);
-                }catch (Exception e){
-                    log.error("宸梾---璐㈠姟绯荤粺椹冲洖淇℃伅鎶ラ敊浜�", e);
+                } catch (Exception e) {
+                    log.error("宸梾---瀹℃壒鏈�氳繃閽夐拤閫氱煡澶辫触锛宨d={}", serviceReimbursement.getId(), e);
                 }
             }
 
@@ -515,8 +552,9 @@
                     log.info("宸梾newSwitch杩斿洖鐨勫�间负:{}", newSwitch);
                     aBoolean1 = sendData(serviceReimbursement);
                     if (!aBoolean1) {
-                        allMap.put("500", "鍙戦�佸け璐�");
-                        return allMap;
+                        // 鎺ㄩ�佸尰闄㈠崗鍙嬬郴缁熷け璐ワ細鏁翠釜瀹℃壒涓嶇敓鏁堬紙浜嬪姟鍥炴粴锛夛紝鍏佽涓嬫閲嶆柊瀹℃壒
+                        log.error("宸梾瀹℃壒鍗曚笂浼犲尰闄㈠崗鍙嬬郴缁熷け璐ワ紝瀹℃壒涓嶇敓鏁堬紝id={}锛岃閲嶆柊瀹℃壒", serviceReimbursement.getId());
+                        throw new ServiceException("鍖婚櫌鍗忓弸绯荤粺鎺ユ敹澶辫触锛屾湰娆″鎵规湭鐢熸晥锛岃绋嶅悗閲嶆柊瀹℃壒");
                     }
                 }
             }
@@ -585,7 +623,30 @@
         return "鏈壘鍒板鎵硅褰�";
     }
 
+    /**
+     * 瀹℃壒鍗曚笂浼犲尰闄㈠崗鍙嬶紙鑷磋繙锛夌郴缁熴��
+     *
+     * <p>2026-10-09锛氬灞傚寘涓�灞傚厹搴曪紝淇濊瘉**浠讳綍寮傚父閮戒笉浼氬悜澶栨姏**锛堝師鏉� strRes 涓� null 鏃�
+     * 浼氬湪 parseObject 鍚庡彇 code 瑙﹀彂 NPE锛屾妸鏁翠釜瀹℃壒璇锋眰鎵撴垚 500锛夈��
+     * 杩斿洖 false 琛ㄧず鎺ㄩ�佸け璐ワ紝璋冪敤鏂规寜"瀹℃壒涓嶇敓鏁堛�佸厑璁镐笅娆¢噸鏂板鎵�"澶勭悊銆�
+     */
     public Boolean sendData(ServiceReimbursement serviceReimbursement) {
+        if (!isUploadOaEnabled()) {
+            // 涓婁紶寮�鍏冲叧闂紙濡傛祴璇曠幆澧冿級锛氳烦杩囦笂浼犲苟瑙嗕负鎴愬姛锛岀粷涓嶈兘鍥犳闃绘柇瀹℃壒
+            log.info("瀹℃壒鍗曚笂浼犲尰闄㈠崗鍙嬬郴缁熷凡鍏抽棴锛坰ys.approval.upload.oa != 1锛夛紝璺宠繃涓婁紶骞惰涓烘垚鍔燂紝id={}",
+                    serviceReimbursement == null ? null : serviceReimbursement.getId());
+            return true;
+        }
+        try {
+            return doSendData(serviceReimbursement);
+        } catch (Throwable t) {
+            log.error("宸梾瀹℃壒鍗曚笂浼犲尰闄㈠崗鍙嬬郴缁熷紓甯革紝瀹℃壒涓嶇敓鏁堬紝id={}",
+                    serviceReimbursement == null ? null : serviceReimbursement.getId(), t);
+            return false;
+        }
+    }
+
+    private Boolean doSendData(ServiceReimbursement serviceReimbursement) {
         // fund鍜宖unddetail鐨勬暟鎹幏鍙�
         addSharedData(serviceReimbursement.getId());
         List<ServiceReimbursementShared> serviceReimbursementSharedList = sharedService.getRemShareInfoByRemId(serviceReimbursement.getId());
@@ -631,7 +692,7 @@
         data.put("summaryId", serviceReimbursement1.getSummaryId() == null ? "" : serviceReimbursement1.getSummaryId());
         map.put("data", data);
         String strRes = null;
-        if (!active.equals("druid")) {
+        if (isUploadOaEnabled()) {
             //濡傛灉鏄湰鍦扮幆澧冿紝灏变笉璋冭繖涓簡
             String token = getToken();
             JSONObject json1 = JSONObject.parseObject(token);
@@ -662,9 +723,28 @@
             }
         }
         log.error("-----Reimbursement-------------strRes鐨勫�间负锛歿}", strRes);
-        JSONObject jsonObject = JSONObject.parseObject(strRes);
+        if (strRes == null || strRes.trim().isEmpty()) {
+            // 鍖婚櫌鍗忓弸绯荤粺鏃犺繑鍥烇紙瓒呮椂/寮傚父/鏈厤缃級锛氭帹閫佸け璐ワ紝鐢辫皟鐢ㄦ柟鍥炴粴鏁翠釜瀹℃壒
+            log.error("宸梾瀹℃壒鍗曚笂浼犲尰闄㈠崗鍙嬬郴缁熷け璐ワ細鎺ュ彛鏃犺繑鍥炲唴瀹癸紝id={}", serviceReimbursement.getId());
+            return false;
+        }
+        JSONObject jsonObject = null;
+        try {
+            jsonObject = JSONObject.parseObject(strRes);
+        } catch (Exception e) {
+            log.error("宸梾瀹℃壒鍗曚笂浼犲尰闄㈠崗鍙嬬郴缁熷け璐ワ細杩斿洖鍐呭鏃犳硶瑙f瀽锛宨d={}锛宻trRes={}",
+                    serviceReimbursement.getId(), strRes, e);
+            return false;
+        }
+        if (jsonObject == null) {
+            log.error("宸梾瀹℃壒鍗曚笂浼犲尰闄㈠崗鍙嬬郴缁熷け璐ワ細杩斿洖鍐呭涓虹┖锛宨d={}锛宻trRes={}",
+                    serviceReimbursement.getId(), strRes);
+            return false;
+        }
         String code = jsonObject.getString("code");
-        if (!code.equals("0")) {
+        if (code == null || !"0".equals(code)) {
+            log.error("宸梾瀹℃壒鍗曚笂浼犲尰闄㈠崗鍙嬬郴缁熷け璐ワ細code={}锛宨d={}锛宻trRes={}",
+                    code, serviceReimbursement.getId(), strRes);
             return false;
         }
 
@@ -876,7 +956,7 @@
         Map<String, Object> map = new HashMap<String, Object>();
         map.put("userName", "opo");
         map.put("password", "4126407a-9821-4874-be41-6568abd6dbe5");
-        map.put("loginName", "OPO绯荤粺");
+        map.put("loginName", "OPO绯荤粺瀹℃壒");
 
         JSONObject jsonObj = new JSONObject(map);
 
diff --git a/ruoyi-project/src/main/java/com/ruoyi/project/service/impl/ServiceRelativesconfirmationServiceImpl.java b/ruoyi-project/src/main/java/com/ruoyi/project/service/impl/ServiceRelativesconfirmationServiceImpl.java
index 4beca60..8f422db 100644
--- a/ruoyi-project/src/main/java/com/ruoyi/project/service/impl/ServiceRelativesconfirmationServiceImpl.java
+++ b/ruoyi-project/src/main/java/com/ruoyi/project/service/impl/ServiceRelativesconfirmationServiceImpl.java
@@ -26,6 +26,7 @@
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.Map;
 
 import com.ruoyi.common.utils.StringUtils;
@@ -221,6 +222,23 @@
             relativeConfirmationVO.setReporterno(user.getUserName());
         }
         List<RelativeConfirmationVO> relativeConfirmationVOS = serviceRelativesconfirmationMapper.selectVOList(relativeConfirmationVO);
+
+        // 涓�娆℃�у彇鍑哄悇鎹愮尞鍩虹瀵瑰簲鐨勬浜℃椂闂达紝閬垮厤鍦ㄥ惊鐜噷鎸� InfoID 閫愭潯鏌ヨ璇佽〃锛圢+1锛�
+        List<Long> infoIds = new ArrayList<>();
+        for (RelativeConfirmationVO item : relativeConfirmationVOS) {
+            if (item.getInfoid() != null) {
+                infoIds.add(item.getInfoid());
+            }
+        }
+        Map<Long, Date> deathTimeMap = new HashMap<>();
+        if (!infoIds.isEmpty()) {
+            for (ServiceDonationwitness witness : serviceDonationwitnessMapper.selectDeathTimeByInfoIds(infoIds)) {
+                if (witness.getInfoid() != null && !deathTimeMap.containsKey(witness.getInfoid())) {
+                    deathTimeMap.put(witness.getInfoid(), witness.getDeathtime());
+                }
+            }
+        }
+
         for (RelativeConfirmationVO relativeConfirmationVO1 : relativeConfirmationVOS) {
             //鍏堢粰涓勾榫勯粯璁ゅ�硷紙鍥犱负age鏄暟瀛楃被鍨嬶紝涓嶈兘鏀炬í鏉狅紝鎵�浠ュ氨鎵�妯墰鏀惧埌鍗曚綅涓婏級
             relativeConfirmationVO1.setAgeunit("-");
@@ -228,22 +246,17 @@
             relativeConfirmationVO1.setAge2(null);
 
             //鑾峰彇姝讳骸鏃堕棿锛屽鏋滆幏鍙栬璇侀噷鏈夋浜℃椂闂达紝鍒欒繘琛岃绠椾粬鐨勫勾榫�
-            ServiceDonationwitness sdw = new ServiceDonationwitness();
-            sdw.setInfoid(relativeConfirmationVO1.getInfoid());
-            List<ServiceDonationwitness> serviceDonationwitnessList = serviceDonationwitnessMapper.selectServiceDonationwitnessList(sdw);
-            if (!CollectionUtils.isEmpty(serviceDonationwitnessList) && relativeConfirmationVO1.getBirthday() != null) {
-                Date deathtime = serviceDonationwitnessList.get(0).getDeathtime();
-                if (ObjectUtils.isNotEmpty(deathtime)) {
-                    Map<String, String> map = CalculateDateUtils.calculateAge(relativeConfirmationVO1.getBirthday().toInstant().atZone(ZoneId.systemDefault()).toLocalDate(), deathtime.toInstant().atZone(ZoneId.systemDefault()).toLocalDate());
-                    if (ObjectUtils.isEmpty(map)) {
-                        log.error("RelativeConfirmationVO鍑虹敓鏃ユ湡锛歿},RelativeConfirmationVO姝讳骸鏃ユ湡锛歿}", relativeConfirmationVO1.getBirthday(), deathtime);
-                        continue;
-                    }
-                    relativeConfirmationVO1.setAge(org.apache.commons.lang3.ObjectUtils.isNotEmpty(map.get("age")) ? Long.valueOf(map.get("age")) : null);
-                    relativeConfirmationVO1.setAgeunit(map.get("ageUnit"));
-                    relativeConfirmationVO1.setAge2(org.apache.commons.lang3.ObjectUtils.isNotEmpty(map.get("age2")) ? Long.valueOf(map.get("age2")) : null);
-                    relativeConfirmationVO1.setAgeunit2(map.get("ageUnit2"));
+            Date deathtime = deathTimeMap.get(relativeConfirmationVO1.getInfoid());
+            if (ObjectUtils.isNotEmpty(deathtime) && relativeConfirmationVO1.getBirthday() != null) {
+                Map<String, String> map = CalculateDateUtils.calculateAge(relativeConfirmationVO1.getBirthday().toInstant().atZone(ZoneId.systemDefault()).toLocalDate(), deathtime.toInstant().atZone(ZoneId.systemDefault()).toLocalDate());
+                if (ObjectUtils.isEmpty(map)) {
+                    log.error("RelativeConfirmationVO鍑虹敓鏃ユ湡锛歿},RelativeConfirmationVO姝讳骸鏃ユ湡锛歿}", relativeConfirmationVO1.getBirthday(), deathtime);
+                    continue;
                 }
+                relativeConfirmationVO1.setAge(org.apache.commons.lang3.ObjectUtils.isNotEmpty(map.get("age")) ? Long.valueOf(map.get("age")) : null);
+                relativeConfirmationVO1.setAgeunit(map.get("ageUnit"));
+                relativeConfirmationVO1.setAge2(org.apache.commons.lang3.ObjectUtils.isNotEmpty(map.get("age2")) ? Long.valueOf(map.get("age2")) : null);
+                relativeConfirmationVO1.setAgeunit2(map.get("ageUnit2"));
             }
         }
         return relativeConfirmationVOS;
diff --git a/ruoyi-project/src/main/resources/mapper/project/ServiceDonationwitnessMapper.xml b/ruoyi-project/src/main/resources/mapper/project/ServiceDonationwitnessMapper.xml
index 858a8fb..656fc8f 100644
--- a/ruoyi-project/src/main/resources/mapper/project/ServiceDonationwitnessMapper.xml
+++ b/ruoyi-project/src/main/resources/mapper/project/ServiceDonationwitnessMapper.xml
@@ -111,6 +111,23 @@
         </where>
     </select>
 
+    <!--
+      鎵归噺鏌ヨ銆屾崘鐚熀纭�ID -> 姝讳骸鏃堕棿銆嶏紝渚涘垪琛ㄩ〉璁$畻骞撮緞浣跨敤銆�
+      浠f浛鍘熷厛鍦ㄨ褰曞惊鐜腑鎸� InfoID 閫愭潯鏌ヨ鐨� N+1 鍐欐硶锛堥椤垫湁 N 鏉¤褰曞氨鍙� N 娆� SQL锛夈��
+      鍙繑鍥� InfoID 涓� DeathTime 涓ゅ垪锛汭nfoid 涓� DeathTime 鍧囦负绌虹殑琛屾棤鎰忎箟锛岀洿鎺ヨ繃婊わ紝
+      鍚屾椂閬垮厤涓� selectServiceDonationwitnessList 杩斿洖鐨勮鏁颁笉涓�鑷淬��
+    -->
+    <select id="selectDeathTimeByInfoIds" resultMap="ServiceDonationwitnessResult">
+        select InfoID, DeathTime from service_donationwitness
+        where InfoID is not null and DeathTime is not null
+        <if test="infoIds != null and infoIds.size() > 0">
+            and InfoID in
+            <foreach collection="infoIds" item="infoId" open="(" separator="," close=")">
+                #{infoId}
+            </foreach>
+        </if>
+    </select>
+
     <select id="selectVOList" resultType="com.ruoyi.project.domain.vo.DonationWitnessVO">
         SELECT
         `service_donatebaseinfo`.`ID` AS `ID`,
diff --git a/ruoyi-project/src/main/resources/mapper/project/ServiceExternalpersonMapper.xml b/ruoyi-project/src/main/resources/mapper/project/ServiceExternalpersonMapper.xml
index 89a9c29..93c1a1e 100644
--- a/ruoyi-project/src/main/resources/mapper/project/ServiceExternalpersonMapper.xml
+++ b/ruoyi-project/src/main/resources/mapper/project/ServiceExternalpersonMapper.xml
@@ -43,7 +43,7 @@
             service_externalperson.del_flag = 0
             <if test="userno != null  and userno != ''">and UserNo = #{userno}</if>
             <if test="username != null  and username != ''">and UserName like concat('%', #{username}, '%')</if>
-            <if test="usertype != null  and usertype != ''">and UserType = #{usertype}</if>
+            <if test="usertype != null  and usertype != ''">and FIND_IN_SET(#{usertype}, UserType)</if>
             <if test="sex != null  and sex != ''">and Sex = #{sex}</if>
             <if test="telephone != null  and telephone != ''">and Telephone = #{telephone}</if>
             <if test="address != null  and address != ''">and Address = #{address}</if>
@@ -59,7 +59,7 @@
 
     <select id="getAllpeople" resultType="com.ruoyi.project.domain.ServiceExternalperson">
         <include refid="selectServiceExternalpersonVo"/>
-        where service_externalperson.del_flag = 0 and UserType = #{usertype}
+        where service_externalperson.del_flag = 0 and FIND_IN_SET(#{usertype}, UserType)
     </select>
     <select id="getInfoByUserNo" resultType="com.ruoyi.project.domain.ServiceExternalperson">
         <include refid="selectServiceExternalpersonVo"/>
diff --git a/ruoyi-project/src/main/resources/mapper/project/ServiceFunddetailMapper.xml b/ruoyi-project/src/main/resources/mapper/project/ServiceFunddetailMapper.xml
index 263f923..cb99db2 100644
--- a/ruoyi-project/src/main/resources/mapper/project/ServiceFunddetailMapper.xml
+++ b/ruoyi-project/src/main/resources/mapper/project/ServiceFunddetailMapper.xml
@@ -20,6 +20,7 @@
         <result property="unitname" column="UnitName"/>
         <result property="unitno" column="UnitNo"/>
         <result property="unituserno" column="UnitUserNo"/>
+        <result property="isunit" column="IsUnit"/>
         <result property="title" column="Title"/>
         <result property="idcardtype" column="IDCardType"/>
         <result property="idcardno" column="IDCardNo"/>
@@ -83,6 +84,7 @@
                UnitName,
                UnitNo,
                UnitUserNo,
+               IsUnit,
                Title,
                OrderNo,
                ItemCode,
@@ -206,6 +208,7 @@
         a.UnitName,
         a.UnitNo,
         a.UnitUserNo,
+        a.IsUnit,
         a.Title,
         a.OrderNo,
         a.ItemCode,
diff --git a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/RyTask.java b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/RyTask.java
index 31ebdfd..0c415fe 100644
--- a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/RyTask.java
+++ b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/RyTask.java
@@ -2,6 +2,7 @@
 
 import com.ruoyi.common.core.domain.entity.SysUser;
 import com.ruoyi.common.utils.bean.DtoConversionUtils;
+import com.ruoyi.project.common.FundNotifyMessageBuilder;
 import com.ruoyi.project.domain.*;
 import com.ruoyi.project.domain.vo.DingTalkReqVo;
 import com.ruoyi.project.service.*;
@@ -563,6 +564,14 @@
     }
 
 
+    /**
+     * 璐㈠姟绯荤粺椹冲洖淇℃伅閽夐拤閫氱煡锛堝畾鏃朵换鍔$敤锛夈��
+     *
+     * @deprecated 2026-10-08 鏍稿疄锛氭湰鏂规硶**宸叉棤璋冪敤鏂�**锛堝師璋冪敤鐐瑰湪鏈被涓凡娉ㄩ噴锛夛紝
+     * 涓� {@code sys_job} 涓病鏈変换浣曚换鍔℃寚鍚戝畠锛屽睘浜庢浠g爜銆�
+     * 涓�"閽夐拤澶辫触琛ュ伩/閲嶈瘯"鏃犲叧锛岃鍕挎嵁姝よ涓哄瓨鍦ㄨˉ鍋挎満鍒躲�備繚鐣欎粎涓洪伩鍏嶈鍒犲巻鍙查�昏緫銆�
+     */
+    @Deprecated
     public void sendMeg(String[] split, String phone, String applyType, Integer fundType, Long fundId) throws ApiException {
         String content = null;
         String time = null;
@@ -607,7 +616,7 @@
         map.put("鎰忚锛�" , content);
         contentList.add(map);
         DingTalkReqVo dingTalkReqVo = new DingTalkReqVo();
-        dingTalkReqVo.setTitle("璐㈠姟绯荤粺椹冲洖淇℃伅");
+        dingTalkReqVo.setTitle(FundNotifyMessageBuilder.TITLE);
         dingTalkReqVo.setNumber(phone);
         dingTalkReqVo.setContents(contentList);
         log.info("閽夐拤鍙戦�佹秷鎭�:{}" , dingTalkReqVo);

--
Gitblit v1.9.3