소스 검색

build 新版报告生成 四种类型报告

mamingxu 1 개월 전
부모
커밋
dcb3b8a54f

+ 17 - 24
easier-report-biz/pom.xml

@@ -9,6 +9,7 @@
         <version>0.0.1-SNAPSHOT</version>
     </parent>
 
+    <groupId>com.yaoyicloud</groupId>
     <artifactId>easier-report-biz</artifactId>
     <packaging>jar</packaging>
 
@@ -48,16 +49,7 @@
             <version>1.2.20</version>
         </dependency>
 
-        <!--注册中心客户端-->
-        <dependency>
-            <groupId>com.alibaba.cloud</groupId>
-            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
-        </dependency>
-        <!--配置中心客户端-->
-        <dependency>
-            <groupId>com.alibaba.cloud</groupId>
-            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
-        </dependency>
+
         <dependency>
             <groupId>com.lowagie</groupId>
             <artifactId>itext</artifactId>
@@ -73,20 +65,6 @@
             <artifactId>pdfbox</artifactId>
             <version>3.0.5</version>
         </dependency>
-        <!-- iText 7 核心 -->
-        <!--        <dependency>-->
-        <!--            <groupId>com.itextpdf</groupId>-->
-        <!--            <artifactId>itext7-core</artifactId>-->
-        <!--            <version>7.2.5</version>-->
-        <!--        </dependency>-->
-
-        <!-- iText 7 PDF/HTML 转换 -->
-        <dependency>
-            <groupId>com.itextpdf</groupId>
-            <artifactId>html2pdf</artifactId>
-            <version>4.0.5</version>
-        </dependency>
-
 
         <dependency>
             <groupId>com.github.librepdf</groupId>
@@ -175,5 +153,20 @@
             <scope>test</scope>
         </dependency>
     </dependencies>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-deploy-plugin</artifactId>
+                <configuration>
+                    <skip>true</skip>
+                </configuration>
+            </plugin>
 
+        </plugins>
+    </build>
 </project>

+ 0 - 2
easier-report-biz/src/main/java/com/yaoyicloud/EasierReportApplication.java

@@ -3,9 +3,7 @@ package com.yaoyicloud;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration;
-import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
 
-@EnableDiscoveryClient
 @SpringBootApplication(exclude = {MongoAutoConfiguration.class})
 public class EasierReportApplication {
     public static void main(String[] args) {

+ 30 - 167
easier-report-biz/src/main/java/com/yaoyicloud/service/impl/ReportServiceImpl.java

@@ -2,22 +2,13 @@ package com.yaoyicloud.service.impl;
 
 import java.io.File;
 import java.io.FileOutputStream;
-
-import java.util.ArrayList;
-import java.util.List;
 import java.util.Map;
-
-import cn.hutool.core.util.StrUtil;
-import com.deepoove.poi.data.NumberingFormat;
-import com.deepoove.poi.data.NumberingRenderData;
-import com.deepoove.poi.data.ParagraphRenderData;
-import com.deepoove.poi.data.PictureType;
-import com.deepoove.poi.data.Pictures;
-import com.deepoove.poi.data.Texts;
 import com.yaoyicloud.constant.enums.ReportType;
 import com.yaoyicloud.service.ReportService;
+import com.yaoyicloud.template.AcademicAssociationReport;
+import com.yaoyicloud.template.FoundationReport;
 import com.yaoyicloud.template.PlatformCompanyReport;
-import org.apache.commons.collections4.CollectionUtils;
+
 import org.springframework.stereotype.Service;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
@@ -32,11 +23,12 @@ import lombok.extern.slf4j.Slf4j;
 @Service
 @RequiredArgsConstructor
 public class ReportServiceImpl implements ReportService {
-
-    // private final AcademicAssociationReport academicAssociationReport;
-    // private final FoundationReport foundationReport;
     private final PlatformCompanyReport platformCompanyReport;
+    private final AcademicAssociationReport academicAssociationReport;
+    private final FoundationReport foundationReport;
+
 
+    @SuppressWarnings("checkstyle:ReturnCount")
     @Override
     public String createPlusVersionCheckReport(
         ReportType reportType, Map<String, Object> data, byte[] templateBytes, String outputBasePath, Long relationId)
@@ -47,171 +39,42 @@ public class ReportServiceImpl implements ReportService {
         try (FileOutputStream fos = new FileOutputStream(tempTemplateFile)) {
             fos.write(templateBytes);
         }
-        // 2.数据处理主要附件以及图片列表 针对raw数据封装poi-tl 1.12
-        String docurl1 = (String) data.get("docurl1");
-        data.put("docurl1", Texts.of(docurl1).link(docurl1).create());
-
-        if (data.containsKey("docurl1Text")) {
-            int i = 2;
-            while (data.containsKey("docurl" + i)) {
-                String url = (String) data.get("docurl" + i);
-                if (StrUtil.isNotBlank(url)) {
-                    data.put("docurl" + i, Texts.of(url).link(url).create());
-                }
-                i++;
-            }
-        }
-
-        String socialSecurityDetailsLink = (String) data.get("socialSecurityDetailsLink");
-        data.put("socialSecurityDetailsLink",
-            Texts.of(socialSecurityDetailsLink).link(socialSecurityDetailsLink).create());
-
-        String taxDeclarationImage = (String) data.get("taxDeclarationImage");
-        data.put("taxDeclarationImage", Texts.of(taxDeclarationImage).link(taxDeclarationImage).create());
-
-        String financialInfoLink = (String) data.get("financialInfoLink");
-        data.put("financialInfoLink", Texts.of(financialInfoLink).link(financialInfoLink).create());
-        List<ParagraphRenderData> paragraphImages = new ArrayList<>();
-
-        List<Map<String, Object>> imageDataList = (List<Map<String, Object>>) data.get("relatedEntitiesImage");
-        if (CollectionUtils.isNotEmpty(imageDataList)) {
-            for (Map<String, Object> imageData : imageDataList) {
-                ParagraphRenderData paragraphRenderData = new ParagraphRenderData();
-
-                if (imageData.containsKey("base64")) {
-                    String base64 = (String) imageData.get("base64");
-
-                    String fileExtension = (String) imageData.get("fileExtension");
-                    PictureType pictureType = PictureType.PNG; // 默认PNG
-                    if (fileExtension != null) {
-                        if (fileExtension.equalsIgnoreCase(".jpg") || fileExtension.equalsIgnoreCase(".jpeg")) {
-                            pictureType = PictureType.JPEG;
-                        } else if (fileExtension.equalsIgnoreCase(".gif")) {
-                            pictureType = PictureType.GIF;
-                        } else if (fileExtension.equalsIgnoreCase(".bmp")) {
-                            pictureType = PictureType.BMP;
-                        } else if (fileExtension.equalsIgnoreCase(".png")) {
-                            pictureType = PictureType.PNG;
-                        } else if (fileExtension.equalsIgnoreCase(".tiff")) {
-                            pictureType = PictureType.TIFF;
-                        }
-                    }
-                    paragraphRenderData.addPicture(
-                        Pictures.ofBase64(base64, pictureType)
-                            .size((Integer) imageData.get("width"), (Integer) imageData.get("height"))
-                            .create());
-                }
-                paragraphImages.add(paragraphRenderData);
-            }
-            NumberingFormat numberingFormat = new NumberingFormat(1, "");
-            NumberingRenderData numberedImages = new NumberingRenderData(numberingFormat, paragraphImages);
-            data.put("relatedEntitiesImage", numberedImages);
-        }
-
-        // 处理 businessLicenseImage
-        processImageListToNumberedRenderData("businessLicenseImage", data);
-
-        // 处理 bankCertificateImage
-        processImageListToNumberedRenderData("bankCertificateImage", data);
-
-        // 处理 isoCertificationImage
-        processImageListToNumberedRenderData("isoCertificationImage", data);
-
-        // 处理 securityLevelCertification
-        processImageListToNumberedRenderData("securityLevelCertification", data);
-
-        // 处理 otherCertifications
-        processImageListToNumberedRenderData("otherCertifications", data);
-
-        // 处理 organizationalStructureImage
-        processImageListToNumberedRenderData("organizationalStructureImage", data);
-
-        // 处理 taxPaymentCertificateImage
-        processImageListToNumberedRenderData("taxPaymentCertificateImage", data);
-
-        // 处理 nsxydjwj
-        processImageListToNumberedRenderData("nsxydjwj", data);
-
-        // 处理 interestConflict
-        processImageListToNumberedRenderData("interestConflict", data);
-
-        // 处理 disanfangcangzhao
-        processImageListToNumberedRenderData("disanfangcangzhao", data);
-
-        // 处理 overallGuaranteeStatement
-        processImageListToNumberedRenderData("overallGuaranteeStatement", data);
+        Map<String, Object> processedData = null;
         switch (reportType) {
             case PLATFORM_COMPANY:
+                 processedData = platformCompanyReport.processData(data);
                 return platformCompanyReport.exportReport(
-                    data,
+                        processedData,
                     tempTemplateFile.getAbsolutePath(),
                     outputBasePath,
                     relationId);
             case ACADEMIC_ASSOCIATIONS:
-                // 其他类型处理...
+                processedData = academicAssociationReport.processData(data);
+                return academicAssociationReport.exportReport(
+                        processedData,
+                        tempTemplateFile.getAbsolutePath(),
+                        outputBasePath,
+                        relationId);
+            case FOUNDATION:
+                processedData = foundationReport.processData(data);
+                return foundationReport.exportReport(
+                        processedData,
+                        tempTemplateFile.getAbsolutePath(),
+                        outputBasePath,
+                        relationId);
+            case PROMOTION:
+                processedData = platformCompanyReport.processData(data);
+                return platformCompanyReport.exportReport(
+                        processedData,
+                        tempTemplateFile.getAbsolutePath(),
+                        outputBasePath,
+                        relationId);
             default:
                 throw new UnsupportedOperationException("Unsupported report type: " + reportType);
         }
     }
 
-    private void processImageListToNumberedRenderData(String key, Map<String, Object> data) {
-        // 从data中获取原始图片数据列表
-        List<Map<String, Object>> rawImageDataList = (List<Map<String, Object>>) data.get(key);
-
-        // 处理空数据情况
-        if (rawImageDataList == null || rawImageDataList.isEmpty()) {
-            String textKey = key + "Text";
-            if (data.containsKey(textKey)) {
-                return;
-            }
-        }
-        // 处理非空图片数据
-        List<ParagraphRenderData> paragraphImages = new ArrayList<>();
-        for (Map<String, Object> imageInfo : rawImageDataList) {
-            ParagraphRenderData paragraph = new ParagraphRenderData();
-            // 提取Base64数据和文件扩展名
-            String base64 = (String) imageInfo.get("base64");
-            String url = (String) imageInfo.get("url");
-            String fileExtension = (String) imageInfo.get("fileExtension");
-            Integer width = (Integer) imageInfo.get("width");
-            Integer height = (Integer) imageInfo.get("height");
-
-            // 确定图片类型(默认为PNG)
-            PictureType pictureType = this.determinePictureType(fileExtension);
 
-            // 添加图片到段落渲染数据
-            paragraph.addPicture(Pictures.ofBase64(base64, pictureType)
-                .size(width, height)
-                .create());
-
-            paragraphImages.add(paragraph);
-
-        }
-        NumberingFormat numberingFormat = new NumberingFormat(1, "");
-        NumberingRenderData numberedImages = new NumberingRenderData(numberingFormat, paragraphImages);
-        data.put(key, numberedImages);
-    }
-    // 辅助方法:根据文件扩展名确定图片类型
-    private PictureType determinePictureType(String fileExtension) {
-        if (fileExtension == null) {
-            return PictureType.PNG;
-        }
-
-        String ext = fileExtension.toLowerCase();
-
-        // 提取扩展名部分(去除可能的前缀点)
-        String normalizedExt = ext.startsWith(".")
-                ? ext.substring(1)
-                : ext;
-
-        return switch (normalizedExt) {
-            case "jpg", "jpeg" -> PictureType.JPEG;
-            case "gif" -> PictureType.GIF;
-            case "bmp" -> PictureType.BMP;
-            case "tiff" -> PictureType.TIFF;
-            default -> PictureType.PNG; // 默认返回 PNG
-        };
-    }
 }
 
 

+ 77 - 111
easier-report-biz/src/main/java/com/yaoyicloud/template/AbstractReportExporter.java

@@ -6,10 +6,16 @@ import java.util.List;
 import java.util.Map;
 
 import cn.hutool.core.util.IdUtil;
+import cn.hutool.core.util.StrUtil;
+import com.deepoove.poi.data.NumberingFormat;
+import com.deepoove.poi.data.NumberingRenderData;
+import com.deepoove.poi.data.ParagraphRenderData;
+import com.deepoove.poi.data.PictureType;
+import com.deepoove.poi.data.Pictures;
+import com.deepoove.poi.data.Texts;
 import com.deepoove.poi.plugin.table.LoopRowTableRenderPolicy;
 import com.yaoyicloud.constant.enums.ReportType;
 import com.yaoyicloud.tools.OfficeUtil1;
-import com.yaoyicloud.tools.TocEntity;
 import org.apache.poi.xwpf.usermodel.XWPFDocument;
 import org.apache.poi.xwpf.usermodel.XWPFParagraph;
 import org.apache.poi.xwpf.usermodel.XWPFRun;
@@ -26,27 +32,83 @@ import com.deepoove.poi.config.ConfigureBuilder;
 import com.deepoove.poi.policy.RenderPolicy;
 import com.deepoove.poi.template.ElementTemplate;
 import com.deepoove.poi.util.TableTools;
-import com.itextpdf.kernel.geom.LineSegment;
-import com.itextpdf.kernel.geom.Rectangle;
-import com.itextpdf.kernel.pdf.PdfDocument;
-import com.itextpdf.kernel.pdf.PdfPage;
-import com.itextpdf.kernel.pdf.PdfReader;
-import com.itextpdf.kernel.pdf.canvas.parser.EventType;
-import com.itextpdf.kernel.pdf.canvas.parser.PdfCanvasProcessor;
-import com.itextpdf.kernel.pdf.canvas.parser.data.IEventData;
-import com.itextpdf.kernel.pdf.canvas.parser.data.TextRenderInfo;
-import com.itextpdf.kernel.pdf.canvas.parser.listener.SimpleTextExtractionStrategy;
-
-
-
 /**
  * 模板方法模式, 定义一个导出流程的骨架
  *
  * @author lixuesong
  * @date 2024/05/30
  */
-public abstract class AbstractReportExporter {
+public abstract class AbstractReportExporter  implements ReportDataProcessor {
+
+    /**
+     * 将原始raw数据设置类型为poitl1.12版本超链接数据类型
+     * @param data raw数据集合
+     * @param key 模版key
+     */
+    protected void processLink(Map<String, Object> data, String key) {
+        String link = (String) data.get(key);
+        if (StrUtil.isNotBlank(link)) {
+            data.put(key, Texts.of(link).link(link).create());
+        }
+    }
+
+    /**
+     * 将原始raw数据设置类型为poitl1.12版本图片列表数据类型
+     * @param data raw数据集合
+     * @param key 模版key
+     */
+    protected void processImageListToNumberedRenderData(String key, Map<String, Object> data) {
+        List<Map<String, Object>> rawImageDataList = (List<Map<String, Object>>) data.get(key);
+        if (rawImageDataList == null || rawImageDataList.isEmpty()) {
+            String textKey = key + "Text";
+            if (data.containsKey(textKey)) {
+                return;
+            }
+        }
+
+        List<ParagraphRenderData> paragraphImages = new ArrayList<>();
+        for (Map<String, Object> imageInfo : rawImageDataList) {
+            ParagraphRenderData paragraph = new ParagraphRenderData();
+            String base64 = (String) imageInfo.get("base64");
+            String fileExtension = (String) imageInfo.get("fileExtension");
+            Integer width = (Integer) imageInfo.get("width");
+            Integer height = (Integer) imageInfo.get("height");
+
+            PictureType pictureType = determinePictureType(fileExtension);
+
+            paragraph.addPicture(Pictures.ofBase64(base64, pictureType)
+                    .size(width, height)
+                    .create());
+
+            paragraphImages.add(paragraph);
+        }
+
+        NumberingFormat numberingFormat = new NumberingFormat(1, "");
+        NumberingRenderData numberedImages = new NumberingRenderData(numberingFormat, paragraphImages);
+        data.put(key, numberedImages);
+    }
 
+    /**
+     * 图片格式
+     * @param fileExtension raw中的后缀
+     * @return
+     */
+    protected PictureType determinePictureType(String fileExtension) {
+        if (fileExtension == null) {
+            return PictureType.PNG;
+        }
+
+        String ext = fileExtension.toLowerCase();
+        String normalizedExt = ext.startsWith(".") ? ext.substring(1) : ext;
+
+        return switch (normalizedExt) {
+            case "jpg", "jpeg" -> PictureType.JPEG;
+            case "gif" -> PictureType.GIF;
+            case "bmp" -> PictureType.BMP;
+            case "tiff" -> PictureType.TIFF;
+            default -> PictureType.PNG;
+        };
+    }
     /**
      * 报告导出
      * @param relationId
@@ -113,54 +175,6 @@ public abstract class AbstractReportExporter {
 
     protected abstract String getBasicPath() throws IOException;
 
-    protected ArrayList<TocEntity> extractHeadings(String pdfPath) throws IOException {
-        ArrayList<TocEntity> headings = new ArrayList<>();
-        try (PdfDocument pdfDoc = new PdfDocument(new PdfReader(pdfPath))) {
-            for (int i = 1; i <= pdfDoc.getNumberOfPages(); i++) {
-                PdfPage page = pdfDoc.getPage(i);
-                final int currentPage = i;
-                new PdfCanvasProcessor(new HeadingDetectionStrategy(headings, pdfDoc, currentPage))
-                        .processPageContent(page);
-            }
-        }
-        return headings;
-    }
-
-    protected ArrayList<TocEntity> processHeadings(ArrayList<TocEntity> headings) {
-        ArrayList<TocEntity> result = new ArrayList<>();
-        if (headings == null || headings.isEmpty()) {
-            return result;
-        }
-        for (int i = 0; i < headings.size(); i++) {
-            TocEntity current = headings.get(i);
-
-            if (!current.getTitle().matches("^\\d+\\..*")) {
-                if (!result.isEmpty()) {
-                    TocEntity last = result.get(result.size() - 1);
-                    if (last.getPageNumber() == current.getPageNumber()) {
-                        TocEntity combined = new TocEntity(last.getTitle() + current.getTitle(), last.getPageNumber(),
-                                last.getLevel(), last.getRect(), last.getFontSize(), last.getParagraphHeight());
-                        result.set(result.size() - 1, combined);
-                        continue;
-                    }
-                }
-            }
-            if (current.getTitle().matches("^\\d+\\.")) {
-                if (i + 1 < headings.size()) {
-                    TocEntity next = headings.get(i + 1);
-                    TocEntity combined = new TocEntity(current.getTitle() + next.getTitle(), current.getPageNumber(),
-                            current.getLevel(), current.getRect(), current.getFontSize(), current.getParagraphHeight());
-                    result.add(combined);
-                    i++;
-                    continue;
-                }
-            }
-            result.add(current);
-        }
-
-        return result;
-    }
-
     protected RenderPolicy getScoreRenderPolicy() {
         RenderPolicy policy = new LoopRowTableRenderPolicy() {
             @SuppressWarnings("checkstyle:NestedForDepth")
@@ -265,52 +279,4 @@ public abstract class AbstractReportExporter {
         CTTcPr ctPr = cttc.addNewTcPr();
         ctPr.addNewVAlign().setVal(STVerticalJc.CENTER);
     }
-
-    private static class HeadingDetectionStrategy extends SimpleTextExtractionStrategy {
-        private static final float LEVEL_1_FONT_SIZE = 16;
-        private static final float LEVEL_2_FONT_SIZE = 12;
-        private final ArrayList<TocEntity> headings;
-        private final PdfDocument pdfDoc;
-        private final int currentPage;
-
-        HeadingDetectionStrategy(ArrayList<TocEntity> headings, PdfDocument pdfDoc, int currentPage) {
-            this.headings = headings;
-            this.pdfDoc = pdfDoc;
-            this.currentPage = currentPage;
-        }
-
-        @Override
-        public void eventOccurred(IEventData data, EventType type) {
-            if (type == EventType.RENDER_TEXT) {
-                TextRenderInfo info = (TextRenderInfo) data;
-                float fontSize = info.getFontSize();
-
-                if (fontSize == LEVEL_1_FONT_SIZE) {
-                    addHeading(info, 1, pdfDoc, currentPage, headings);
-                } else if (fontSize == LEVEL_2_FONT_SIZE) {
-                    addHeading(info, 2, pdfDoc, currentPage, headings);
-                }
-            }
-
-            super.eventOccurred(data, type);
-        }
-
-        private void addHeading(TextRenderInfo info, int level, PdfDocument pdfDoc, int i,
-                                ArrayList<TocEntity> headings) {
-            String text = info.getText().trim();
-            LineSegment ascentLine = info.getAscentLine();
-            LineSegment descentLine = info.getDescentLine();
-            float ascentY = ascentLine.getStartPoint().get(1);
-            float descentY = descentLine.getStartPoint().get(1);
-            float paragraphHeight = ascentY - descentY;
-
-            Rectangle rect = info.getBaseline().getBoundingRectangle();
-            if (!text.isEmpty()) {
-                headings.add(new TocEntity(text, i, level, rect, paragraphHeight, info.getFontSize()
-
-                ));
-            }
-        }
-
-    }
 }

+ 248 - 0
easier-report-biz/src/main/java/com/yaoyicloud/template/AcademicAssociationReport.java

@@ -0,0 +1,248 @@
+package com.yaoyicloud.template;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.collections4.CollectionUtils;
+import org.springframework.stereotype.Component;
+
+import com.deepoove.poi.XWPFTemplate;
+import com.deepoove.poi.config.Configure;
+import com.deepoove.poi.config.ConfigureBuilder;
+import com.deepoove.poi.data.NumberingFormat;
+import com.deepoove.poi.data.NumberingRenderData;
+import com.deepoove.poi.data.ParagraphRenderData;
+import com.deepoove.poi.data.PictureType;
+import com.deepoove.poi.data.Pictures;
+import com.deepoove.poi.data.Texts;
+import com.deepoove.poi.plugin.table.LoopRowTableRenderPolicy;
+import com.deepoove.poi.policy.RenderPolicy;
+import com.yaoyicloud.config.FilerepoProperties;
+import com.yaoyicloud.constant.enums.ReportType;
+
+import cn.hutool.core.util.StrUtil;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class AcademicAssociationReport extends AbstractReportExporter {
+    private final FilerepoProperties filerepoProperties;
+
+    @Override
+    protected String getReportImagePath() {
+        return filerepoProperties.getReportImagePath();
+    }
+
+
+
+    @Override
+    protected String getTemplate(ReportType reportType, String basePath) {
+        String reportTemplateFileName = getReportTemplateFileName(reportType);
+        return basePath + File.separator + reportTemplateFileName;
+    }
+
+    @Override
+    protected void bindConfigure(ConfigureBuilder builder) {
+        RenderPolicy scoreRenderPolicy = this.getScoreRenderPolicy();
+        LoopRowTableRenderPolicy hackLoopTableRenderPolicy = new LoopRowTableRenderPolicy();
+        builder.bind("checkItemScores", scoreRenderPolicy).bind("basicInfoChecks", hackLoopTableRenderPolicy)
+            .bind("businessAbnormals", hackLoopTableRenderPolicy).bind("dishonestPersons", hackLoopTableRenderPolicy)
+            .bind("penaltyRecords", hackLoopTableRenderPolicy).bind("taxPenalties", hackLoopTableRenderPolicy)
+            .bind("severeViolations", hackLoopTableRenderPolicy).bind("questionnaireItems", hackLoopTableRenderPolicy)
+            .bind("indicators", hackLoopTableRenderPolicy).bind("superiorAuthority", hackLoopTableRenderPolicy);
+    }
+
+    @Override
+    protected String imagePath() {
+        return filerepoProperties.getReportImagePath();
+    }
+
+
+    @Override
+    protected void renderTemplate(String reportTempWordFile, String templatePath, ConfigureBuilder builder,
+        Map<String, Object> data) throws IOException {
+        Configure config = builder.build();
+        XWPFTemplate template = XWPFTemplate.compile(templatePath, config).render(data);
+        template.writeToFile(reportTempWordFile);
+        template.close();
+    }
+
+
+
+    @Override
+    protected String getBasicPath() throws IOException {
+        return filerepoProperties.getBasePath();
+    }
+
+    /**
+     * 获取模板文件路径
+     *
+     * @param reportType
+     * @return
+     */
+    public String getReportTemplateFileName(ReportType reportType) {
+        return reportType.getType().toLowerCase() + "_template.docx";
+    }
+
+    @Override
+    protected List<String> getFontPaths() {
+        return Arrays.asList(filerepoProperties.getSourceHanSansCnBoldFontPath(),
+            filerepoProperties.getSourceHanSansCnFontPath());
+    }
+
+    @Override
+    public Map<String, Object> processData(Map<String, Object> rawData) throws Exception {
+        Map<String, Object> processedData = new HashMap<>(rawData);
+
+        String docurl1 = (String) processedData.get("docurl1");
+        processedData.put("docurl1", Texts.of(docurl1).link(docurl1).create());
+
+        if (processedData.containsKey("docurl1Text")) {
+            int i = 2;
+            while (processedData.containsKey("docurl" + i)) {
+                String url = (String) processedData.get("docurl" + i);
+                if (StrUtil.isNotBlank(url)) {
+                    processedData.put("docurl" + i, Texts.of(url).link(url).create());
+                }
+                i++;
+            }
+        }
+
+        List<Map<String, Object>> imageDataList = (List<Map<String, Object>>) processedData.get("files");
+        List<ParagraphRenderData> paragraphImages = new ArrayList<>();
+        if (CollectionUtils.isNotEmpty(imageDataList)) {
+            for (Map<String, Object> imageData : imageDataList) {
+                ParagraphRenderData paragraphRenderData = new ParagraphRenderData();
+
+                if (imageData.containsKey("base64")) {
+                    String base64 = (String) imageData.get("base64");
+
+                    String fileExtension = (String) imageData.get("fileExtension");
+                    PictureType pictureType = PictureType.PNG; // 默认PNG
+                    if (fileExtension != null) {
+                        if (fileExtension.equalsIgnoreCase(".jpg") || fileExtension.equalsIgnoreCase(".jpeg")) {
+                            pictureType = PictureType.JPEG;
+                        } else if (fileExtension.equalsIgnoreCase(".gif")) {
+                            pictureType = PictureType.GIF;
+                        } else if (fileExtension.equalsIgnoreCase(".bmp")) {
+                            pictureType = PictureType.BMP;
+                        } else if (fileExtension.equalsIgnoreCase(".png")) {
+                            pictureType = PictureType.PNG;
+                        } else if (fileExtension.equalsIgnoreCase(".tiff")) {
+                            pictureType = PictureType.TIFF;
+                        }
+                    }
+                    paragraphRenderData.addPicture(
+                            Pictures.ofBase64(base64, pictureType)
+                                    .size((Integer) imageData.get("width"), (Integer) imageData.get("height"))
+                                    .create());
+                }
+                paragraphImages.add(paragraphRenderData);
+            }
+            NumberingFormat numberingFormat = new NumberingFormat(1, "");
+            NumberingRenderData numberedImages = new NumberingRenderData(numberingFormat, paragraphImages);
+            processedData.put("files", numberedImages);
+        }
+
+        List<Map<String, Object>> relatedEntitiesImage = (List<Map<String, Object>>) processedData.get("relatedEntitiesImage");
+        List<ParagraphRenderData> relatedEntitiesImages = new ArrayList<>();
+        if (CollectionUtils.isNotEmpty(relatedEntitiesImage)) {
+            for (Map<String, Object> imageData : relatedEntitiesImage) {
+                ParagraphRenderData paragraphRenderData = new ParagraphRenderData();
+
+                if (imageData.containsKey("base64")) {
+                    String base64 = (String) imageData.get("base64");
+
+                    String fileExtension = (String) imageData.get("fileExtension");
+                    PictureType pictureType = PictureType.PNG; // 默认PNG
+                    if (fileExtension != null) {
+                        if (fileExtension.equalsIgnoreCase(".jpg") || fileExtension.equalsIgnoreCase(".jpeg")) {
+                            pictureType = PictureType.JPEG;
+                        } else if (fileExtension.equalsIgnoreCase(".gif")) {
+                            pictureType = PictureType.GIF;
+                        } else if (fileExtension.equalsIgnoreCase(".bmp")) {
+                            pictureType = PictureType.BMP;
+                        } else if (fileExtension.equalsIgnoreCase(".png")) {
+                            pictureType = PictureType.PNG;
+                        } else if (fileExtension.equalsIgnoreCase(".tiff")) {
+                            pictureType = PictureType.TIFF;
+                        }
+                    }
+                    paragraphRenderData.addPicture(
+                            Pictures.ofBase64(base64, pictureType)
+                                    .size((Integer) imageData.get("width"), (Integer) imageData.get("height"))
+                                    .create());
+                }
+                relatedEntitiesImages.add(paragraphRenderData);
+            }
+            NumberingFormat numberingFormat = new NumberingFormat(1, "");
+            NumberingRenderData numberedImages = new NumberingRenderData(numberingFormat, relatedEntitiesImages);
+            processedData.put("relatedEntitiesImage", numberedImages);
+        }
+
+        List<Map<String, Object>> interestConflictList = (List<Map<String, Object>>) processedData.get("interestConflict");
+        List<ParagraphRenderData> interestConflictparagraphImages = new ArrayList<>();
+        if (CollectionUtils.isNotEmpty(interestConflictList)) {
+            for (Map<String, Object> imageData : interestConflictList) {
+                ParagraphRenderData paragraphRenderData = new ParagraphRenderData();
+                if (imageData.containsKey("base64")) {
+                    String base64 = (String) imageData.get("base64");
+                    String fileExtension = (String) imageData.get("fileExtension");
+                    PictureType pictureType = PictureType.PNG; // 默认PNG
+                    if (fileExtension != null) {
+                        if (fileExtension.equalsIgnoreCase(".jpg") || fileExtension.equalsIgnoreCase(".jpeg")) {
+                            pictureType = PictureType.JPEG;
+                        } else if (fileExtension.equalsIgnoreCase(".gif")) {
+                            pictureType = PictureType.GIF;
+                        } else if (fileExtension.equalsIgnoreCase(".bmp")) {
+                            pictureType = PictureType.BMP;
+                        } else if (fileExtension.equalsIgnoreCase(".png")) {
+                            pictureType = PictureType.PNG;
+                        } else if (fileExtension.equalsIgnoreCase(".tiff")) {
+                            pictureType = PictureType.TIFF;
+                        }
+                    }
+                    paragraphRenderData.addPicture(
+                            Pictures.ofBase64(base64, pictureType)
+                                    .size((Integer) imageData.get("width"), (Integer) imageData.get("height"))
+                                    .create());
+                }
+                interestConflictparagraphImages.add(paragraphRenderData);
+            }
+            NumberingFormat numberingFormat = new NumberingFormat(1, "");
+            NumberingRenderData numberedImages = new NumberingRenderData(numberingFormat, interestConflictparagraphImages);
+            processedData.put("files", numberedImages);
+        }
+        // Process other specific links
+        processLink(processedData, "socialSecurityDetailsLink");
+        processLink(processedData, "taxDeclarationImage");
+        processLink(processedData, "financialInfoLink");
+
+        // Process image lists
+        processImageListToNumberedRenderData("businessLicenseImage", processedData);
+        processImageListToNumberedRenderData("legalRegistrationCertImages", processedData);
+        processImageListToNumberedRenderData("annualInspectionResultImage", processedData);
+        processImageListToNumberedRenderData("bankCertificationImages", processedData);
+        processImageListToNumberedRenderData("assessmentLevelCertImage", processedData);
+        processImageListToNumberedRenderData("fullCharterImage", processedData);
+        processImageListToNumberedRenderData("topDonorsListImage", processedData);
+        processImageListToNumberedRenderData("topExpenditureListImage", processedData);
+        processImageListToNumberedRenderData("managementFilingFormImage", processedData);
+        processImageListToNumberedRenderData("jigoupinggu", processedData);
+        processImageListToNumberedRenderData("nianjianjieguo", processedData);
+        processImageListToNumberedRenderData("branchInfoImage", processedData);
+        processImageListToNumberedRenderData("principalInfoImage", processedData);
+        processImageListToNumberedRenderData("projectInfoImage", processedData);
+        processImageListToNumberedRenderData("otherInfoImage", processedData);
+        processImageListToNumberedRenderData("zongti", processedData);
+
+        return processedData;
+    }
+}

+ 245 - 0
easier-report-biz/src/main/java/com/yaoyicloud/template/FoundationReport.java

@@ -0,0 +1,245 @@
+package com.yaoyicloud.template;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.collections4.CollectionUtils;
+import org.springframework.stereotype.Component;
+
+import com.deepoove.poi.XWPFTemplate;
+import com.deepoove.poi.config.Configure;
+import com.deepoove.poi.config.ConfigureBuilder;
+import com.deepoove.poi.data.NumberingFormat;
+import com.deepoove.poi.data.NumberingRenderData;
+import com.deepoove.poi.data.ParagraphRenderData;
+import com.deepoove.poi.data.PictureType;
+import com.deepoove.poi.data.Pictures;
+import com.deepoove.poi.data.Texts;
+import com.deepoove.poi.plugin.table.LoopRowTableRenderPolicy;
+import com.deepoove.poi.policy.RenderPolicy;
+import com.yaoyicloud.config.FilerepoProperties;
+import com.yaoyicloud.constant.enums.ReportType;
+
+import cn.hutool.core.util.StrUtil;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class FoundationReport extends AbstractReportExporter {
+    private final FilerepoProperties filerepoProperties;
+
+    @Override
+    protected String getReportImagePath() {
+        return filerepoProperties.getReportImagePath();
+    }
+
+
+
+    @Override
+    protected String getTemplate(ReportType reportType, String basePath) {
+        String reportTemplateFileName = getReportTemplateFileName(reportType);
+        return basePath + File.separator + reportTemplateFileName;
+    }
+
+    @Override
+    protected void bindConfigure(ConfigureBuilder builder) {
+        RenderPolicy scoreRenderPolicy = this.getScoreRenderPolicy();
+        LoopRowTableRenderPolicy hackLoopTableRenderPolicy = new LoopRowTableRenderPolicy();
+        builder.bind("checkItemScores", scoreRenderPolicy).bind("basicInfoChecks", hackLoopTableRenderPolicy)
+                .bind("businessAbnormals", hackLoopTableRenderPolicy).bind("dishonestPersons", hackLoopTableRenderPolicy)
+                .bind("penaltyRecords", hackLoopTableRenderPolicy).bind("taxPenalties", hackLoopTableRenderPolicy)
+                .bind("severeViolations", hackLoopTableRenderPolicy).bind("questionnaireItems", hackLoopTableRenderPolicy)
+                .bind("indicators", hackLoopTableRenderPolicy);
+    }
+
+    @Override
+    protected String imagePath() {
+        return filerepoProperties.getReportImagePath();
+    }
+
+
+    @Override
+    protected void renderTemplate(String reportTempWordFile, String templatePath, ConfigureBuilder builder,
+        Map<String, Object> data) throws IOException {
+        Configure config = builder.build();
+        XWPFTemplate template = XWPFTemplate.compile(templatePath, config).render(data);
+        template.writeToFile(reportTempWordFile);
+        template.close();
+    }
+
+
+
+    @Override
+    protected String getBasicPath() throws IOException {
+        return filerepoProperties.getBasePath();
+    }
+
+    /**
+     * 获取模板文件路径
+     *
+     * @param reportType
+     * @return
+     */
+    public String getReportTemplateFileName(ReportType reportType) {
+        return reportType.getType().toLowerCase() + "_template.docx";
+    }
+
+    @Override
+    protected List<String> getFontPaths() {
+        return Arrays.asList(filerepoProperties.getSourceHanSansCnBoldFontPath(),
+            filerepoProperties.getSourceHanSansCnFontPath());
+    }
+
+    @Override
+    public Map<String, Object> processData(Map<String, Object> rawData) throws Exception {
+        Map<String, Object> processedData = new HashMap<>(rawData);
+
+        String docurl1 = (String) processedData.get("docurl1");
+        processedData.put("docurl1", Texts.of(docurl1).link(docurl1).create());
+
+        if (processedData.containsKey("docurl1Text")) {
+            int i = 2;
+            while (processedData.containsKey("docurl" + i)) {
+                String url = (String) processedData.get("docurl" + i);
+                if (StrUtil.isNotBlank(url)) {
+                    processedData.put("docurl" + i, Texts.of(url).link(url).create());
+                }
+                i++;
+            }
+        }
+
+        List<Map<String, Object>> imageDataList = (List<Map<String, Object>>) processedData.get("files");
+        List<ParagraphRenderData> paragraphImages = new ArrayList<>();
+        if (CollectionUtils.isNotEmpty(imageDataList)) {
+            for (Map<String, Object> imageData : imageDataList) {
+                ParagraphRenderData paragraphRenderData = new ParagraphRenderData();
+
+                if (imageData.containsKey("base64")) {
+                    String base64 = (String) imageData.get("base64");
+
+                    String fileExtension = (String) imageData.get("fileExtension");
+                    PictureType pictureType = PictureType.PNG; // 默认PNG
+                    if (fileExtension != null) {
+                        if (fileExtension.equalsIgnoreCase(".jpg") || fileExtension.equalsIgnoreCase(".jpeg")) {
+                            pictureType = PictureType.JPEG;
+                        } else if (fileExtension.equalsIgnoreCase(".gif")) {
+                            pictureType = PictureType.GIF;
+                        } else if (fileExtension.equalsIgnoreCase(".bmp")) {
+                            pictureType = PictureType.BMP;
+                        } else if (fileExtension.equalsIgnoreCase(".png")) {
+                            pictureType = PictureType.PNG;
+                        } else if (fileExtension.equalsIgnoreCase(".tiff")) {
+                            pictureType = PictureType.TIFF;
+                        }
+                    }
+                    paragraphRenderData.addPicture(
+                            Pictures.ofBase64(base64, pictureType)
+                                    .size((Integer) imageData.get("width"), (Integer) imageData.get("height"))
+                                    .create());
+                }
+                paragraphImages.add(paragraphRenderData);
+            }
+            NumberingFormat numberingFormat = new NumberingFormat(1, "");
+            NumberingRenderData numberedImages = new NumberingRenderData(numberingFormat, paragraphImages);
+            processedData.put("files", numberedImages);
+        }
+
+        List<Map<String, Object>> relatedEntitiesImage = (List<Map<String, Object>>) processedData.get("relatedEntitiesImage");
+        List<ParagraphRenderData> relatedEntitiesImages = new ArrayList<>();
+        if (CollectionUtils.isNotEmpty(relatedEntitiesImage)) {
+            for (Map<String, Object> imageData : relatedEntitiesImage) {
+                ParagraphRenderData paragraphRenderData = new ParagraphRenderData();
+
+                if (imageData.containsKey("base64")) {
+                    String base64 = (String) imageData.get("base64");
+
+                    String fileExtension = (String) imageData.get("fileExtension");
+                    PictureType pictureType = PictureType.PNG; // 默认PNG
+                    if (fileExtension != null) {
+                        if (fileExtension.equalsIgnoreCase(".jpg") || fileExtension.equalsIgnoreCase(".jpeg")) {
+                            pictureType = PictureType.JPEG;
+                        } else if (fileExtension.equalsIgnoreCase(".gif")) {
+                            pictureType = PictureType.GIF;
+                        } else if (fileExtension.equalsIgnoreCase(".bmp")) {
+                            pictureType = PictureType.BMP;
+                        } else if (fileExtension.equalsIgnoreCase(".png")) {
+                            pictureType = PictureType.PNG;
+                        } else if (fileExtension.equalsIgnoreCase(".tiff")) {
+                            pictureType = PictureType.TIFF;
+                        }
+                    }
+                    paragraphRenderData.addPicture(
+                            Pictures.ofBase64(base64, pictureType)
+                                    .size((Integer) imageData.get("width"), (Integer) imageData.get("height"))
+                                    .create());
+                }
+                relatedEntitiesImages.add(paragraphRenderData);
+            }
+            NumberingFormat numberingFormat = new NumberingFormat(1, "");
+            NumberingRenderData numberedImages = new NumberingRenderData(numberingFormat, relatedEntitiesImages);
+            processedData.put("relatedEntitiesImage", numberedImages);
+        }
+
+        List<Map<String, Object>> interestConflictList = (List<Map<String, Object>>) processedData.get("interestConflict");
+        List<ParagraphRenderData> interestConflictparagraphImages = new ArrayList<>();
+        if (CollectionUtils.isNotEmpty(interestConflictList)) {
+            for (Map<String, Object> imageData : interestConflictList) {
+                ParagraphRenderData paragraphRenderData = new ParagraphRenderData();
+                if (imageData.containsKey("base64")) {
+                    String base64 = (String) imageData.get("base64");
+                    String fileExtension = (String) imageData.get("fileExtension");
+                    PictureType pictureType = PictureType.PNG; // 默认PNG
+                    if (fileExtension != null) {
+                        if (fileExtension.equalsIgnoreCase(".jpg") || fileExtension.equalsIgnoreCase(".jpeg")) {
+                            pictureType = PictureType.JPEG;
+                        } else if (fileExtension.equalsIgnoreCase(".gif")) {
+                            pictureType = PictureType.GIF;
+                        } else if (fileExtension.equalsIgnoreCase(".bmp")) {
+                            pictureType = PictureType.BMP;
+                        } else if (fileExtension.equalsIgnoreCase(".png")) {
+                            pictureType = PictureType.PNG;
+                        } else if (fileExtension.equalsIgnoreCase(".tiff")) {
+                            pictureType = PictureType.TIFF;
+                        }
+                    }
+                    paragraphRenderData.addPicture(
+                            Pictures.ofBase64(base64, pictureType)
+                                    .size((Integer) imageData.get("width"), (Integer) imageData.get("height"))
+                                    .create());
+                }
+                interestConflictparagraphImages.add(paragraphRenderData);
+            }
+            NumberingFormat numberingFormat = new NumberingFormat(1, "");
+            NumberingRenderData numberedImages = new NumberingRenderData(numberingFormat, interestConflictparagraphImages);
+            processedData.put("files", numberedImages);
+        }
+        // Process other specific links
+        processLink(processedData, "financialStatementsForLastThreeYears");
+
+
+        // Process image lists
+        processImageListToNumberedRenderData("foundationLegalPersonRegistrationCertificate", processedData);
+        processImageListToNumberedRenderData("foundationLegalPersonRegistrationCertificateLatest", processedData);
+        processImageListToNumberedRenderData("bankAccountCertificateOrCreditCertificate", processedData);
+        processImageListToNumberedRenderData("evaluationLevelQualificationCertificate", processedData);
+        processImageListToNumberedRenderData("completeArticlesOfAssociationCopy", processedData);
+        processImageListToNumberedRenderData("topTenDonorList", processedData);
+        processImageListToNumberedRenderData("topTenSpenderList", processedData);
+        processImageListToNumberedRenderData("organizationManagement", processedData);
+        processImageListToNumberedRenderData("relatedEntitySituation", processedData);
+        processImageListToNumberedRenderData("organizationPrincipal", processedData);
+        processImageListToNumberedRenderData("projectInformation", processedData);
+        processImageListToNumberedRenderData("organizationalStructureScan", processedData);
+        processImageListToNumberedRenderData("overallGuaranteeStatement", processedData);
+
+
+        return processedData;
+    }
+}

+ 84 - 0
easier-report-biz/src/main/java/com/yaoyicloud/template/PlatformCompanyReport.java

@@ -2,13 +2,23 @@ package com.yaoyicloud.template;
 
 import java.io.File;
 import java.io.IOException;
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+import cn.hutool.core.util.StrUtil;
+import com.deepoove.poi.data.NumberingFormat;
+import com.deepoove.poi.data.NumberingRenderData;
+import com.deepoove.poi.data.ParagraphRenderData;
+import com.deepoove.poi.data.PictureType;
+import com.deepoove.poi.data.Pictures;
+import com.deepoove.poi.data.Texts;
 import com.deepoove.poi.plugin.table.LoopRowTableRenderPolicy;
 import com.yaoyicloud.config.FilerepoProperties;
 import com.yaoyicloud.constant.enums.ReportType;
+import org.apache.commons.collections4.CollectionUtils;
 import org.springframework.stereotype.Component;
 import com.deepoove.poi.XWPFTemplate;
 import com.deepoove.poi.config.Configure;
@@ -87,4 +97,78 @@ public class PlatformCompanyReport extends AbstractReportExporter {
             filerepoProperties.getSourceHanSansCnFontPath());
     }
 
+    @Override
+    public Map<String, Object> processData(Map<String, Object> rawData) throws Exception {
+        Map<String, Object> processedData = new HashMap<>(rawData);
+
+        // Process docurl links
+        String docurl1 = (String) processedData.get("docurl1");
+        processedData.put("docurl1", Texts.of(docurl1).link(docurl1).create());
+
+        if (processedData.containsKey("docurl1Text")) {
+            int i = 2;
+            while (processedData.containsKey("docurl" + i)) {
+                String url = (String) processedData.get("docurl" + i);
+                if (StrUtil.isNotBlank(url)) {
+                    processedData.put("docurl" + i, Texts.of(url).link(url).create());
+                }
+                i++;
+            }
+        }
+
+        List<Map<String, Object>> imageDataList = (List<Map<String, Object>>) processedData.get("relatedEntitiesImage");
+        List<ParagraphRenderData> paragraphImages = new ArrayList<>();
+        if (CollectionUtils.isNotEmpty(imageDataList)) {
+            for (Map<String, Object> imageData : imageDataList) {
+                ParagraphRenderData paragraphRenderData = new ParagraphRenderData();
+
+                if (imageData.containsKey("base64")) {
+                    String base64 = (String) imageData.get("base64");
+
+                    String fileExtension = (String) imageData.get("fileExtension");
+                    PictureType pictureType = PictureType.PNG; // 默认PNG
+                    if (fileExtension != null) {
+                        if (fileExtension.equalsIgnoreCase(".jpg") || fileExtension.equalsIgnoreCase(".jpeg")) {
+                            pictureType = PictureType.JPEG;
+                        } else if (fileExtension.equalsIgnoreCase(".gif")) {
+                            pictureType = PictureType.GIF;
+                        } else if (fileExtension.equalsIgnoreCase(".bmp")) {
+                            pictureType = PictureType.BMP;
+                        } else if (fileExtension.equalsIgnoreCase(".png")) {
+                            pictureType = PictureType.PNG;
+                        } else if (fileExtension.equalsIgnoreCase(".tiff")) {
+                            pictureType = PictureType.TIFF;
+                        }
+                    }
+                    paragraphRenderData.addPicture(
+                            Pictures.ofBase64(base64, pictureType)
+                                    .size((Integer) imageData.get("width"), (Integer) imageData.get("height"))
+                                    .create());
+                }
+                paragraphImages.add(paragraphRenderData);
+            }
+            NumberingFormat numberingFormat = new NumberingFormat(1, "");
+            NumberingRenderData numberedImages = new NumberingRenderData(numberingFormat, paragraphImages);
+            processedData.put("relatedEntitiesImage", numberedImages);
+        }
+        // Process other specific links
+        processLink(processedData, "socialSecurityDetailsLink");
+        processLink(processedData, "taxDeclarationImage");
+        processLink(processedData, "financialInfoLink");
+
+        // Process image lists
+        processImageListToNumberedRenderData("businessLicenseImage", processedData);
+        processImageListToNumberedRenderData("bankCertificateImage", processedData);
+        processImageListToNumberedRenderData("isoCertificationImage", processedData);
+        processImageListToNumberedRenderData("securityLevelCertification", processedData);
+        processImageListToNumberedRenderData("otherCertifications", processedData);
+        processImageListToNumberedRenderData("organizationalStructureImage", processedData);
+        processImageListToNumberedRenderData("taxPaymentCertificateImage", processedData);
+        processImageListToNumberedRenderData("nsxydjwj", processedData);
+        processImageListToNumberedRenderData("interestConflict", processedData);
+        processImageListToNumberedRenderData("disanfangcangzhao", processedData);
+        processImageListToNumberedRenderData("overallGuaranteeStatement", processedData);
+
+        return processedData;
+    }
 }

+ 9 - 0
easier-report-biz/src/main/java/com/yaoyicloud/template/ReportDataProcessor.java

@@ -0,0 +1,9 @@
+package com.yaoyicloud.template;
+
+import java.util.Map;
+
+public interface ReportDataProcessor {
+    Map<String, Object> processData(Map<String, Object> rawData) throws Exception;
+}
+
+

+ 0 - 45
easier-report-biz/src/main/java/com/yaoyicloud/tools/FancyParagraphRenderer.java

@@ -1,45 +0,0 @@
-package com.yaoyicloud.tools;
-
-import com.itextpdf.kernel.colors.DeviceRgb;
-import com.itextpdf.kernel.geom.Rectangle;
-import com.itextpdf.kernel.pdf.PdfDocument;
-import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
-import com.itextpdf.layout.element.Paragraph;
-import com.itextpdf.layout.renderer.DrawContext;
-import com.itextpdf.layout.renderer.IRenderer;
-import com.itextpdf.layout.renderer.ParagraphRenderer;
-
-
-public  class FancyParagraphRenderer extends ParagraphRenderer {
-
-    private PdfDocument document;
-
-    public FancyParagraphRenderer(Paragraph modelElement, PdfDocument document) {
-        super(modelElement);
-
-        this.document = document;
-    }
-
-    @Override
-    public void draw(DrawContext drawContext) {
-        PdfCanvas canvas = drawContext.getCanvas();
-
-
-        Rectangle rect = getOccupiedArea().getBBox();
-
-        canvas.saveState()
-                .setStrokeColor(new DeviceRgb(20, 116, 252))
-                .setLineWidth(0.8f)
-                .moveTo(rect.getX(), rect.getY() - 2)
-                .lineTo(document.getDefaultPageSize().getWidth() - 36, rect.getY() - 2)
-                .stroke()
-                .restoreState();
-
-        super.draw(drawContext);
-    }
-
-    @Override
-    public IRenderer getNextRenderer() {
-        return new FancyParagraphRenderer((Paragraph) modelElement, document);
-    }
-    }

+ 0 - 273
easier-report-biz/src/main/java/com/yaoyicloud/tools/OfficeUtil.java

@@ -1,273 +0,0 @@
-package com.yaoyicloud.tools;
-
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.List;
-
-import org.apache.poi.xwpf.usermodel.XWPFDocument;
-import org.jsoup.Jsoup;
-import org.jsoup.nodes.Document;
-import org.jsoup.nodes.Element;
-import org.jsoup.nodes.Entities;
-import org.jsoup.select.Elements;
-
-import com.itextpdf.html2pdf.ConverterProperties;
-import com.itextpdf.html2pdf.HtmlConverter;
-import com.itextpdf.html2pdf.css.apply.impl.DefaultCssApplierFactory;
-import com.itextpdf.html2pdf.resolver.font.DefaultFontProvider;
-import com.itextpdf.io.font.FontProgramFactory;
-import com.itextpdf.io.font.PdfEncodings;
-import com.itextpdf.kernel.events.Event;
-import com.itextpdf.kernel.events.IEventHandler;
-import com.itextpdf.kernel.events.PdfDocumentEvent;
-import com.itextpdf.kernel.font.PdfFont;
-import com.itextpdf.kernel.font.PdfFontFactory;
-import com.itextpdf.kernel.pdf.PdfDocument;
-import com.itextpdf.kernel.pdf.PdfPage;
-import com.itextpdf.kernel.pdf.PdfWriter;
-import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
-import com.itextpdf.layout.Canvas;
-import com.itextpdf.layout.element.Paragraph;
-import com.itextpdf.layout.font.FontProvider;
-import com.itextpdf.layout.properties.TextAlignment;
-import com.itextpdf.styledxmlparser.css.media.MediaDeviceDescription;
-import com.itextpdf.styledxmlparser.css.media.MediaType;
-
-import fr.opensagres.poi.xwpf.converter.core.FileURIResolver;
-import fr.opensagres.poi.xwpf.converter.core.ImageManager;
-import fr.opensagres.poi.xwpf.converter.xhtml.XHTMLConverter;
-import fr.opensagres.poi.xwpf.converter.xhtml.XHTMLOptions;
-
-//import org.apache.poi.xwpf.converter.core.FileImageExtractor;
-//import org.apache.poi.xwpf.converter.core.FileURIResolver;
-
-/**
- * 使用poi+itextpdf进行word转pdf 先将word转成html,再将html转成pdf
- *
- * @author :hewie
- * @date :Created in 2020/2/27 22:41
- */
-public class OfficeUtil {
-
-    /**
-     * 将docx转为html
-     *
-     * @param docxPath 输入docx文件路径
-     * @return 生成的HTML内容
-     */
-    public static String convert(String docxPath, String imageDir) throws IOException {
-        File imageDirFile = new File(imageDir);
-        if (!imageDirFile.exists() && !imageDirFile.mkdirs()) {
-            throw new IOException("无法创建图片目录: " + imageDir);
-        }
-
-        try (InputStream docxIn = new FileInputStream(docxPath);
-             XWPFDocument document = new XWPFDocument(docxIn);
-             ByteArrayOutputStream htmlOut = new ByteArrayOutputStream()) {
-
-            // 自定义 ImageManager:禁止生成 word/media 目录,强制使用 imageDir 根目录
-            ImageManager imageManager = new ImageManager(imageDirFile, "") {
-                @Override
-                public String resolve(String uri) {
-
-                    return new File(imageDir, uri).getAbsolutePath().replace("/", "\\").toString();
-                }
-
-            };
-
-            @SuppressWarnings("deprecation")
-            XHTMLOptions options = XHTMLOptions.create()
-                    .setImageManager(imageManager)
-                    .URIResolver(new FileURIResolver(imageDirFile) {
-                        @Override
-                        public String resolve(String uri) {
-                            // 去除 word/media/ 前缀
-                            String filename = uri.replace("word/media/", "");
-                            return new File(imageDirFile, filename)
-                                    .getAbsolutePath()
-                                    .replace("/", "\\");
-                        }
-                    });
-
-            XHTMLConverter.getInstance().convert(document, htmlOut, options);
-            return htmlOut.toString("UTF-8");
-        }
-    }
-
-
-    /**
-     * 使用jsoup规范化html
-     *
-     * @param html html内容
-     * @return 规范化后的html
-     */
-    public static String formatHtml(String html) {
-        Document doc = Jsoup.parse(html);
-
-        // 1. 添加基础样式
-        String baseCss = "@page { size: A4; } "
-                +   "table { "
-                +  "  width: 100%; "
-                +  "  border-collapse: collapse; "
-                +  "  page-break-inside: auto; "
-                +   "} "
-                +   "td, th { "
-                +   "  page-break-inside: avoid; "  // 尽量保持单元格不分页
-                +   "  -fs-table-paginate: paginate; "  // 允许分页
-                +   "  background-clip: padding-box; "  // 确保背景色覆盖
-                +   "  -webkit-print-color-adjust: exact; "  // 确保打印时颜色准确
-                +   "}";
-        doc.head().appendElement("style").text(baseCss);
-        Elements images = doc.select("img");
-        Element firstImg = images.first();
-
-        // 4. 删除第一个img元素
-        firstImg.remove();
-        Elements div = doc.select("div");
-        div.attr("style", "page-break-before:always; ");
-
-        Elements table = doc.select("table");
-        String style = table.attr("style");
-        style += "width:100%;";
-        table.attr("style", style);
-
-        // 处理 td 和 p 标签
-        Elements tds = doc.select("td");
-        for (Element td : tds) {
-            Elements ps = td.select("p");
-            if (ps.size() > 1) {
-                for (int i = 1; i < ps.size(); i++) {
-                    ps.get(i).remove();
-                }
-                Element p = ps.first();
-                String pStyle = p.attr("style");
-                pStyle += " display: table-cell; vertical-align: middle;";
-                p.attr("style", pStyle);
-            }
-            if (ps.size() > 0) {
-                Element p = ps.first();
-                String oriPstyle = p.attr("style");
-                p.attr("style", oriPstyle + " margin-left:0.5em;");
-            }
-            // 修改单元格样式 - 关键修改点
-            String oristyle = td.attr("style");
-            oristyle = (oristyle == null) ? "" : oristyle;
-            // 移除可能干扰分页的固定高度设置
-            oristyle += " border-collapse: collapse; border: 0.75pt solid #E3EDFB;";
-            oristyle += " -fs-table-paginate: paginate;"; // 允许分页
-            oristyle += " background-clip: padding-box;"; // 确保背景完整
-            td.attr("style", oristyle);
-        }
-
-        Elements elementsWithMargin = doc.select("span.X1.X2");
-        for (Element el : elementsWithMargin) {
-            String x1Sytle = el.attr("style");
-            x1Sytle = x1Sytle.replaceAll("margin-left:\\s*[^;]+;?", "");
-            if (!el.text().contains("重要声明")) {
-                x1Sytle += "color:#1677ff; ";
-            }
-
-            el.attr("style", x1Sytle);
-        }
-        Elements select = doc.select("p.X1.X2");
-        for (Element el : select) {
-            String style1 = el.attr("style");
-            style1 += "page-break-before:always;";
-            el.attr("style", style1);
-        }
-
-        Elements selectp = doc.select("p");
-        for (Element el : selectp) {
-            if (el.text().trim() != null) {
-                String styleP = el.attr("style");
-                styleP += " margin-top:6pt; margin-bottom:6pt";
-                el.attr("style", styleP);
-            }
-        }
-        Elements x3SpanStyle = doc.select("p.X1.X3");
-        for (Element el : x3SpanStyle) {
-            // 原有样式修改
-            String x3style = el.attr("style");
-            x3style = x3style.replaceAll("margin-bottom:0.0pt", "margin-bottom:7pt");
-            el.attr("style", x3style);
-            Element nextP = el.nextElementSibling();
-            if (nextP != null && "p".equals(nextP.tagName())) {
-                if (nextP.text().trim().isEmpty()) {  // 判断是否为空内容
-                    nextP.remove();  // 删除空p标签
-                }
-            }
-        }
-        doc.outputSettings().syntax(Document.OutputSettings.Syntax.xml);
-        doc.outputSettings().escapeMode(Entities.EscapeMode.xhtml);
-        doc.head().prepend("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">");
-        return doc.html();
-    }
-
-
-
-    public static String convertHtmlToPdf(String htmlString, String outputPdfPath, List<String> fontPaths,
-        boolean simpleFooter, int coverPageCount) throws IOException {
-        File outputFile = new File(outputPdfPath);
-        try (OutputStream os = new FileOutputStream(outputFile); PdfWriter writer = new PdfWriter(os);
-            PdfDocument pdf = new PdfDocument(writer)) {
-            String boldFont = null;
-            String regularFont = null;
-            for (String path : fontPaths) {
-                if (path.contains("bold")) {
-                    boldFont = path;
-                } else if (path.contains("regular")) {
-                    regularFont = path;
-                }
-            }
-            pdf.addEventHandler(PdfDocumentEvent.END_PAGE, new IEventHandler() {
-
-                @Override
-                public void handleEvent(Event event) {
-                    PdfDocumentEvent docEvent = (PdfDocumentEvent) event;
-                    PdfPage page = docEvent.getPage();
-                    int currentPageNumber = docEvent.getDocument().getPageNumber(page);
-
-                    if (currentPageNumber <= coverPageCount) {
-                        return;
-                    }
-
-                    PdfCanvas pdfCanvas =
-                        new PdfCanvas(page.newContentStreamAfter(), page.getResources(), docEvent.getDocument());
-                    Canvas canvas = new Canvas(pdfCanvas, page.getPageSize());
-
-                    float x = (page.getPageSize().getLeft() + page.getPageSize().getRight()) / 2;
-                    float y = page.getPageSize().getBottom() + 20;
-
-                    Paragraph p = simpleFooter
-                        ? new Paragraph(String.valueOf(currentPageNumber - coverPageCount)).setFontSize(9).setMargin(0)
-                            .setFixedPosition(x, y, 50).setTextAlignment(TextAlignment.CENTER)
-                        : new Paragraph("第 " + String.valueOf(currentPageNumber - coverPageCount) + " 页").setFontSize(9).setMargin(0)
-                            .setFixedPosition(x, y, 50).setTextAlignment(TextAlignment.CENTER); // .setFontColor(new Color());
-
-                    canvas.add(p);
-                    canvas.close();
-                }
-            });
-            FontProvider fontProvider = new DefaultFontProvider(false, false, false);
-            PdfFont microsoft = PdfFontFactory.createFont(FontProgramFactory.createFont(boldFont));
-            fontProvider.addFont(microsoft.getFontProgram(), PdfEncodings.IDENTITY_H);
-            PdfFont microsoft1 = PdfFontFactory.createFont(FontProgramFactory.createFont(regularFont));
-            fontProvider.addFont(microsoft1.getFontProgram(), PdfEncodings.IDENTITY_H);
-            ConverterProperties converterProps = new ConverterProperties();
-            converterProps.setFontProvider(fontProvider);
-            converterProps.setMediaDeviceDescription(new MediaDeviceDescription(MediaType.PRINT));
-            converterProps.setCssApplierFactory(new DefaultCssApplierFactory());
-
-            // 先进行 HTML 到 PDF 的转换
-            HtmlConverter.convertToPdf(htmlString, pdf, converterProps);
-
-            return regularFont;
-        }
-    }
-
-}

+ 0 - 426
easier-report-biz/src/main/java/com/yaoyicloud/tools/PdfProcessor.java

@@ -1,426 +0,0 @@
-package com.yaoyicloud.tools;
-import java.io.IOException;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
-
-import com.itextpdf.io.font.FontProgramFactory;
-import com.itextpdf.io.image.ImageData;
-import com.itextpdf.io.image.ImageDataFactory;
-import com.itextpdf.kernel.colors.DeviceRgb;
-import com.itextpdf.kernel.font.PdfFont;
-import com.itextpdf.kernel.font.PdfFontFactory;
-import com.itextpdf.kernel.geom.LineSegment;
-import com.itextpdf.kernel.geom.Rectangle;
-import com.itextpdf.kernel.pdf.PdfDocument;
-import com.itextpdf.kernel.pdf.PdfOutline;
-import com.itextpdf.kernel.pdf.PdfPage;
-import com.itextpdf.kernel.pdf.PdfReader;
-import com.itextpdf.kernel.pdf.PdfWriter;
-import com.itextpdf.kernel.pdf.annot.PdfAnnotation;
-import com.itextpdf.kernel.pdf.annot.PdfLinkAnnotation;
-import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
-import com.itextpdf.kernel.pdf.canvas.draw.DottedLine;
-import com.itextpdf.kernel.pdf.canvas.parser.EventType;
-import com.itextpdf.kernel.pdf.canvas.parser.PdfCanvasProcessor;
-import com.itextpdf.kernel.pdf.canvas.parser.PdfTextExtractor;
-import com.itextpdf.kernel.pdf.canvas.parser.data.IEventData;
-import com.itextpdf.kernel.pdf.canvas.parser.data.TextRenderInfo;
-import com.itextpdf.kernel.pdf.canvas.parser.listener.SimpleTextExtractionStrategy;
-import com.itextpdf.kernel.pdf.navigation.PdfDestination;
-import com.itextpdf.kernel.pdf.navigation.PdfExplicitDestination;
-import com.itextpdf.layout.Canvas;
-import com.itextpdf.layout.element.Image;
-import com.itextpdf.layout.element.Paragraph;
-import com.itextpdf.layout.element.Tab;
-import com.itextpdf.layout.element.TabStop;
-import com.itextpdf.layout.layout.LayoutArea;
-import com.itextpdf.layout.layout.LayoutContext;
-import com.itextpdf.layout.properties.Property;
-import com.itextpdf.layout.properties.TabAlignment;
-import com.itextpdf.layout.properties.TextAlignment;
-
-
-public class PdfProcessor {
-    public static String processPdf(String inputPath, String backgroundImagePath, String fontPath, Integer coverPage)
-            throws IOException {
-        // 标题列表
-        String outputPath = getNewPdfPath(inputPath);
-
-        ArrayList<TocEntity> headings = extractHeadings(inputPath, coverPage);
-        ArrayList<TocEntity> tocEntities = processHeadings(headings);
-        try (PdfDocument pdfDoc = new PdfDocument(new PdfReader(inputPath), new PdfWriter(outputPath))) {
-            //       List<Integer> deletedPages  = removeBlankPages(pdfDoc);
-
-
-//            if (!deletedPages.isEmpty()) {
-//                updateHeadingPageNumbers(tocEntities, deletedPages);
-//            }
-            if (backgroundImagePath != null && !backgroundImagePath.isEmpty()) {
-                // 封面背景图
-                addBackgroundToFirstPage(pdfDoc, backgroundImagePath);
-            }
-            // 标题背景样式
-            modifyHeadings(pdfDoc, tocEntities, coverPage);
-            // 目录
-            if (tocEntities != null && !tocEntities.isEmpty()) {
-                generateTableOfContents(pdfDoc, tocEntities, fontPath, coverPage);
-            }
-        }
-        return outputPath;
-    }
-
-    protected static void updateHeadingPageNumbers(List<TocEntity> headings, List<Integer> deletedPages) {
-        // 确保被删除的页码是升序排列(方便计算)
-        Collections.sort(deletedPages);
-
-        for (TocEntity heading : headings) {
-            int originalPage = heading.getPageNumber();
-            int offset = 0; // 计算页码需要减少的偏移量
-
-            // 遍历所有被删除的页,计算当前标题的页码应该减多少
-            for (int deletedPage : deletedPages) {
-                if (deletedPage < originalPage) {
-                    offset++; // 如果被删除的页在当前页之前,当前页的页码要减1
-                } else {
-                    break; // 后面的被删除页不影响当前页
-                }
-            }
-            // 更新标题的页码
-            heading.setPageNumber(originalPage - offset);
-        }
-    }
-
-    public static String getNewPdfPath(String reportBastPath) {
-        Path path = Paths.get(reportBastPath);
-        // 获取文件名和扩展名
-        String fileName = path.getFileName().toString();
-        int dotIndex = fileName.lastIndexOf('.');
-        String baseName = (dotIndex == -1) ? fileName : fileName.substring(0, dotIndex);
-        String extension = (dotIndex == -1) ? "" : fileName.substring(dotIndex);
-        // 构建新文件名
-        String newFileName = baseName + "1" + extension;
-        // 构建完整新路径
-        String newPdfPath = path.resolveSibling(newFileName).toString();
-        return newPdfPath;
-    }
-
-    protected static  List<Integer> removeBlankPages(PdfDocument pdfDoc) {
-        int totalPages = pdfDoc.getNumberOfPages();
-        List<Integer> deletedPages = new ArrayList<>(); // 记录被删除的页
-
-        for (int i = totalPages; i > 0; i--) {
-            PdfPage page = pdfDoc.getPage(i);
-            String pageText = PdfTextExtractor.getTextFromPage(page);
-
-            if (pageText.trim().isEmpty() || pageText.trim().matches("\\d+")) {
-                pdfDoc.removePage(i);
-                deletedPages.add(i);
-
-            }
-        }
-        return deletedPages;
-    }
-
-    private static void addBackgroundToFirstPage(PdfDocument pdfDoc, String backgroundImagePath) throws IOException {
-        PdfPage firstPage = pdfDoc.getFirstPage();
-        ImageData imageData = ImageDataFactory.create(backgroundImagePath);
-        Image backgroundImage = new Image(imageData);
-
-        PdfCanvas pdfCanvas = new PdfCanvas(firstPage.newContentStreamBefore(), firstPage.getResources(), pdfDoc);
-        Canvas canvas = new Canvas(pdfCanvas, firstPage.getPageSize());
-
-        backgroundImage.setAutoScale(true);
-        backgroundImage.setProperty(Property.UNDERLINE, true);
-        canvas.add(backgroundImage);
-        canvas.close();
-    }
-
-    /**
-     * 标题添加圆圈背景
-     *
-     * @param pdfDoc
-     * @param tocEntities
-     *
-     * @return TOC前面的页数
-     */
-    private static int modifyHeadings(PdfDocument pdfDoc, List<TocEntity> tocEntities, Integer coverPage) {
-        Map<Integer, List<TocEntity>> tocByPage =
-            tocEntities.stream().collect(Collectors.groupingBy(TocEntity::getPageNumber));
-
-        int ret = 0;
-        for (int pageNum = 1; pageNum <= pdfDoc.getNumberOfPages(); pageNum++) {
-            if (!tocByPage.containsKey(pageNum)) {
-                if (pageNum - ret == 1) {
-                    ret++;
-                }
-                continue; // 跳过没有标题的页面
-            }
-
-            PdfPage page = pdfDoc.getPage(pageNum + coverPage);
-            List<TocEntity> pageTocEntities = tocByPage.get(pageNum);
-
-            // 1. 背景层(圆圈)
-            PdfCanvas backgroundCanvas = new PdfCanvas(page.newContentStreamBefore(), page.getResources(), pdfDoc);
-            for (TocEntity info : pageTocEntities) {
-                if (shouldStyleHeading(info)) { // 判断是否需要样式
-                    drawCircleBackground(backgroundCanvas, info);
-                }
-            }
-            backgroundCanvas.release();
-
-            // 2. 文本层
-            PdfCanvas textCanvas = new PdfCanvas(page.newContentStreamAfter(), page.getResources(), pdfDoc);
-            Canvas canvas = new Canvas(textCanvas, page.getPageSize());
-            for (TocEntity info : pageTocEntities) {
-                if (shouldStyleHeading(info)) {
-                    Paragraph paragraph = createStyledParagraph(info, pageNum);
-                    paragraph.setNextRenderer(new FancyParagraphRenderer(paragraph, pdfDoc));
-                    canvas.add(paragraph);
-                }
-            }
-            canvas.close();
-        }
-        return ret;
-    }
-
-    // 判断是否是应该应用样式的标题
-    private static boolean shouldStyleHeading(TocEntity info) {
-        return info.getFontSize() == 16 && info.getTitle().matches("^\\d+\\..*");
-    }
-
-    /**
-     * 绘制圆圈背景
-     *
-     * @param canvas
-     * @param info
-     */
-    private static void drawCircleBackground(PdfCanvas canvas, TocEntity info) {
-        Rectangle rect = info.getRect();
-        canvas.saveState().setFillColor(new DeviceRgb(210, 235, 255))
-                .circle(rect.getX() + info.getParagraphHeight() / 2 - 1, rect.getY() + info.getParagraphHeight() / 2 - 1,
-                        info.getParagraphHeight() / 2 + 2)
-                .fill().restoreState();
-    }
-
-    private static Paragraph createStyledParagraph(TocEntity info, int pageNum) {
-        return new Paragraph().setFontSize(info.getFontSize()).setFixedPosition(pageNum, info.getRect().getX(),
-            info.getRect().getY(), info.getRect().getWidth());
-    }
-
-    private static void generateTableOfContents(PdfDocument pdfDoc, List<TocEntity> headings, String fontPath,
-                                                int coverPageCount) throws IOException {
-        PdfFont font = PdfFontFactory.createFont(FontProgramFactory.createFont(fontPath));
-        float pageHeight = pdfDoc.getDefaultPageSize().getHeight();
-        float startY = pageHeight - 50;
-        float endY = 50;
-        float lineHeight = 15;
-
-        List<List<TocEntity>> pagesHeadings = new ArrayList<>();
-        List<TocEntity> currentPageHeadings = new ArrayList<>();
-        float currentHeight = 0;
-
-        for (TocEntity heading : headings) {
-            // 计算当前目录项所需高度(考虑多行情况)
-            float entryHeight = lineHeight * (1 + (float) Math.ceil(heading.getTitle().length() / 50f));
-
-            if (currentHeight - entryHeight < endY) {  // 如果剩余空间不足
-                if (!currentPageHeadings.isEmpty()) {
-                    pagesHeadings.add(currentPageHeadings);
-                }
-                // 创建新页,并将当前heading作为新页的第一项
-                currentPageHeadings = new ArrayList<>();
-                currentPageHeadings.add(heading);
-                currentHeight = startY - entryHeight;  // 从顶部开始,减去当前项高度
-            } else {
-                // 当前页有足够空间,直接添加
-                currentPageHeadings.add(heading);
-                currentHeight -= entryHeight;  // 更新当前Y位置
-            }
-        }
-
-        // 添加最后一页的目录项
-        if (!currentPageHeadings.isEmpty()) {
-            pagesHeadings.add(currentPageHeadings);
-        }
-
-        Map<TocEntity, PdfDestination> destMap = new HashMap<>();
-        float pageWidth = pdfDoc.getDefaultPageSize().getWidth();
-        float leftMargin = 10;
-        float rightMargin = 25;
-        float tabStopPosition = pageWidth - rightMargin;
-
-        for (int i = 0; i < pagesHeadings.size(); i++) {
-            PdfPage tocPage = pdfDoc.addNewPage(coverPageCount + i + 1);
-            Canvas canvas = new Canvas(tocPage, pdfDoc.getDefaultPageSize());
-
-            float currentY;
-            if (i == 0) {
-                Paragraph title = new Paragraph("目录")
-                        .setFont(font)
-                        .setFontSize(12)
-                        .setBold()
-                        .setTextAlignment(TextAlignment.CENTER)
-                        .setMarginTop(50)
-                        .setMarginBottom(20);
-                canvas.add(title);
-                currentY = startY - 12 - title.getMarginBottom().getValue() - 15;  // 标题高度 + 间距
-            } else {
-                currentY = startY;
-            }
-
-            for (TocEntity heading : pagesHeadings.get(i)) {
-                float indent = leftMargin + heading.getLevel() * 15;
-
-                Paragraph p = new Paragraph().setFont(font).setFontSize(10)
-                        .addTabStops(new TabStop(tabStopPosition, TabAlignment.RIGHT, new DottedLine()))
-                        .setFixedPosition(indent, currentY - lineHeight, pageWidth - indent - rightMargin);
-
-                p.add(heading.getTitle()).add(new Tab()).add(String.valueOf(heading.getPageNumber()));
-
-                float paragraphHeight = p.createRendererSubTree().setParent(canvas.getRenderer())
-                        .layout(new LayoutContext(new LayoutArea(1, new Rectangle(pageWidth - indent - rightMargin, 1000))))
-                        .getOccupiedArea().getBBox().getHeight();
-                if (currentY - paragraphHeight < endY) {
-                    canvas.close();
-                    tocPage = pdfDoc.addNewPage(2 + ++i);
-                    canvas = new Canvas(tocPage, pdfDoc.getDefaultPageSize());
-                    currentY = startY;
-                }
-                canvas.add(p);
-                PdfPage targetPage = pdfDoc.getPage(heading.getPageNumber() + i + 1 + coverPageCount);
-                Rectangle targetRect = heading.getRect();
-                PdfDestination dest =
-                        PdfExplicitDestination.createXYZ(targetPage, targetRect.getLeft(), targetRect.getTop(), 0);
-                destMap.put(heading, dest);
-
-                Rectangle clickRect = new Rectangle(indent, currentY - paragraphHeight,
-                        pageWidth - indent - rightMargin, paragraphHeight);
-
-                PdfLinkAnnotation link = new PdfLinkAnnotation(clickRect).setDestination(dest)
-                        .setBorderStyle(PdfAnnotation.STYLE_UNDERLINE).setHighlightMode(PdfLinkAnnotation.HIGHLIGHT_INVERT);
-
-                tocPage.addAnnotation(link);
-                currentY -= paragraphHeight;
-            }
-            canvas.close();
-        }
-
-        PdfOutline root = pdfDoc.getOutlines(true);
-        for (TocEntity heading : headings) {
-            PdfOutline outline = root.addOutline(heading.getTitle());
-            outline.addDestination(destMap.get(heading));
-        }
-        // 删除最后一页
-        int lastPageIndex = pdfDoc.getNumberOfPages();
-        PdfPage page = pdfDoc.getPage(lastPageIndex);
-        String pageText = PdfTextExtractor.getTextFromPage(page);
-
-        if (pageText.trim().isEmpty() || pageText.trim().matches("\\d+")) {
-            pdfDoc.removePage(lastPageIndex);
-        }
-
-    }
-
-    public static ArrayList<TocEntity> extractHeadings(String pdfPath, Integer coverPage) throws IOException {
-        ArrayList<TocEntity> headings = new ArrayList<>();
-        try (PdfDocument pdfDoc = new PdfDocument(new PdfReader(pdfPath))) {
-            for (int i = 1; i <= pdfDoc.getNumberOfPages(); i++) {
-                PdfPage page = pdfDoc.getPage(i);
-                final int currentPage = i;
-                new PdfCanvasProcessor(new HeadingDetectionStrategy(headings, pdfDoc, currentPage - coverPage))
-                        .processPageContent(page);
-            }
-        }
-        return headings;
-    }
-
-    public static ArrayList<TocEntity> processHeadings(ArrayList<TocEntity> headings) {
-        ArrayList<TocEntity> result = new ArrayList<>();
-        if (headings == null || headings.isEmpty()) {
-            return result;
-        }
-        for (int i = 0; i < headings.size(); i++) {
-            TocEntity current = headings.get(i);
-
-            if (!current.getTitle().matches("^\\d+\\..*")) {
-                if (!result.isEmpty()) {
-                    TocEntity last = result.get(result.size() - 1);
-                    if (last.getPageNumber() == current.getPageNumber()) {
-                        TocEntity combined = new TocEntity(last.getTitle() + current.getTitle(), last.getPageNumber(),
-                                last.getLevel(), last.getRect(), last.getFontSize(), last.getParagraphHeight());
-                        result.set(result.size() - 1, combined);
-                        continue;
-                    }
-                }
-            }
-            if (current.getTitle().matches("^\\d+\\.")) {
-                if (i + 1 < headings.size()) {
-                    TocEntity next = headings.get(i + 1);
-                    TocEntity combined = new TocEntity(current.getTitle() + next.getTitle(), current.getPageNumber(),
-                            current.getLevel(), current.getRect(), current.getFontSize(), current.getParagraphHeight());
-                    result.add(combined);
-                    i++;
-                    continue;
-                }
-            }
-            result.add(current);
-        }
-
-        return result;
-    }
-
-    private static class HeadingDetectionStrategy extends SimpleTextExtractionStrategy {
-        private static final float LEVEL_1_FONT_SIZE = 16;
-        private static final float LEVEL_2_FONT_SIZE = 12;
-        private final ArrayList<TocEntity> headings;
-        private final PdfDocument pdfDoc;
-        private final int currentPage;
-
-        HeadingDetectionStrategy(ArrayList<TocEntity> headings, PdfDocument pdfDoc, int currentPage) {
-            this.headings = headings;
-            this.pdfDoc = pdfDoc;
-            this.currentPage = currentPage;
-        }
-
-        @Override
-        public void eventOccurred(IEventData data, EventType type) {
-            if (type == EventType.RENDER_TEXT) {
-                TextRenderInfo info = (TextRenderInfo) data;
-                float fontSize = info.getFontSize();
-
-                if (fontSize == LEVEL_1_FONT_SIZE) {
-                    addHeading(info, 1, pdfDoc, currentPage, headings);
-                } else if (fontSize == LEVEL_2_FONT_SIZE) {
-                    addHeading(info, 2, pdfDoc, currentPage, headings);
-                }
-            }
-
-            super.eventOccurred(data, type);
-        }
-
-        private void addHeading(TextRenderInfo info, int level, PdfDocument pdfDoc, int i,
-                                ArrayList<TocEntity> headings) {
-            String text = info.getText().trim();
-            LineSegment ascentLine = info.getAscentLine();
-            LineSegment descentLine = info.getDescentLine();
-            float ascentY = ascentLine.getStartPoint().get(1);
-            float descentY = descentLine.getStartPoint().get(1);
-            float paragraphHeight = ascentY - descentY;
-
-            Rectangle rect = info.getBaseline().getBoundingRectangle();
-            if (!text.isEmpty()) {
-                headings.add(new TocEntity(text, i, level, rect, paragraphHeight, info.getFontSize()
-
-                ));
-            }
-        }
-
-    }
-
-}

+ 77 - 0
easier-report-biz/src/main/java/com/yaoyicloud/tools/ProcessDataUtil.java

@@ -0,0 +1,77 @@
+package com.yaoyicloud.tools;
+
+import cn.hutool.core.util.StrUtil;
+import com.deepoove.poi.data.NumberingFormat;
+import com.deepoove.poi.data.NumberingRenderData;
+import com.deepoove.poi.data.ParagraphRenderData;
+import com.deepoove.poi.data.PictureType;
+import com.deepoove.poi.data.Pictures;
+import com.deepoove.poi.data.Texts;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+public class ProcessDataUtil {
+    public void processLink(Map<String, Object> data, String key) {
+        String link = (String) data.get(key);
+        if (StrUtil.isNotBlank(link)) {
+            data.put(key, Texts.of(link).link(link).create());
+        }
+    }
+    public void processImageListToNumberedRenderData(String key, Map<String, Object> data) {
+        // 从data中获取原始图片数据列表
+        List<Map<String, Object>> rawImageDataList = (List<Map<String, Object>>) data.get(key);
+
+        // 处理空数据情况
+        if (rawImageDataList == null || rawImageDataList.isEmpty()) {
+            String textKey = key + "Text";
+            if (data.containsKey(textKey)) {
+                return;
+            }
+        }
+        // 处理非空图片数据
+        List<ParagraphRenderData> paragraphImages = new ArrayList<>();
+        for (Map<String, Object> imageInfo : rawImageDataList) {
+            ParagraphRenderData paragraph = new ParagraphRenderData();
+            // 提取Base64数据和文件扩展名
+            String base64 = (String) imageInfo.get("base64");
+            String url = (String) imageInfo.get("url");
+            String fileExtension = (String) imageInfo.get("fileExtension");
+            Integer width = (Integer) imageInfo.get("width");
+            Integer height = (Integer) imageInfo.get("height");
+
+            // 确定图片类型(默认为PNG)
+            PictureType pictureType = this.determinePictureType(fileExtension);
+
+            // 添加图片到段落渲染数据
+            paragraph.addPicture(Pictures.ofBase64(base64, pictureType)
+                    .size(width, height)
+                    .create());
+
+            paragraphImages.add(paragraph);
+
+        }
+        NumberingFormat numberingFormat = new NumberingFormat(1, "");
+        NumberingRenderData numberedImages = new NumberingRenderData(numberingFormat, paragraphImages);
+        data.put(key, numberedImages);
+    }
+    // 辅助方法:根据文件扩展名确定图片类型
+    private PictureType determinePictureType(String fileExtension) {
+        if (fileExtension == null) {
+            return PictureType.PNG;
+        }
+        String ext = fileExtension.toLowerCase();
+        // 提取扩展名部分(去除前缀点)
+        String normalizedExt = ext.startsWith(".")
+                ? ext.substring(1)
+                : ext;
+        return switch (normalizedExt) {
+            case "jpg", "jpeg" -> PictureType.JPEG;
+            case "gif" -> PictureType.GIF;
+            case "bmp" -> PictureType.BMP;
+            case "tiff" -> PictureType.TIFF;
+            default -> PictureType.PNG; // 默认返回 PNG
+        };
+    }
+}

+ 0 - 24
easier-report-biz/src/main/java/com/yaoyicloud/tools/TocEntity.java

@@ -1,24 +0,0 @@
-package com.yaoyicloud.tools;
-
-import com.itextpdf.kernel.geom.Rectangle;
-
-import lombok.Data;
-
-@Data
-public class TocEntity {
-    private String title;
-    private int pageNumber;
-    private int level;
-    private Rectangle rect;
-    private float fontSize;
-    private  float paragraphHeight;
-
-    public TocEntity(String title, int pageNumber, int level, Rectangle rect, float fontSize, float paragraphHeight) {
-        this.title = title;
-        this.pageNumber = pageNumber;
-        this.level = level;
-        this.rect = rect;
-        this.fontSize = fontSize;
-        this.paragraphHeight = paragraphHeight;
-    }
-}

+ 1 - 2
easier-report-biz/src/main/java/com/yaoyicloud/tools/Util.java

@@ -19,8 +19,7 @@ public final class Util {
      * 合并第n列
      *
      * @param table 表格对象
-     * @param sizeMap 任务汇总map
-     * @param count 合并前n列
+
      */
     public static void mergeFirstNCol(XWPFTable table, int n, int keySeq) {
         if (table.getNumberOfRows() < 1) {

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

@@ -1,27 +1,257 @@
 server:
-  port: @profiles.report.biz.port@
+  port: 14070
+
+
+# 配置文件加密根密码
+jasypt:
+  encryptor:
+    password: bwXg0Guz
+    algorithm: PBEWithMD5AndDES
+    iv-generator-classname: org.jasypt.iv.NoIvGenerator
 
 spring:
-  profiles:
-    active: @profiles.active@
-  application:
-    name: @artifactId@
+  redis:
+    host: 127.0.0.1
+    port: 6379
+    # port: 6677
+    password: 123456
+    database: 11
+  servlet:
+    multipart:
+      max-file-size: 100MB
+      max-request-size: 100MB
   cloud:
-    nacos:
-      username: @nacos.username@
-      password: @nacos.password@
-      discovery:
-        server-addr: @nacos.server-addr@
-        namespace: @nacos.namespace@
-        group: ${spring.profiles.active}
-      config:
-        server-addr: ${spring.cloud.nacos.discovery.server-addr}
-        namespace: ${spring.cloud.nacos.discovery.namespace}
-        group: ${spring.profiles.active}
-  config:
-    import:
-      - optional:nacos:application.yml
-      - optional:nacos:${spring.application.name}.yml
+    sentinel:
+      eager: true
+      transport:
+        dashboard: easier-sentinel:5020
+
+  data:
+    mongodb:
+      #uri: mongodb://admin:admin@127.0.0.1:27717/admin
+      uri: mongodb://127.0.0.1:27017/ent_risk_info
+  datasource:
+    type: com.alibaba.druid.pool.DruidDataSource
+    druid:
+      driver-class-name: com.mysql.cj.jdbc.Driver
+      username: ${MYSQL_USER:service}
+      password: ${MYSQL_PWD:onAkOWDw^Tn8I5v8}
+      url: jdbc:mysql://rm-2ze1uc3f397s1a3smzo.mysql.rds.aliyuncs.com:3306/let_file?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8&allowMultiQueries=true&allowPublicKeyRetrieval=true
+      #url: jdbc:mysql://127.0.0.1:3366/easier_file?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8&allowMultiQueries=true&allowPublicKeyRetrieval=true
+      stat-view-servlet:
+        enabled: true
+        allow: ""
+        url-pattern: /druid/*
+        #login-username: admin
+        #login-password: admin
+      filter:
+        stat:
+          enabled: true
+          log-slow-sql: true
+          slow-sql-millis: 10000
+          merge-sql: false
+        wall:
+          config:
+            multi-statement-allow: true
+  mail:
+    host: smtp.feishu.cn
+    port: 465
+    username: yaoyi_report@yaoyi.net
+    protocol: smtps
+    password: heY0drWAGsgGNwxX
+    properties:
+      mail:
+        smtp:
+          auth: true
+          starttls:
+            enable: true
+        ssl:
+          enable: true
+    default-encoding: utf-8
+  thymeleaf:
+    prefix: classpath:/templates/mail/
+    suffix: .html
+    mode: HTML5
+    encoding: UTF-8
+feign:
+  sentinel:
+    enabled: true
+  okhttp:
+    enabled: true
+  httpclient:
+    enabled: false
+    connection-timeout: 20000
+  compression:
+    request:
+      enabled: true
+    response:
+      enabled: true
+
+# 端点对外暴露
+management:
+  endpoints:
+    web:
+      exposure:
+        include: '*'
+  endpoint:
+    restart:
+      enabled: true
+    health:
+      show-details: ALWAYS
+
+#开启灰度
+gray:
+  rule:
+    enabled: true
+
+# mybatis-plus 配置
+mybatis-plus:
+  tenant-enable: ture
+  mapper-locations: classpath:/mapper/*Mapper.xml
+  global-config:
+    capitalMode: true
+    banner: false
+    db-config:
+      id-type: auto
+      select-strategy: not_empty
+      insert-strategy: not_empty
+      update-strategy: not_null
+      logic-delete-value: "'DEL'"
+      logic-not-delete-value: "'OK'"
+  type-handlers-package: com.yaoyicloud.easier.common.data.handler
+  configuration:
+    jdbc-type-for-null: 'null'
+    call-setters-on-nulls: true
+    shrink-whitespaces-in-sql: true
+    defaultEnumTypeHandler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler
+  typeEnumsPackage: com.yaoyicloud.easier.common.domain.enums
+# mybatis-plus-join 配置
+mybatis-plus-join:
+  # 关闭连表查询组件banner
+  banner: false
+
+tencloud:
+  sts:
+    enable: true
+    secret-id: aa
+    secret-key: aa
+  ocr:
+    enable: true
+    secret-id: aa
+    secret-key: aa
+  faceid:
+    enable: true
+    secret-id: aa
+    secret-key: aa
+    end-merchant: aa
+    loc-pri-key: aa
+  sms:
+    enable: true
+    secret-id: aa
+    secret-key: aa
+    app-id: 123
+    sign-name: aa
+    template-map: {"MEMBER_LOGIN":"23"}
+
+## spring security 配置
+security:
+  oauth2:
+    client:
+      ignore-urls:
+        - /druid/**
+
+# 文件系统
+file:
+  bucket-name: yyc3-1321096020
+  local:
+    enable: true
+    basePath: D:/tmp
+  oss:
+    info: true
+    enable: true
+    endpoint: cos.ap-beijing.myqcloud.com
+    region: ap-beijing
+    access-key: AKIDRilauFg4fDfE9B6tJoNxTvHSdovqXBfw
+    secret-key: 8LeAWksnUDsXAhN0WEoBMYaCvmcbmx5G
+    # 使用云OSS 需要关闭
+    path-style-access: false
+
+# Logger Config
+logging:
+  level:
+    com.yaoyicloud.easier.filerepo.mapper: debug
+
+wfq:
+  interfaceCode: 7b34eaa548174b28bf7609c8d61abe94tdtpd
+  secretKey: spWfZgjNzv0TH9PDQ0blKA4Fo8vHDUK8zw3QD4CGUQgG9gNCtmrmvw1mq2ft2XmW
+  aesKey: SYZXjz5otdNNyig/uKXt+w==
+  endpoint: https://api.wfq2020.com
+  # authUrl: https://www.wfq2020.com
+  authUrl: https://tax.yaoeasier.com
+  cburl: https://pre.yaoeasier.com/cms/third-callback/financial-tax/authorize-link
+  channelCode: 5l5k9
+
+qcc:
+  app-key: a64bc37da347451d93ab06b4421bb365
+  secret-key: F79FCAB25F7FF662A788B4039AFA943D
+
+netocr:
+  app-key: CYjNVQuq5RJUAAdfTzayma
+  secret-key: e1164f4f71cb43d59075c46558257be5
 
+qxb:
+  appKey: 9d39bd82-4f50-4932-a931-e76c736e8c2c
+  secretKey: ffe8972d-b807-4c07-9b62-77fdc8df76ea
 
+allinpay:
+  orgid:
+  cusid: 5505810078000YD
+  appid: 00002811
+  apiurl: https://syb-test.allinpay.com/apiweb
+  signType: SM2
+  rsa_cus_prikey: MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCfw/st1+lYn9k5wDuIIdsKuk2Ju/lijbyL/jJVcQxfaiit5iTSeVrReoaANtl8QqJdnB0KxySCzvONR/J2xHRgh5OsVZxuuV4RHkg8tqCJB5AckeDf97T61wt7byrr/tMutFqe8Jjmvicx7c0KZrCScT7bBfxlKCcpXHkTgbnv5o4o8xiAJV3ei47oEaKcShCjMzGIwNjjBqhK2hBAA7R7z7iuOrLYQD4PATBw1SAnprRYGIecOI2HZBaiMoLvtITCwAAauGnUZ51DaUFZPkeMrMWjoi2vMaS33sFh9h3tDWr2P5XZoW8dmcKRpp92YbQckfUlnHOziyUdxmhpcEeBAgMBAAECggEAAg+ntmwyLPwG8+lIe1Wge09y/6NmsMBOXen+IT8Pn02Bz9iHwhVhuBEiGhZbEPDVImsIruJp1Kwx1TFH7gNT0wj8vTzvgzgt//+JhAsBIDNyRwQUyB7sfU337nQ9NAU6GUCnaKSG/HcYj1rXidpQTdtbKb02h+GQO8bfIwLJ8M/d7Y2EK2/9+jIAvmKSO4ZyGEVrzbgYQC0V8KCKuTx64fErYurQH/aBlhxN0GxTcxeX/y5RkUwfaW55JEhApwm+SpzhjLJJfri14bMcVT8av4yoDGnmLEPBpPnFxR1EQoBJLTtc7TS7u/51I/JJwAe/75OOPSYIQWYVnlOLDng7yQKBgQDTFNNgvwr9zwdInnQfiibUx7TJfKSJqvbEXhsIWXKBCfFyQdu3d9RLd2FgRE3vgsFx3PMaT/ILVs15jPEI/mP4tCwQdCXc+l1NoiuuabUc4UwgY290fa2S5oRrf7ltmuscrC/xCa0Iqaio5dqfZN2XaBdv97ETDvZ3ReUxGsX0HQKBgQDBw5n5Ky2gpbOG0EG79tViF+S5JlTwNzQJjm+YskauZZcFwPAAIzh1z9Kz8lodSoC1wb/rrFmr9PnAbk4Puv9NbNdoIifp9CshonQ3PJyykh/SMTn2wmrQpmIiJIjgOvUjSgyRad6ePzM3hh9bQpD9kkRg73b85eDSqHIhp5g7tQKBgC3e3riti5Pwg6KyXIXmHd4rsAwBPDh2oL23vaQo3AtSv9eWnErYjZgAz3Z+IXmlLqix3VqgePch2/FIQbE0p0EK1nCU7Q2Ckvgl/9wdOLCX/VUkhroH/cposeoyjXdWLTXD7X8yHRo+1Fov6TyuTMF0a3N3nlGH9OOimtX6/X25AoGBAIUv5o6XV22teJGaZRTGvjYHJnj+GDRmPaaz+ZGEOYF24zBZRp9RlmWkzLhURg0MQRyuaTWd6qWAZowXRiEZ8JNP1WEG2Vi/NUaRXED7sNouByF8JNOxH6r8M0g0xMEcxZPUOn9ZvmQYHSR1VOhuASvLdqUK9Ucw3DDxCEKJ6OJhAoGBAKZYojmufECdq4YL5bsHBKo9okdOxzbAguQF4D8R0y7xYOTtQlU5qKQADmfMUxQwD/m+xgGewCoqRk8fDl2CTZDE4pmOrK5LAG2ZMZoTLErX95SmR/9VQgkddfWWKwyBQ1AcxshhTjADT71EYIvq12TJfL8iAcZCqC+4DmFcaYRg
+  rsa_tl_pubkey: MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYXfu4b7xgDSmEGQpQ8Sn3RzFgl5CE4gL4TbYrND4FtCYOrvbgLijkdFgIrVVWi2hUW4K0PwBsmlYhXcbR+JSmqv9zviVXZiym0lK3glJGVCN86r9EPvNTusZZPm40TOEKMVENSYaUjCxZ7JzeZDfQ4WCeQQr2xirqn6LdJjpZ5wIDAQAB
+  sm2p_privatekey: MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQgKq+zfelNxrtYkJh3zX4b3miICXYN3ki3ZTREqUXSBfSgCgYIKoEcz1UBgi2hRANCAATSXuGjTUMlEvvUwl+BEXfzzNZ8CXMKjUza8taH1mCxUPc91TFzqK1FGcQflWTWn68b+H0RLQnv/TySkL5GfDJi
+  sm2_tl_pubkey: MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAE/BnA8BawehBtH0ksPyayo4pmzL/u1FQ2sZcqwOp6bjVqQX4tjo930QAvHZPJ2eez8sCz/RYghcqv4LvMq+kloQ==
+  version: 11
+  validtime: 2
+  notify_url: https://pre.yaoeasier.com/cms/pay/callback
+# 租户表维护
+easier:
+  common:
+    ip2RegionPath: C:/Users/yyy/Desktop/新建文件夹 (2)/easier-be/easier-common/easier-common-core/src/main/resources/xdb/ip2region.xdb
+  office:
+    pdf:
+      rootPath: C:/Users/yyy/dev/yyc3/easier-be
 
+  seq:
+    snowflake:
+      datacenter-id: 0
+      worker-id: 0
+      step: 1000
+      step-start: 0
+      biz-name: cms
+  tenant:
+    column: tenant_id
+    tables:
+      - cms_file
+      - cms_file_group
+      - cms_log
+      - cms_message
+      - cms_message_relation
+      - cms_audit_log
+      - cms_ent_risk_info_rel
+      - cms_ent_risk_invoice
+      - cms_ent_risk_info_decl
+      - cms_ent_risk_info_ckt
+      - cms_ent_risk_info_ckt_rule
+      - cms_course
+      - cms_lesson
+      - cms_ent_risk_financial_tax_auth
+      - cms_ent_risk_financial_tax
+      - cms_recharge
+      - cms_recharge_usage_record
+      - cms_ent_risk_qxb_info_rel
+      - cms_ent_risk_info_indicator_standard
+      - cms_ent_risk_info_review_item_config
+      - cms_ent_risk_inv_recog_his