Browse Source

build fxy新版报告

mamingxu 1 day ago
parent
commit
15c590e338
23 changed files with 7634 additions and 5184 deletions
  1. 2 1
      easier-report-api/src/main/java/com/yaoyicloud/constant/enums/ModuleType.java
  2. 13 15
      easier-report-biz/src/main/java/com/yaoyicloud/controller/ReportUpdateController.java
  3. 24 20
      easier-report-biz/src/main/java/com/yaoyicloud/factory/AbstractRender.java
  4. 67 45
      easier-report-biz/src/main/java/com/yaoyicloud/factory/FXYAbstractRender.java
  5. 6 9
      easier-report-biz/src/main/java/com/yaoyicloud/render/CoverRender.java
  6. 0 1
      easier-report-biz/src/main/java/com/yaoyicloud/render/cso/EntHeaderSectionRender.java
  7. 1 1
      easier-report-biz/src/main/java/com/yaoyicloud/render/cso/EntProductIntroductionRender.java
  8. 1 1
      easier-report-biz/src/main/java/com/yaoyicloud/render/cso/EntPromotionDetailsRender.java
  9. 1 1
      easier-report-biz/src/main/java/com/yaoyicloud/render/cso/EntPromotionSummaryRender.java
  10. 7 9
      easier-report-biz/src/main/java/com/yaoyicloud/render/platform/AttachmentSectionRender.java
  11. 16 0
      easier-report-biz/src/main/java/com/yaoyicloud/render/platform/update/BusinessRender.java
  12. 1 1
      easier-report-biz/src/main/java/com/yaoyicloud/render/platform/update/JudicialRender.java
  13. 8 4
      easier-report-biz/src/main/java/com/yaoyicloud/render/platform/update/OperationalRender.java
  14. 38 10
      easier-report-biz/src/main/java/com/yaoyicloud/render/platform/update/OtherRender.java
  15. 1 1
      easier-report-biz/src/main/java/com/yaoyicloud/render/platform/update/TaxRender.java
  16. 8 50
      easier-report-biz/src/main/java/com/yaoyicloud/service/impl/FxyReportUpdateServiceImpl.java
  17. 2 3
      easier-report-biz/src/main/java/com/yaoyicloud/template/AbstractReportExporter.java
  18. 76 107
      easier-report-biz/src/main/java/com/yaoyicloud/tools/DocxUtil.java
  19. 185 219
      easier-report-biz/src/main/java/com/yaoyicloud/tools/OfficeUtil.java
  20. 8 0
      easier-report-biz/src/main/java/com/yaoyicloud/tools/Util.java
  21. 7 2
      easier-report-biz/src/main/proto/fxy.proto
  22. 1 1
      easier-report-biz/src/main/resources/application.yml
  23. 7161 4683
      logs/easier-report-biz/debug.log

+ 2 - 1
easier-report-api/src/main/java/com/yaoyicloud/constant/enums/ModuleType.java

@@ -36,7 +36,8 @@ public enum ModuleType {
     PROJECT("PROJECT", "项目信息"),
     INTERESTCONFLICTS("INTERESTCONFLICTS", "利益冲突"),
     ANTIBRIBERY("ANTIBRIBERY", "诚信保证"),
-    COMMON("COMMON", "公共模块封面"),
+    COVER("COVER", "封面"),
+
     PLATFORM_COMPANY_FINANCIALINFO("PLATFORM_COMPANY_FINANCIALINFO", "平台公司财务"),
     FOUNDATION_FINANCIALINFO("FOUNDATION_FINANCIALINFO", "基金会财务"),
     PLATFORM_COMPANY_ATTACHMENTSECTION("PLATFORM_COMPANY_ATTACHMENTSECTION", "平台公司附件"),

+ 13 - 15
easier-report-biz/src/main/java/com/yaoyicloud/controller/ReportUpdateController.java

@@ -1,13 +1,12 @@
 package com.yaoyicloud.controller;
 
-
 import com.yaoyicloud.annotation.EasierLog;
 import com.yaoyicloud.config.CommonDataCache;
 import com.yaoyicloud.config.RelationCounterRedisUtil;
-import com.yaoyicloud.constant.enums.ModuleType;
 import com.yaoyicloud.dto.ReportDTO;
 import com.yaoyicloud.entity.ReportGenerationResult;
 import com.yaoyicloud.service.ReportUpdateService;
+import com.yaoyicloud.tools.DocxUtil;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
@@ -16,15 +15,12 @@ import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import javax.servlet.http.HttpServletRequest;
 
-
 import java.util.HashMap;
 
 import java.util.Map;
 
-
 import static com.yaoyicloud.config.SessionInterceptor.SESSION_MAP;
 
-
 /**
  * 报告控制器
  *
@@ -38,6 +34,8 @@ public class ReportUpdateController {
     private final ReportUpdateService reportService;
     private final RelationCounterRedisUtil relationCounterRedisUtil;
     private final CommonDataCache commonDataCache;
+    private final DocxUtil docxUtil;
+
     /**
      * 创建Plus版本审核报告
      *
@@ -47,27 +45,27 @@ public class ReportUpdateController {
     @EasierLog("创建Plus版本审核报告")
     @PostMapping("/report/create-report-new")
     public Map<String, Object> createPlusVersionCheckReport(
-            @Validated @RequestBody ReportDTO.OnCreatePlusVersionReport resource,
-            HttpServletRequest request
-    ) throws Exception {
+        @Validated @RequestBody ReportDTO.OnCreatePlusVersionReport resource,
+        HttpServletRequest request) throws Exception {
         // 1. 解码文件并生成报告
         String relationId = request.getHeader("relationId");
-        ModuleType moduleType = resource.getModuleType();
 
         ReportGenerationResult plusVersionCheckReport = reportService.createPlusVersionCheckReport(
-                resource.getData(),
-                Long.valueOf(relationId),
-                resource.getModuleType()
-        );
+            resource.getData(),
+            Long.valueOf(relationId),
+            resource.getModuleType());
         String sessionId = SESSION_MAP.get(relationId);
         // 3. 构建响应
         Map<String, Object> response = new HashMap<>();
         // 根据是否是最后一个模块决定返回哪个路径
         if (plusVersionCheckReport.isLastModule() && plusVersionCheckReport.getMergedReportPath() != null) {
-            response.put("reportResult", plusVersionCheckReport.getMergedReportPath());
-            response.put("isFinalReport", true);
+            // word 转pdf
             commonDataCache.removeSessionData(relationId);
             relationCounterRedisUtil.delete(Long.valueOf(relationId));
+            String pdfDocumentPath = docxUtil.wordToPdf(plusVersionCheckReport.getMergedReportPath());
+            response.put("reportResult", pdfDocumentPath);
+            response.put("isFinalReport", true);
+
         } else {
             response.put("reportResult", plusVersionCheckReport.getModulePath());
             response.put("isFinalReport", false);

+ 24 - 20
easier-report-biz/src/main/java/com/yaoyicloud/factory/AbstractRender.java

@@ -1,6 +1,7 @@
 package com.yaoyicloud.factory;
 
 import java.awt.image.BufferedImage;
+
 import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.IOException;
@@ -22,6 +23,7 @@ import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 import javax.imageio.ImageIO;
+
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.pdfbox.Loader;
 import org.apache.pdfbox.pdmodel.PDDocument;
@@ -488,8 +490,15 @@ public abstract class AbstractRender {
             List<Map<String, Object>> mpData = (List<Map<String, Object>>) data;
             mpData.sort((a, b) -> Integer.valueOf(a.getOrDefault("rank", "0").toString())
                 - Integer.valueOf(b.getOrDefault("rank", "0").toString()));
-
-            super.render(eleTemplate, data, template);
+            for (Map<String, Object> map : mpData) {
+                for (Map.Entry<String, Object> entry : map.entrySet()) {
+                    Object value = entry.getValue();
+                    if (value != null && "".equals(value.toString())) {
+                        entry.setValue("-");
+                    }
+                }
+            }
+            super.render(eleTemplate, mpData, template);
 
             try {
                 // merge the first column
@@ -624,9 +633,11 @@ public abstract class AbstractRender {
                         mergedCell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);
                         for (XWPFParagraph paragraph : mergedCell.getParagraphs()) {
                             paragraph.setAlignment(ParagraphAlignment.CENTER);
+                            for (XWPFRun runa : paragraph.getRuns()) {
+                                runa.setFontFamily("思源黑体 Medium");
+                            }
                         }
                         try {
-
                             Util.mergeFirstNColSimple(table, 1, 0);
                         } catch (Exception e) {
                             throw new RenderException(
@@ -682,9 +693,9 @@ public abstract class AbstractRender {
     /**
      * Protobuf数据专用渲染策略
      *
-     * 功能特点: - 自动处理空值为"-" - 支持从模板提取变量名
+     * 功能特点: - 自动处理空值为"-" - 支持从模板提取变量名, 并删除表格最后一行
      */
-    protected RenderPolicy indicatorsRenderPolicyToProtobuf(Boolean delFlag) {
+    protected RenderPolicy indicatorsRenderPolicyToProtobuf() {
         return new LoopRowTableRenderPolicy() {
             @Override
             public void render(ElementTemplate eleTemplate, Object data, XWPFTemplate template) {
@@ -704,20 +715,6 @@ public abstract class AbstractRender {
                 }
                 // 调用父类渲染处理后的数据
                 super.render(eleTemplate, processedData, template);
-                if (!delFlag) {
-
-                    RunTemplate runTemplate = (RunTemplate) eleTemplate;
-                    XWPFRun run = runTemplate.getRun();
-                    XWPFTableCell tagCell = (XWPFTableCell) ((XWPFParagraph) run.getParent()).getBody();
-                    XWPFTable table = tagCell.getTableRow().getTable();
-                    List<XWPFTableRow> rows = table.getRows();
-                    if (rows != null && rows.size() > 0) {
-                        // 获取最后一行的索引(行索引从0开始)
-                        int lastRowIndex = rows.size() - 1;
-                        // 删除最后一行
-                        table.removeRow(lastRowIndex);
-                    }
-                }
             }
 
         };
@@ -797,7 +794,14 @@ public abstract class AbstractRender {
                     return map.entrySet().stream()
                         .collect(Collectors.toMap(
                             Map.Entry::getKey,
-                            e -> e.getValue() == null ? "-" : e.getValue()));
+                            e -> {
+                                Object value = e.getValue();
+                                // 若值为null或空字符串,转为"-"
+                                if (value == null || "".equals(value)) {
+                                    return "-";
+                                }
+                                return value;
+                            }));
                 }
 
                 return item;

+ 67 - 45
easier-report-biz/src/main/java/com/yaoyicloud/factory/FXYAbstractRender.java

@@ -1,16 +1,24 @@
 package com.yaoyicloud.factory;
 
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.List;
 import java.util.Map;
-import com.deepoove.poi.config.ConfigureBuilder;
-import lombok.extern.slf4j.Slf4j;
 
+import com.deepoove.poi.config.ConfigureBuilder;
 
+import lombok.extern.slf4j.Slf4j;
+import org.apache.poi.xwpf.usermodel.XWPFDocument;
+import org.apache.poi.xwpf.usermodel.XWPFParagraph;
+import org.apache.poi.xwpf.usermodel.XWPFRun;
+import org.apache.poi.xwpf.usermodel.XWPFTable;
+import org.apache.poi.xwpf.usermodel.XWPFTableCell;
+import org.apache.poi.xwpf.usermodel.XWPFTableRow;
 
 @Slf4j
-public abstract class FXYAbstractRender extends AbstractRender  {
-
+public abstract class FXYAbstractRender extends AbstractRender {
 
     public FXYAbstractRender(String cwd) {
         super(cwd);
@@ -18,58 +26,72 @@ public abstract class FXYAbstractRender extends AbstractRender  {
 
     @SuppressWarnings("checkstyle:ParameterNumber")
     public final String createFXYDocument(String info, InputStream inputStream, String relationId, Integer counter,
-         String moduleType)
+        String moduleType)
         throws IOException {
         // 获取数据
         Map<String, Object> originalMap = this.renderDocx(info, relationId, counter);
         ConfigureBuilder builder = this.builder(relationId);
-        String docxResultPath = this.documentCompile(originalMap, inputStream, builder, relationId, moduleType);
-
+        // String docxResultPath = this.documentCompile(originalMap, inputStream, builder, relationId, moduleType);
+        String docxResultPath = this.fxyCompile(originalMap, inputStream, builder, relationId, moduleType);
         log.info("文档导出成功,文档路径为: {}", docxResultPath);
         return docxResultPath;
     }
 
-    @SuppressWarnings("checkstyle:ParameterNumber")
+    @SuppressWarnings({"checkstyle:ParameterNumber", "checkstyle:NestedIfDepth"})
     public String fxyCompile(Map<String, Object> dataMap, InputStream inputStream,
-                             ConfigureBuilder builder, String relationId, String moduleType)
-            throws IOException {
+        ConfigureBuilder builder, String relationId, String moduleType)
+        throws IOException {
         String resultPath = super.documentCompile(dataMap, inputStream, builder, relationId, moduleType);
 
-        // ArrayList<String> templateDele = new ArrayList<>();
-        // for (Map.Entry<String, Object> entry : specialMap.entrySet()) {
-        // String key = entry.getKey();
-        // Object value = entry.getValue();
-        // if (value.equals("")) {
-        // templateDele.add(key);
-        // }
-        // }
-        // Map<String, String> keywordMap = new HashMap<>();
-        // keywordMap.put("suggestion", "建议");
-        // keywordMap.put("score", "分");
-        // keywordMap.put("riskSummary", "-");
-        // XWPFDocument doc = template.getXWPFDocument();
-        // List<XWPFTable> tables = doc.getTables();
-        // XWPFTable xwpfTable = tables.get(tables.size() - 1);
-        // for (int i = xwpfTable.getNumberOfRows() - 1; i >= 0; i--) {
-        // XWPFTableRow row = xwpfTable.getRow(i);
-        // StringBuilder rowText = new StringBuilder();
-        // for (XWPFTableCell cell : row.getTableCells()) {
-        // rowText.append(cell.getText());
-        // }
-        // for (String codeKeyword : templateDele) {
-        // String templateKeyword = keywordMap.get(codeKeyword);
-        // if (rowText.toString().contains(templateKeyword)) {
-        // xwpfTable.removeRow(i);
-        // break;
-        // }
-        // }
-        // }
-
-        return this.docxResultPath;
+        // 特别处理经营异常模块 财务信息表格行动态展示
+        Boolean financialInfoFlag = (Boolean) dataMap.get("financialInfo_flag");
+        if (financialInfoFlag != null && !financialInfoFlag) {
+
+
+            try (XWPFDocument doc = new XWPFDocument(new FileInputStream(resultPath))) {
+                List<XWPFTable> tables = doc.getTables();
+
+                if (tables.size() > 1) {
+                    XWPFTable targetTable = tables.get(1);
+                    List<XWPFTableRow> rows = targetTable.getRows();
+
+                    if (!rows.isEmpty()) {
+
+                        XWPFTableRow firstRow = rows.get(0);
+
+                        if (!firstRow.getTableCells().isEmpty()) {
+                            XWPFTableCell firstCell = firstRow.getTableCells().get(0);
+                            StringBuilder cellContent = new StringBuilder();
+                            for (XWPFParagraph para : firstCell.getParagraphs()) {
+                                for (XWPFRun run : para.getRuns()) {
+                                    String text = run.getText(0);
+                                    if (text != null) {
+                                        cellContent.append(text);
+                                    }
+                                }
+                            }
+                            String cellText = cellContent.toString().trim();
+
+                            if (cellText.contains("审查项")) {
+                                if (rows.size() > 0) {
+                                    int lastRowIndex = rows.size() - 1;
+                                    targetTable.removeRow(lastRowIndex);
+                                }
+                            }
+                        }
+                    }
+
+                    try (FileOutputStream out = new FileOutputStream(resultPath)) {
+                        doc.write(out);
+                    }
+                }
+            } catch (IOException e) {
+                throw new RuntimeException("处理表格行时发生错误", e);
+            }
+
+        }
+
+        return resultPath;
     }
 
-
-
-
-
 }

+ 6 - 9
easier-report-biz/src/main/java/com/yaoyicloud/render/ServiceProviderInfoRender.java → easier-report-biz/src/main/java/com/yaoyicloud/render/CoverRender.java

@@ -24,11 +24,11 @@ import lombok.extern.slf4j.Slf4j;
  *
  */
 @Slf4j
-public final class ServiceProviderInfoRender extends FXYAbstractRender {
+public final class CoverRender extends FXYAbstractRender {
     private final FilerepoProperties filerepoProperties;
     private final CommonDataCache commonDataCache;
 
-    public ServiceProviderInfoRender(String cwd, FilerepoProperties filerepoProperties,
+    public CoverRender(String cwd, FilerepoProperties filerepoProperties,
         CommonDataCache commonDataCache) {
         super(cwd);
         this.filerepoProperties = filerepoProperties;
@@ -39,18 +39,17 @@ public final class ServiceProviderInfoRender extends FXYAbstractRender {
     protected Map<String, Object> renderDocx(String info, String relationId, Integer counter) throws IOException {
         log.info("开始渲染公共封面模块,relationId: {}", relationId);
 
-
         FxyProtos.AuditResult.Builder auditResultBuilder = FxyProtos.AuditResult.newBuilder();
         JsonFormat.parser().merge(info, auditResultBuilder);
 
         FxyProtos.AuditResult defaultInstance = FxyProtos.AuditResult.getDefaultInstance();
         FxyProtos.AuditResult mergedProto = defaultInstance.toBuilder()
-                .mergeFrom(auditResultBuilder.build())
-                .build();
+            .mergeFrom(auditResultBuilder.build())
+            .build();
 
         String completeJson = JsonFormat.printer()
-                .includingDefaultValueFields()
-                .print(mergedProto);
+            .includingDefaultValueFields()
+            .print(mergedProto);
         ObjectMapper objectMapper = new ObjectMapper();
         Map<String, Object> data = objectMapper.readValue(completeJson, new TypeReference<Map<String, Object>>() {});
         data.replaceAll((k, v) -> v.equals("") ? "-" : v);
@@ -71,8 +70,6 @@ public final class ServiceProviderInfoRender extends FXYAbstractRender {
         return data;
     }
 
-
-
     @Override
     protected ConfigureBuilder builder(String relationId) {
         // 配置POI-TL渲染器

+ 0 - 1
easier-report-biz/src/main/java/com/yaoyicloud/render/cso/EntHeaderSectionRender.java

@@ -74,7 +74,6 @@ public final class EntHeaderSectionRender extends CSOAbstractRender {
     @Override
     protected ConfigureBuilder builder(String relationId) {
         ConfigureBuilder builder = Configure.builder();
-        builder.bind("drugDetails", this.indicatorsRenderPolicyToProtobuf(true));
         return builder;
     }
 

+ 1 - 1
easier-report-biz/src/main/java/com/yaoyicloud/render/cso/EntProductIntroductionRender.java

@@ -59,7 +59,7 @@ public final class EntProductIntroductionRender extends CSOAbstractRender {
     @Override
     protected ConfigureBuilder builder(String relationId) {
         ConfigureBuilder builder = Configure.builder();
-        builder.bind("drugDetails", this.indicatorsRenderPolicyToProtobuf(true));
+        builder.bind("drugDetails", this.indicatorsRenderPolicyToProtobuf());
         return builder;
     }
 

+ 1 - 1
easier-report-biz/src/main/java/com/yaoyicloud/render/cso/EntPromotionDetailsRender.java

@@ -63,7 +63,7 @@ public final class EntPromotionDetailsRender extends CSOAbstractRender {
     @Override
     protected ConfigureBuilder builder(String relationId) {
         ConfigureBuilder builder = Configure.builder();
-        RenderPolicy policy = this.indicatorsRenderPolicyToProtobuf(true);
+        RenderPolicy policy = this.indicatorsRenderPolicyToProtobuf();
         builder.bind("userTasks", policy);
         builder.bind("tasks", policy);
         builder.bind("meetingList", policy);

+ 1 - 1
easier-report-biz/src/main/java/com/yaoyicloud/render/cso/EntPromotionSummaryRender.java

@@ -102,7 +102,7 @@ public final class EntPromotionSummaryRender extends CSOAbstractRender {
         builder.bind("task_promotion_count_5_1_1", twoLevelTableDynamicPolicy);
         builder.bind("task_promotion_count_5_1_1_last", lastRowDaynamicPolicy);
         builder.bind("task_promotioner_5_4", tableDynamicPolicy);
-        builder.bind("task_promotioner_quality_5_4_1", this.indicatorsRenderPolicyToProtobuf(true));
+        builder.bind("task_promotioner_quality_5_4_1", this.indicatorsRenderPolicyToProtobuf());
         builder.bind("task_promotioner_quality_5_4_1_last", lastRowDaynamicPolicy);
         return builder;
     }

+ 7 - 9
easier-report-biz/src/main/java/com/yaoyicloud/render/platform/AttachmentSectionRender.java

@@ -27,6 +27,7 @@ import org.apache.commons.collections4.MapUtils;
 public final class AttachmentSectionRender extends FXYAbstractRender {
     private final FilerepoProperties filerepoProperties;
     private final CommonDataCache commonDataCache;
+
     public AttachmentSectionRender(String cwd, FilerepoProperties filerepoProperties, CommonDataCache commonDataCache) {
         super(cwd);
         this.filerepoProperties = filerepoProperties;
@@ -42,8 +43,8 @@ public final class AttachmentSectionRender extends FXYAbstractRender {
 
         FxyProtos.AttachmentSection defaultInstance = FxyProtos.AttachmentSection.getDefaultInstance();
         FxyProtos.AttachmentSection mergedProto = defaultInstance.toBuilder()
-                .mergeFrom(attachmentSection.build())
-                .build();
+            .mergeFrom(attachmentSection.build())
+            .build();
 
         Map<String, Object> newAddtionMap = new HashMap<>();
         Descriptors.Descriptor descriptor = mergedProto.getDescriptorForType();
@@ -57,8 +58,8 @@ public final class AttachmentSectionRender extends FXYAbstractRender {
         }
 
         String completeJson = JsonFormat.printer()
-                .includingDefaultValueFields()
-                .print(mergedProto);
+            .includingDefaultValueFields()
+            .print(mergedProto);
         ObjectMapper objectMapper = new ObjectMapper();
         Map<String, Object> data = objectMapper.readValue(completeJson, new TypeReference<Map<String, Object>>() {});
         if (newAddtionMap != null) {
@@ -77,8 +78,8 @@ public final class AttachmentSectionRender extends FXYAbstractRender {
     protected ConfigureBuilder builder(String relationId) {
         // 配置POI-TL渲染器
         ConfigureBuilder builder = Configure.builder();
-        builder.addPlugin('^',  this.pictureRenderPolicy());
-        builder.addPlugin('`',  this.hyperlinkRenderPolicy());
+        builder.addPlugin('^', this.pictureRenderPolicy());
+        builder.addPlugin('`', this.hyperlinkRenderPolicy());
         return builder;
     }
 
@@ -92,8 +93,6 @@ public final class AttachmentSectionRender extends FXYAbstractRender {
         return filerepoProperties.getReportImagePath();
     }
 
-
-
     /**
      * 填充默认值,确保所有必要字段都存在
      */
@@ -107,5 +106,4 @@ public final class AttachmentSectionRender extends FXYAbstractRender {
 
     }
 
-
 }

+ 16 - 0
easier-report-biz/src/main/java/com/yaoyicloud/render/platform/update/BusinessRender.java

@@ -4,6 +4,9 @@ import java.io.IOException;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
 import com.deepoove.poi.config.Configure;
 import com.deepoove.poi.config.ConfigureBuilder;
 import com.deepoove.poi.policy.RenderPolicy;
@@ -126,6 +129,19 @@ public final class BusinessRender extends FXYAbstractRender {
         processJsonData(data, "sameaddress");
         processJsonData(data, "samecontactNumberDatas");
         processJsonData(data, "sameExecutivesNames");
+
+        List<Map<String, Object>> sameExecutivesNames = (List<Map<String, Object>>) data.get("sameExecutivesNames");
+
+        if (CollectionUtils.isNotEmpty(sameExecutivesNames)) {
+            Map<Object, Long> nameCountMap = sameExecutivesNames.stream()
+                .map(item -> item.get("name"))
+                .filter(Objects::nonNull)
+                .collect(Collectors.groupingBy(name -> name, Collectors.counting()));
+
+            int size = nameCountMap.size();
+            data.put("sameNameSize", size);
+        }
+        data.put("sameNameSize", 0);
     }
 
     private void fillCommonDataCacheData(Map<String, Object> data, String relationId) {

+ 1 - 1
easier-report-biz/src/main/java/com/yaoyicloud/render/platform/update/JudicialRender.java

@@ -86,7 +86,7 @@ public final class JudicialRender extends FXYAbstractRender {
     protected ConfigureBuilder builder(String relationId) {
         // 配置POI-TL渲染器
         ConfigureBuilder builder = Configure.builder();
-        RenderPolicy indicatorsRenderPolicy = this.indicatorsRenderPolicyToProtobuf(true);
+        RenderPolicy indicatorsRenderPolicy = this.indicatorsRenderPolicyToProtobuf();
         Map<String, Object> commonDataCacheData = commonDataCache.getData(relationId);
         builder.bind("dishonestPersons",
             this.addDefaultRowForEmptyTable((Boolean) commonDataCacheData.get("dishonest_person_error_flag")));

+ 8 - 4
easier-report-biz/src/main/java/com/yaoyicloud/render/platform/update/OperationalRender.java

@@ -73,8 +73,7 @@ public final class OperationalRender extends FXYAbstractRender {
         builder.bind("indicators", new LoopRowIncludeStatisticsTableRenderPolicy("values"));
         builder.bind("financialDataSeq", new LoopColumnStaticTableRenderPolicy("[", "]", false, true, 2));
         builder.bind("financialCheckDetails", new LoopRowCutAndMergeFirstColTableRenderPolicy());
-        builder.bind("businessRiskChecks", this
-            .indicatorsRenderPolicyToProtobuf((Boolean) commonDataCache.getDataItem(relationId, "financialInfo_flag")));
+        builder.bind("businessRiskChecks", this.indicatorsRenderPolicyToProtobuf());
         return builder;
     }
 
@@ -96,7 +95,6 @@ public final class OperationalRender extends FXYAbstractRender {
             financialFlag = true;
         }
         data.put("financialInfo_flag", financialFlag);
-        commonDataCache.insertData(relationId, "financialInfo_flag", financialFlag);
 
         Integer index = 1;
         Map<String, Object> operationalMap = new HashMap<>();
@@ -123,20 +121,26 @@ public final class OperationalRender extends FXYAbstractRender {
 
         Map<String, Object> financialSummary = (Map<String, Object>) data.get("financialSummary");
         financialSummary.replaceAll((k, v) -> v.equals("") ? "-" : v);
-
+        data.put("certReceived_source", "(自主申报)");
+        data.put("bankLicense_source", "(自主申报)");
+        data.put("annualInspectionResult_source", "(自主申报)");
+        data.put("financialDataSeqFlag_source", "(授权)");
         Object certReceived = data.get("certReceived");
         if (Objects.equals(certReceived, "-")) {
             data.put("certReceived", "否");
+            data.put("certReceived_source", "");
         }
 
         Object bankLicense = data.get("bankLicense");
         if (Objects.equals(bankLicense, "-")) {
             data.put("bankLicense", "否");
+            data.put("bankLicense_source", "");
         }
 
         Object annualInspectionResult = data.get("annualInspectionResult");
         if (Objects.equals(annualInspectionResult, "-")) {
             data.put("annualInspectionResult", "否");
+            data.put("annualInspectionResult_source", "");
         }
 
         List<Map<String, Object>> financialDataSeq = (List<Map<String, Object>>) data.get("financialDataSeq");

+ 38 - 10
easier-report-biz/src/main/java/com/yaoyicloud/render/platform/update/OtherRender.java

@@ -1,7 +1,6 @@
 package com.yaoyicloud.render.platform.update;
 
 import java.io.IOException;
-
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -15,7 +14,6 @@ import com.yaoyicloud.config.CommonDataCache;
 import com.yaoyicloud.config.FilerepoProperties;
 import com.yaoyicloud.factory.FXYAbstractRender;
 import com.yaoyicloud.message.FxyProtos;
-
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.collections4.MapUtils;
@@ -59,6 +57,7 @@ public final class OtherRender extends FXYAbstractRender {
 
         ObjectMapper objectMapper = new ObjectMapper();
         Map<String, Object> data = objectMapper.readValue(completeJson, new TypeReference<Map<String, Object>>() {});
+
         Map<String, Object> commonDataCacheData = commonDataCache.getData(relationId);
         if (MapUtils.isNotEmpty(commonDataCacheData)) {
             data.putAll(commonDataCacheData);
@@ -74,6 +73,15 @@ public final class OtherRender extends FXYAbstractRender {
         Map<String, Object> otherMap = new HashMap<>();
         commonDataCache.insertData(relationId, "integrity_guarantee_flag", false);
         data.put("relatedEntityImage_flag", false);
+
+        data.put("files_flag", false);
+
+        data.put("questionnaireItems_flag", false);
+
+        data.put("questionnaireItemsTable_flag", false);
+
+        data.put("questionnairs_flag", false);
+
         List<Map<String, Object>> otherRiskChecks = (List<Map<String, Object>>) data.get("otherRiskChecks");
 
         if (CollectionUtils.isEmpty(otherRiskChecks)) {
@@ -84,18 +92,40 @@ public final class OtherRender extends FXYAbstractRender {
                 if (category == null) {
                     continue;
                 }
-
                 switch (category) {
-                    case "interest_conflict_questionnaire":
-
+                    case "interest_conflict":
                         index++;
                         otherMap.put("relatedEntityImage", index.toString());
                         data.put("relatedEntityImage_flag", true);
                         break;
                     case "integrity_guarantee":
                         index++;
+                        data.put("questionnaireItems_flag", true);
+                        List<Map<String, Object>> questionnaireItems =
+                            (List<Map<String, Object>>) data.get("questionnaireItems");
+                        if (CollectionUtils.isNotEmpty(questionnaireItems)) {
+                            data.put("questionnaireItemsTable_flag", true);
+                        }
+
+                        Object o = data.get("questionnairs");
+                        if (o != null) {
+                            data.put("questionnairs_flag", true);
+                        }
+
                         otherMap.put("questionnaireItems", index.toString());
-                        commonDataCache.insertData(relationId, "integrity_guarantee_flag", true);
+                        break;
+                    case "project_information":
+                        index++;
+                        otherMap.put("files", index.toString());
+                        data.put("files_flag", true);
+                        List<Map<String, Object>> files =
+                            (List<Map<String, Object>>) data.get("files");
+                        if (CollectionUtils.isEmpty(files)) {
+                            data.put("filesAltText", "未上传");
+                        } else {
+                            data.put("filesAltText", "");
+                        }
+
                         break;
 
                     default:
@@ -113,10 +143,9 @@ public final class OtherRender extends FXYAbstractRender {
     protected ConfigureBuilder builder(String relationId) {
         // 配置POI-TL渲染器
         ConfigureBuilder builder = Configure.builder();
-        RenderPolicy indicatorsRenderPolicy = this.indicatorsRenderPolicyToProtobuf(true);
+        RenderPolicy indicatorsRenderPolicy = this.indicatorsRenderPolicyToProtobuf();
         Map<String, Object> commonDataCacheData = commonDataCache.getData(relationId);
-        builder.bind("questionnaireItems",
-            this.addDefaultRowForEmptyTable((Boolean) commonDataCacheData.get("integrity_guarantee_flag")));
+        builder.bind("questionnaireItems", indicatorsRenderPolicy);
         builder.bind("otherRiskChecks", indicatorsRenderPolicy);
         builder.addPlugin('^', this.pictureRenderPolicy());
         builder.useSpringEL();
@@ -131,7 +160,6 @@ public final class OtherRender extends FXYAbstractRender {
         summary.replaceAll((k, v) -> v.equals("") ? "-" : v);
 
         processJsonData(data, "questionnaireItems");
-
     }
 
 }

+ 1 - 1
easier-report-biz/src/main/java/com/yaoyicloud/render/platform/update/TaxRender.java

@@ -93,7 +93,7 @@ public final class TaxRender extends FXYAbstractRender {
     protected ConfigureBuilder builder(String relationId) {
         // 配置POI-TL渲染器
         ConfigureBuilder builder = Configure.builder();
-        RenderPolicy indicatorsRenderPolicy = this.indicatorsRenderPolicyToProtobuf(true);
+        RenderPolicy indicatorsRenderPolicy = this.indicatorsRenderPolicyToProtobuf();
         Map<String, Object> commonDataCacheData = commonDataCache.getData(relationId);
         builder.bind("taxPenalties",
             this.addDefaultRowForEmptyTable((Boolean) commonDataCacheData.get("tax_error_flag")));

+ 8 - 50
easier-report-biz/src/main/java/com/yaoyicloud/service/impl/FxyReportUpdateServiceImpl.java

@@ -15,11 +15,8 @@ import com.yaoyicloud.constant.enums.ModuleType;
 import com.yaoyicloud.easier.common.file.core.FileProperties;
 import com.yaoyicloud.easier.common.file.core.FileTemplate;
 import com.yaoyicloud.entity.ReportGenerationResult;
-
-import com.yaoyicloud.render.ServiceProviderInfoRender;
-
+import com.yaoyicloud.render.CoverRender;
 import com.yaoyicloud.render.platform.AttachmentSectionRender;
-
 import com.yaoyicloud.render.platform.update.OtherRender;
 import com.yaoyicloud.render.platform.update.BusinessRender;
 import com.yaoyicloud.render.platform.update.OperationalRender;
@@ -96,50 +93,27 @@ public class FxyReportUpdateServiceImpl implements ReportUpdateService {
         String reportPath = null;
         String type = moduleType.getType();
         switch (moduleType) {
-//            case ANTIBRIBERY:
-//                reportPath = new AntiBriberyRender(sessionId, filerepoProperties, commonDataCache)
-//                    .createFXYDocument(data, inputStream, String.valueOf(relationId));
-//                break;
+
             case OTHER:
                 reportPath = new OtherRender(sessionId, filerepoProperties, commonDataCache)
                     .createFXYDocument(data, inputStream, String.valueOf(relationId), counter, type);
                 break;
-//            case PLATFORM_COMPANY_BASICINFO:
-//                reportPath = new BasicInfoRender(sessionId, filerepoProperties, commonDataCache)
-//                    .createFXYDocument(data, inputStream, String.valueOf(relationId));
-//                break;
+
             case PLATFORM_COMPANY_ATTACHMENTSECTION:
                 reportPath = new AttachmentSectionRender(sessionId, filerepoProperties, commonDataCache)
                     .createFXYDocument(data, inputStream, String.valueOf(relationId), counter, type);
                 break;
-//            case ASSOCIATION_ATTACHMENTSECTION:
-//                reportPath = new AssociationAttachmentSectionRender(sessionId, filerepoProperties, commonDataCache)
-//                    .createFXYDocument(data, inputStream, String.valueOf(relationId));
-//                break;
-//            case FOUNDATION_ATTACHMENTSECTION:
-//                reportPath = new FoundationAttachmentSectionRender(sessionId, filerepoProperties, commonDataCache)
-//                    .createFXYDocument(data, inputStream, String.valueOf(relationId));
-//                break;
-            case COMMON:
-                reportPath = new ServiceProviderInfoRender(sessionId, filerepoProperties, commonDataCache)
+
+            case COVER:
+                reportPath = new CoverRender(sessionId, filerepoProperties, commonDataCache)
                     .createFXYDocument(data, inputStream, String.valueOf(relationId), counter, type);
                 break;
-//            case PLATFORM_COMPANY_FINANCIALINFO:
-//                reportPath = new FinancialInfoRender(sessionId, filerepoProperties, commonDataCache)
-//                    .createFXYDocument(data, inputStream, String.valueOf(relationId));
-//                break;
+
             case OPERATIONAL:
                 reportPath = new OperationalRender(sessionId, filerepoProperties, commonDataCache)
                     .createFXYDocument(data, inputStream, String.valueOf(relationId), counter, type);
                 break;
-//            case FOUNDATION_FINANCIALINFO:
-//                reportPath = new FoundationfinancialInfoRender(sessionId, filerepoProperties, commonDataCache)
-//                    .createFXYDocument(data, inputStream, String.valueOf(relationId));
-//                break;
-//            case PUBLIC_RECORD:
-//                reportPath = new PublicRecordRender(sessionId, filerepoProperties, commonDataCache)
-//                    .createFXYDocument(data, inputStream, String.valueOf(relationId));
-//                break;
+
             case JUDICIAL:
                 reportPath = new JudicialRender(sessionId, filerepoProperties, commonDataCache)
                     .createFXYDocument(data, inputStream, String.valueOf(relationId), counter, type);
@@ -148,22 +122,6 @@ public class FxyReportUpdateServiceImpl implements ReportUpdateService {
                 reportPath = new BusinessRender(sessionId, filerepoProperties, commonDataCache)
                     .createFXYDocument(data, inputStream, String.valueOf(relationId), counter, type);
                 break;
-//            case FOUNDATION_BASICINFO:
-//                reportPath = new FoundationBasicInfoRender(sessionId, filerepoProperties, commonDataCache)
-//                    .createFXYDocument(data, inputStream, String.valueOf(relationId));
-//                break;
-//            case ASSOCIATION_BASICINFO:
-//                reportPath = new AssociationBasicInfoRender(sessionId, filerepoProperties, commonDataCache)
-//                    .createFXYDocument(data, inputStream, String.valueOf(relationId));
-//                break;
-//            case PROJECT:
-//                reportPath = new ProjectInfoRender(sessionId, filerepoProperties, commonDataCache)
-//                    .createFXYDocument(data, inputStream, String.valueOf(relationId));
-//                break;
-//            case INTERESTCONFLICTS:
-//                reportPath = new InterestConflictsRender(sessionId, filerepoProperties, commonDataCache)
-//                    .createFXYDocument(data, inputStream, String.valueOf(relationId));
-//                break;
             case TAX:
                 reportPath = new TaxRender(sessionId, filerepoProperties, commonDataCache)
                     .createFXYDocument(data, inputStream, String.valueOf(relationId), counter, type);

+ 2 - 3
easier-report-biz/src/main/java/com/yaoyicloud/template/AbstractReportExporter.java

@@ -141,7 +141,6 @@ public abstract class AbstractReportExporter  implements ReportDataProcessor {
                         entry -> entry.getValue() != null ? entry.getValue() : "-"
                 ));
         this.renderTemplate(reportTempWordFile, templatePath, builder, processedData);
-        String imagePath = this.imagePath();
         // word转pdf
         String html = OfficeUtil.convert(reportTempWordFile, reportImagePath);
         try (BufferedWriter writer2 = new BufferedWriter(new FileWriter("1.html"))) {
@@ -157,7 +156,7 @@ public abstract class AbstractReportExporter  implements ReportDataProcessor {
             System.err.println("写入 2.html 文件时发生错误: " + e.getMessage());
             e.printStackTrace();
         }
-        OfficeUtil.convertHtmlToPdf(html1, reportBastPath, getFontPaths(), imagePath, true);
+        OfficeUtil.convertHtmlToPdf(html1, reportBastPath, getFontPaths(), reportImagePath, true);
         String html2 = OfficeUtil.formatHtml(html);
 
         try (BufferedWriter writer2 = new BufferedWriter(new FileWriter("3.html"))) {
@@ -166,7 +165,7 @@ public abstract class AbstractReportExporter  implements ReportDataProcessor {
             System.err.println("写入 3.html 文件时发生错误: " + e.getMessage());
             e.printStackTrace();
         }
-        return OfficeUtil.convertHtmlToPdf(html2, reportBastPath, getFontPaths(), imagePath,  false);
+        return OfficeUtil.convertHtmlToPdf(html2, reportBastPath, getFontPaths(), reportImagePath,  false);
     }
 
     protected abstract String getReportImagePath();

+ 76 - 107
easier-report-biz/src/main/java/com/yaoyicloud/tools/DocxUtil.java

@@ -1,12 +1,14 @@
 package com.yaoyicloud.tools;
 
+import java.io.BufferedWriter;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
+import java.io.FileWriter;
 import java.io.IOException;
-import java.util.HashMap;
+import java.util.Arrays;
 import java.util.List;
-import java.util.Map;
-
+import com.yaoyicloud.config.FilerepoProperties;
+import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
 import org.apache.poi.xwpf.usermodel.IBodyElement;
@@ -15,22 +17,85 @@ import org.apache.poi.xwpf.usermodel.XWPFParagraph;
 import org.apache.poi.xwpf.usermodel.XWPFPicture;
 import org.apache.poi.xwpf.usermodel.XWPFPictureData;
 import org.apache.poi.xwpf.usermodel.XWPFRun;
-import org.apache.poi.xwpf.usermodel.XWPFStyle;
-import org.apache.poi.xwpf.usermodel.XWPFStyles;
 import org.apache.poi.xwpf.usermodel.XWPFTable;
-import org.apache.poi.xwpf.usermodel.XWPFTableCell;
-import org.apache.poi.xwpf.usermodel.XWPFTableRow;
 import org.openxmlformats.schemas.drawingml.x2006.main.CTBlip;
 import org.openxmlformats.schemas.drawingml.x2006.main.CTBlipFillProperties;
 import org.openxmlformats.schemas.drawingml.x2006.picture.CTPicture;
-import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTStyle;
-import org.openxmlformats.schemas.wordprocessingml.x2006.main.STStyleType;
 
 import com.deepoove.poi.xwpf.XWPFStructuredDocumentTag;
+import org.springframework.stereotype.Component;
 
-
+@Component
 @Slf4j
+@RequiredArgsConstructor
 public final class DocxUtil {
+    private final FilerepoProperties filerepoProperties;
+
+    /**
+     *
+     * @return 获取图片文件夹路径
+     */
+    private String imagePath() {
+        return filerepoProperties.getReportImagePath();
+    }
+
+    /**
+     *
+     * @return 获取文档转换时所需字体列表
+     */
+    private List<String> getFontPaths() {
+        return Arrays.asList(
+            filerepoProperties.getSourceHanSansCnFontMediumPath());
+    }
+
+    private String getReportImagePath() {
+        return filerepoProperties.getReportImagePath();
+    }
+
+    /**
+     * 将Word文件转换为PDF文件
+     * @param reportTempWordFile 待转换的Word文件路径(.docx格式)
+     * @return 转换后最终的PDF文件路径
+     * @throws Exception 转换过程中发生的异常(如文件操作、格式转换错误等)
+     */
+    public  String wordToPdf(String reportTempWordFile) throws Exception {
+        String imagePath = this.imagePath();
+        String reportImagePath = this.getReportImagePath();
+        // 第一步:将Word文件转换为HTML字符串,同时提取图片到reportImagePath
+        // (OfficeUtil.convert内部实现Word到HTML的转换,包含文本、图片等元素的解析)
+        String html = OfficeUtil.convert(reportTempWordFile, reportImagePath);
+        try (BufferedWriter writer2 = new BufferedWriter(new FileWriter("1.html"))) {
+            writer2.write(html);
+        } catch (IOException e) {
+            System.err.println("写入 1.html 文件时发生错误: " + e.getMessage());
+            e.printStackTrace();
+        }
+        // 第二步:对原始HTML进行格式化处理(如修复标签、调整样式等,确保后续PDF转换兼容)
+        String html1 = OfficeUtil.formatHtml(html);
+        try (BufferedWriter writer2 = new BufferedWriter(new FileWriter("2.html"))) {
+            writer2.write(html1);
+        } catch (IOException e) {
+            System.err.println("写入 2.html 文件时发生错误: " + e.getMessage());
+            e.printStackTrace();
+        }
+        // 生成PDF文件路径:与原Word文件同目录、同名,仅替换扩展名为.pdf
+        String reportBastPath = reportTempWordFile.replace(".docx", ".pdf");
+
+        // 第三步:使用格式化后的html1生成PDF(可能是带水印或中间状态的PDF)
+        // (getFontPaths()获取字体路径列表,确保PDF中文字正常显示;flag为true表示首次转换,处理目录)
+        OfficeUtil.convertHtmlToPdf(html1, reportBastPath, getFontPaths(), imagePath, true);
+
+        // 再次对原始HTML进行格式化
+        String html2 = OfficeUtil.formatHtml(html);
+        try (BufferedWriter writer2 = new BufferedWriter(new FileWriter("3.html"))) {
+            writer2.write(html2);
+        } catch (IOException e) {
+            System.err.println("写入 3.html 文件时发生错误: " + e.getMessage());
+            e.printStackTrace();
+        }
+        // 第四步:使用第二次格式化后的html2生成最终PDF(flag为false可能表示最终转换,
+        return OfficeUtil.convertHtmlToPdf(html2, reportBastPath, getFontPaths(), imagePath, false);
+    }
 
     public static void mergeDocx(XWPFDocument target, List<XWPFDocument> sources, String outputPath, Long relationId)
         throws InvalidFormatException, FileNotFoundException, IOException {
@@ -39,7 +104,7 @@ public final class DocxUtil {
     }
 
     public static void mergeDocx(XWPFDocument target, List<XWPFDocument> sources, String outputPath,
-        boolean clearTargetBody) throws InvalidFormatException, FileNotFoundException, IOException {
+                                 boolean clearTargetBody) throws InvalidFormatException, FileNotFoundException, IOException {
         if (clearTargetBody) {
             target.getDocument().unsetBody();
             target.getDocument().addNewBody();
@@ -48,13 +113,6 @@ public final class DocxUtil {
         // 2. 处理每个源文档的样式并合并
         for (int i = 0; i < sources.size(); i++) {
             XWPFDocument source = sources.get(i);
-            String sourcePrefix = "source" + (i + 1) + "_"; // 动态生成前缀:source1_, source2_等
-
-            // 为源文档样式添加带序号的前缀
-            prefixStyles(source, sourcePrefix);
-
-            // 合并样式表
-            mergeStyles(target, source, sourcePrefix);
 
             // 合并内容
             appendSourceContent(target, source);
@@ -66,95 +124,6 @@ public final class DocxUtil {
         log.info("文档合并成功,文档路径为:{}", outputPath);
     }
 
-    private static void prefixStyles(XWPFDocument doc, String prefix) {
-        XWPFStyles styles = doc.getStyles();
-        if (styles == null) {
-            return;
-        }
-
-        // 创建一个样式ID映射表
-        Map<String, String> styleIdMap = new HashMap<>();
-
-        // 处理所有样式
-        for (XWPFStyle style : styles.getStyles()) {
-            String oldId = style.getStyleId();
-            if (oldId != null && !oldId.startsWith(prefix)) {
-                String newId = prefix + oldId;
-                styleIdMap.put(oldId, newId);
-                style.setStyleId(newId);
-            }
-        }
-
-        // 更新文档中所有引用了样式的段落和表格
-        updateStyleReferences(doc, styleIdMap);
-    }
-
-    @SuppressWarnings("checkstyle:NestedForDepth")
-    private static void updateStyleReferences(XWPFDocument doc, Map<String, String> styleIdMap) {
-        // 更新段落样式引用
-        for (XWPFParagraph p : doc.getParagraphs()) {
-            String styleId = p.getStyleID();
-            if (styleId != null && styleIdMap.containsKey(styleId)) {
-                p.setStyle(styleIdMap.get(styleId));
-            }
-        }
-
-        // 更新表格样式引用
-        for (XWPFTable table : doc.getTables()) {
-            String styleId = table.getStyleID();
-            if (styleId != null && styleIdMap.containsKey(styleId)) {
-                table.setStyleID(styleIdMap.get(styleId));
-            }
-
-            // 更新表格中的单元格样式
-            for (XWPFTableRow row : table.getRows()) {
-                for (XWPFTableCell cell : row.getTableCells()) {
-                    for (XWPFParagraph p : cell.getParagraphs()) {
-                        String cellStyleId = p.getStyleID();
-                        if (cellStyleId != null && styleIdMap.containsKey(cellStyleId)) {
-                            p.setStyle(styleIdMap.get(cellStyleId));
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    private static void mergeStyles(XWPFDocument target, XWPFDocument source, String prefix) {
-        XWPFStyles targetStyles = target.getStyles();
-        XWPFStyles sourceStyles = source.getStyles();
-        if (sourceStyles == null) {
-            return;
-        }
-
-        // 确保目标文档有样式表
-        if (targetStyles == null) {
-            target.createStyles();
-            targetStyles = target.getStyles();
-        }
-
-        // 遍历源文档的所有样式
-        for (XWPFStyle sourceStyle : sourceStyles.getStyles()) {
-            // 获取原始样式ID和类型
-            String oldStyleId = sourceStyle.getStyleId();
-            STStyleType.Enum styleType = sourceStyle.getType();
-            if (oldStyleId == null || styleType == null) {
-                continue;
-            }
-
-            // 生成带前缀的新样式ID(如 "source1_1")
-            CTStyle copy = (CTStyle) sourceStyle.getCTStyle().copy();
-
-            // 1. 深拷贝源样式(包括所有XML属性)
-            XWPFStyle styleCopy = new XWPFStyle(copy, targetStyles);
-            styleCopy.setStyleId(oldStyleId);  // 更新ID
-
-            // 2. 直接添加整个样式对象(利用自定义的addStyle方法)
-            targetStyles.addStyle(styleCopy);  // 调用您提供的addStyle(XWPFStyle)
-
-        }
-    }
-
     private static void appendSourceContent(XWPFDocument target, XWPFDocument source) throws InvalidFormatException {
         if (!target.getBodyElements().isEmpty()) {
             insertPageBreak(target);

+ 185 - 219
easier-report-biz/src/main/java/com/yaoyicloud/tools/OfficeUtil.java

@@ -1,4 +1,5 @@
 package com.yaoyicloud.tools;
+
 import com.lowagie.text.Image;
 import com.lowagie.text.PageSize;
 import com.lowagie.text.pdf.BaseFont;
@@ -43,8 +44,17 @@ import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
 public class OfficeUtil {
-    private static final org.slf4j.Logger OFFICE_UTIL_LOGGER  = org.slf4j.LoggerFactory.getLogger(OfficeUtil.class);
+    private static final org.slf4j.Logger OFFICE_UTIL_LOGGER = org.slf4j.LoggerFactory.getLogger(OfficeUtil.class);
     private static Map<String, Integer> pageNumberMap = new LinkedHashMap<>();
+
+    /**
+     * 把word 转为html
+     * 
+     * @param docxPath word文档路径
+     * @param imageDir 图片文件夹路径
+     * @return
+     * @throws IOException
+     */
     public static String convert(String docxPath, String imageDir) throws IOException {
         File imageDirFile = new File(imageDir);
         if (!imageDirFile.exists() && !imageDirFile.mkdirs()) {
@@ -52,8 +62,8 @@ public class OfficeUtil {
         }
 
         try (InputStream docxIn = new FileInputStream(docxPath);
-             XWPFDocument document = new XWPFDocument(docxIn);
-             ByteArrayOutputStream htmlOut = new ByteArrayOutputStream()) {
+            XWPFDocument document = new XWPFDocument(docxIn);
+            ByteArrayOutputStream htmlOut = new ByteArrayOutputStream()) {
 
             // 1. 遍历所有表格,检查是否需要删除
             List<XWPFTable> tablesToRemove = new ArrayList<>();
@@ -78,16 +88,16 @@ public class OfficeUtil {
             };
 
             XHTMLOptions options = XHTMLOptions.create()
-                    .setImageManager(imageManager)
-                    .URIResolver(new FileURIResolver(imageDirFile) {
-                        @Override
-                        public String resolve(String uri) {
-                            String filename = uri.replace("word/media/", "");
-                            return new File(imageDirFile, filename)
-                                    .getAbsolutePath()
-                                    .replace("/", "\\");
-                        }
-                    });
+                .setImageManager(imageManager)
+                .URIResolver(new FileURIResolver(imageDirFile) {
+                    @Override
+                    public String resolve(String uri) {
+                        String filename = uri.replace("word/media/", "");
+                        return new File(imageDirFile, filename)
+                            .getAbsolutePath()
+                            .replace("/", "\\");
+                    }
+                });
             options.setIgnoreStylesIfUnused(false);
 
             XHTMLConverter.getInstance().convert(document, htmlOut, options);
@@ -148,30 +158,30 @@ public class OfficeUtil {
         }
 
         String baseCss =
-                 "@page {"
-                        + "  size: A4;"
-                        + "  @bottom-center {"
-                        + "    content: none;"  // 只显示数字页码
-                        + "  }"
-                        + "}"
-                        + "@page show-page-number {"
-                        + "  @bottom-center {"
-                        + "    content: counter(page);"
-                        + "    font-family: 思源黑体 Medium;"
-                        + "    font-size: 9pt;"
-                        + "    color: #000000;"
-                        + "  }"
-                        + "}"
-                        + // 为最后一个div设置页码显示并重置计数器
-                         ".start-counting {"
-                        + "  page: show-page-number;"
-                        + "}"
-                        + "td, th { "
-                        + "  page-break-inside: avoid; "  // 尽量保持单元格不分页
-                        + "  -fs-table-paginate: paginate; "  // 允许分页
-                        + "  background-clip: padding-box; "  // 确保背景色覆盖
-                        + "  -webkit-print-color-adjust: exact; "  // 确保打印时颜色准确
-                        + "}";
+            "@page {"
+                + "  size: A4;"
+                + "  @bottom-center {"
+                + "    content: none;" // 只显示数字页码
+                + "  }"
+                + "}"
+                + "@page show-page-number {"
+                + "  @bottom-center {"
+                + "    content: counter(page);"
+                + "    font-family: 思源黑体 Medium;"
+                + "    font-size: 9pt;"
+                + "    color: #000000;"
+                + "  }"
+                + "}"
+                + // 为最后一个div设置页码显示并重置计数器
+                ".start-counting {"
+                + "  page: show-page-number;"
+                + "}"
+                + "td, th { "
+                + "  page-break-inside: avoid; " // 尽量保持单元格不分页
+                + "  -fs-table-paginate: paginate; " // 允许分页
+                + "  background-clip: padding-box; " // 确保背景色覆盖
+                + "  -webkit-print-color-adjust: exact; " // 确保打印时颜色准确
+                + "}";
         Elements table = doc.select("table");
         String tbaleStyle = table.attr("style");
         tbaleStyle += "width:100%;";
@@ -186,44 +196,6 @@ public class OfficeUtil {
         }
         doc.head().appendElement("style").text(baseCss);
 
-//        int groupId = 0;
-//        for (Element row : doc.select("tr:has(td[rowspan], th[rowspan])")) {
-//            int rowspan = Integer.parseInt(row.select("[rowspan]").first().attr("rowspan"));
-//            row.attr("data-group-id", String.valueOf(groupId++));
-//
-//            // 标记被rowspan覆盖的行
-//            Element nextRow = row.nextElementSibling();
-//            for (int i = 1; i < rowspan && nextRow != null; i++) {
-//                nextRow.attr("data-group-child", "true");
-//                nextRow = nextRow.nextElementSibling();
-//            }
-//        }
-//
-//        doc.head().appendElement("style")
-//                .text("tr[data-group-id], tr[data-group-child] { "
-//                        + "page-break-inside: avoid !important; "
-//                        + "}");
-
-//        //合并单元格的处理
-//        Elements rowsWithRowspan = doc.select("tr:has(td[rowspan], th[rowspan])");
-//
-//        // 遍历所有包含合并单元格的行
-//        for (Element row : rowsWithRowspan) {
-//            // 找到合并单元格的跨行数
-//            int rowspan = Integer.parseInt(row.select("td[rowspan], th[rowspan]").first().attr("rowspan"));
-//
-//            // 创建新的 tbody 包裹当前行及后续受影响的行
-//            Element tbody = new Element("tbody").attr("style", "page-break-inside: avoid;  width: 100%;");
-//            for (int i = 0; i < rowspan; i++) {
-//                Element nextRow = row.nextElementSibling();
-//                row.before(tbody);
-//                tbody.appendChild(row);
-//                if (nextRow != null) {
-//                    row = nextRow; // 处理后续行
-//                }
-//            }
-//        }
-
         Elements tds = doc.select("td");
         for (Element td : tds) {
             Elements ps = td.select("p");
@@ -231,7 +203,7 @@ public class OfficeUtil {
                 String originalStyle = p.attr("style");
                 // 添加新样式,保留原有样式但覆盖冲突属性
                 String newStyle = "margin-left: 0.5em; margin-right: 0.5em; "
-                        + "line-height: 1.2; margin-top: 6px!important; margin-bottom: 6px!important; " + originalStyle;
+                    + "line-height: 1.2; margin-top: 6px!important; margin-bottom: 6px!important; " + originalStyle;
                 p.attr("style", newStyle);
             }
             if (ps.size() > 1) {
@@ -308,7 +280,7 @@ public class OfficeUtil {
 
         }
 
-        //二级标题上边距调整
+        // 二级标题上边距调整
         Elements secondaryHeadingStyle = doc.select("p.X1.X3");
         for (Element secondaryelement : secondaryHeadingStyle) {
 
@@ -318,16 +290,18 @@ public class OfficeUtil {
             } else {
                 secondarycurrentStyle += " margin-top: 13pt;";
             }
-            secondaryelement.attr("style",  secondarycurrentStyle + "line-height: 1.5; margin-bottom: 1pt; margin-left: 0.5em");
+            secondaryelement.attr("style",
+                secondarycurrentStyle + "line-height: 1.5; margin-bottom: 1pt; margin-left: 0.5em");
         }
 
-       //三级标题样式
+        // 三级标题样式
         Elements otherElements = doc.select("p.X1.X4");
         for (Element element : otherElements) {
             String style3 = element.attr("style");
-            element.attr("style",  style3 + "margin-top: 1pt !important; margin-bottom: 0pt  !important; margin-left: 0.5em");
+            element.attr("style",
+                style3 + "margin-top: 1pt !important; margin-bottom: 0pt  !important; margin-left: 0.5em");
         }
-        //六级标题样式
+        // 六级标题样式
         Elements select1 = doc.select("p.X1.X6");
         for (Element element : select1) {
             element.attr("style", element.attr("style") + "line-height: 1.5; margin-top: 5pt; margin-bottom: 5pt;");
@@ -336,16 +310,18 @@ public class OfficeUtil {
         for (Element element : select5) {
             element.attr("style", element.attr("style") + "line-height: 1.5; margin-top: 5pt; margin-bottom: 5pt;");
         }
-        //超链接
+        // 超链接
         Elements select9 = doc.select("p.X1.X9");
         for (Element element : select9) {
-            element.attr("style", element.attr("style") + "word-break: break-all; overflow-wrap: anywhere; max-width: 100%;");
+            element.attr("style",
+                element.attr("style") + "word-break: break-all; overflow-wrap: anywhere; max-width: 100%;");
         }
         Elements select8 = doc.select("p.X1.X8");
         for (Element element : select8) {
-            element.attr("style", element.attr("style") + "word-break: break-all; overflow-wrap: anywhere; max-width: 100%;");
+            element.attr("style",
+                element.attr("style") + "word-break: break-all; overflow-wrap: anywhere; max-width: 100%;");
         }
-        //1.3合并的单元格 不分页
+        // 1.3合并的单元格 不分页
         Elements select11 = doc.select("td.X10.X11");
         for (Element element : select11) {
             element.attr("style", element.attr("style") + "page-break-inside: avoid;");
@@ -359,8 +335,6 @@ public class OfficeUtil {
         return doc.html();
     }
 
-
-
     /**
      * 合并表格中相同内容的单元格
      *
@@ -401,7 +375,7 @@ public class OfficeUtil {
     }
 
     /**
-     *     移除 white-space:pre-wrap 并替换为 normal
+     * 移除 white-space:pre-wrap 并替换为 normal
      */
     private static String removeWhiteSpacePreWrap(String style) {
         if (style == null) {
@@ -415,98 +389,110 @@ public class OfficeUtil {
         }
         return style.trim();
     }
+
     /**
      * 添加目录
+     * 
      * @param doc
      */
     private static void addTableOfContents(Document doc) {
 
-            // 目录样式
-            String tocCss = ".toc-container { margin: 20px 0; font-family: 思源黑体 Medium; }"
-                    + ".toc-title { text-align: center; font-size: 12pt; margin-bottom: 15px; color: black; }"
-                    + ".toc-list { list-style-type: none; padding: 0; width: 100%; }"
-                    + ".toc-item { margin: 5px 0;     padding-top: 2px; padding-bottom: 2px;       line-height: 2;  }"
-                    + ".toc-level-1 { padding-left: 0; }"
-                    + ".toc-level-2 { padding-left: 2em; }"
-                    + ".toc-link { "
-                    + "  display: block; "
-                    + "  position: relative; "
-                    + "  color: black !important; "
-                    + "  text-decoration: none !important; "
-                    + "  line-height: 1.5; "  // 新增:控制整体行高
-                    + "}"
-                    + ".toc-line-container { "
-                    + "  display: table; "
-                    + "  width: 100%; "
-                    + "  vertical-align: middle; "  // 关键:控制容器内垂直对齐
-                    + "}"
-                    + ".toc-text { "
-                    + "  display: table-cell; "
-                    + "  font-size: 9pt; "
-                    + "  white-space: nowrap; "
-                    + "  padding-right: 5px; "
-                    + "  vertical-align: middle; "  // 改为middle对齐
-                    + "}"
-                    + ".toc-dots { "
-                    + "  display: table-cell; "
-                    + "  width: 100%; "
-                    + "  vertical-align: middle; "  // 关键:改为middle对齐
-                    + "  border-bottom: 1px dotted #000000; "
-                    + "  height: 1em; "  // 固定高度
-                    + "  margin-top: 2px; "  // 关键:正值下移,负值上移(按需调整)
-                    + "}"
-                    + "p.X1.X2 { -fs-pdf-bookmark: level 1; }"
-                    + "p.X1.X3 { -fs-pdf-bookmark: level 2; }"
-                    +  ".toc-page { "
-                    + "  display: table-cell; "
-                    + "  font-size: 9pt; "
-                    + "  white-space: nowrap; "
-                    + "  padding-left: 5px; "
-                    + "  vertical-align: middle; "  // 改为middle对齐
-                    + "}";
-            doc.head().appendElement("style").text(tocCss);
-
-            // 构建目录内容
-            Element tocList = new Element("ul").addClass("toc-list");
-            doc.select("p.X1.X2, p.X1.X3").forEach(el -> {
-                boolean isLevel1 = el.hasClass("X2");
-                String id = "sec_" + el.text().hashCode();
-                el.attr("id", id);
-                Integer pageNumber = pageNumberMap.getOrDefault(el.text(), 1);
-
-                Element li = tocList.appendElement("li")
-                        .addClass("toc-item " + (isLevel1 ? "toc-level-1" : "toc-level-2"));
-
-                Element link = li.appendElement("a")
-                        .attr("href", "#" + id)
-                        .addClass("toc-link");
-                Element lineContainer = link.appendElement("div").addClass("toc-line-container");
-                lineContainer.appendElement("span").addClass("toc-text").text(el.text());
-                lineContainer.appendElement("span").addClass("toc-dots");
-                lineContainer.appendElement("span").addClass("toc-page").text(String.valueOf(pageNumber));
-            });
-
-            // 插入目录
-            Element firstDiv = doc.select("div").first();
-            if (firstDiv != null) {
-                firstDiv.after(
-                        "<div class='toc-container' style='page-break-before: always;'>"
-                                + "<h1 class='toc-title'>目录</h1>"
-                                + tocList.outerHtml()
-                                + "</div>"
-                );
-            } else {
-                doc.body().prepend(
-                        "<div class='toc-container' style='page-break-before: always;'>"
-                                + "<h1 class='toc-title'>目录</h1>"
-                                + tocList.outerHtml()
-                                + "</div>"
-                );
-            }
+        // 目录样式
+        String tocCss = ".toc-container { margin: 20px 0; font-family: 思源黑体 Medium; }"
+            + ".toc-title { text-align: center; font-size: 12pt; margin-bottom: 15px; color: black; }"
+            + ".toc-list { list-style-type: none; padding: 0; width: 100%; }"
+            + ".toc-item { margin: 5px 0;     padding-top: 2px; padding-bottom: 2px;       line-height: 2;  }"
+            + ".toc-level-1 { padding-left: 0; }"
+            + ".toc-level-2 { padding-left: 2em; }"
+            + ".toc-link { "
+            + "  display: block; "
+            + "  position: relative; "
+            + "  color: black !important; "
+            + "  text-decoration: none !important; "
+            + "  line-height: 1.5; " // 新增:控制整体行高
+            + "}"
+            + ".toc-line-container { "
+            + "  display: table; "
+            + "  width: 100%; "
+            + "  vertical-align: middle; " // 关键:控制容器内垂直对齐
+            + "}"
+            + ".toc-text { "
+            + "  display: table-cell; "
+            + "  font-size: 9pt; "
+            + "  white-space: nowrap; "
+            + "  padding-right: 5px; "
+            + "  vertical-align: middle; " // 改为middle对齐
+            + "}"
+            + ".toc-dots { "
+            + "  display: table-cell; "
+            + "  width: 100%; "
+            + "  vertical-align: middle; " // 关键:改为middle对齐
+            + "  border-bottom: 1px dotted #000000; "
+            + "  height: 1em; " // 固定高度
+            + "  margin-top: 2px; " // 关键:正值下移,负值上移(按需调整)
+            + "}"
+            + "p.X1.X2 { -fs-pdf-bookmark: level 1; }"
+            + "p.X1.X3 { -fs-pdf-bookmark: level 2; }"
+            + ".toc-page { "
+            + "  display: table-cell; "
+            + "  font-size: 9pt; "
+            + "  white-space: nowrap; "
+            + "  padding-left: 5px; "
+            + "  vertical-align: middle; " // 改为middle对齐
+            + "}";
+        doc.head().appendElement("style").text(tocCss);
+
+        // 构建目录内容
+        Element tocList = new Element("ul").addClass("toc-list");
+        doc.select("p.X1.X2, p.X1.X3").forEach(el -> {
+            boolean isLevel1 = el.hasClass("X2");
+            String id = "sec_" + el.text().hashCode();
+            el.attr("id", id);
+            Integer pageNumber = pageNumberMap.getOrDefault(el.text(), 1);
+
+            Element li = tocList.appendElement("li")
+                .addClass("toc-item " + (isLevel1 ? "toc-level-1" : "toc-level-2"));
+
+            Element link = li.appendElement("a")
+                .attr("href", "#" + id)
+                .addClass("toc-link");
+            Element lineContainer = link.appendElement("div").addClass("toc-line-container");
+            lineContainer.appendElement("span").addClass("toc-text").text(el.text());
+            lineContainer.appendElement("span").addClass("toc-dots");
+            lineContainer.appendElement("span").addClass("toc-page").text(String.valueOf(pageNumber));
+        });
+
+        // 插入目录
+        Element firstDiv = doc.select("div").first();
+        if (firstDiv != null) {
+            firstDiv.after(
+                "<div class='toc-container' style='page-break-before: always;'>"
+                    + "<h1 class='toc-title'>目录</h1>"
+                    + tocList.outerHtml()
+                    + "</div>");
+        } else {
+            doc.body().prepend(
+                "<div class='toc-container' style='page-break-before: always;'>"
+                    + "<h1 class='toc-title'>目录</h1>"
+                    + tocList.outerHtml()
+                    + "</div>");
+        }
 
     }
 
-    public static String convertHtmlToPdf(String html, String outputPdfPath, List<String> fontPaths, String imagePath, boolean flag) throws Exception {
+    /**
+     * 将 HTML 内容转换为 PDF 文件
+     * 
+     * @param html 要转换的 HTML 字符串内容
+     * @param outputPdfPath 生成 PDF 文件的输出路径
+     * @param fontPaths 字体文件路径列表,用于解决 PDF 中文显示等字体问题
+     * @param imagePath 图片相关路径,用于后续 PDF 处理(如添加水印等操作)
+     * @param flag 标志位,用于控制后续 PDF 处理的逻辑(如是否添加特定内容等)
+     * @return 处理后最终的 PDF 文件路径
+     * @throws Exception 转换过程中出现异常时抛出
+     */
+    public static String convertHtmlToPdf(String html, String outputPdfPath, List<String> fontPaths, String imagePath,
+        boolean flag) throws Exception {
         try (OutputStream os = new FileOutputStream(outputPdfPath)) {
             ITextRenderer renderer = new ITextRenderer();
             ITextFontResolver fontResolver = renderer.getFontResolver();
@@ -524,21 +510,19 @@ public class OfficeUtil {
             }
             // 字体路径
             fontResolver.addFont(
-                    mediumFont,
-                    "思源黑体 Medium",
-                    BaseFont.IDENTITY_H,
-                    true,
-                    null
-            );
+                mediumFont,
+                "思源黑体 Medium",
+                BaseFont.IDENTITY_H,
+                true,
+                null);
             fontResolver.addFont(
-                    mediumFont,
-                    "Arial",
-                    BaseFont.IDENTITY_H,
-                    true,
-                    null
-            );
+                mediumFont,
+                "Arial",
+                BaseFont.IDENTITY_H,
+                true,
+                null);
             html = html.replace("C:\\", "file:///C:/")
-                    .replace("\\", "/");
+                .replace("\\", "/");
             // 设置HTML(确保CSS中使用相同的font-family)
             renderer.setDocumentFromString(html, "file:///");
             // 渲染PDF
@@ -561,22 +545,23 @@ public class OfficeUtil {
     }
 
     /**
-     *  操作已生成的pdf
-     * @param inputPdfPath   输入pdf
-     * @param outputPdfPath  输出pdf
-     * @param backgroundImagePath  图片文件夹位置
+     * 操作已生成的pdf
+     * 
+     * @param inputPdfPath 输入pdf
+     * @param outputPdfPath 输出pdf
+     * @param backgroundImagePath 图片文件夹位置
      * @param onlyCollectPageNumbers 是否是遍历目录获取标题位置
      * @throws Exception
      */
     private static void pdfReader(String inputPdfPath, String outputPdfPath,
-                                  String backgroundImagePath, boolean onlyCollectPageNumbers)
-            throws Exception {
+        String backgroundImagePath, boolean onlyCollectPageNumbers)
+        throws Exception {
         PdfReader reader = new PdfReader(inputPdfPath);
 
         PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(outputPdfPath));
         int startPage = 1;
         if (onlyCollectPageNumbers) {
-        pageNumberMap.clear();
+            pageNumberMap.clear();
             Pattern startPattern = Pattern.compile("^1\\.\\s+报告概述$");
 
             // 查找起始页
@@ -597,9 +582,8 @@ public class OfficeUtil {
 
             // 收集标题和页码
             Pattern titlePattern = Pattern.compile(
-                    "^((\\d+)\\.\\s+|(\\d+\\.\\d+)\\s+)([\\u4e00-\\u9fa5a-zA-Z0-9].*)$",
-                    Pattern.MULTILINE
-            );
+                "^((\\d+)\\.\\s+|(\\d+\\.\\d+)\\s+)([\\u4e00-\\u9fa5a-zA-Z0-9].*)$",
+                Pattern.MULTILINE);
             Pattern specialPattern = Pattern.compile("^重要声明\\s*[::]?\\s*(.*)$");
 
             for (int pageNum = startPage; pageNum <= reader.getNumberOfPages(); pageNum++) {
@@ -610,11 +594,11 @@ public class OfficeUtil {
                     if (line.isEmpty()) {
                         continue;
                     }
-                    if (line.startsWith("6.3 ISO体系认证证书或行业经营许可证")) {
+                    if (line.contains(".3 ISO体系认证证书或行业经营许可证")) {
                         String nextLine = (i + 1 < lines.length) ? lines[i + 1].trim() : "";
                         line = line + (nextLine.isEmpty() ? "" : nextLine);
                     }
-                    if (line.startsWith("7.8 机构管理层(法定代表人,理事长,秘书长)")) {
+                    if (line.contains(".8 机构管理层(法定代表人,理事长,秘书长)")) {
                         String nextLine = (i + 1 < lines.length) ? lines[i + 1].trim() : "";
                         line = line + (nextLine.isEmpty() ? "" : nextLine);
                     }
@@ -633,7 +617,7 @@ public class OfficeUtil {
                 }
             }
         }
-        //一级标题图形背景
+        // 一级标题图形背景
         Pattern firstLevelTitlePattern = Pattern.compile("^(\\d+)\\.\\s+([\\u4e00-\\u9fa5a-zA-Z].*)$");
         Set<Integer> styledPages = new HashSet<>();
         startPage = pageNumberMap.get("startPage");
@@ -662,9 +646,9 @@ public class OfficeUtil {
             underContent.saveState();
             underContent.setColorFill(new Color(210, 235, 255)); // 浅蓝色填充
             underContent.circle(
-                    xPos,
-                    yPos - 8,  // 圆形中心Y
-                    10         // 半径
+                xPos,
+                yPos - 8, // 圆形中心Y
+                10 // 半径
             );
             underContent.fill();
             underContent.restoreState();
@@ -680,7 +664,7 @@ public class OfficeUtil {
 
         }
 
-        //封面背景
+        // 封面背景
         PdfContentByte background = stamper.getUnderContent(1);
         Image image = Image.getInstance(backgroundImagePath);
         image.scaleAbsolute(PageSize.A4.getWidth(), PageSize.A4.getHeight());
@@ -690,22 +674,4 @@ public class OfficeUtil {
         stamper.close();
         reader.close();
     }
-
-//    private static boolean isTableNearBottom(PdfWriter writer, PdfPTable table, float bottom) {
-//        try {
-//            // 获取当前页面的剩余高度
-//            float remainingHeight = writer.getVerticalPosition(true) - bottom;
-//
-//            // 估算当前行高度
-//            float estimatedRowHeight = 30f;
-//            float estimatedTableHeight = table.getRows().size() * estimatedRowHeight;
-//
-//            // 如果剩余空间不足以容纳整个表格,则换页
-//            return remainingHeight < estimatedTableHeight;
-//        } catch (Exception e) {
-//            e.printStackTrace();
-//            return false;
-//        }
-//    }
-
 }

+ 8 - 0
easier-report-biz/src/main/java/com/yaoyicloud/tools/Util.java

@@ -46,6 +46,14 @@ public final class Util {
         }
     }
 
+    /**
+     * 简单合并表格中前N列的垂直单元格(按指定列的关键字分组合并)
+     * 功能:遍历表格行,根据指定列(keySeq)的关键字是否相同,将前N列的单元格进行垂直合并
+     *
+     * @param table   要处理的XWPF表格对象
+     * @param n       需要合并的前N列(例如n=2表示合并第0列和第1列)
+     * @param keySeq  用于判断是否合并的关键字所在列的索引(以此列的内容作为分组依据)
+     */
     public static void mergeFirstNColSimple(XWPFTable table, int n, int keySeq) {
         if (table.getNumberOfRows() < 1) {
             return;

+ 7 - 2
easier-report-biz/src/main/proto/fxy.proto

@@ -16,11 +16,13 @@ message CheckItemDetail {
   optional string result = 4;      //
   optional int64 score = 5;      //
   optional string reviewResult = 6; // 复核结果
-  optional int32 reviewScore = 7; // 复核评分
+ // optional int32 reviewScore = 7; // 复核评分
   optional string category = 8;
   optional int32 rank = 9;  // 展示排序
   optional string formula = 10; // 计算公式(如"公益支出/上年基金余额")
   optional string avg = 11; // 服务商数据(平均值/收入)
+  optional string reviewScore = 12; // 复核评分
+
 }
 
 message CheckItemScore {
@@ -30,9 +32,10 @@ message CheckItemScore {
 }
 
 message CheckSummary {
-  optional int32 score = 1; // ${基本信息评分及建议:基本信息总分}
+  // optional int32 score = 1; // ${基本信息评分及建议:基本信息总分}
   optional string riskSummary = 2; // ${基本信息评分及建议:风险综述}
   optional string suggestion = 3 ; // ${基本信息评分及建议:建议}
+  optional string score = 4; // ${基本信息评分及建议:基本信息总分}
 }
 
 message AuditResult {
@@ -306,5 +309,7 @@ message RiskModule{
   optional string updateSource = 12; //数据来源
   repeated CheckItemDetail taxInfoChecks = 13; // 税务风险
   map<string, string>  taxPenalties = 14; //税务处罚情况
+  repeated Attachment files = 15;  // 项目信息
+  repeated Attachment questionnairs = 16;  // 反贿赂反腐败诚信保证问卷图片
 
 }

+ 1 - 1
easier-report-biz/src/main/resources/application.yml

@@ -14,7 +14,7 @@ spring:
     host: 127.0.0.1
     port: 6379
     password: 8F4tJuQEgAE7MZyX
-  #  password: 123456
+   # password: 123456
     database: 10
   servlet:
     multipart:

File diff suppressed because it is too large
+ 7161 - 4683
logs/easier-report-biz/debug.log


Some files were not shown because too many files changed in this diff