From 40158f61b8bf3f07c3ebc928ccd8e5ccbc2e22ff Mon Sep 17 00:00:00 2001
From: 无关风月 <443237572@qq.com>
Date: 星期四, 06 三月 2025 19:22:55 +0800
Subject: [PATCH] Merge branch 'master' of https://gitee.com/xiaochen991015/xizang

---
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/TContractController.java             |   54 ++--
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/tool/WordTemplateProcessor.java          |   87 +++++++
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/tool/WordUtil.java                       |  313 +++++++++++++++++++++++--
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TCheckAcceptRecordServiceImpl.java |    9 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/tool/PdfUtils.java                       |  218 +++++++++++++++--
 5 files changed, 585 insertions(+), 96 deletions(-)

diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/TContractController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/TContractController.java
index 493393b..58f8f56 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/TContractController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/TContractController.java
@@ -298,46 +298,46 @@
 
             THouse tHouse = houseService.getById(contract.getHouseId());
             Map<String, Object> templateParam = new HashMap<>(5);
-            templateParam.put("partyOneName", contract.getPartyOneName());
-            templateParam.put("partyTwoName", contract.getPartyTwoName());
-            templateParam.put("houseAddress", tHouse.getHouseAddress());
-            templateParam.put("houseArea", tHouse.getHouseArea()+"m²");
+            templateParam.put("${partyOneName}", contract.getPartyOneName());
+            templateParam.put("${partyTwoName}", contract.getPartyTwoName());
+            templateParam.put("${houseAddress}", tHouse.getHouseAddress());
+            templateParam.put("${houseArea}", tHouse.getHouseArea()+"m²");
             long between = ChronoUnit.DAYS.between(contract.getStartTime(), contract.getStartPayTime())+1;
-            templateParam.put("day", between);
-            templateParam.put("endTimeFree", DateUtils.localDateTimeToStringYear(contract.getStartPayTime().plusDays(1)));
-            templateParam.put("startPayTime", DateUtils.localDateTimeToStringYear(contract.getStartPayTime()));
-            templateParam.put("startTime", DateUtils.localDateTimeToStringYear(contract.getStartTime()));
-            templateParam.put("endTime", DateUtils.localDateTimeToStringYear(contract.getEndTime()));
-            templateParam.put("monthRent", "¥¥"+contract.getMonthRent()+"元");
-            templateParam.put("monthRentString", "人民币"+NumberToChineseUtils.numberToChinese(contract.getMonthRent().setScale(2, BigDecimal.ROUND_DOWN).doubleValue()));
+            templateParam.put("${day}", between);
+            templateParam.put("${endTimeFree}", DateUtils.localDateTimeToStringYear(contract.getStartPayTime().plusDays(1)));
+            templateParam.put("${startPayTime}", DateUtils.localDateTimeToStringYear(contract.getStartPayTime()));
+            templateParam.put("${startTime}", DateUtils.localDateTimeToStringYear(contract.getStartTime()));
+            templateParam.put("${endTime}", DateUtils.localDateTimeToStringYear(contract.getEndTime()));
+            templateParam.put("${monthRent}", "¥"+contract.getMonthRent()+"元");
+            templateParam.put("${monthRentString}", "人民币"+NumberToChineseUtils.numberToChinese(contract.getMonthRent().setScale(2, BigDecimal.ROUND_DOWN).doubleValue()));
             String totalYear = Objects.nonNull(contract.getTotalYear())?contract.getTotalYear().toString():"";
-            templateParam.put("totalYear", "¥¥"+totalYear+"元");
+            templateParam.put("${totalYear}", "¥"+totalYear+"元");
             String totalYearString = StringUtils.isNotEmpty(totalYear)?NumberToChineseUtils.numberToChinese(contract.getTotalYear().setScale(2, BigDecimal.ROUND_DOWN).doubleValue()):"";
-            templateParam.put("totalYearString", "人民币"+totalYearString);
-            templateParam.put("payType", contract.getPayType().equals("1")?"月":contract.getPayType().equals("2")?"季":"年");
+            templateParam.put("${totalYearString}", "人民币"+totalYearString);
+            templateParam.put("${payType}", contract.getPayType().equals("1")?"月":contract.getPayType().equals("2")?"季":"年");
             if(firstBill!=null){
-                templateParam.put("firstRent", "¥"+(firstBill.getPayableFeesMoney())+"元");
+                templateParam.put("${firstRent}", "¥"+(firstBill.getPayableFeesMoney())+"元");
             }else{
-                templateParam.put("firstRent", "");
+                templateParam.put("${firstRent}", "");
 
             }
-            templateParam.put("firstRentString", "人民币"+NumberToChineseUtils.numberToChinese((contract.getPayType().equals("1")?contract.getMonthRent():contract.getPayType().equals("2")?contract.getMonthRent().multiply(new BigDecimal("3")):contract.getMonthRent().multiply(new BigDecimal("12")).setScale(2,BigDecimal.ROUND_DOWN)).doubleValue()));
-            templateParam.put("nextPayTime", contract.getPayType().equals("1")?"月":contract.getPayType().equals("2")?"季":"年");
-            templateParam.put("deposit", "¥"+contract.getDeposit()+"元");
-            templateParam.put("depositString", NumberToChineseUtils.numberToChinese(contract.getDeposit().setScale(2, BigDecimal.ROUND_DOWN).doubleValue()));
-            templateParam.put("partyOnePerson", contract.getPartyOnePerson());
-            templateParam.put("partyOnePhone", contract.getPartyOnePhone());
-            templateParam.put("partyTwoPerson", contract.getPartyTwoPerson());
-            templateParam.put("partyTwoPhone", contract.getPartyTwoPhone());
+            templateParam.put("${firstRentString}", "人民币"+NumberToChineseUtils.numberToChinese((contract.getPayType().equals("1")?contract.getMonthRent():contract.getPayType().equals("2")?contract.getMonthRent().multiply(new BigDecimal("3")):contract.getMonthRent().multiply(new BigDecimal("12")).setScale(2,BigDecimal.ROUND_DOWN)).doubleValue()));
+            templateParam.put("${nextPayTime}", contract.getPayType().equals("1")?"月":contract.getPayType().equals("2")?"季":"年");
+            templateParam.put("${deposit}", "¥"+contract.getDeposit()+"元");
+            templateParam.put("${depositString}", NumberToChineseUtils.numberToChinese(contract.getDeposit().setScale(2, BigDecimal.ROUND_DOWN).doubleValue()));
+            templateParam.put("${partyOnePerson}", contract.getPartyOnePerson());
+            templateParam.put("${partyOnePhone}", contract.getPartyOnePhone());
+            templateParam.put("${partyTwoPerson}", contract.getPartyTwoPerson());
+            templateParam.put("${partyTwoPhone}", contract.getPartyTwoPhone());
             // 验收时间
             TCheckAcceptRecord tCheckAcceptRecord = checkAcceptRecordService.lambdaQuery().eq(TCheckAcceptRecord::getContractId, contract.getId()).last("limit 1").one();
             if (tCheckAcceptRecord!=null &&tCheckAcceptRecord.getCheckTime()!=null ){
-                templateParam.put("checkTime", DateUtils.localDateTimeToStringYear(tCheckAcceptRecord.getCheckTime()));
+                templateParam.put("${checkTime}", DateUtils.localDateTimeToStringYear(tCheckAcceptRecord.getCheckTime()));
             }else{
-                templateParam.put("checkTime", "");
+                templateParam.put("${checkTime}", "");
 
             }
-            String url = wordUtil.generatePdf("/template", "1_yzj_租赁合同.xml", templateParam, "租赁合同", "E:\\");
+            String url = wordUtil.generatePdf("/usr/local/project/file/", "1_yzj_租赁合同.docx", templateParam, "租赁合同", "/usr/local/project/file/");
             res.add(url);
         }
 
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/tool/PdfUtils.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/tool/PdfUtils.java
index 9c274d7..172bfd6 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/tool/PdfUtils.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/tool/PdfUtils.java
@@ -4,6 +4,7 @@
 import com.documents4j.api.IConverter;
 import com.documents4j.job.LocalConverter;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.poi.xwpf.usermodel.*;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.mock.web.MockMultipartFile;
 import org.springframework.stereotype.Component;
@@ -11,7 +12,11 @@
 
 import java.io.*;
 import java.net.URL;
+import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
 import java.util.concurrent.TimeUnit;
 
 @Slf4j
@@ -22,7 +27,6 @@
     /**
      * word 转 pdf
      *
-     * @param url
      */
 //    public  String wordToPdf(String url,String filePath, String fileName) {
 //        try {
@@ -62,48 +66,192 @@
 //        return null;
 //    }
 
-    public String wordToPdf(String url, String filePath, String fileName) {
+    public String wordToPdf(String filePath, String fileName) {
         try {
-            DocumentType documentType = DocumentType.DOC;
-            if (url.contains(".docx")) {
-                documentType = DocumentType.DOCX;
-            } else if (url.contains(".doc")) {
-                documentType = DocumentType.DOC;
-            } else if (url.contains(".xlsx")) {
-                documentType = DocumentType.XLSX;
-            } else if (url.contains(".xls")) {
-                documentType = DocumentType.XLS;
-            }
+            // 1. 首先确保输入文件是UTF-8编码
+            String inputFile = filePath + fileName;
+            String outputDir = filePath + "/pdf";
+            String outputFileName = fileName.substring(0, fileName.lastIndexOf(".")) + ".pdf";
 
-            // Ensure the URL has a protocol part
-            if (!url.startsWith("file://") && !url.startsWith("http://") && !url.startsWith("https://")) {
-                url = "file://" + url;
-            }
+            // 2. 创建临时文件用于转换
+            String tempDocx = createTempFileWithEncoding(inputFile);
 
-            // 使用LibreOffice进行转换
-            ProcessBuilder pb = new ProcessBuilder(
-                    "soffice",
-                    "--headless",
-                    "--convert-to", "pdf",
-                    "--outdir", new File(filePath+ "/pdf"+fileName.substring(0, fileName.lastIndexOf(".")) + ".pdf").getParent(),
-                    filePath+fileName
-            );
+            // 3. 使用更详细的LibreOffice转换参数
+            List<String> command = new ArrayList<>();
+            command.add("/usr/bin/soffice");
+            command.add("--headless");
+            command.add("--convert-to");
+            command.add("pdf:writer_pdf_Export:PDFExport{'EmbedStandardFonts':true}");
+            command.add("--outdir");
+            command.add(outputDir);
+            command.add(tempDocx);
+
+            ProcessBuilder pb = new ProcessBuilder(command);
+
+            // 4. 设置更完整的环境变量
+            Map<String, String> env = pb.environment();
+            env.put("LC_ALL", "zh_CN.UTF-8");
+            env.put("LANG", "zh_CN.UTF-8");
+            env.put("LANGUAGE", "zh_CN.UTF-8");
+            env.put("PYTHONIOENCODING", "utf8");
+            env.put("JAVA_TOOL_OPTIONS", "-Dfile.encoding=UTF-8");
+
+            // 5. 执行转换
             Process process = pb.start();
 
-            // 等待转换完成
-            int exitCode = process.waitFor();
-            if (exitCode == 0) {
-                System.out.println("PDF转换成功!");
-            } else {
-                System.out.println("PDF转换失败!");
+            // 6. 读取输出
+            StringBuilder output = new StringBuilder();
+            try (BufferedReader reader = new BufferedReader(
+                    new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8))) {
+                String line;
+                while ((line = reader.readLine()) != null) {
+                    output.append(line).append("\n");
+                }
             }
-            return "";
+
+            // 7. 等待进程完成
+            int exitCode = process.waitFor();
+
+            // 8. 清理临时文件
+            new File(tempDocx).delete();
+
+            if (exitCode == 0) {
+                return outputDir + "/" + outputFileName;
+            } else {
+                throw new RuntimeException("转换失败: " + output.toString());
+            }
+
         } catch (Exception e) {
-            e.printStackTrace();
-            throw new RuntimeException("Failed to generate PDF: " + e.getMessage(), e);
+            throw new RuntimeException("PDF转换失败: " + e.getMessage(), e);
+        }
+    }
+    private static String createTempFileWithEncoding(String inputFile) {
+        try {
+            // 1. 读取原始文档
+            XWPFDocument doc = new XWPFDocument(new FileInputStream(inputFile));
+
+            // 2. 修改文档字体和编码
+            for (XWPFParagraph paragraph : doc.getParagraphs()) {
+                for (XWPFRun run : paragraph.getRuns()) {
+                    // 设置中文字体
+                    run.setFontFamily("WenQuanYi Zen Hei");
+                    run.setFontFamily("WenQuanYi Zen Hei", XWPFRun.FontCharRange.eastAsia);
+
+                    // 确保文本是UTF-8编码
+                    String text = run.getText(0);
+                    if (text != null) {
+                        text = new String(text.getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8);
+                        run.setText(text, 0);
+                    }
+                }
+            }
+
+            // 3. 处理表格中的文本
+            for (XWPFTable table : doc.getTables()) {
+                for (XWPFTableRow row : table.getRows()) {
+                    for (XWPFTableCell cell : row.getTableCells()) {
+                        for (XWPFParagraph paragraph : cell.getParagraphs()) {
+                            for (XWPFRun run : paragraph.getRuns()) {
+                                run.setFontFamily("WenQuanYi Zen Hei");
+                                run.setFontFamily("WenQuanYi Zen Hei", XWPFRun.FontCharRange.eastAsia);
+
+                                String text = run.getText(0);
+                                if (text != null) {
+                                    text = new String(text.getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8);
+                                    run.setText(text, 0);
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+
+            // 4. 保存为临时文件
+            String tempFile = inputFile + ".temp.docx";
+            try (FileOutputStream out = new FileOutputStream(tempFile)) {
+                doc.write(out);
+            }
+
+            return tempFile;
+
+        } catch (Exception e) {
+            throw new RuntimeException("处理文档编码失败: " + e.getMessage(), e);
         }
     }
 
+    // 在转换之前执行的环境检查
+    private static void preConversionCheck() {
+        try {
+            // 1. 检查并安装必要的字体
+            installRequiredFonts();
+
+            // 2. 验证LibreOffice安装
+            verifyLibreOfficeInstallation();
+
+            // 3. 设置字体配置
+            setupFontConfig();
+
+        } catch (Exception e) {
+            throw new RuntimeException("环境检查失败: " + e.getMessage(), e);
+        }
+    }
+
+    private static void installRequiredFonts() {
+        try {
+            ProcessBuilder pb = new ProcessBuilder(
+                    "sudo", "apt-get", "install", "-y",
+                    "fonts-wqy-zenhei",
+                    "fonts-wqy-microhei",
+                    "fonts-arphic-ukai",
+                    "fonts-arphic-uming"
+            );
+            pb.inheritIO();
+            Process p = pb.start();
+            p.waitFor();
+        } catch (Exception e) {
+            System.err.println("警告: 安装字体失败 - " + e.getMessage());
+        }
+    }
+
+    private static void verifyLibreOfficeInstallation() {
+        try {
+            Process p = Runtime.getRuntime().exec("soffice --version");
+            try (BufferedReader reader = new BufferedReader(
+                    new InputStreamReader(p.getInputStream()))) {
+                String version = reader.readLine();
+                if (version == null || !version.contains("LibreOffice")) {
+                    throw new RuntimeException("LibreOffice未正确安装");
+                }
+            }
+        } catch (Exception e) {
+            throw new RuntimeException("LibreOffice检查失败: " + e.getMessage());
+        }
+    }
+
+    private static void setupFontConfig() {
+        try {
+            String fontConfig =
+                    "<?xml version='1.0'?>\n" +
+                            "<!DOCTYPE fontconfig SYSTEM 'fonts.dtd'>\n" +
+                            "<fontconfig>\n" +
+                            "  <match target=\"pattern\">\n" +
+                            "    <test name=\"family\"><string>SimSun</string></test>\n" +
+                            "    <edit name=\"family\" mode=\"assign\" binding=\"same\">\n" +
+                            "      <string>WenQuanYi Zen Hei</string>\n" +
+                            "    </edit>\n" +
+                            "  </match>\n" +
+                            "</fontconfig>";
+
+            String userHome = System.getProperty("user.home");
+            File fontConfigFile = new File(userHome + "/.fonts.conf");
+
+            try (FileWriter writer = new FileWriter(fontConfigFile)) {
+                writer.write(fontConfig);
+            }
+        } catch (Exception e) {
+            System.err.println("警告: 设置字体配置失败 - " + e.getMessage());
+        }
+    }
 
     public static MultipartFile convertToMultipartFile(ByteArrayOutputStream baos, String fileName) throws IOException {
         // 创建一个临时文件
@@ -251,12 +399,12 @@
     }
 
     public String test(String fileName){
-        String url = "file:///usr/local/project/file/"+fileName;
+//        String url = "file:///usr/local/project/file/"+fileName;
 //        String filePath = "E:\\qiyeweixin\\WXWork\\1688855207501340\\Cache\\File\\2024-09";
 //        String fileName = "专业技术工作总结.docx";4
         String filePath = "/usr/local/project/file/";
 
-        String s = wordToPdf(url, filePath, fileName);
+        String s = wordToPdf(filePath, fileName);
         System.err.println(s);
 
         return s;
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/tool/WordTemplateProcessor.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/tool/WordTemplateProcessor.java
new file mode 100644
index 0000000..6b32fe3
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/tool/WordTemplateProcessor.java
@@ -0,0 +1,87 @@
+package com.ruoyi.web.controller.tool;
+
+import org.apache.poi.xwpf.usermodel.*;
+import java.io.*;
+import java.util.*;
+
+public class WordTemplateProcessor {
+    
+    public static void fillTemplate(String templatePath, String outputPath,Map<String, String> dataMap) {
+        try {
+            // 读取模板文件
+            FileInputStream fis = new FileInputStream(templatePath);
+            XWPFDocument document = new XWPFDocument(fis);
+            
+            // 替换段落中的标记
+            for (XWPFParagraph paragraph : document.getParagraphs()) {
+                replaceParagraph(paragraph, dataMap);
+            }
+            
+            // 替换表格中的标记
+            for (XWPFTable table : document.getTables()) {
+                for (XWPFTableRow row : table.getRows()) {
+                    for (XWPFTableCell cell : row.getTableCells()) {
+                        for (XWPFParagraph paragraph : cell.getParagraphs()) {
+                            replaceParagraph(paragraph, dataMap);
+                        }
+                    }
+                }
+            }
+            
+            // 保存文件
+            FileOutputStream fos = new FileOutputStream(outputPath);
+            document.write(fos);
+            
+            // 关闭资源
+            fos.close();
+            fis.close();
+            document.close();
+            
+            System.out.println("模板填充完成!文件保存在: " + outputPath);
+            
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+    
+    private static void replaceParagraph(XWPFParagraph paragraph, Map<String, String> dataMap) {
+        String paragraphText = paragraph.getText();
+        for (Map.Entry<String, String> entry : dataMap.entrySet()) {
+            if (paragraphText.contains(entry.getKey())) {
+                List<XWPFRun> runs = paragraph.getRuns();
+                TextSegment found = paragraph.searchText(entry.getKey(), new PositionInParagraph());
+                if (found != null) {
+                    // 替换文本
+                    int beginRun = found.getBeginRun();
+                    int endRun = found.getEndRun();
+                    
+                    if (beginRun >= 0 && endRun >= 0) {
+                        // 删除原有runs
+                        for (int runPos = beginRun; runPos <= endRun; runPos++) {
+                            paragraph.removeRun(runPos);
+                        }
+                        // 创建新run
+                        XWPFRun newRun = paragraph.insertNewRun(beginRun);
+                        newRun.setText(entry.getValue());
+                        // 复制原有格式
+                        if (runs.size() > 0 && runs.get(0) != null) {
+                            XWPFRun styleRun = runs.get(0);
+                            newRun.setFontFamily(styleRun.getFontFamily());
+                            newRun.setFontSize(styleRun.getFontSize());
+                            newRun.setBold(styleRun.isBold());
+                            newRun.setItalic(styleRun.isItalic());
+                        }
+                    }
+                }
+            }
+        }
+    }
+    
+    public static void main(String[] args) {
+
+        String templatePath = "/path/to/template.docx";
+        String outputPath = "/path/to/output.docx";
+        
+//        fillTemplate(templatePath, outputPath, user);
+    }
+}
\ No newline at end of file
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/tool/WordUtil.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/tool/WordUtil.java
index ce14b96..60d821a 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/tool/WordUtil.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/tool/WordUtil.java
@@ -6,6 +6,7 @@
 import freemarker.template.TemplateException;
 import lombok.extern.slf4j.Slf4j;
 
+import org.apache.poi.xwpf.usermodel.*;
 import org.springframework.mock.web.MockMultipartFile;
 import org.springframework.stereotype.Component;
 import org.springframework.web.multipart.MultipartFile;
@@ -15,7 +16,9 @@
 import java.io.*;
 import java.net.URLEncoder;
 import java.nio.charset.StandardCharsets;
-import java.util.Map;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 @Slf4j
 @Component
@@ -110,35 +113,38 @@
     }
 
 
-    public String generatePdf(String basePackagePath, String templateFileName, Object templateParam, String fileName, String saveDirectory) {
+    public String generatePdf(String basePackagePath, String templateFileName, Map<String,Object> templateParam, String fileName, String saveDirectory) {
         try {
+
+            fillTemplate(basePackagePath+templateFileName, saveDirectory+fileName+".docx", templateParam);
+
             // 创建 Freemarker 的 Configuration 对象,设置默认的不兼容改进选项
-            Configuration configuration = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
-            configuration.setDefaultEncoding("utf-8");
-            // 设置模板加载器,加载模板文件
-            configuration.setTemplateLoader(new ClassTemplateLoader(getClass(), basePackagePath));
-            Template t = configuration.getTemplate(templateFileName, "utf-8");
-
-            // 使用 URLEncoder 对文件名进行编码,以防止中文文件名在不同浏览器和操作系统下出现乱码问题
-//            String encodedFileName = URLEncoder.encode(fileName + "_" + System.currentTimeMillis(), "utf-8");
-            String encodedFileName =fileName ;
-
-            // 定义保存文件的路径
-            File saveDir = new File(saveDirectory);
-            if (!saveDir.exists()) {
-                saveDir.mkdirs();
-            }
-
-            // 定义文件名
-            String filePath = saveDir.getAbsolutePath() + File.separator + encodedFileName + ".doc";
-
-            // 创建 Writer 对象,用于将生成的文档写到文件中,缓存区大小设为 10KB
-            Writer out = new BufferedWriter(new FileWriter(filePath), 10240);
-
-            // 将模型数据与模板结合生成 Word 文档,写入到 Writer 对象中
-            t.process(templateParam, out);
-            out.close();
-
+//            Configuration configuration = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
+//            configuration.setDefaultEncoding("utf-8");
+//            // 设置模板加载器,加载模板文件
+//            configuration.setTemplateLoader(new ClassTemplateLoader(getClass(), basePackagePath));
+//            Template t = configuration.getTemplate(templateFileName, "utf-8");
+//
+//            // 使用 URLEncoder 对文件名进行编码,以防止中文文件名在不同浏览器和操作系统下出现乱码问题
+////            String encodedFileName = URLEncoder.encode(fileName + "_" + System.currentTimeMillis(), "utf-8");
+//            String encodedFileName =fileName ;
+//
+//            // 定义保存文件的路径
+//            File saveDir = new File(saveDirectory);
+//            if (!saveDir.exists()) {
+//                saveDir.mkdirs();
+//            }
+//
+//            // 定义文件名
+//            String filePath = saveDir.getAbsolutePath() + File.separator + encodedFileName + ".doc";
+//
+//            // 创建 Writer 对象,用于将生成的文档写到文件中,缓存区大小设为 10KB
+//            Writer out = new BufferedWriter(new FileWriter(filePath), 10240);
+//
+//            // 将模型数据与模板结合生成 Word 文档,写入到 Writer 对象中
+//            t.process(templateParam, out);
+//            out.close();
+            String filePath = saveDirectory + File.separator + fileName + ".docx";
             File file = new File(filePath);
 
             // 检查文件是否存在
@@ -152,16 +158,263 @@
                 fis.read(fileContent);
             }
 
-            String test = pdfUtils.test(encodedFileName + ".doc");
+            String test = pdfUtils.test(fileName + ".docx");
 //            MultipartFile mockMultipartFile = new MockMultipartFile(encodedFileName+".doc", fileContent);
 //            String s = ObsUploadUtil.obsUpload(mockMultipartFile);
             return test;
-        } catch (IOException | TemplateException e) {
+        } catch (IOException e) {
             log.error("生成pdf异常,异常原因:{}", e.getMessage(), e);
             throw new RuntimeException("生成pdf异常,异常原因:" + e.getMessage());
         }
     }
 
+    public static void fillTemplate(String templatePath, String outputPath,Map<String, Object> dataMap) {
+        try (FileInputStream fis = new FileInputStream(templatePath)) {
+            // 设置默认编码为UTF-8
+            System.setProperty("file.encoding", "UTF-8");
+
+            XWPFDocument document = new XWPFDocument(fis);
+
+            // 处理段落
+            for (XWPFParagraph paragraph : document.getParagraphs()) {
+                replaceParagraph(paragraph, dataMap);
+            }
+
+            // 处理表格
+            for (XWPFTable table : document.getTables()) {
+                for (XWPFTableRow row : table.getRows()) {
+                    for (XWPFTableCell cell : row.getTableCells()) {
+                        for (XWPFParagraph paragraph : cell.getParagraphs()) {
+                            replaceParagraph(paragraph, dataMap);
+                        }
+                    }
+                }
+            }
+
+            // 使用UTF-8编码保存文件
+            try (FileOutputStream fos = new FileOutputStream(outputPath)) {
+                document.write(fos);
+            }
+
+            System.out.println("模板填充完成!文件保存在: " + outputPath);
+
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    private static void replaceParagraph(XWPFParagraph paragraph, Map<String, Object> dataMap) {
+        // 获取段落中所有runs
+        List<XWPFRun> runs = paragraph.getRuns();
+        if (runs == null || runs.isEmpty()) return;
+
+        // 首先合并所有runs的文本,以便正确识别占位符
+        StringBuilder fullText = new StringBuilder();
+        for (XWPFRun run : runs) {
+            String text = run.getText(0);
+            if (text != null) {
+                fullText.append(text);
+            }
+        }
+
+        String paragraphText = fullText.toString();
+
+        // 使用正则表达式查找所有占位符,包括括号内的
+        Pattern pattern = Pattern.compile("\\$\\{[^}]+\\}|\\([^)]*\\$\\{[^}]+\\}[^)]*\\)");
+        Matcher matcher = pattern.matcher(paragraphText);
+
+        List<ReplacementInfo> replacements = new ArrayList<>();
+
+        // 收集所有需要替换的信息
+        while (matcher.find()) {
+            String matched = matcher.group();
+            int start = matcher.start();
+            int end = matcher.end();
+
+            // 找出涉及到的runs
+            int startRun = -1;
+            int endRun = -1;
+            int currentPos = 0;
+
+            for (int i = 0; i < runs.size(); i++) {
+                XWPFRun run = runs.get(i);
+                String runText = run.getText(0);
+                if (runText == null) continue;
+
+                int runLength = runText.length();
+                if (startRun == -1 && currentPos + runLength > start) {
+                    startRun = i;
+                }
+                if (currentPos + runLength >= end) {
+                    endRun = i;
+                    break;
+                }
+                currentPos += runLength;
+            }
+
+            if (startRun != -1 && endRun != -1) {
+                // 处理括号内的占位符
+                String replacement = processPlaceholder(matched, dataMap);
+                replacements.add(new ReplacementInfo(startRun, endRun, matched, replacement));
+            }
+        }
+
+        // 从后向前替换,避免位置变化影响
+        Collections.sort(replacements, (a, b) -> b.startRun - a.startRun);
+
+        for (ReplacementInfo info : replacements) {
+            replaceRunRange(paragraph, info);
+        }
+    }
+
+    private static String processPlaceholder(String text, Map<String, Object> dataMap) {
+        // 处理括号内的占位符
+        Pattern placeholderPattern = Pattern.compile("\\$\\{([^}]+)\\}");
+        Matcher matcher = placeholderPattern.matcher(text);
+
+        StringBuffer result = new StringBuffer();
+        while (matcher.find()) {
+            String placeholder = matcher.group(0); // 完整的占位符
+            String key = matcher.group(1); // 占位符中的键
+            String replacement = Objects.nonNull(dataMap.get("${" + key + "}"))?String.valueOf(dataMap.get("${" + key + "}")):"";
+
+            if (replacement != null) {
+                // 如果在括号内,保留括号
+                if (text.startsWith("(") && text.endsWith(")")) {
+                    matcher.appendReplacement(result, replacement);
+                } else {
+                    matcher.appendReplacement(result, Matcher.quoteReplacement(replacement));
+                }
+            }
+        }
+        matcher.appendTail(result);
+
+        return result.toString();
+    }
+
+    private static class ReplacementInfo {
+        int startRun;
+        int endRun;
+        String originalText;
+        String replacementText;
+
+        ReplacementInfo(int startRun, int endRun, String originalText, String replacementText) {
+            this.startRun = startRun;
+            this.endRun = endRun;
+            this.originalText = originalText;
+            this.replacementText = replacementText;
+        }
+    }
+
+    private static void replaceRunRange(XWPFParagraph paragraph, ReplacementInfo info) {
+        List<XWPFRun> runs = paragraph.getRuns();
+
+        // 保存第一个run的样式
+        XWPFRun styleRun = runs.get(info.startRun);
+        RunStyle style = new RunStyle(styleRun);
+
+        // 删除范围内的所有runs
+        for (int i = info.endRun; i >= info.startRun; i--) {
+            paragraph.removeRun(i);
+        }
+
+        // 创建新的run并设置文本
+        XWPFRun newRun = paragraph.insertNewRun(info.startRun);
+        newRun.setText(info.replacementText);
+
+        // 应用样式
+        style.applyStyle(newRun);
+    }
+
+    // 用于保存和恢复运行样式的辅助类
+    private static class RunStyle {
+        String fontFamily;
+        int fontSize;
+        boolean bold;
+        boolean italic;
+        String color;
+        UnderlinePatterns underline;
+
+        RunStyle(XWPFRun run) {
+            this.fontFamily = run.getFontFamily();
+            this.fontSize = run.getFontSize();
+            this.bold = run.isBold();
+            this.italic = run.isItalic();
+            this.color = run.getColor();
+            this.underline = run.getUnderline();
+        }
+
+        void applyStyle(XWPFRun run) {
+            if (fontFamily != null) {
+                run.setFontFamily(fontFamily);
+                run.setFontFamily(fontFamily, XWPFRun.FontCharRange.eastAsia);
+            }
+            if (fontSize != -1) {
+                run.setFontSize(fontSize);
+            }
+            run.setBold(bold);
+            run.setItalic(italic);
+            if (color != null) {
+                run.setColor(color);
+            }
+            if (underline != null) {
+                run.setUnderline(underline);
+            }
+        }
+    }
+
+//    public String generatePdf(String basePackagePath, String templateFileName, Object templateParam, String fileName, String saveDirectory) {
+//        try {
+//            // 创建 Freemarker 的 Configuration 对象,设置默认的不兼容改进选项
+//            Configuration configuration = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
+//            configuration.setDefaultEncoding("utf-8");
+//            // 设置模板加载器,加载模板文件
+//            configuration.setTemplateLoader(new ClassTemplateLoader(getClass(), basePackagePath));
+//            Template t = configuration.getTemplate(templateFileName, "utf-8");
+//
+//            // 使用 URLEncoder 对文件名进行编码,以防止中文文件名在不同浏览器和操作系统下出现乱码问题
+////            String encodedFileName = URLEncoder.encode(fileName + "_" + System.currentTimeMillis(), "utf-8");
+//            String encodedFileName =fileName ;
+//
+//            // 定义保存文件的路径
+//            File saveDir = new File(saveDirectory);
+//            if (!saveDir.exists()) {
+//                saveDir.mkdirs();
+//            }
+//
+//            // 定义文件名
+//            String filePath = saveDir.getAbsolutePath() + File.separator + encodedFileName + ".doc";
+//
+//            // 创建 Writer 对象,用于将生成的文档写到文件中,缓存区大小设为 10KB
+//            Writer out = new BufferedWriter(new FileWriter(filePath), 10240);
+//
+//            // 将模型数据与模板结合生成 Word 文档,写入到 Writer 对象中
+//            t.process(templateParam, out);
+//            out.close();
+//
+//            File file = new File(filePath);
+//
+//            // 检查文件是否存在
+//            if (!file.exists()) {
+//                throw new FileNotFoundException("文件不存在: " + filePath);
+//            }
+//
+//            // 读取文件内容
+//            byte[] fileContent = new byte[(int) file.length()];
+//            try (FileInputStream fis = new FileInputStream(file)) {
+//                fis.read(fileContent);
+//            }
+//
+//            String test = pdfUtils.test(encodedFileName + ".doc");
+////            MultipartFile mockMultipartFile = new MockMultipartFile(encodedFileName+".doc", fileContent);
+////            String s = ObsUploadUtil.obsUpload(mockMultipartFile);
+//            return test;
+//        } catch (IOException | TemplateException e) {
+//            log.error("生成pdf异常,异常原因:{}", e.getMessage(), e);
+//            throw new RuntimeException("生成pdf异常,异常原因:" + e.getMessage());
+//        }
+//    }
+
 
 
 
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TCheckAcceptRecordServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TCheckAcceptRecordServiceImpl.java
index 984f88e..f4e9e68 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TCheckAcceptRecordServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TCheckAcceptRecordServiceImpl.java
@@ -17,6 +17,7 @@
 import com.ruoyi.system.vo.TCheckAcceptRecordVO;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
+import org.springframework.util.StringUtils;
 
 import java.util.List;
 
@@ -40,10 +41,10 @@
         PageInfo<TCheckAcceptRecordVO> pageInfo = new PageInfo<>(query.getPageNum(), query.getPageSize());
         List<TCheckAcceptRecordVO> list = this.baseMapper.pageList(query,pageInfo);
         list.forEach(item -> {
-            item.setCleanSituation(item.getCleanSituation()!=null?(DictUtils.getDictLabel(DictConstants.DICT_TYPE_CHECK_SITUATION,item.getCleanSituation())):"");
-            item.setOverallSituation(item.getOverallSituation()!=null?(DictUtils.getDictLabel(DictConstants.DICT_TYPE_CHECK_SITUATION,item.getOverallSituation())):"");
-            item.setDeviceSituation(item.getDeviceSituation()!=null?(DictUtils.getDictLabel(DictConstants.DICT_TYPE_CHECK_SITUATION,item.getDeviceSituation())):"");
-            item.setFurnitureSituation(item.getDeviceSituation()!=null?(DictUtils.getDictLabel(DictConstants.DICT_TYPE_CHECK_SITUATION,item.getFurnitureSituation())):"");
+            item.setCleanSituation(StringUtils.hasLength(item.getCleanSituation()) ?(DictUtils.getDictLabel(DictConstants.DICT_TYPE_CHECK_SITUATION,item.getCleanSituation())):"");
+            item.setOverallSituation(StringUtils.hasLength(item.getOverallSituation())?(DictUtils.getDictLabel(DictConstants.DICT_TYPE_CHECK_SITUATION,item.getOverallSituation())):"");
+            item.setDeviceSituation(StringUtils.hasLength(item.getDeviceSituation())?(DictUtils.getDictLabel(DictConstants.DICT_TYPE_CHECK_SITUATION,item.getDeviceSituation())):"");
+            item.setFurnitureSituation(StringUtils.hasLength(item.getDeviceSituation())?(DictUtils.getDictLabel(DictConstants.DICT_TYPE_CHECK_SITUATION,item.getFurnitureSituation())):"");
 
         });
         pageInfo.setRecords(list);

--
Gitblit v1.7.1