Explorar o código

模块化生成报告平台公司老版 部分新版

mamingxu hai 1 semana
pai
achega
5e5c6b9601
Modificáronse 29 ficheiros con 1128 adicións e 540 borrados
  1. 9 1
      easier-report-api/src/main/java/com/yaoyicloud/constant/enums/ModuleType.java
  2. 7 0
      easier-report-api/src/main/java/com/yaoyicloud/dto/ReportDTO.java
  3. 5 2
      easier-report-biz/src/main/java/com/yaoyicloud/config/SessionInterceptor.java
  4. 11 16
      easier-report-biz/src/main/java/com/yaoyicloud/controller/ReportController.java
  5. 331 3
      easier-report-biz/src/main/java/com/yaoyicloud/render/AbstractRender.java
  6. 1 1
      easier-report-biz/src/main/java/com/yaoyicloud/render/AntiBriberyRender.java
  7. 4 1
      easier-report-biz/src/main/java/com/yaoyicloud/render/AttachmentSectionRender.java
  8. 0 132
      easier-report-biz/src/main/java/com/yaoyicloud/render/AuditResultRender.java
  9. 1 1
      easier-report-biz/src/main/java/com/yaoyicloud/render/BasicInfoRender.java
  10. 20 215
      easier-report-biz/src/main/java/com/yaoyicloud/render/FinancialInfoRender.java
  11. 319 141
      easier-report-biz/src/main/java/com/yaoyicloud/render/PublicRecordRender.java
  12. 6 5
      easier-report-biz/src/main/java/com/yaoyicloud/render/ServiceProviderInfoRender.java
  13. 98 0
      easier-report-biz/src/main/java/com/yaoyicloud/render/update/BasicInfoNewRender.java
  14. 254 0
      easier-report-biz/src/main/java/com/yaoyicloud/render/update/PublicRecordNewRender.java
  15. 4 1
      easier-report-biz/src/main/java/com/yaoyicloud/service/ReportService.java
  16. 45 13
      easier-report-biz/src/main/java/com/yaoyicloud/service/impl/ReportServiceImpl.java
  17. 13 8
      easier-report-biz/src/test/java/com/yaoyicloud/render/test/TestFinancialInfoRender.java
  18. BIN=BIN
      easier-report-biz/src/test/resources/docx/antiBribery.docx
  19. BIN=BIN
      easier-report-biz/src/test/resources/docx/antiBribery_new.docx
  20. BIN=BIN
      easier-report-biz/src/test/resources/docx/attachments.docx
  21. BIN=BIN
      easier-report-biz/src/test/resources/docx/basic_info.docx
  22. BIN=BIN
      easier-report-biz/src/test/resources/docx/basic_info_new.docx
  23. BIN=BIN
      easier-report-biz/src/test/resources/docx/check_overview.docx
  24. BIN=BIN
      easier-report-biz/src/test/resources/docx/finance.docx
  25. BIN=BIN
      easier-report-biz/src/test/resources/docx/finance_new.docx
  26. BIN=BIN
      easier-report-biz/src/test/resources/docx/public_record.docx
  27. BIN=BIN
      easier-report-biz/src/test/resources/docx/public_record_new.docx
  28. BIN=BIN
      easier-report-biz/src/test/resources/docx/service_provider_info.docx
  29. BIN=BIN
      easier-report-biz/src/test/resources/docx/tax_new.docx

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

@@ -14,8 +14,16 @@ public enum ModuleType {
     PLATFORM_COMPANY_BASICINFO("PLATFORM_COMPANY_BASICINFO", "平台公司基本信息"),
     ANTIBRIBERY("ANTIBRIBERY", "反贿赂反腐败诚信保证"),
     COMMON("COMMON", "公共模块封面"),
-    PLATFORM_COMPANY_ATTACHMENTSECTION("PLATFORM_COMPANY_ATTACHMENTSECTION", "平台公司附件");
+    PLATFORM_COMPANY_FinancialInfo("PLATFORM_COMPANY_FinancialInfo", "财务"),
+    PLATFORM_COMPANY_ATTACHMENTSECTION("PLATFORM_COMPANY_ATTACHMENTSECTION", "平台公司附件"),
+    PUBLIC_RECORD("PUBLIC_RECORD", "公共记录"),
 
+
+
+    PLATFORM_COMPANY_BASICINFO_NEW("PLATFORM_COMPANY_BASICINFO", "工商信息"),
+    ANTIBRIBERY_NEW("ANTIBRIBERY", "其他风险"),
+    PLATFORM_COMPANY_FinancialInfo_NEW("PLATFORM_COMPANY_FinancialInfo", "经营风险"),
+    PUBLIC_RECORD_NEW("PUBLIC_RECORD", "司法风险");
     /**
      * 类型
      */

+ 7 - 0
easier-report-api/src/main/java/com/yaoyicloud/dto/ReportDTO.java

@@ -44,5 +44,12 @@ public class ReportDTO {
 
         @NotNull(message = "租户名称必填")
         private String tenantName;
+
+        @NotNull(message = "服务商名称")
+        private String name;
+
+        @NotNull(message = "标题等级")
+        private Integer levelCount;
+
     }
 }

+ 5 - 2
easier-report-biz/src/main/java/com/yaoyicloud/config/SessionInterceptor.java

@@ -12,7 +12,7 @@ import java.util.Map;
 
 public class SessionInterceptor implements HandlerInterceptor {
 
-    public static final Map<String, HttpSession> SESSION_MAP = new HashMap<>();
+    public static final Map<String, String> SESSION_MAP = new HashMap<>();
 
     @Override
     public boolean preHandle(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response,
@@ -22,7 +22,10 @@ public class SessionInterceptor implements HandlerInterceptor {
         String mysession = request.getHeader("X-Session-Id");
         if (mysession == null) {
             HttpSession session = request.getSession(true);
-            SESSION_MAP.put(relationId, session);
+            SESSION_MAP.put(relationId, session.getId());
+        }
+        if (mysession != null && SESSION_MAP.get(relationId) == null) {
+            SESSION_MAP.put(relationId, mysession);
         }
         return true;
     }

+ 11 - 16
easier-report-biz/src/main/java/com/yaoyicloud/controller/ReportController.java

@@ -10,15 +10,14 @@ import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RestController;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
-
 import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpSession;
-import java.util.ArrayList;
+
+
 import java.util.Base64;
 import java.util.HashMap;
-import java.util.List;
+
 import java.util.Map;
-import java.util.Optional;
+
 
 import static com.yaoyicloud.config.SessionInterceptor.SESSION_MAP;
 
@@ -56,24 +55,20 @@ public class ReportController {
                 resource.getReportBastPath(),
                 Long.valueOf(relationId),
                 request,
-                resource.getModuleType()
+                resource.getModuleType(),
+                resource.getName(),
+                resource.getLevelCount(),
+                resource.getTenantName()
+
         );
 
-        HttpSession session = SESSION_MAP.get(relationId);
+        String sessionId = SESSION_MAP.get(relationId);
         // 2. 线程安全地更新 Session 中的报告路径列表
-        synchronized (session) {
-            List<String> reportPaths = Optional.ofNullable(
-                    (List<String>) session.getAttribute(relationId)
-            ).orElseGet(ArrayList::new);
-
-            reportPaths.add(reportPath);
-            session.setAttribute(relationId, reportPaths);
-        }
 
         // 3. 返回响应
         Map<String, Object> response = new HashMap<>();
         response.put("reportResult", reportPath);
-        response.put("sessionId", session.getId());
+        response.put("sessionId", sessionId);
         response.put("reportResult", reportPath);
         return response;
     }

+ 331 - 3
easier-report-biz/src/main/java/com/yaoyicloud/render/AbstractRender.java

@@ -6,12 +6,17 @@ import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.IOException;
 import java.net.URL;
+import java.text.DecimalFormat;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.stream.Collectors;
 
 import cn.hutool.core.lang.Pair;
-import cn.hutool.core.util.IdUtil;
+
 import cn.hutool.core.util.StrUtil;
 import com.deepoove.poi.XWPFTemplate;
 import com.deepoove.poi.config.Configure;
@@ -28,15 +33,24 @@ import com.deepoove.poi.policy.RenderPolicy;
 import com.deepoove.poi.policy.TextRenderPolicy;
 import com.deepoove.poi.template.ElementTemplate;
 import com.deepoove.poi.template.run.RunTemplate;
+import com.deepoove.poi.util.TableTools;
 import com.deepoove.poi.xwpf.BodyContainer;
 import com.deepoove.poi.xwpf.BodyContainerFactory;
+import com.yaoyicloud.tools.Util;
 import org.apache.pdfbox.Loader;
 import org.apache.pdfbox.pdmodel.PDDocument;
 import org.apache.pdfbox.rendering.PDFRenderer;
 import org.apache.poi.xwpf.usermodel.UnderlinePatterns;
+import org.apache.poi.xwpf.usermodel.XWPFDocument;
 import org.apache.poi.xwpf.usermodel.XWPFHyperlinkRun;
 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;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTc;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTcPr;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.STVerticalJc;
 
 import javax.imageio.ImageIO;
 
@@ -79,12 +93,12 @@ public abstract class AbstractRender {
      * @throws IOException
      */
     public final String renderDocx(Map<String, Object> dataMap, byte[] templateFileContent,
-        ConfigureBuilder builder, String relationId) throws IOException {
+        ConfigureBuilder builder, String relationId, String moduleType) throws IOException {
 
         // 注: 报告模板的模板变量按照json序列化的结果命名
         String basicPath = this.getBasicPath();
         String reportImagePath = this.getReportImagePath();
-        String label = relationId + "_" + IdUtil.fastSimpleUUID();
+        String label = relationId + "_" + moduleType;
         //word导出位置
         String reportTempWordFile = basicPath + "/" + cwd + "/" + label + ".docx";
         // 新增:创建文件夹
@@ -320,4 +334,318 @@ public abstract class AbstractRender {
             }
         };
     }
+
+
+    protected RenderPolicy getScoreRenderPolicy() {
+        RenderPolicy policy = new LoopRowTableRenderPolicy() {
+            @SuppressWarnings("checkstyle:NestedForDepth")
+            @Override
+            public void render(ElementTemplate eleTemplate, Object data, XWPFTemplate template) {
+                // 检查数据是否为空
+                if (data == null || (data instanceof Collection && ((Collection<?>) data).isEmpty())) {
+                    // 数据为空时,删除整个表格
+                    //      removeTemplateTable(eleTemplate, template);
+                    return;
+                }
+
+                super.render(eleTemplate, data, template);
+                XWPFDocument doc = template.getXWPFDocument();
+                for (XWPFTable table : doc.getTables()) {
+                    boolean isTargetTable = false;
+                    // 判断是否为目标表格:通过检查表格第一行是否包含货物明细相关表头关键词
+                    List<String> headerKeywords = List.of("删除");
+                    XWPFTableRow firstRow = table.getRow(0);
+                    if (firstRow != null) {
+                        for (XWPFTableCell cell : firstRow.getTableCells()) {
+                            for (XWPFParagraph para : cell.getParagraphs()) {
+                                for (XWPFRun run : para.getRuns()) {
+                                    String text = run.text().trim();
+                                    if (headerKeywords.contains(text)) {
+                                        isTargetTable = true;
+                                        break;
+                                    }
+                                }
+                                if (isTargetTable) {
+                                    break;
+                                }
+                            }
+                            if (isTargetTable) {
+                                break;
+                            }
+                        }
+                    }
+                    if (isTargetTable) {
+                        // 删除表头(假设表头是第一行)
+                        if (table.getRows().size() > 0) {
+                            table.removeRow(0);
+                        }
+                        // 合并第一列相同内容单元格并居中
+                        mergeAndCenterFirstColumn(table);
+                    }
+                }
+            }
+
+            private void mergeAndCenterFirstColumn(XWPFTable table) {
+                if (table.getNumberOfRows() < 2) {
+                    return;
+                }
+
+                int startRow = 0;
+                String currentValue = getCellText(table.getRow(0)).get(0);
+
+                for (int i = 1; i < table.getNumberOfRows(); i++) {
+                    List<String> rowValues = getCellText(table.getRow(i));
+                    if (rowValues.isEmpty()) {
+                        continue;
+                    }
+
+                    String firstCellValue = rowValues.get(0);
+                    if (firstCellValue.equals(currentValue)) {
+                        // 继续查找相同值的行
+                        continue;
+                    } else {
+                        // 合并从startRow到i-1行的第一列单元格
+                        if (i - 1 > startRow) {
+                            TableTools.mergeCellsVertically(table, 0, startRow, i - 1);
+                            // 设置合并后单元格内容居中
+                            setCellCenterAlignment(table.getRow(startRow).getCell(0));
+                        }
+                        startRow = i;
+                        currentValue = firstCellValue;
+                    }
+                }
+
+                // 处理最后一组相同值
+                if (table.getNumberOfRows() - 1 > startRow) {
+                    TableTools.mergeCellsVertically(table, 0, startRow, table.getNumberOfRows() - 1);
+                    setCellCenterAlignment(table.getRow(startRow).getCell(0));
+                }
+            }
+        };
+        return policy;
+    }
+    private List<String> getCellText(XWPFTableRow row) {
+        List<String> texts = new ArrayList<>();
+        if (row == null) {
+            return texts;
+        }
+        for (XWPFTableCell cell : row.getTableCells()) {
+            StringBuilder sb = new StringBuilder();
+            for (XWPFParagraph para : cell.getParagraphs()) {
+                for (XWPFRun run : para.getRuns()) {
+                    sb.append(run.text());
+                }
+            }
+            texts.add(sb.toString().trim());
+        }
+        return texts;
+    }
+
+    private void setCellCenterAlignment(XWPFTableCell cell) {
+        CTTc cttc = cell.getCTTc();
+        CTTcPr ctPr = cttc.addNewTcPr();
+        ctPr.addNewVAlign().setVal(STVerticalJc.CENTER);
+    }
+    /**
+     * 这些render policy类都应当是共享的 重要设计假设: data的类型cast都可以建立在json通用反序列化后的基本类型基础上。
+     */
+    public class LoopColumnStaticTableRenderPolicy implements RenderPolicy {
+
+        private String prefix;
+        private String suffix;
+        private boolean onSameLine;
+        private boolean reverse;
+        private int valColIndex;
+
+        public LoopColumnStaticTableRenderPolicy() {
+            this(false);
+        }
+
+        public LoopColumnStaticTableRenderPolicy(boolean onSameLine) {
+            this("[", "]", onSameLine);
+        }
+
+        public LoopColumnStaticTableRenderPolicy(String prefix, String suffix) {
+            this(prefix, suffix, false);
+        }
+
+        public LoopColumnStaticTableRenderPolicy(String prefix, String suffix, boolean onSameLine) {
+            this(prefix, suffix, onSameLine, false);
+        }
+
+        public LoopColumnStaticTableRenderPolicy(String prefix, String suffix, boolean onSameLine, boolean reverse) {
+            this(prefix, suffix, onSameLine, false, 1);
+        }
+
+        public LoopColumnStaticTableRenderPolicy(String prefix, String suffix, boolean onSameLine, boolean reverse,
+                                                 int valRowIndex) {
+            this.prefix = prefix;
+            this.suffix = suffix;
+            this.onSameLine = onSameLine;
+            this.reverse = reverse;
+            this.valColIndex = valRowIndex;
+        }
+
+        @Override
+        public void render(ElementTemplate eleTemplate, Object data, XWPFTemplate template) {
+            RunTemplate runTemplate = (RunTemplate) eleTemplate;
+            XWPFRun run = runTemplate.getRun();
+            try {
+                if (!TableTools.isInsideTable(run)) {
+                    throw new IllegalStateException(
+                            "The template tag " + runTemplate.getSource() + " must be inside a table");
+                }
+                XWPFTableCell tagCell = (XWPFTableCell) ((XWPFParagraph) run.getParent()).getBody();
+                XWPFTable table = tagCell.getTableRow().getTable();
+                run.setText("", 0);
+
+                int templateColIndex = getTemplateColIndex(tagCell);
+                // 模版变量列总是写在左边
+                int minIndex = templateColIndex;
+                int maxIndex = table.getRows().get(valColIndex).getTableCells().size() - 1;
+                int currIndex = reverse ? maxIndex : minIndex;
+                int indexDelta = reverse ? -1 : 1;
+
+                // 目前expression当作数据Map的key来对待,将来可以当作POI-TL变量一致化的处理
+                Map<Integer, String> idx2Expression = new HashMap<>();
+                for (int i = 0; i < table.getRows().size(); i++) {
+                    XWPFTableCell cell = table.getRows().get(i).getCell(templateColIndex);
+                    String text = cell.getText().trim();
+                    if (text.startsWith(prefix) && text.endsWith(suffix)) {
+                        idx2Expression.put(i, text.substring(1, text.length() - 1));
+                        cell.setText("");
+                    }
+                }
+
+                int rowSize = table.getRows().size();
+                @SuppressWarnings("unchecked")
+                List<Map<String, Object>> mpData = (List<Map<String, Object>>) data;
+
+                for (Map<String, Object> realData : mpData) {
+                    for (int i = 0; i < rowSize; i++) {
+                        if (!idx2Expression.containsKey(i)) {
+                            continue;
+                        }
+                        XWPFTableRow row = table.getRow(i);
+                        XWPFTableCell valueCell = row.getCell(currIndex);
+                        String valStr = realData.getOrDefault(idx2Expression.get(i), "-").toString();
+                        valueCell.setText(valStr);
+                    }
+                    currIndex += indexDelta;
+                }
+
+            } catch (Exception e) {
+                throw new RenderException("HackLoopTable for " + eleTemplate + "error: " + e.getMessage(), e);
+            }
+        }
+
+        private int getTemplateColIndex(XWPFTableCell tagCell) {
+            return onSameLine ? Util.getColIndexOfFirstRow(tagCell) : (Util.getColIndexOfFirstRow(tagCell) + 1);
+        }
+    }
+
+    public class LoopRowCutAndMergeFirstColTableRenderPolicy extends LoopRowTableRenderPolicy {
+
+        @Override
+        public void render(ElementTemplate eleTemplate, Object data, XWPFTemplate template) {
+            RunTemplate runTemplate = (RunTemplate) eleTemplate;
+            XWPFRun run = runTemplate.getRun();
+            XWPFTable table = null;
+            try {
+                if (!TableTools.isInsideTable(run)) {
+                    throw new IllegalStateException(
+                            "The template tag " + runTemplate.getSource() + " must be inside a table");
+                }
+                // Reserve the first two rows
+                XWPFTableCell tagCell = (XWPFTableCell) ((XWPFParagraph) run.getParent()).getBody();
+                table = tagCell.getTableRow().getTable();
+                for (int i = table.getNumberOfRows() - 1; i > 1; i--) {
+                    table.removeRow(i);
+                }
+            } catch (Exception e) {
+                throw new RenderException(
+                        "LoopRowCutAndMergeFirstColTable for " + eleTemplate + " error: " + e.getMessage(), e);
+            }
+
+            // in case data not sorted by rank
+            @SuppressWarnings("unchecked")
+            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);
+
+            try {
+                // merge the first column
+                Util.mergeFirstNColSimple(table, 1, 0);
+            } catch (Exception e) {
+                throw new RenderException(
+                        "LoopRowCutAndMergeFirstColTable for " + eleTemplate + " error: " + e.getMessage(), e);
+            }
+        }
+    }
+
+    public class LoopRowIncludeStatisticsTableRenderPolicy extends LoopRowTableRenderPolicy {
+
+        private String valueTag;
+
+        public LoopRowIncludeStatisticsTableRenderPolicy(String valueTag) {
+            this.valueTag = valueTag;
+        }
+
+        @Override
+        public void render(ElementTemplate eleTemplate, Object data, XWPFTemplate template) {
+            @SuppressWarnings("unchecked")
+            List<Map<String, Object>> mpData = (List<Map<String, Object>>) data;
+
+            for (Map<String, Object> row : mpData) {
+                @SuppressWarnings("unchecked")
+                List<String> values = (List<String>) row.get(valueTag);
+
+                // 检查是否有百分号结尾的值
+                boolean hasPercentage = values.stream().anyMatch(v -> v != null && v.endsWith("%"));
+
+                // 处理百分号并转换为数值
+                List<Double> processedValues = values.stream()
+                        .filter(Objects::nonNull)
+                        .map(v -> {
+                            if (v.endsWith("%")) {
+                                return v.substring(0, v.length() - 1);
+                            }
+                            return v;
+                        })
+                        .map(v -> {
+                            try {
+                                return Double.valueOf(v);
+                            } catch (NumberFormatException e) {
+                                return Double.NaN;
+                            }
+                        })
+                        .filter(v -> !Double.isNaN(v))
+                        .collect(Collectors.toList());
+
+                // 计算平均值并保留两位小数
+                double avg = processedValues.stream()
+                        .mapToDouble(Double::doubleValue)
+                        .average()
+                        .orElse(Double.NaN);
+
+                // 格式化结果
+                String formattedAvg;
+                if (Double.isNaN(avg)) {
+                    formattedAvg = "-"; // 处理无有效数据的情况
+                } else {
+                    DecimalFormat df = new DecimalFormat("#0.00"); // 保留两位小数
+                    formattedAvg = df.format(avg);
+                    if (hasPercentage) {
+                        formattedAvg += "%"; // 添加百分号
+                    }
+                }
+
+                row.put("avg", formattedAvg);
+            }
+
+            super.render(eleTemplate, data, template);
+        }
+    }
 }

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

@@ -67,7 +67,7 @@ public final class AntiBriberyRender extends AbstractRender {
         data.replaceAll((k, v) -> v == null ? "-" : v);
         try {
             // 渲染文档
-            String resultPath = this.renderDocx(data, templateFileContent, builder, relationId);
+            String resultPath = this.renderDocx(data, templateFileContent, builder, relationId, "antiBribery");
             log.info("防贿赂报告渲染成功,文件路径: {}", resultPath);
             return resultPath;
         } catch (Exception e) {

+ 4 - 1
easier-report-biz/src/main/java/com/yaoyicloud/render/AttachmentSectionRender.java

@@ -84,11 +84,14 @@ public final class AttachmentSectionRender extends AbstractRender {
         if (newAddtionMap != null) {
             data.putAll(newAddtionMap);
         }
+        if (addtionalMap != null) {
+            data.putAll(addtionalMap);
+        }
 
         fillDefaultValues(data);
         try {
             // 渲染文档
-            String resultPath = this.renderDocx(data, templateFileContent, builder, relationId);
+            String resultPath = this.renderDocx(data, templateFileContent, builder, relationId, "attachmentSection");
             log.info("渲染附件模块成功,文件路径: {}", resultPath);
             return resultPath;
         } catch (Exception e) {

+ 0 - 132
easier-report-biz/src/main/java/com/yaoyicloud/render/AuditResultRender.java

@@ -1,132 +0,0 @@
-//package com.yaoyicloud.render;
-//
-//import java.io.IOException;
-//import java.nio.file.Paths;
-//import java.util.Map;
-//import java.util.UUID;
-//
-//import com.deepoove.poi.config.Configure;
-//import com.deepoove.poi.config.ConfigureBuilder;
-//import com.deepoove.poi.plugin.table.LoopRowTableRenderPolicy;
-//import com.fasterxml.jackson.core.JsonGenerator;
-//import com.fasterxml.jackson.core.JsonProcessingException;
-//import com.fasterxml.jackson.databind.ObjectMapper;
-//import com.fasterxml.jackson.databind.SerializerProvider;
-//import com.fasterxml.jackson.databind.module.SimpleModule;
-//import com.fasterxml.jackson.databind.ser.std.StdSerializer;
-//import com.yaoyicloud.message.FxyProtos.AuditResult;
-//import com.yaoyicloud.message.FxyProtos.CheckItemScore;
-//import com.yaoyicloud.message.FxyProtos.CheckSummary;
-//
-//import cn.hutool.core.util.StrUtil;
-//
-///**
-// * AuditResult渲染器
-// *
-// */
-//public final class AuditResultRender extends AbstractRender {
-//
-//    public AuditResultRender(String cwd) {
-//        super(cwd);
-//    }
-//
-//    /**
-//     * Docx 渲染
-//     *
-//     * @param info 数据
-//     * @param templateFileContent 模板内容
-//     * @return 本地文件目录
-//     * @throws IOException
-//     */
-//    public String renderDocx(AuditResult info, Map<String, Object> addtionalMap, byte[] templateFileContent) throws IOException {
-//        ObjectMapper mapper = new ObjectMapper();
-//        SimpleModule module = new SimpleModule();
-//        module.addSerializer(new AuditResultSerializer(AuditResult.class));
-//        module.addSerializer(new CheckItemScoreSerializer(CheckItemScore.class));
-//        module.addSerializer(new CheckSummarySerializer(CheckSummary.class));
-//        mapper.registerModule(module);
-//
-//        String jsonStr = mapper.writeValueAsString(info);
-//
-//        // 注: 报告模板的模板变量按照json序列化的结果命名
-//        // 注: 目前的实现假设:一个session对应一个cwd目录
-//        ConfigureBuilder builder = Configure.builder();
-//        builder.bind("checkItemScores", new LoopRowTableRenderPolicy());
-//        this.docxResultPath = this.renderDocx(jsonStr, addtionalMap, templateFileContent, builder,
-//            Paths.get(cwd, UUID.randomUUID().toString() + ".docx").toString());
-//        return this.docxResultPath;
-//    }
-//
-//    /*
-//     * 通过序列化和反序列化
-//     * 1. 默认显示规则的数据转换
-//     * 2. 避免TL处理模板面对复杂数据类型
-//     */
-//    public class AuditResultSerializer extends StdSerializer<AuditResult> {
-//
-//        public AuditResultSerializer() {
-//            this(null);
-//        }
-//
-//        public AuditResultSerializer(Class<AuditResult> t) {
-//            super(t);
-//        }
-//
-//        @Override
-//        public void serialize(AuditResult value, JsonGenerator jgen, SerializerProvider provider)
-//            throws IOException, JsonProcessingException {
-//
-//            jgen.writeStartObject();
-//            jgen.writeStringField("opinion", StrUtil.isBlank(value.getOpinion()) ? "-" : value.getOpinion());
-//            jgen.writeStringField("serviceProviderName", value.getServiceProviderName());
-//            // Note: ignore reportVersion
-//            jgen.writeStringField("auditDate", value.getAuditDate());
-//            jgen.writeObjectField("overallSummary", value.getOverallSummary());
-//            jgen.writeObjectField("checkItemScores", value.getCheckItemScoresList());
-//            jgen.writeEndObject();
-//        }
-//    }
-//
-//    public class CheckItemScoreSerializer extends StdSerializer<CheckItemScore> {
-//
-//        public CheckItemScoreSerializer() {
-//            this(null);
-//        }
-//
-//        public CheckItemScoreSerializer(Class<CheckItemScore> t) {
-//            super(t);
-//        }
-//
-//        @Override
-//        public void serialize(CheckItemScore value, JsonGenerator jgen, SerializerProvider provider)
-//            throws IOException, JsonProcessingException {
-//
-//            jgen.writeStartObject();
-//            jgen.writeStringField("category", StrUtil.isBlank(value.getCategory()) ? "-" : value.getCategory());
-//            jgen.writeStringField("itemName", value.getItemName());
-//            jgen.writeNumberField("score", value.getScore());
-//            jgen.writeEndObject();
-//        }
-//    }
-//
-//    public class CheckSummarySerializer extends StdSerializer<CheckSummary> {
-//
-//        public CheckSummarySerializer() {
-//            this(null);
-//        }
-//
-//        public CheckSummarySerializer(Class<CheckSummary> t) {
-//            super(t);
-//        }
-//
-//        @Override
-//        public void serialize(CheckSummary value, JsonGenerator jgen, SerializerProvider provider)
-//            throws IOException, JsonProcessingException {
-//            jgen.writeStartObject();
-//            jgen.writeStringField("score", value.getScore() < 0 ? "-" : String.valueOf(value.getScore()));
-//            jgen.writeStringField("riskSummary", value.getRiskSummary());
-//            jgen.writeStringField("suggestion", value.getSuggestion());
-//            jgen.writeEndObject();
-//        }
-//    }
-//}

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

@@ -77,7 +77,7 @@ public final class BasicInfoRender extends AbstractRender {
 
         try {
             // 渲染文档
-            String resultPath = this.renderDocx(data, templateFileContent, builder, relationId);
+            String resultPath = this.renderDocx(data, templateFileContent, builder, relationId, "basicInfo");
             log.info("渲染基础信息报告模块成功,文件路径: {}", resultPath);
             return resultPath;
         } catch (Exception e) {

+ 20 - 215
easier-report-biz/src/main/java/com/yaoyicloud/render/FinancialInfoRender.java

@@ -1,32 +1,21 @@
 package com.yaoyicloud.render;
 
 import java.io.IOException;
-import java.util.HashMap;
-import java.util.List;
+
 import java.util.Map;
 
+
 import com.fasterxml.jackson.core.type.TypeReference;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.yaoyicloud.config.FilerepoProperties;
 import com.yaoyicloud.message.FxyProtos;
 import lombok.extern.slf4j.Slf4j;
-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;
-import com.deepoove.poi.XWPFTemplate;
+
 import com.deepoove.poi.config.Configure;
 import com.deepoove.poi.config.ConfigureBuilder;
-import com.deepoove.poi.exception.RenderException;
-import com.deepoove.poi.plugin.table.LoopRowTableRenderPolicy;
-import com.deepoove.poi.policy.RenderPolicy;
-import com.deepoove.poi.template.ElementTemplate;
-import com.deepoove.poi.template.run.RunTemplate;
-import com.deepoove.poi.util.TableTools;
+
 import com.google.protobuf.util.JsonFormat;
-import com.yaoyicloud.message.FxyProtos.FinancialInfo;
-import com.yaoyicloud.tools.Util;
+
 
 /**
  * FinancialInfo渲染器
@@ -35,9 +24,9 @@ import com.yaoyicloud.tools.Util;
 @Slf4j
 public final class FinancialInfoRender extends AbstractRender {
     private final FilerepoProperties filerepoProperties;
-    public FinancialInfoRender(String cwd, FilerepoProperties filerepoProperties, FilerepoProperties filerepoProperties1) {
+    public FinancialInfoRender(String cwd, FilerepoProperties filerepoProperties) {
         super(cwd);
-        this.filerepoProperties = filerepoProperties1;
+        this.filerepoProperties = filerepoProperties;
     }
     @Override
     protected String getBasicPath() throws IOException {
@@ -59,17 +48,20 @@ public final class FinancialInfoRender extends AbstractRender {
      */
 
     public String renderDocx(String info, Map<String, Object> addtionalMap, byte[] templateFileContent, String relationId) throws IOException {
-        log.info("开始渲染附件模块,relationId: {}", relationId);
+        log.info("开始渲染财务模块,relationId: {}", relationId);
 
         // 配置POI-TL渲染器
         ConfigureBuilder builder = Configure.builder();
-        RenderPolicy indicatorsRenderPolicy = this.indicatorsRenderPolicy();
-        builder.bind("basicInfoChecks", indicatorsRenderPolicy);
-        FxyProtos.BasicInfo.Builder basicInfoBuilder = FxyProtos.BasicInfo.newBuilder();
+        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.BasicInfo defaultInstance = FxyProtos.BasicInfo.getDefaultInstance();
-        FxyProtos.BasicInfo mergedProto = defaultInstance.toBuilder()
+        FxyProtos.FinancialInfo defaultInstance = FxyProtos.FinancialInfo.getDefaultInstance();
+        FxyProtos.FinancialInfo mergedProto = defaultInstance.toBuilder()
                 .mergeFrom(basicInfoBuilder.build())
                 .build();
 
@@ -87,11 +79,11 @@ public final class FinancialInfoRender extends AbstractRender {
 
         try {
             // 渲染文档
-            String resultPath = this.renderDocx(data, templateFileContent, builder, relationId);
-            log.info("渲染附件模块成功,文件路径: {}", resultPath);
+            String resultPath = this.renderDocx(data, templateFileContent, builder, relationId, "financialInfo");
+            log.info("渲染财务模块成功,文件路径: {}", resultPath);
             return resultPath;
         } catch (Exception e) {
-            log.error("渲染附件模块失败,relationId: {}", relationId, e);
+            log.error("渲染财务模块失败,relationId: {}", relationId, e);
             throw new IOException("文档渲染失败", e);
         }
     }
@@ -99,197 +91,10 @@ public final class FinancialInfoRender extends AbstractRender {
      * 填充默认值,确保所有必要字段都存在
      */
     private void fillBasicDefaultValues(Map<String, Object> data) {
-        Map<String, Object> basicInfoSummary = (Map<String, Object>) data.get("basicInfoSummary");
+        Map<String, Object> basicInfoSummary = (Map<String, Object>) data.get("financialSummary");
         basicInfoSummary.replaceAll((k, v) -> v.equals("") ? "-" : v);
-        Map<String, Object> platformExt = (Map<String, Object>) data.get("platformExt");
-        platformExt.replaceAll((k, v) -> v.equals("") ? "-" : v);
-        Object certReceived = data.get("certReceived");
-        if (certReceived.equals("-")) {
-            data.put("certReceived", "否");
-        }
-        Object bankLicense = data.get("bankLicense");
-        if (bankLicense.equals("-")) {
-            data.put("bankLicense", "否");
-        }
     }
 
-//    public String renderDocx(FinancialInfo info, Map<String, Object> addtionalMap, byte[] templateFileContent) throws IOException {
-//
-//        // 不需要定制展示逻辑的时候,使用protobuf的转json方法
-//        String jsonStr = JsonFormat.printer().print(info);
-//
-//        // 注: 报告模板的模板变量按照json序列化的结果命名
-//        // 注: 目前的实现假设:一个session对应一个cwd目录
-//        ConfigureBuilder builder = Configure.builder();
-//        builder.bind("indicators", new LoopRowIncludeStatisticsTableRenderPolicy("values"));
-//        builder.bind("financialDataSeq", new LoopColumnStaticTableRenderPolicy("[", "]", false, true, 2));
-//        builder.bind("financialCheckDetails", new LoopRowCutAndMergeFirstColTableRenderPolicy());
-//        // 注意使用了SpringEL之后,每个模板变量都要设置值,不然会报错
-//        builder.useSpringEL();
-//
-//        this.docxResultPath = this.renderDocx(jsonStr, addtionalMap, templateFileContent, builder,
-//            Paths.get(cwd, UUID.randomUUID().toString() + ".docx").toString());
-//        return this.docxResultPath;
-//    }
-
-    /**
-     * 这些render policy类都应当是共享的 重要设计假设: data的类型cast都可以建立在json通用反序列化后的基本类型基础上。
-     */
-    public class LoopColumnStaticTableRenderPolicy implements RenderPolicy {
-
-        private String prefix;
-        private String suffix;
-        private boolean onSameLine;
-        private boolean reverse;
-        private int valColIndex;
-
-        public LoopColumnStaticTableRenderPolicy() {
-            this(false);
-        }
-
-        public LoopColumnStaticTableRenderPolicy(boolean onSameLine) {
-            this("[", "]", onSameLine);
-        }
-
-        public LoopColumnStaticTableRenderPolicy(String prefix, String suffix) {
-            this(prefix, suffix, false);
-        }
-
-        public LoopColumnStaticTableRenderPolicy(String prefix, String suffix, boolean onSameLine) {
-            this(prefix, suffix, onSameLine, false);
-        }
-
-        public LoopColumnStaticTableRenderPolicy(String prefix, String suffix, boolean onSameLine, boolean reverse) {
-            this(prefix, suffix, onSameLine, false, 1);
-        }
-
-        public LoopColumnStaticTableRenderPolicy(String prefix, String suffix, boolean onSameLine, boolean reverse,
-            int valRowIndex) {
-            this.prefix = prefix;
-            this.suffix = suffix;
-            this.onSameLine = onSameLine;
-            this.reverse = reverse;
-            this.valColIndex = valRowIndex;
-        }
 
-        @Override
-        public void render(ElementTemplate eleTemplate, Object data, XWPFTemplate template) {
-            RunTemplate runTemplate = (RunTemplate) eleTemplate;
-            XWPFRun run = runTemplate.getRun();
-            try {
-                if (!TableTools.isInsideTable(run)) {
-                    throw new IllegalStateException(
-                        "The template tag " + runTemplate.getSource() + " must be inside a table");
-                }
-                XWPFTableCell tagCell = (XWPFTableCell) ((XWPFParagraph) run.getParent()).getBody();
-                XWPFTable table = tagCell.getTableRow().getTable();
-                run.setText("", 0);
 
-                int templateColIndex = getTemplateColIndex(tagCell);
-                // 模版变量列总是写在左边
-                int minIndex = templateColIndex;
-                int maxIndex = table.getRows().get(valColIndex).getTableCells().size() - 1;
-                int currIndex = reverse ? maxIndex : minIndex;
-                int indexDelta = reverse ? -1 : 1;
-
-                // 目前expression当作数据Map的key来对待,将来可以当作POI-TL变量一致化的处理
-                Map<Integer, String> idx2Expression = new HashMap<>();
-                for (int i = 0; i < table.getRows().size(); i++) {
-                    XWPFTableCell cell = table.getRows().get(i).getCell(templateColIndex);
-                    String text = cell.getText().trim();
-                    if (text.startsWith(prefix) && text.endsWith(suffix)) {
-                        idx2Expression.put(i, text.substring(1, text.length() - 1));
-                        cell.setText("");
-                    }
-                }
-
-                int rowSize = table.getRows().size();
-                @SuppressWarnings("unchecked")
-                List<Map<String, Object>> mpData = (List<Map<String, Object>>) data;
-
-                for (Map<String, Object> realData : mpData) {
-                    for (int i = 0; i < rowSize; i++) {
-                        if (!idx2Expression.containsKey(i)) {
-                            continue;
-                        }
-                        XWPFTableRow row = table.getRow(i);
-                        XWPFTableCell valueCell = row.getCell(currIndex);
-                        String valStr = realData.getOrDefault(idx2Expression.get(i), "-").toString();
-                        valueCell.setText(valStr);
-                    }
-                    currIndex += indexDelta;
-                }
-
-            } catch (Exception e) {
-                throw new RenderException("HackLoopTable for " + eleTemplate + "error: " + e.getMessage(), e);
-            }
-        }
-
-        private int getTemplateColIndex(XWPFTableCell tagCell) {
-            return onSameLine ? Util.getColIndexOfFirstRow(tagCell) : (Util.getColIndexOfFirstRow(tagCell) + 1);
-        }
-    }
-
-    public class LoopRowCutAndMergeFirstColTableRenderPolicy extends LoopRowTableRenderPolicy {
-
-        @Override
-        public void render(ElementTemplate eleTemplate, Object data, XWPFTemplate template) {
-            RunTemplate runTemplate = (RunTemplate) eleTemplate;
-            XWPFRun run = runTemplate.getRun();
-            XWPFTable table = null;
-            try {
-                if (!TableTools.isInsideTable(run)) {
-                    throw new IllegalStateException(
-                        "The template tag " + runTemplate.getSource() + " must be inside a table");
-                }
-                // Reserve the first two rows
-                XWPFTableCell tagCell = (XWPFTableCell) ((XWPFParagraph) run.getParent()).getBody();
-                table = tagCell.getTableRow().getTable();
-                for (int i = table.getNumberOfRows() - 1; i > 1; i--) {
-                    table.removeRow(i);
-                }
-            } catch (Exception e) {
-                throw new RenderException(
-                    "LoopRowCutAndMergeFirstColTable for " + eleTemplate + " error: " + e.getMessage(), e);
-            }
-
-            // in case data not sorted by rank
-            @SuppressWarnings("unchecked")
-            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);
-
-            try {
-                // merge the first column
-                Util.mergeFirstNColSimple(table, 1, 0);
-            } catch (Exception e) {
-                throw new RenderException(
-                    "LoopRowCutAndMergeFirstColTable for " + eleTemplate + " error: " + e.getMessage(), e);
-            }
-        }
-    }
-
-    public class LoopRowIncludeStatisticsTableRenderPolicy extends LoopRowTableRenderPolicy {
-
-        private String valueTag;
-
-        public LoopRowIncludeStatisticsTableRenderPolicy(String valueTag) {
-            this.valueTag = valueTag;
-        }
-
-        @Override
-        public void render(ElementTemplate eleTemplate, Object data, XWPFTemplate template) {
-            @SuppressWarnings("unchecked")
-            List<Map<String, Object>> mpData = (List<Map<String, Object>>) data;
-            for (Map<String, Object> row : mpData) {
-                @SuppressWarnings("unchecked")
-                List<String> values = (List<String>) row.get(valueTag);
-                row.put("avg", values.stream().mapToLong(Long::valueOf).average().orElse(Double.NaN));
-            }
-
-            super.render(eleTemplate, data, template);
-        }
-    }
 }

+ 319 - 141
easier-report-biz/src/main/java/com/yaoyicloud/render/PublicRecordRender.java

@@ -1,141 +1,319 @@
-//package com.yaoyicloud.render;
-//
-//import java.io.IOException;
-//import java.nio.file.Paths;
-//import java.util.List;
-//import java.util.Map;
-//import java.util.UUID;
-//import java.util.stream.Collectors;
-//
-//import com.deepoove.poi.config.Configure;
-//import com.deepoove.poi.config.ConfigureBuilder;
-//import com.deepoove.poi.plugin.table.LoopRowTableRenderPolicy;
-//import com.fasterxml.jackson.core.JsonGenerator;
-//import com.fasterxml.jackson.core.JsonProcessingException;
-//import com.fasterxml.jackson.databind.ObjectMapper;
-//import com.fasterxml.jackson.databind.SerializerProvider;
-//import com.fasterxml.jackson.databind.module.SimpleModule;
-//import com.fasterxml.jackson.databind.ser.std.StdSerializer;
-//import com.google.protobuf.InvalidProtocolBufferException;
-//import com.google.protobuf.MessageOrBuilder;
-//import com.google.protobuf.util.JsonFormat;
-//import com.yaoyicloud.message.FxyProtos.PublicRecord;
-//
-///**
-// * PublicRecord渲染器
-// *
-// */
-//public final class PublicRecordRender extends AbstractRender {
-//
-//    public PublicRecordRender(String cwd) {
-//        super(cwd);
-//    }
-//
-//    /**
-//     * Docx 渲染
-//     *
-//     * @param info 数据
-//     * @param templateFileContent 模板内容
-//     * @return 本地文件目录
-//     * @throws IOException
-//     */
-////    public String renderDocx(PublicRecord info, Map<String, Object> addtionalMap, byte[] templateFileContent) throws IOException {
-////        // TODO: let mapper be package static
-////        ObjectMapper mapper = new ObjectMapper();
-////        SimpleModule module = new SimpleModule();
-////        module.addSerializer(new PublicRecordSerializer(PublicRecord.class));
-////        mapper.registerModule(module);
-////
-////        String jsonStr = mapper.writeValueAsString(info);
-////
-////        // 注: 报告模板的模板变量按照json序列化的结果命名
-////        // 注: 目前的实现假设:一个session对应一个cwd目录
-////        ConfigureBuilder builder = Configure.builder();
-////        builder.bind("dishonestPersons", new LoopRowTableRenderPolicy());
-////        builder.bind("businessAbnormals", new LoopRowTableRenderPolicy());
-////        builder.bind("penaltyRecords", new LoopRowTableRenderPolicy());
-////        builder.bind("taxPenalties", new LoopRowTableRenderPolicy());
-////        builder.bind("severeViolations", new LoopRowTableRenderPolicy());
-////        this.docxResultPath =
-////            this.renderDocx(jsonStr, addtionalMap, templateFileContent, builder,
-////                Paths.get(cwd, UUID.randomUUID().toString() + ".docx").toString());
-////        return this.docxResultPath;
-////    }
-//
-//    /*
-//     * 通过序列化和反序列化
-//     * 1. 进行默认显示规则的数据转换
-//     * 2. 避免POI-TL处理模板面对复杂数据类型
-//     */
-//    public class PublicRecordSerializer extends StdSerializer<PublicRecord> {
-//
-//        public PublicRecordSerializer() {
-//            this(null);
-//        }
-//
-//        public PublicRecordSerializer(Class<PublicRecord> t) {
-//            super(t);
-//        }
-//
-//        /**
-//         * 为了增加*Count的数值,定制了序列化方法。 TODO: 可能更简单的方法是使用POI-TL的Spring表达式能力
-//         */
-//        @Override
-//        public void serialize(PublicRecord value, JsonGenerator jgen, SerializerProvider provider)
-//            throws IOException, JsonProcessingException {
-//
-//            jgen.writeStartObject();
-//
-//            jgen.writeArrayFieldStart("dishonestPersons");
-//            writeRawArray(
-//                value.getDishonestPersonsList().stream().map(o -> (MessageOrBuilder) o).collect(Collectors.toList()),
-//                jgen);
-//            jgen.writeEndArray();
-//            jgen.writeNumberField("dishonestPersonsCount", value.getDishonestPersonsCount());
-//
-//            jgen.writeArrayFieldStart("businessAbnormals");
-//            writeRawArray(
-//                value.getBusinessAbnormalsList().stream().map(o -> (MessageOrBuilder) o).collect(Collectors.toList()),
-//                jgen);
-//            jgen.writeEndArray();
-//            jgen.writeNumberField("businessAbnormalsCount", value.getBusinessAbnormalsCount());
-//
-//            jgen.writeArrayFieldStart("penaltyRecords");
-//            writeRawArray(
-//                value.getPenaltyRecordsList().stream().map(o -> (MessageOrBuilder) o).collect(Collectors.toList()),
-//                jgen);
-//            jgen.writeEndArray();
-//            jgen.writeNumberField("penaltyRecordsCount", value.getPenaltyRecordsCount());
-//
-//            jgen.writeArrayFieldStart("taxPenalties");
-//            writeRawArray(
-//                value.getTaxPenaltiesList().stream().map(o -> (MessageOrBuilder) o).collect(Collectors.toList()), jgen);
-//            jgen.writeEndArray();
-//            jgen.writeNumberField("taxPenaltiesCount", value.getTaxPenaltiesCount());
-//
-//            jgen.writeArrayFieldStart("severeViolations");
-//            writeRawArray(
-//                value.getSevereViolationsList().stream().map(o -> (MessageOrBuilder) o).collect(Collectors.toList()),
-//                jgen);
-//            jgen.writeEndArray();
-//            jgen.writeNumberField("severeViolationsCount", value.getSevereViolationsCount());
-//
-//            jgen.writeRaw(", \"publicRecordSummary\": " + JsonFormat.printer().print(value.getPublicRecordSummary()));
-//
-//            jgen.writeEndObject();
-//        }
-//
-//        private void writeRawArray(List<MessageOrBuilder> values, JsonGenerator jgen)
-//            throws IOException, InvalidProtocolBufferException {
-//            String comma = null;
-//            for (MessageOrBuilder item : values) {
-//                if (comma != null) {
-//                    jgen.writeRaw(comma);
-//                } else {
-//                    comma = ",";
-//                }
-//                jgen.writeRaw(JsonFormat.printer().print(item));
-//            }
-//        }
-//    }
-//}
+package com.yaoyicloud.render;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import com.deepoove.poi.config.Configure;
+import com.deepoove.poi.config.ConfigureBuilder;
+import com.deepoove.poi.policy.RenderPolicy;
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+import com.google.protobuf.InvalidProtocolBufferException;
+import com.google.protobuf.MessageOrBuilder;
+import com.google.protobuf.util.JsonFormat;
+import com.yaoyicloud.config.FilerepoProperties;
+
+import com.yaoyicloud.message.FxyProtos.PublicRecord;
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * PublicRecord渲染器
+ *
+ */
+@Slf4j
+public final class PublicRecordRender extends AbstractRender {
+    private final FilerepoProperties filerepoProperties;
+
+    public PublicRecordRender(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();
+        RenderPolicy indicatorsRenderPolicy = this.indicatorsRenderPolicy();
+
+        builder.bind("dishonestPersons", indicatorsRenderPolicy);
+        builder.bind("businessAbnormals", indicatorsRenderPolicy);
+        builder.bind("penaltyRecords", indicatorsRenderPolicy);
+        builder.bind("taxPenalties", indicatorsRenderPolicy);
+        builder.bind("severeViolations", indicatorsRenderPolicy);
+
+        ObjectMapper objectMapper = new ObjectMapper();
+        Map<String, Object> data = objectMapper.readValue(info, 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, "publicRecord");
+            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("publicRecordSummary");
+
+        // 如果存在 summary 对象,则处理其字段
+        if (basicInfoSummary != null) {
+            // 确保所有需要的字段都有默认值
+            setDefaultIfNull(basicInfoSummary, "score", "-");
+            setDefaultIfNull(basicInfoSummary, "riskSummary", "-");
+            setDefaultIfNull(basicInfoSummary, "suggestion", "-");
+        } else {
+            // 如果 summary 对象不存在,则创建并设置默认值
+            Map<String, Object> defaultSummary = new HashMap<>();
+            defaultSummary.put("score", "-");
+            defaultSummary.put("riskSummary", "-");
+            defaultSummary.put("suggestion", "-");
+            data.put("publicRecordSummary", defaultSummary);
+        }
+        basicInfoSummary.replaceAll((k, v) -> v.equals("") ? "-" : v);
+
+        Map<String, Object> dishonestPersonsMap = (Map<String, Object>) data.get("dishonestPersons");
+        if (dishonestPersonsMap != null) {
+            dishonestPersonsMap.replaceAll((k, v) -> v.equals("") ? "-" : v);
+            data.put("dishonestPersonsCount", dishonestPersonsMap.size());
+        } else {
+            Map<String, Object> defaultDishonestPerson = new HashMap<>();
+            defaultDishonestPerson.put("id", "1");
+            defaultDishonestPerson.put("inDate", "-");
+            defaultDishonestPerson.put("caseNumber", "-");
+            defaultDishonestPerson.put("amount", "-");
+            defaultDishonestPerson.put("executionDesc", "-");
+            defaultDishonestPerson.put("executionStatus", "-");
+            defaultDishonestPerson.put("court", "-");
+            defaultDishonestPerson.put("disabled", "-");
+
+            List<Map<String, Object>> defaultDishonestPersonList = Collections.singletonList(defaultDishonestPerson);
+
+            data.put("dishonestPersons", defaultDishonestPersonList);
+            data.put("dishonestPersonsCount", 0);
+        }
+
+        Map<String, Object> businessAbnormalsMap = (Map<String, Object>) data.get("businessAbnormals");
+        if (businessAbnormalsMap != null) {
+            businessAbnormalsMap.replaceAll((k, v) -> v.equals("") ? "-" : v);
+            data.put("businessAbnormalsCount", businessAbnormalsMap.size());
+        } else {
+            Map<String, Object> defaultBusinessAbnormal = new HashMap<>();
+            defaultBusinessAbnormal.put("id", "1");
+            defaultBusinessAbnormal.put("inDate", "-");
+            defaultBusinessAbnormal.put("department", "-");
+            defaultBusinessAbnormal.put("inReason", "-");
+            defaultBusinessAbnormal.put("disabled", "-");
+            List<Map<String, Object>> defaultBusinessAbnormalList = Collections.singletonList(defaultBusinessAbnormal);
+
+            data.put("businessAbnormals", defaultBusinessAbnormalList);
+            data.put("businessAbnormalsCount", 0);
+        }
+
+        Map<String, Object> penaltyRecordsMap = (Map<String, Object>) data.get("penaltyRecords");
+        if (penaltyRecordsMap != null) {
+            penaltyRecordsMap.replaceAll((k, v) -> v.equals("") ? "-" : v);
+            data.put("penaltyRecordsCount", penaltyRecordsMap.size());
+        } else {
+            Map<String, Object> defaultPenaltyRecord = new HashMap<>();
+            defaultPenaltyRecord.put("id", "1");
+            defaultPenaltyRecord.put("seqNo", "-");
+            defaultPenaltyRecord.put("number", "-");
+            defaultPenaltyRecord.put("penaltyData", "-");
+            defaultPenaltyRecord.put("content", "-");
+            defaultPenaltyRecord.put("punishAmnt", "-");
+            defaultPenaltyRecord.put("department", "-");
+            defaultPenaltyRecord.put("description", "-");
+            List<Map<String, Object>> defaultPenaltyRecordList = Collections.singletonList(defaultPenaltyRecord);
+
+            data.put("penaltyRecords", defaultPenaltyRecordList);
+            data.put("penaltyRecordsCount", 0);
+        }
+
+        Map<String, Object> taxPenaltiesMap = (Map<String, Object>) data.get("taxPenalties");
+        if (taxPenaltiesMap != null) {
+            taxPenaltiesMap.replaceAll((k, v) -> v.equals("") ? "-" : v);
+            data.put("taxPenaltiesCount", taxPenaltiesMap.size());
+        } else {
+            Map<String, Object> defaultTaxPenalty = new HashMap<>();
+            defaultTaxPenalty.put("id", "1");
+            defaultTaxPenalty.put("time", "-");
+            defaultTaxPenalty.put("type", "-");
+            defaultTaxPenalty.put("result", "-");
+            List<Map<String, Object>> defaultTaxPenaltyList = Collections.singletonList(defaultTaxPenalty);
+
+            data.put("taxPenalties", defaultTaxPenaltyList);
+            data.put("taxPenaltiesCount", 0);
+        }
+
+        Map<String, Object> severeViolationsMap = (Map<String, Object>) data.get("severeViolations");
+        if (severeViolationsMap != null) {
+            severeViolationsMap.replaceAll((k, v) -> v.equals("") ? "-" : v);
+            data.put("severeViolationsCount", severeViolationsMap.size());
+        } else {
+            Map<String, Object> defaultSevereViolation = new HashMap<>();
+            defaultSevereViolation.put("id", "1");
+            defaultSevereViolation.put("time", "-");
+            defaultSevereViolation.put("decisionDept", "-");
+            defaultSevereViolation.put("inReason", "-");
+            defaultSevereViolation.put("isHistory", "-");
+            List<Map<String, Object>> defaultSevereViolationList = Collections.singletonList(defaultSevereViolation);
+            data.put("severeViolations", defaultSevereViolationList);
+            data.put("severeViolationsCount", 0);
+        }
+    }
+
+    private void setDefaultIfNull(Map<String, Object> map, String key, Object defaultValue) {
+        if (!map.containsKey(key) || map.get(key) == null) {
+            map.put(key, defaultValue);
+        }
+    }
+
+    // /**
+    // * Docx 渲染
+    // *
+    // * @param info 数据
+    // * @param templateFileContent 模板内容
+    // * @return 本地文件目录
+    // * @throws IOException
+    // */
+    // public String renderDocx(PublicRecord info, Map<String, Object> addtionalMap, byte[] templateFileContent) throws IOException {
+    // // TODO: let mapper be package static
+    // ObjectMapper mapper = new ObjectMapper();
+    // SimpleModule module = new SimpleModule();
+    // module.addSerializer(new PublicRecordSerializer(PublicRecord.class));
+    // mapper.registerModule(module);
+    //
+    // String jsonStr = mapper.writeValueAsString(info);
+    //
+    // // 注: 报告模板的模板变量按照json序列化的结果命名
+    // // 注: 目前的实现假设:一个session对应一个cwd目录
+    // ConfigureBuilder builder = Configure.builder();
+    // builder.bind("dishonestPersons", new LoopRowTableRenderPolicy());
+    // builder.bind("businessAbnormals", new LoopRowTableRenderPolicy());
+    // builder.bind("penaltyRecords", new LoopRowTableRenderPolicy());
+    // builder.bind("taxPenalties", new LoopRowTableRenderPolicy());
+    // builder.bind("severeViolations", new LoopRowTableRenderPolicy());
+    // this.docxResultPath =
+    // this.renderDocx(jsonStr, addtionalMap, templateFileContent, builder,
+    // Paths.get(cwd, UUID.randomUUID().toString() + ".docx").toString());
+    // return this.docxResultPath;
+    // }
+
+    /*
+     * 通过序列化和反序列化
+     * 1. 进行默认显示规则的数据转换
+     * 2. 避免POI-TL处理模板面对复杂数据类型
+     */
+    public class PublicRecordSerializer extends StdSerializer<PublicRecord> {
+
+        public PublicRecordSerializer() {
+            this(null);
+        }
+
+        public PublicRecordSerializer(Class<PublicRecord> t) {
+            super(t);
+        }
+
+        /**
+         * 为了增加*Count的数值,定制了序列化方法。 TODO: 可能更简单的方法是使用POI-TL的Spring表达式能力
+         */
+        @Override
+        public void serialize(PublicRecord value, JsonGenerator jgen, SerializerProvider provider)
+            throws IOException, JsonProcessingException {
+
+            jgen.writeStartObject();
+
+            jgen.writeArrayFieldStart("dishonestPersons");
+            writeRawArray(
+                value.getDishonestPersonsList().stream().map(o -> (MessageOrBuilder) o).collect(Collectors.toList()),
+                jgen);
+            jgen.writeEndArray();
+            jgen.writeNumberField("dishonestPersonsCount", value.getDishonestPersonsCount());
+
+            jgen.writeArrayFieldStart("businessAbnormals");
+            writeRawArray(
+                value.getBusinessAbnormalsList().stream().map(o -> (MessageOrBuilder) o).collect(Collectors.toList()),
+                jgen);
+            jgen.writeEndArray();
+            jgen.writeNumberField("businessAbnormalsCount", value.getBusinessAbnormalsCount());
+
+            jgen.writeArrayFieldStart("penaltyRecords");
+            writeRawArray(
+                value.getPenaltyRecordsList().stream().map(o -> (MessageOrBuilder) o).collect(Collectors.toList()),
+                jgen);
+            jgen.writeEndArray();
+            jgen.writeNumberField("penaltyRecordsCount", value.getPenaltyRecordsCount());
+
+            jgen.writeArrayFieldStart("taxPenalties");
+            writeRawArray(
+                value.getTaxPenaltiesList().stream().map(o -> (MessageOrBuilder) o).collect(Collectors.toList()), jgen);
+            jgen.writeEndArray();
+            jgen.writeNumberField("taxPenaltiesCount", value.getTaxPenaltiesCount());
+
+            jgen.writeArrayFieldStart("severeViolations");
+            writeRawArray(
+                value.getSevereViolationsList().stream().map(o -> (MessageOrBuilder) o).collect(Collectors.toList()),
+                jgen);
+            jgen.writeEndArray();
+            jgen.writeNumberField("severeViolationsCount", value.getSevereViolationsCount());
+
+            jgen.writeRaw(", \"publicRecordSummary\": " + JsonFormat.printer().print(value.getPublicRecordSummary()));
+
+            jgen.writeEndObject();
+        }
+
+        private void writeRawArray(List<MessageOrBuilder> values, JsonGenerator jgen)
+            throws IOException, InvalidProtocolBufferException {
+            String comma = null;
+            for (MessageOrBuilder item : values) {
+                if (comma != null) {
+                    jgen.writeRaw(comma);
+                } else {
+                    comma = ",";
+                }
+                jgen.writeRaw(JsonFormat.printer().print(item));
+            }
+        }
+    }
+}

+ 6 - 5
easier-report-biz/src/main/java/com/yaoyicloud/render/ServiceProviderInfoRender.java

@@ -1,7 +1,7 @@
 package com.yaoyicloud.render;
 
 import java.io.IOException;
-import java.util.ArrayList;
+
 import java.util.Map;
 import com.deepoove.poi.config.Configure;
 import com.deepoove.poi.config.ConfigureBuilder;
@@ -50,7 +50,7 @@ public final class ServiceProviderInfoRender extends AbstractRender {
 
         // 配置POI-TL渲染器
         ConfigureBuilder builder = Configure.builder();
-        RenderPolicy indicatorsRenderPolicy = this.indicatorsRenderPolicy();
+        RenderPolicy indicatorsRenderPolicy = this.getScoreRenderPolicy();
         builder.bind("checkItemScores", indicatorsRenderPolicy);
         FxyProtos.AuditResult.Builder auditResultBuilder = FxyProtos.AuditResult.newBuilder();
         JsonFormat.parser().merge(info, auditResultBuilder);
@@ -70,11 +70,11 @@ public final class ServiceProviderInfoRender extends AbstractRender {
         if (addtionalMap != null) {
             data.putAll(addtionalMap);
         }
-    //    fillDefaultValues(data);
+        fillDefaultValues(data);
 
         try {
             // 渲染文档
-            String resultPath = this.renderDocx(data, templateFileContent, builder, relationId);
+            String resultPath = this.renderDocx(data, templateFileContent, builder, relationId, "serviceProviderInfo");
             log.info("渲染公共封面成功,文件路径: {}", resultPath);
             return resultPath;
         } catch (Exception e) {
@@ -86,7 +86,8 @@ public final class ServiceProviderInfoRender extends AbstractRender {
      * 填充默认值,确保所有必要字段都存在
      */
     private void fillDefaultValues(Map<String, Object> data) {
-        Object checkItemScores = data.get("checkItemScores");
+        Map<String, Object> basicInfoSummary = (Map<String, Object>) data.get("overallSummary");
+        basicInfoSummary.replaceAll((k, v) -> v.equals("") ? "-" : v);
 
     }
 

+ 98 - 0
easier-report-biz/src/main/java/com/yaoyicloud/render/update/BasicInfoNewRender.java

@@ -0,0 +1,98 @@
+package com.yaoyicloud.render.update;
+
+import java.io.IOException;
+import java.util.Map;
+
+import com.deepoove.poi.config.Configure;
+import com.deepoove.poi.config.ConfigureBuilder;
+import com.deepoove.poi.policy.RenderPolicy;
+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;
+
+/**
+ * BasicInfo渲染器
+ *
+ */
+@Slf4j
+public final class BasicInfoNewRender extends AbstractRender {
+    private final FilerepoProperties filerepoProperties;
+    public BasicInfoNewRender(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();
+        RenderPolicy indicatorsRenderPolicy = this.indicatorsRenderPolicy();
+        builder.bind("basicInfoChecks", indicatorsRenderPolicy);
+        builder.addPlugin('^',  this.pictureRenderPolicy());
+        //通过默认protobuf实例来填充不存在的key
+        FxyProtos.BasicInfo.Builder basicInfoBuilder = FxyProtos.BasicInfo.newBuilder();
+        JsonFormat.parser().merge(info, basicInfoBuilder);
+
+        FxyProtos.BasicInfo defaultInstance = FxyProtos.BasicInfo.getDefaultInstance();
+        FxyProtos.BasicInfo 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, "basicInfo");
+            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("basicInfoSummary");
+        basicInfoSummary.replaceAll((k, v) -> v.equals("") ? "-" : v);
+        Map<String, Object> platformExt = (Map<String, Object>) data.get("platformExt");
+        platformExt.replaceAll((k, v) -> v.equals("") ? "-" : v);
+    }
+
+}

+ 254 - 0
easier-report-biz/src/main/java/com/yaoyicloud/render/update/PublicRecordNewRender.java

@@ -0,0 +1,254 @@
+package com.yaoyicloud.render.update;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import com.deepoove.poi.config.Configure;
+import com.deepoove.poi.config.ConfigureBuilder;
+import com.deepoove.poi.policy.RenderPolicy;
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+import com.google.protobuf.InvalidProtocolBufferException;
+import com.google.protobuf.MessageOrBuilder;
+import com.google.protobuf.util.JsonFormat;
+import com.yaoyicloud.config.FilerepoProperties;
+import com.yaoyicloud.message.FxyProtos.PublicRecord;
+
+import com.yaoyicloud.render.AbstractRender;
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * PublicRecord渲染器
+ *
+ */
+@Slf4j
+public final class PublicRecordNewRender extends AbstractRender {
+    private final FilerepoProperties filerepoProperties;
+
+    public PublicRecordNewRender(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();
+        RenderPolicy indicatorsRenderPolicy = this.indicatorsRenderPolicy();
+
+        builder.bind("dishonestPersons", indicatorsRenderPolicy);
+        builder.bind("judicialRiskChecks", indicatorsRenderPolicy);
+
+        builder.bind("severeViolations", indicatorsRenderPolicy);
+
+        ObjectMapper objectMapper = new ObjectMapper();
+        Map<String, Object> data = objectMapper.readValue(info, 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, "publicRecord");
+            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("publicRecordSummary");
+        basicInfoSummary.replaceAll((k, v) -> v.equals("") ? "-" : v);
+
+        Map<String, Object> dishonestPersonsMap = (Map<String, Object>) data.get("dishonestPersons");
+        if (dishonestPersonsMap != null) {
+            dishonestPersonsMap.replaceAll((k, v) -> v.equals("") ? "-" : v);
+            data.put("dishonestPersonsCount", dishonestPersonsMap.size());
+        } else {
+            Map<String, Object> defaultDishonestPerson = new HashMap<>();
+            defaultDishonestPerson.put("id", "1");
+            defaultDishonestPerson.put("inDate", "-");
+            defaultDishonestPerson.put("caseNumber", "-");
+            defaultDishonestPerson.put("amount", "-");
+            defaultDishonestPerson.put("executionDesc", "-");
+            defaultDishonestPerson.put("executionStatus", "-");
+            defaultDishonestPerson.put("court", "-");
+            defaultDishonestPerson.put("disabled", "-");
+
+            List<Map<String, Object>> defaultDishonestPersonList = Collections.singletonList(defaultDishonestPerson);
+
+            data.put("dishonestPersons", defaultDishonestPersonList);
+            data.put("dishonestPersonsCount", 0);
+        }
+        Map<String, Object> severeViolationsMap = (Map<String, Object>) data.get("severeViolations");
+        if (severeViolationsMap != null) {
+            severeViolationsMap.replaceAll((k, v) -> v.equals("") ? "-" : v);
+            data.put("severeViolationsCount", severeViolationsMap.size());
+        } else {
+            Map<String, Object> defaultSevereViolation = new HashMap<>();
+            defaultSevereViolation.put("id", "1");
+            defaultSevereViolation.put("time", "-");
+            defaultSevereViolation.put("decisionDept", "-");
+            defaultSevereViolation.put("inReason", "-");
+            defaultSevereViolation.put("isHistory", "-");
+            List<Map<String, Object>> defaultSevereViolationList = Collections.singletonList(defaultSevereViolation);
+            data.put("severeViolations", defaultSevereViolationList);
+            data.put("severeViolationsCount", 0);
+        }
+        Map<String, Object> judicialRiskChecksMap = (Map<String, Object>) data.get("judicialRiskChecks");
+        if (judicialRiskChecksMap != null) {
+            data.put("judicialRiskCount", judicialRiskChecksMap.size());
+        }
+    }
+
+    private void setDefaultIfNull(Map<String, Object> map, String key, Object defaultValue) {
+        if (!map.containsKey(key) || map.get(key) == null) {
+            map.put(key, defaultValue);
+        }
+    }
+
+    // /**
+    // * Docx 渲染
+    // *
+    // * @param info 数据
+    // * @param templateFileContent 模板内容
+    // * @return 本地文件目录
+    // * @throws IOException
+    // */
+    // public String renderDocx(PublicRecord info, Map<String, Object> addtionalMap, byte[] templateFileContent) throws IOException {
+    // // TODO: let mapper be package static
+    // ObjectMapper mapper = new ObjectMapper();
+    // SimpleModule module = new SimpleModule();
+    // module.addSerializer(new PublicRecordSerializer(PublicRecord.class));
+    // mapper.registerModule(module);
+    //
+    // String jsonStr = mapper.writeValueAsString(info);
+    //
+    // // 注: 报告模板的模板变量按照json序列化的结果命名
+    // // 注: 目前的实现假设:一个session对应一个cwd目录
+    // ConfigureBuilder builder = Configure.builder();
+    // builder.bind("dishonestPersons", new LoopRowTableRenderPolicy());
+    // builder.bind("businessAbnormals", new LoopRowTableRenderPolicy());
+    // builder.bind("penaltyRecords", new LoopRowTableRenderPolicy());
+    // builder.bind("taxPenalties", new LoopRowTableRenderPolicy());
+    // builder.bind("severeViolations", new LoopRowTableRenderPolicy());
+    // this.docxResultPath =
+    // this.renderDocx(jsonStr, addtionalMap, templateFileContent, builder,
+    // Paths.get(cwd, UUID.randomUUID().toString() + ".docx").toString());
+    // return this.docxResultPath;
+    // }
+
+    /*
+     * 通过序列化和反序列化
+     * 1. 进行默认显示规则的数据转换
+     * 2. 避免POI-TL处理模板面对复杂数据类型
+     */
+    public class PublicRecordSerializer extends StdSerializer<PublicRecord> {
+
+        public PublicRecordSerializer() {
+            this(null);
+        }
+
+        public PublicRecordSerializer(Class<PublicRecord> t) {
+            super(t);
+        }
+
+        /**
+         * 为了增加*Count的数值,定制了序列化方法。 TODO: 可能更简单的方法是使用POI-TL的Spring表达式能力
+         */
+        @Override
+        public void serialize(PublicRecord value, JsonGenerator jgen, SerializerProvider provider)
+            throws IOException, JsonProcessingException {
+
+            jgen.writeStartObject();
+
+            jgen.writeArrayFieldStart("dishonestPersons");
+            writeRawArray(
+                value.getDishonestPersonsList().stream().map(o -> (MessageOrBuilder) o).collect(Collectors.toList()),
+                jgen);
+            jgen.writeEndArray();
+            jgen.writeNumberField("dishonestPersonsCount", value.getDishonestPersonsCount());
+
+            jgen.writeArrayFieldStart("businessAbnormals");
+            writeRawArray(
+                value.getBusinessAbnormalsList().stream().map(o -> (MessageOrBuilder) o).collect(Collectors.toList()),
+                jgen);
+            jgen.writeEndArray();
+            jgen.writeNumberField("businessAbnormalsCount", value.getBusinessAbnormalsCount());
+
+            jgen.writeArrayFieldStart("penaltyRecords");
+            writeRawArray(
+                value.getPenaltyRecordsList().stream().map(o -> (MessageOrBuilder) o).collect(Collectors.toList()),
+                jgen);
+            jgen.writeEndArray();
+            jgen.writeNumberField("penaltyRecordsCount", value.getPenaltyRecordsCount());
+
+            jgen.writeArrayFieldStart("taxPenalties");
+            writeRawArray(
+                value.getTaxPenaltiesList().stream().map(o -> (MessageOrBuilder) o).collect(Collectors.toList()), jgen);
+            jgen.writeEndArray();
+            jgen.writeNumberField("taxPenaltiesCount", value.getTaxPenaltiesCount());
+
+            jgen.writeArrayFieldStart("severeViolations");
+            writeRawArray(
+                value.getSevereViolationsList().stream().map(o -> (MessageOrBuilder) o).collect(Collectors.toList()),
+                jgen);
+            jgen.writeEndArray();
+            jgen.writeNumberField("severeViolationsCount", value.getSevereViolationsCount());
+
+            jgen.writeRaw(", \"publicRecordSummary\": " + JsonFormat.printer().print(value.getPublicRecordSummary()));
+
+            jgen.writeEndObject();
+        }
+
+        private void writeRawArray(List<MessageOrBuilder> values, JsonGenerator jgen)
+            throws IOException, InvalidProtocolBufferException {
+            String comma = null;
+            for (MessageOrBuilder item : values) {
+                if (comma != null) {
+                    jgen.writeRaw(comma);
+                } else {
+                    comma = ",";
+                }
+                jgen.writeRaw(JsonFormat.printer().print(item));
+            }
+        }
+    }
+}

+ 4 - 1
easier-report-biz/src/main/java/com/yaoyicloud/service/ReportService.java

@@ -23,7 +23,10 @@ public interface ReportService {
             String outputBasePath,
             Long relationId,
             HttpServletRequest request,
-            ModuleType moduleType
+            ModuleType moduleType,
+            String name,
+            Integer levelInteger,
+            String tenantName
     ) throws Exception;
 
 }

+ 45 - 13
easier-report-biz/src/main/java/com/yaoyicloud/service/impl/ReportServiceImpl.java

@@ -12,7 +12,11 @@ import com.yaoyicloud.constant.enums.ReportType;
 import com.yaoyicloud.render.AntiBriberyRender;
 import com.yaoyicloud.render.AttachmentSectionRender;
 import com.yaoyicloud.render.BasicInfoRender;
+import com.yaoyicloud.render.FinancialInfoRender;
+import com.yaoyicloud.render.PublicRecordRender;
 import com.yaoyicloud.render.ServiceProviderInfoRender;
+import com.yaoyicloud.render.update.BasicInfoNewRender;
+import com.yaoyicloud.render.update.PublicRecordNewRender;
 import com.yaoyicloud.service.ReportService;
 import com.yaoyicloud.template.AcademicAssociationReport;
 import com.yaoyicloud.template.FoundationReport;
@@ -24,6 +28,8 @@ import lombok.extern.slf4j.Slf4j;
 
 import javax.servlet.http.HttpServletRequest;
 
+import static com.yaoyicloud.config.SessionInterceptor.SESSION_MAP;
+
 /**
  * 报告服务
  *
@@ -43,7 +49,7 @@ public class ReportServiceImpl implements ReportService {
     @Override
     public String createPlusVersionCheckReport(
         ReportType reportType, String data, byte[] templateBytes, String outputBasePath, Long relationId,
-        HttpServletRequest request, ModuleType moduleType)
+        HttpServletRequest request, ModuleType moduleType, String name, Integer level, String tenantName)
         throws Exception {
 
         // 1. 将字节流模版写入临时文件
@@ -54,32 +60,58 @@ public class ReportServiceImpl implements ReportService {
         Map<String, Object> processedData = new HashMap<>();
         processedData.put("reportDate", LocalDate.now().toString());
         processedData.put("type", reportType.getDesc());
-        String sessionId = request.getSession().getId();
-        String reportPath = null;
+        processedData.put("name", name);
+        processedData.put("tenantName", tenantName);
+        processedData.put("levelInteger", level);
+
+        String sessionId = SESSION_MAP.get(relationId.toString());
+
+        String reportPath;
         switch (moduleType) {
             case ANTIBRIBERY:
                 reportPath =
-                    new AntiBriberyRender("temp", filerepoProperties).renderDocx(data, processedData, templateBytes,
+                    new AntiBriberyRender(sessionId, filerepoProperties).renderDocx(data, processedData, templateBytes,
                         String.valueOf(relationId));
-                break;
+                return reportPath;
             case PLATFORM_COMPANY_BASICINFO:
                 reportPath =
-                    new BasicInfoRender("temp", filerepoProperties).renderDocx(data, processedData, templateBytes,
+                    new BasicInfoRender(sessionId, filerepoProperties).renderDocx(data, processedData, templateBytes,
                         String.valueOf(relationId));
-                break;
+                return reportPath;
             case PLATFORM_COMPANY_ATTACHMENTSECTION:
-                reportPath = new AttachmentSectionRender("temp", filerepoProperties).renderDocx(data, processedData,
-                    templateBytes, String.valueOf(relationId));
-                break;
+                reportPath =
+                    new AttachmentSectionRender(sessionId, filerepoProperties).renderDocx(data, processedData,
+                        templateBytes, String.valueOf(relationId));
+                return reportPath;
             case COMMON:
-                reportPath = new ServiceProviderInfoRender("temp", filerepoProperties).renderDocx(data, processedData,
+                reportPath =
+                    new ServiceProviderInfoRender(sessionId, filerepoProperties).renderDocx(data, processedData,
+                        templateBytes, String.valueOf(relationId));
+                return reportPath;
+            case PLATFORM_COMPANY_FinancialInfo:
+                reportPath = new FinancialInfoRender(sessionId, filerepoProperties).renderDocx(data, processedData,
                     templateBytes, String.valueOf(relationId));
-                break;
+                return reportPath;
+            case PUBLIC_RECORD:
+                reportPath = new PublicRecordRender(sessionId, filerepoProperties).renderDocx(data, processedData,
+                    templateBytes, String.valueOf(relationId));
+                return reportPath;
+            case PUBLIC_RECORD_NEW:
+                reportPath = new PublicRecordNewRender(sessionId, filerepoProperties).renderDocx(data, processedData,
+                        templateBytes, String.valueOf(relationId));
+                return reportPath;
+
+            case PLATFORM_COMPANY_BASICINFO_NEW:
+                reportPath =
+                        new BasicInfoNewRender(sessionId, filerepoProperties).renderDocx(data, processedData, templateBytes,
+                                String.valueOf(relationId));
+                return reportPath;
+
+
             default:
                 throw new UnsupportedOperationException("Unsupported module type: " + moduleType);
 
         }
-        return reportPath;
     }
 
 }

+ 13 - 8
easier-report-biz/src/test/java/com/yaoyicloud/render/test/TestFinancialInfoRender.java

@@ -15,29 +15,34 @@
 //import com.yaoyicloud.message.FxyProtos.FinancialInfo;
 //import com.yaoyicloud.render.FinancialInfoRender;
 //
+//import javax.annotation.Resource;
+//
 //public class TestFinancialInfoRender {
 //
+//    @Resource
+//
 //    @Test
 //    public void testRenderDocx() throws IOException {
 //
 //        byte[] content = Files
 //            .readAllBytes(Paths.get(getClass().getClassLoader().getResource("docx/finance.docx").getFile()));
 //        FinancialInfoRender render = new FinancialInfoRender("../temp/");
-//        String retPath = render.renderDocx(
-//            FinancialInfo.newBuilder().setNeProfit("20").addYears("2024").addYears("2023").addYears("2022")
+//        FinancialInfo.newBuilder().setNeProfit("20").addYears("2024").addYears("2023").addYears("2022")
 //                .setOperatingRevenue("999")
 //                .setFinancialSummary(CheckSummary.newBuilder().setRiskSummary("high risk").setSuggestion("accept it"))
 //                .addIndicators(
-//                    FinancialIndicator.newBuilder().setCategory("cate1").setIndicatorName("name1").addValues("13")
-//                        .addValues("14").addValues("15").setFormula("magic"))
+//                        FinancialIndicator.newBuilder().setCategory("cate1").setIndicatorName("name1").addValues("13")
+//                                .addValues("14").addValues("15").setFormula("magic"))
 //                .addFinancialDataSeq(FinancialData.newBuilder().setFixedAsset("1000").build())
 //                .addFinancialCheckDetails(CheckItemDetail.newBuilder().setCategory("cate1").setName("n2")
-//                    .setResult("r1").setScore(0).setReviewResult("rr1").setReviewScore(0).setRank(1))
+//                        .setResult("r1").setScore(0).setReviewResult("rr1").setReviewScore(0).setRank(1))
 //                .addFinancialCheckDetails(CheckItemDetail.newBuilder().setCategory("cate2").setName("n3")
-//                    .setResult("r1").setScore(0).setReviewResult("rr1").setReviewScore(0).setRank(2))
+//                        .setResult("r1").setScore(0).setReviewResult("rr1").setReviewScore(0).setRank(2))
 //                .addFinancialCheckDetails(CheckItemDetail.newBuilder().setCategory("cate1").setName("n1")
-//                    .setResult("r1").setScore(0).setReviewResult("rr1").setReviewScore(0).setRank(0))
-//                .build(),
+//                        .setResult("r1").setScore(0).setReviewResult("rr1").setReviewScore(0).setRank(0))
+//                .build()
+//        String retPath = render.renderDocx(
+//           ,
 //            Map.of(),
 //            content);
 //

BIN=BIN
easier-report-biz/src/test/resources/docx/antiBribery.docx


BIN=BIN
easier-report-biz/src/test/resources/docx/antiBribery_new.docx


BIN=BIN
easier-report-biz/src/test/resources/docx/attachments.docx


BIN=BIN
easier-report-biz/src/test/resources/docx/basic_info.docx


BIN=BIN
easier-report-biz/src/test/resources/docx/basic_info_new.docx


BIN=BIN
easier-report-biz/src/test/resources/docx/check_overview.docx


BIN=BIN
easier-report-biz/src/test/resources/docx/finance.docx


BIN=BIN
easier-report-biz/src/test/resources/docx/finance_new.docx


BIN=BIN
easier-report-biz/src/test/resources/docx/public_record.docx


BIN=BIN
easier-report-biz/src/test/resources/docx/public_record_new.docx


BIN=BIN
easier-report-biz/src/test/resources/docx/service_provider_info.docx


BIN=BIN
easier-report-biz/src/test/resources/docx/tax_new.docx