Ver Fonte

build 模块化生成报告(老版)

mamingxu há 6 dias atrás
pai
commit
c5b274a889

+ 6 - 5
easier-report-api/src/main/java/com/yaoyicloud/constant/enums/ModuleType.java

@@ -22,7 +22,8 @@ public enum ModuleType {
 
     ANTIBRIBERY("ANTIBRIBERY", "反贿赂反腐败诚信保证"),
     COMMON("COMMON", "公共模块封面"),
-    PLATFORM_COMPANY_FinancialInfo("PLATFORM_COMPANY_FinancialInfo", "财务"),
+    PLATFORM_COMPANY_FINANCIALINFO("PLATFORM_COMPANY_FINANCIALINFO", "平台公司财务"),
+    FOUNDATION_FINANCIALINFO("FOUNDATION_FINANCIALINFO", "基金会财务"),
     PLATFORM_COMPANY_ATTACHMENTSECTION("PLATFORM_COMPANY_ATTACHMENTSECTION", "平台公司附件"),
     ASSOCIATION_ATTACHMENTSECTION("ASSOCIATION_ATTACHMENTSECTION", "学协会附件"),
     FOUNDATION_ATTACHMENTSECTION("FOUNDATION_ATTACHMENTSECTION", "基金会附件"),
@@ -30,10 +31,10 @@ public enum ModuleType {
 
 
 
-    PLATFORM_COMPANY_BASICINFO_NEW("PLATFORM_COMPANY_BASICINFO", "工商信息"),
-    ANTIBRIBERY_NEW("ANTIBRIBERY", "其他风险"),
-    PLATFORM_COMPANY_FinancialInfo_NEW("PLATFORM_COMPANY_FinancialInfo", "经营风险"),
-    PUBLIC_RECORD_NEW("PUBLIC_RECORD", "司法风险");
+    PLATFORM_COMPANY_BASICINFO_NEW("PLATFORM_COMPANY_BASICINFO_NEW", "工商信息"),
+    ANTIBRIBERY_NEW("ANTIBRIBERY_NEW", "其他风险"),
+    PLATFORM_COMPANY_FinancialInfo_NEW("PLATFORM_COMPANY_FinancialInfo_NEW", "经营风险"),
+    PUBLIC_RECORD_NEW("PUBLIC_RECORD_NEW", "司法风险");
     /**
      * 类型
      */

+ 10 - 2
easier-report-biz/src/main/java/com/yaoyicloud/render/AbstractRender.java

@@ -168,13 +168,14 @@ public abstract class AbstractRender {
 
     /**
      * 针对于protobuf传递来的数据处理
+     * 
      * @return
      */
     protected RenderPolicy indicatorsRenderPolicyToProtobuf() {
         return new LoopRowTableRenderPolicy() {
             @Override
             public void render(ElementTemplate eleTemplate, Object data, XWPFTemplate template) {
-                //获取模板中的变量如:[name]
+                // 获取模板中的变量如:[name]
                 ArrayList<String> strings = processElement(eleTemplate, data);
                 List<Map<String, Object>> processedData = null;
                 if (null != data && data instanceof Iterable) {
@@ -192,9 +193,9 @@ public abstract class AbstractRender {
                 super.render(eleTemplate, processedData, template);
             }
 
-
         };
     }
+
     @SuppressWarnings("checkstyle:NestedForDepth")
     private ArrayList<String> processElement(ElementTemplate eleTemplate, Object data) {
         RunTemplate runTemplate = (RunTemplate) eleTemplate;
@@ -232,6 +233,7 @@ public abstract class AbstractRender {
 
     /**
      * 针对于json格式全量传输数据的列表处理 将默认值null转为“-”
+     * 
      * @return
      */
     protected RenderPolicy indicatorsRenderPolicy() {
@@ -387,6 +389,11 @@ public abstract class AbstractRender {
         };
     }
 
+    /**
+     * 超链接列表策略
+     * 
+     * @return
+     */
     protected RenderPolicy hyperlinkRenderPolicy() {
         return new ParagraphRenderPolicy() {
             @Override
@@ -715,6 +722,7 @@ public abstract class AbstractRender {
                     if (hasPercentage) {
                         formattedAvg += "%"; // 添加百分号
                     }
+
                 }
 
                 row.put("avg", formattedAvg);

+ 3 - 3
easier-report-biz/src/main/java/com/yaoyicloud/render/association/AssociationAttachmentSectionRender.java

@@ -14,7 +14,7 @@ import com.google.protobuf.Descriptors;
 import com.google.protobuf.util.JsonFormat;
 import com.yaoyicloud.config.FilerepoProperties;
 import com.yaoyicloud.message.FxyProtos;
-import com.yaoyicloud.message.FxyProtos.AttachmentSection;
+
 import com.yaoyicloud.render.AbstractRender;
 
 import lombok.extern.slf4j.Slf4j;
@@ -92,10 +92,10 @@ public final class AssociationAttachmentSectionRender extends AbstractRender {
         try {
             // 渲染文档
             String resultPath = this.renderDocx(data, templateFileContent, builder, relationId, "attachmentSection");
-            log.info("渲染附件模块成功,文件路径: {}", resultPath);
+            log.info("渲染学协会附件模块成功,文件路径: {}", resultPath);
             return resultPath;
         } catch (Exception e) {
-            log.error("渲染附件模块失败,relationId: {}", relationId, e);
+            log.error("渲染学协会附件模块失败,relationId: {}", relationId, e);
             throw new IOException("文档渲染失败", e);
         }
     }

+ 117 - 0
easier-report-biz/src/main/java/com/yaoyicloud/render/foundation/FoundationAttachmentSectionRender.java

@@ -0,0 +1,117 @@
+package com.yaoyicloud.render.foundation;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.deepoove.poi.config.Configure;
+import com.deepoove.poi.config.ConfigureBuilder;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.protobuf.Descriptors;
+import com.google.protobuf.util.JsonFormat;
+import com.yaoyicloud.config.FilerepoProperties;
+import com.yaoyicloud.message.FxyProtos;
+import com.yaoyicloud.render.AbstractRender;
+
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * AttachmentSection渲染器
+ *
+ */
+@Slf4j
+public final class FoundationAttachmentSectionRender extends AbstractRender {
+    private final FilerepoProperties filerepoProperties;
+    public FoundationAttachmentSectionRender(String cwd, FilerepoProperties filerepoProperties) {
+        super(cwd);
+        this.filerepoProperties = filerepoProperties;
+    }
+    @Override
+    protected String getBasicPath() throws IOException {
+        return filerepoProperties.getBasePath();
+    }
+
+    @Override
+    protected String getReportImagePath() {
+        return filerepoProperties.getReportImagePath();
+    }
+
+    /**
+     * Docx 渲染
+     *
+     * @param info 数据
+     * @param templateFileContent 模板内容
+     * @return 本地文件目录
+     * @throws IOException
+     */
+
+    public String renderDocx(String info, Map<String, Object> addtionalMap, byte[] templateFileContent, String relationId) throws IOException {
+        log.info("开始渲染基金会附件模块,relationId: {}", relationId);
+
+        // 配置POI-TL渲染器
+        ConfigureBuilder builder = Configure.builder();
+        builder.addPlugin('^',  this.pictureRenderPolicy());
+        builder.addPlugin('`',  this.hyperlinkRenderPolicy());
+
+        FxyProtos.AssociationattachmentSection.Builder associationattachmentSection = FxyProtos.AssociationattachmentSection.newBuilder();
+        JsonFormat.parser().merge(info, associationattachmentSection);
+
+        FxyProtos.AssociationattachmentSection defaultInstance = FxyProtos.AssociationattachmentSection.getDefaultInstance();
+        FxyProtos.AssociationattachmentSection mergedProto = defaultInstance.toBuilder()
+                .mergeFrom(associationattachmentSection.build())
+                .build();
+
+        Map<String, Object> newAddtionMap = new HashMap<>();
+        Descriptors.Descriptor descriptor = mergedProto.getDescriptorForType();
+        for (Descriptors.FieldDescriptor field : descriptor.getFields()) {
+            if (field.isRepeated()) {
+                List<?> li = (List<?>) mergedProto.getField(field);
+                if (li.size() == 0) {
+                    newAddtionMap.put(field.getName() + "AltText", "未上传");
+                }
+            }
+        }
+
+        String completeJson = JsonFormat.printer()
+                .includingDefaultValueFields()
+                .print(mergedProto);
+        ObjectMapper objectMapper = new ObjectMapper();
+        Map<String, Object> data = objectMapper.readValue(completeJson, new TypeReference<Map<String, Object>>() {});
+        if (newAddtionMap != null) {
+            data.putAll(newAddtionMap);
+        }
+        if (addtionalMap != null) {
+            data.putAll(addtionalMap);
+        }
+
+        fillDefaultValues(data);
+        try {
+            // 渲染文档
+            String resultPath = this.renderDocx(data, templateFileContent, builder, relationId, "attachmentSection");
+            log.info("渲染基金会附件模块成功,文件路径: {}", resultPath);
+            return resultPath;
+        } catch (Exception e) {
+            log.error("渲染基金会附件模块失败,relationId: {}", relationId, e);
+            throw new IOException("文档渲染失败", e);
+        }
+    }
+
+
+    /**
+     * 填充默认值,确保所有必要字段都存在
+     */
+    private void fillDefaultValues(Map<String, Object> data) {
+
+        ArrayList<String> fillDeclLinks = (ArrayList) data.get("fillDeclLinks");
+        if (fillDeclLinks != null) {
+            data.put("fillDeclLinksExits", true);
+
+        }
+
+    }
+
+
+}

+ 1 - 0
easier-report-biz/src/main/java/com/yaoyicloud/render/foundation/FoundationBasicInfoRender.java

@@ -60,6 +60,7 @@ public final class FoundationBasicInfoRender extends AbstractRender {
         RenderPolicy indicatorsRenderPolicyToProtobuf = this.indicatorsRenderPolicyToProtobuf();
         builder.bind("basicInfoChecks", indicatorsRenderPolicyToProtobuf).bind("superiorAuthority", indicatorsRenderPolicyToProtobuf);
         builder.addPlugin('^', this.pictureRenderPolicy());
+        builder.useSpringEL();
         // 通过默认protobuf实例来填充不存在的key
         FxyProtos.BasicInfo.Builder basicInfoBuilder = FxyProtos.BasicInfo.newBuilder();
         JsonFormat.parser().merge(info, basicInfoBuilder);

+ 117 - 0
easier-report-biz/src/main/java/com/yaoyicloud/render/foundation/FoundationfinancialInfoRender.java

@@ -0,0 +1,117 @@
+package com.yaoyicloud.render.foundation;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+import com.deepoove.poi.config.Configure;
+import com.deepoove.poi.config.ConfigureBuilder;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.protobuf.util.JsonFormat;
+import com.yaoyicloud.config.FilerepoProperties;
+import com.yaoyicloud.message.FxyProtos;
+import com.yaoyicloud.render.AbstractRender;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
+
+
+/**
+ * FinancialInfo渲染器
+ *
+ */
+@Slf4j
+public final class FoundationfinancialInfoRender extends AbstractRender {
+    private final FilerepoProperties filerepoProperties;
+    public FoundationfinancialInfoRender(String cwd, FilerepoProperties filerepoProperties) {
+        super(cwd);
+        this.filerepoProperties = filerepoProperties;
+    }
+    @Override
+    protected String getBasicPath() throws IOException {
+        return filerepoProperties.getBasePath();
+    }
+
+    @Override
+    protected String getReportImagePath() {
+        return filerepoProperties.getReportImagePath();
+    }
+
+    /**
+     * Docx 渲染
+     *
+     * @param info 数据
+     * @param templateFileContent 模板内容
+     * @return 本地文件目录
+     * @throws IOException
+     */
+
+    public String renderDocx(String info, Map<String, Object> addtionalMap, byte[] templateFileContent, String relationId) throws IOException {
+        log.info("开始渲染基金会财务模块,relationId: {}", relationId);
+
+        // 配置POI-TL渲染器
+        ConfigureBuilder builder = Configure.builder();
+        builder.useSpringEL();
+
+        builder.bind("indicators", new LoopRowIncludeStatisticsTableRenderPolicy("values"));
+        builder.bind("financialDataSeq", new LoopColumnStaticTableRenderPolicy("[", "]", false, true, 2));
+        builder.bind("financialCheckDetails", new LoopRowCutAndMergeFirstColTableRenderPolicy());
+        FxyProtos.FinancialInfo.Builder basicInfoBuilder = FxyProtos.FinancialInfo.newBuilder();
+        JsonFormat.parser().merge(info, basicInfoBuilder);
+
+        FxyProtos.FinancialInfo defaultInstance = FxyProtos.FinancialInfo.getDefaultInstance();
+        FxyProtos.FinancialInfo mergedProto = defaultInstance.toBuilder()
+                .mergeFrom(basicInfoBuilder.build())
+                .build();
+
+        String completeJson = JsonFormat.printer()
+                .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);
+
+        if (addtionalMap != null) {
+            data.putAll(addtionalMap);
+        }
+        fillBasicDefaultValues(data);
+
+        try {
+            // 渲染文档
+            String resultPath = this.renderDocx(data, templateFileContent, builder, relationId, "financialInfo");
+            log.info("渲染基金会财务模块成功,文件路径: {}", resultPath);
+            return resultPath;
+        } catch (Exception e) {
+            log.error("渲染基金会财务模块失败,relationId: {}", relationId, e);
+            throw new IOException("文档渲染失败", e);
+        }
+    }
+
+    /**
+     * 填充默认值,确保所有必要字段都存在
+     */
+    private void fillBasicDefaultValues(Map<String, Object> data) {
+        Map<String, Object> basicInfoSummary = (Map<String, Object>) data.get("financialSummary");
+        basicInfoSummary.replaceAll((k, v) -> v.equals("") ? "-" : v);
+
+        List<Map<String, Object>> financialDataSeq = (List<Map<String, Object>>) data.get("financialDataSeq");
+        for (Map<String, Object> stringObjectMap : financialDataSeq) {
+            stringObjectMap.replaceAll((k, v) -> v.equals("") ? "-" : v);
+        }
+
+        List<Map<String, Object>> indicators = (List<Map<String, Object>>) data.get("indicators");
+        for (Map<String, Object> indicator : indicators) {
+            ArrayList<String> strings = (ArrayList<String>) indicator.get("values");
+            if (CollectionUtils.isEmpty(strings)) {
+                indicator.put("values", Arrays.asList("-", "-", "-"));
+
+            }
+        }
+    }
+
+
+
+}

+ 12 - 3
easier-report-biz/src/main/java/com/yaoyicloud/service/impl/ReportServiceImpl.java

@@ -3,6 +3,7 @@ package com.yaoyicloud.service.impl;
 import java.io.File;
 import java.io.FileOutputStream;
 import java.time.LocalDate;
+
 import java.util.HashMap;
 import java.util.Map;
 
@@ -14,6 +15,8 @@ import com.yaoyicloud.render.ProjectInfoRender;
 import com.yaoyicloud.render.PublicRecordRender;
 
 import com.yaoyicloud.render.association.AssociationAttachmentSectionRender;
+import com.yaoyicloud.render.foundation.FoundationAttachmentSectionRender;
+import com.yaoyicloud.render.foundation.FoundationfinancialInfoRender;
 import com.yaoyicloud.render.platform.AntiBriberyRender;
 import com.yaoyicloud.render.platform.AttachmentSectionRender;
 import com.yaoyicloud.render.platform.BasicInfoRender;
@@ -91,12 +94,13 @@ public class ReportServiceImpl implements ReportService {
                 return reportPath;
             case ASSOCIATION_ATTACHMENTSECTION:
                 reportPath =
-                    new AssociationAttachmentSectionRender(sessionId, filerepoProperties).renderDocx(data, processedData,
+                    new AssociationAttachmentSectionRender(sessionId, filerepoProperties).renderDocx(data,
+                        processedData,
                         templateBytes, String.valueOf(relationId));
                 return reportPath;
             case FOUNDATION_ATTACHMENTSECTION:
                 reportPath =
-                    new AttachmentSectionRender(sessionId, filerepoProperties).renderDocx(data, processedData,
+                    new FoundationAttachmentSectionRender(sessionId, filerepoProperties).renderDocx(data, processedData,
                         templateBytes, String.valueOf(relationId));
                 return reportPath;
             case COMMON:
@@ -104,10 +108,15 @@ public class ReportServiceImpl implements ReportService {
                     new ServiceProviderInfoRender(sessionId, filerepoProperties).renderDocx(data, processedData,
                         templateBytes, String.valueOf(relationId));
                 return reportPath;
-            case PLATFORM_COMPANY_FinancialInfo:
+            case PLATFORM_COMPANY_FINANCIALINFO:
                 reportPath = new FinancialInfoRender(sessionId, filerepoProperties).renderDocx(data, processedData,
                     templateBytes, String.valueOf(relationId));
                 return reportPath;
+            case FOUNDATION_FINANCIALINFO:
+                reportPath =
+                    new FoundationfinancialInfoRender(sessionId, filerepoProperties).renderDocx(data, processedData,
+                        templateBytes, String.valueOf(relationId));
+                return reportPath;
             case PUBLIC_RECORD:
                 reportPath = new PublicRecordRender(sessionId, filerepoProperties).renderDocx(data, processedData,
                     templateBytes, String.valueOf(relationId));

+ 122 - 6
easier-report-biz/src/main/java/com/yaoyicloud/tools/DocxUtil.java

@@ -3,7 +3,9 @@ package com.yaoyicloud.tools;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
 import org.apache.poi.xwpf.usermodel.IBodyElement;
@@ -12,39 +14,142 @@ 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 com.deepoove.poi.xwpf.XWPFStructuredDocumentTag;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTStyle;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.STStyleType;
 
 public final class DocxUtil {
 
     public static void mergeDocx(XWPFDocument target, List<XWPFDocument> sources, String outputPath)
         throws InvalidFormatException, FileNotFoundException, IOException {
-        mergeDocx(target, sources, outputPath, true);
+        mergeDocx(target, sources, outputPath, false);
     }
 
-    /*
-     * 只更新target的内容,全局设定(fonts, styles, custom items)都使用target docx
-     */
     public static void mergeDocx(XWPFDocument target, List<XWPFDocument> sources, String outputPath,
         boolean clearTargetBody) throws InvalidFormatException, FileNotFoundException, IOException {
         if (clearTargetBody) {
             target.getDocument().unsetBody();
             target.getDocument().addNewBody();
         }
-        for (XWPFDocument source : sources) {
+
+        // 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);
         }
-
         try (FileOutputStream out = new FileOutputStream(outputPath)) {
             target.write(out);
             target.close();
         }
     }
 
+    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 {
         for (IBodyElement element : source.getBodyElements()) {
             if (element instanceof XWPFParagraph) {
@@ -56,11 +161,17 @@ public final class DocxUtil {
                 continue;
             }
         }
+
     }
 
     private static void appendTable(XWPFDocument target, XWPFTable oldTable) {
         XWPFTable newTable = target.createTable();
         newTable.getCTTbl().set(oldTable.getCTTbl().copy());
+        // 更新表格样式引用
+        String styleId = oldTable.getStyleID();
+        if (styleId != null) {
+            newTable.setStyleID(styleId);
+        }
     }
 
     private static void appendParagraph(XWPFDocument target, XWPFParagraph oldParagraph) throws InvalidFormatException {
@@ -96,6 +207,11 @@ public final class DocxUtil {
         // Copy Xml content
         XWPFParagraph newParagraph = target.createParagraph();
         newParagraph.getCTP().set(oldParagraph.getCTP().copy());
+        // 更新段落样式引用
+        String styleId = oldParagraph.getStyleID();
+        if (styleId != null) {
+            newParagraph.setStyle(styleId);
+        }
     }
 
 }

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

@@ -365,6 +365,12 @@ message AssociationattachmentSection {
 
   repeated Attachment otherInfoImage = 28; //其他分支机构
 
-
   repeated Attachment branchInfoImage = 29; //地方分会情况图片路径
+
+  repeated Attachment financialStatementsForLastThreeYears = 31; //最近三年财务报表
+
+  repeated Attachment relatedEntitySituation = 32; //关联实体情况
+
+  repeated Attachment organizationalStructureScan = 33; //组织结构-扫描件并加盖公章
+
 }

+ 6 - 8
easier-report-biz/src/test/java/com/yaoyicloud/render/test/TestDocxOperations.java

@@ -16,16 +16,14 @@ public class TestDocxOperations {
     @Test
     public void testMergeDocx() throws IOException, InvalidFormatException {
 
-        FileInputStream streamMerge =
-            new FileInputStream(getClass().getClassLoader().getResource("docx/check_overview.docx").getFile());
-        FileInputStream stream1 =
-            new FileInputStream(getClass().getClassLoader().getResource("docx/service_provider_info.docx").getFile());
-        FileInputStream stream2 =
-            new FileInputStream(getClass().getClassLoader().getResource("docx/check_overview.docx").getFile());
+        // 直接使用文件路径创建FileInputStream
+        FileInputStream streamMerge = new FileInputStream("C:\\Users\\yyy\\dev\\yyc3\\easier-be\\temp\\560E3B64F6AB87FEC22EF84EDBC84272\\1930150383555809281_serviceProviderInfo.docx");
+        FileInputStream stream1 = new FileInputStream("C:\\Users\\yyy\\dev\\yyc3\\easier-be\\temp\\560E3B64F6AB87FEC22EF84EDBC84272\\1930150383555809281_publicRecord.docx");
+        FileInputStream stream2 = new FileInputStream("C:\\Users\\yyy\\dev\\yyc3\\easier-be\\temp\\560E3B64F6AB87FEC22EF84EDBC84272\\1930150383555809281_attachmentSection.docx");
 
         DocxUtil.mergeDocx(new XWPFDocument(streamMerge),
-            List.of(new XWPFDocument(stream1), new XWPFDocument(stream2)),
-            "../temp/merged.docx");
+                List.of(new XWPFDocument(stream1),new XWPFDocument(stream2)),
+                "C:\\Users\\yyy\\Desktop\\11.docx");
 
         assertTrue(true);
     }

BIN
easier-report-biz/src/test/resources/docx/doundation_finance.docx


BIN
easier-report-biz/src/test/resources/docx/foundataion_basic_info.docx


BIN
easier-report-biz/src/test/resources/docx/foundation_attachment.docx


BIN
easier-report-biz/src/test/resources/docx/foundation_basic_info.docx


BIN
easier-report-biz/src/test/resources/docx/foundation_finance.docx