Prechádzať zdrojové kódy

只保留确认单解析

wangzaijun 1 týždeň pred
rodič
commit
9d96c26880
26 zmenil súbory, kde vykonal 1595 pridanie a 1617 odobranie
  1. BIN
      compressed_image.jpg
  2. 9 9
      mo-daq-openai/web/main.py
  3. 225 225
      mo-daq-openai/web/route.py
  4. 14 34
      mo-daq/pom.xml
  5. 60 60
      mo-daq/src/main/java/com/smppw/modaq/application/components/report/parser/ReportParserConstant.java
  6. 13 13
      mo-daq/src/main/java/com/smppw/modaq/application/components/report/parser/ai/AIAnnuallyReportParser.java
  7. 68 68
      mo-daq/src/main/java/com/smppw/modaq/application/components/report/parser/ai/AIMonthlyReportParser.java
  8. 45 45
      mo-daq/src/main/java/com/smppw/modaq/application/components/report/parser/ai/AIOtherReportParser.java
  9. 147 147
      mo-daq/src/main/java/com/smppw/modaq/application/components/report/parser/ai/AIQuarterlyReportParser.java
  10. 48 48
      mo-daq/src/main/java/com/smppw/modaq/application/components/report/parser/ai/AIWeeklyReportParser.java
  11. 4 5
      mo-daq/src/main/java/com/smppw/modaq/application/components/report/parser/ai/AbstractAIReportParser.java
  12. 148 148
      mo-daq/src/main/java/com/smppw/modaq/application/components/report/parser/pdf/PDAnnuallyReportParser.java
  13. 104 104
      mo-daq/src/main/java/com/smppw/modaq/application/components/report/parser/pdf/PDMonthlyReportParser.java
  14. 269 269
      mo-daq/src/main/java/com/smppw/modaq/application/components/report/parser/pdf/PDQuarterlyReportParser.java
  15. 14 14
      mo-daq/src/main/java/com/smppw/modaq/application/components/report/writer/AnnuallyReportWriter.java
  16. 35 35
      mo-daq/src/main/java/com/smppw/modaq/application/components/report/writer/MonthlyReportWriter.java
  17. 18 18
      mo-daq/src/main/java/com/smppw/modaq/application/components/report/writer/OtherReportWriter.java
  18. 62 62
      mo-daq/src/main/java/com/smppw/modaq/application/components/report/writer/QuarterlyReportWriter.java
  19. 11 11
      mo-daq/src/main/java/com/smppw/modaq/application/components/report/writer/ReportWriterConstant.java
  20. 18 18
      mo-daq/src/main/java/com/smppw/modaq/application/components/report/writer/WeeklyReportWriter.java
  21. 109 109
      mo-daq/src/main/java/com/smppw/modaq/application/task/ParseSchedulerTask.java
  22. 2 2
      mo-daq/src/main/java/com/smppw/modaq/common/enums/ReportParserFileType.java
  23. 19 19
      mo-daq/src/main/java/com/smppw/modaq/common/enums/ReportType.java
  24. 134 135
      mo-daq/src/main/java/com/smppw/modaq/domain/service/EmailParseService.java
  25. 14 14
      mo-daq/src/main/java/com/smppw/modaq/infrastructure/util/PdfUtil.java
  26. 5 5
      mo-daq/src/main/resources/application.yml

BIN
compressed_image.jpg


+ 9 - 9
mo-daq-openai/web/main.py

@@ -1,9 +1,9 @@
-from route import app, logger
-
-
-if __name__ == '__main__':
-    import uvicorn
-
-    logger.info(f'启动 {app.title} 应用')
-
-    uvicorn.run('main:app', host="0.0.0.0", port=8088, reload=True, log_config=None)
+# from route import app, logger
+#
+#
+# if __name__ == '__main__':
+#     import uvicorn
+#
+#     logger.info(f'启动 {app.title} 应用')
+#
+#     uvicorn.run('main:app', host="0.0.0.0", port=8088, reload=True, log_config=None)

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 225 - 225
mo-daq-openai/web/route.py


+ 14 - 34
mo-daq/pom.xml

@@ -146,48 +146,28 @@
             </exclusions>
         </dependency>
 
-        <!-- docx 转 pdf依赖 -->
-        <dependency>
-            <groupId>org.docx4j</groupId>
-            <artifactId>docx4j-core</artifactId>
-            <version>11.5.3</version> <!-- 检查最新版本 -->
-        </dependency>
-        <dependency>
-            <groupId>org.docx4j</groupId>
-            <artifactId>docx4j-export-fo</artifactId>
-            <version>11.5.3</version>
-        </dependency>
+        <!-- 阿里AI工具 -->
         <dependency>
-            <groupId>org.docx4j</groupId>
-            <artifactId>docx4j-JAXB-ReferenceImpl</artifactId>
-            <version>11.5.3</version>
+            <groupId>com.alibaba</groupId>
+            <artifactId>dashscope-sdk-java</artifactId>
+            <version>2.20.3</version>
         </dependency>
 
-<!--        &lt;!&ndash; 通义千问 ai &ndash;&gt;-->
-<!--        <dependency>-->
-<!--            <groupId>com.alibaba</groupId>-->
-<!--            <artifactId>dashscope-sdk-java</artifactId>-->
-<!--            <version>2.18.2</version>-->
-<!--        </dependency>-->
-<!--        <dependency>-->
-<!--            <groupId>com.squareup.okio</groupId>-->
-<!--            <artifactId>okio</artifactId>-->
-<!--            <version>3.6.0</version>-->
-<!--        </dependency>-->
+        <!-- docx 转 pdf依赖 -->
 <!--        <dependency>-->
-<!--            <groupId>com.squareup.okhttp3</groupId>-->
-<!--            <artifactId>logging-interceptor</artifactId>-->
-<!--            <version>4.12.0</version>-->
+<!--            <groupId>org.docx4j</groupId>-->
+<!--            <artifactId>docx4j-core</artifactId>-->
+<!--            <version>11.5.3</version> &lt;!&ndash; 检查最新版本 &ndash;&gt;-->
 <!--        </dependency>-->
 <!--        <dependency>-->
-<!--            <groupId>com.squareup.okhttp3</groupId>-->
-<!--            <artifactId>okhttp-sse</artifactId>-->
-<!--            <version>4.12.0</version>-->
+<!--            <groupId>org.docx4j</groupId>-->
+<!--            <artifactId>docx4j-export-fo</artifactId>-->
+<!--            <version>11.5.3</version>-->
 <!--        </dependency>-->
 <!--        <dependency>-->
-<!--            <groupId>com.squareup.okhttp3</groupId>-->
-<!--            <artifactId>okhttp</artifactId>-->
-<!--            <version>4.12.0</version>-->
+<!--            <groupId>org.docx4j</groupId>-->
+<!--            <artifactId>docx4j-JAXB-ReferenceImpl</artifactId>-->
+<!--            <version>11.5.3</version>-->
 <!--        </dependency>-->
 
         <dependency>

+ 60 - 60
mo-daq/src/main/java/com/smppw/modaq/application/components/report/parser/ReportParserConstant.java

@@ -14,46 +14,46 @@ import java.util.Map;
 public final class ReportParserConstant {
     public static final Map<ReportType, Map<ReportParserFileType, String>> REPORT_PARSER_BEAN_MAP = MapUtil.newHashMap(8);
 
-    // 其他报告
-    public static final String PARSER_AI_OTHER = "report-parser:ai:other";
-
-    // 周报
-    public static final String PARSER_AI_WEEKLY = "report-parser:ai:weekly";
+//    // 其他报告
+//    public static final String PARSER_AI_OTHER = "report-parser:ai:other";
+//
+//    // 周报
+//    public static final String PARSER_AI_WEEKLY = "report-parser:ai:weekly";
 
     // 交易流水确认函解析
     public static final String PARSER_PDF_LETTER = "report-parser:pdf:letter";
     public static final String PARSER_AI_LETTER = "report-parser:ai:letter";
 
-    public static final String PARSER_PDF_MONTHLY = "report-parser:pdf:monthly";
-    public static final String PARSER_EXCEL_MONTHLY = "report-parser:excel:monthly";
-    public static final String PARSER_AI_MONTHLY = "report-parser:ai:monthly";
-
-    public static final String PARSER_PDF_QUARTERLY = "report-parser:pdf:quarterly";
-    public static final String PARSER_EXCEL_QUARTERLY = "report-parser:excel:quarterly";
-    public static final String PARSER_AI_QUARTERLY = "report-parser:ai:quarterly";
-
-    public static final String PARSER_PDF_ANNUALLY = "report-parser:pdf:annually";
-    public static final String PARSER_EXCEL_ANNUALLY = "report-parser:excel:annually";
-    public static final String PARSER_AI_ANNUALLY = "report-parser:ai:annually";
+//    public static final String PARSER_PDF_MONTHLY = "report-parser:pdf:monthly";
+//    public static final String PARSER_EXCEL_MONTHLY = "report-parser:excel:monthly";
+//    public static final String PARSER_AI_MONTHLY = "report-parser:ai:monthly";
+//
+//    public static final String PARSER_PDF_QUARTERLY = "report-parser:pdf:quarterly";
+//    public static final String PARSER_EXCEL_QUARTERLY = "report-parser:excel:quarterly";
+//    public static final String PARSER_AI_QUARTERLY = "report-parser:ai:quarterly";
+//
+//    public static final String PARSER_PDF_ANNUALLY = "report-parser:pdf:annually";
+//    public static final String PARSER_EXCEL_ANNUALLY = "report-parser:excel:annually";
+//    public static final String PARSER_AI_ANNUALLY = "report-parser:ai:annually";
 
     static {
-        // 其他报告解析
-        REPORT_PARSER_BEAN_MAP.put(ReportType.OTHER,
-                Map.of(
-                        ReportParserFileType.AI, PARSER_AI_OTHER,
-                        ReportParserFileType.IMG, PARSER_AI_OTHER,
-                        ReportParserFileType.WORD, PARSER_AI_OTHER
-                )
-        );
-
-        // 周报
-        REPORT_PARSER_BEAN_MAP.put(ReportType.WEEKLY,
-                Map.of(
-                        ReportParserFileType.AI, PARSER_AI_WEEKLY,
-                        ReportParserFileType.IMG, PARSER_AI_WEEKLY,
-                        ReportParserFileType.WORD, PARSER_AI_WEEKLY
-                )
-        );
+//        // 其他报告解析
+//        REPORT_PARSER_BEAN_MAP.put(ReportType.OTHER,
+//                Map.of(
+//                        ReportParserFileType.AI, PARSER_AI_OTHER,
+//                        ReportParserFileType.IMG, PARSER_AI_OTHER,
+//                        ReportParserFileType.WORD, PARSER_AI_OTHER
+//                )
+//        );
+//
+//        // 周报
+//        REPORT_PARSER_BEAN_MAP.put(ReportType.WEEKLY,
+//                Map.of(
+//                        ReportParserFileType.AI, PARSER_AI_WEEKLY,
+//                        ReportParserFileType.IMG, PARSER_AI_WEEKLY,
+//                        ReportParserFileType.WORD, PARSER_AI_WEEKLY
+//                )
+//        );
 
         // 交易流水确认函解析
         REPORT_PARSER_BEAN_MAP.put(ReportType.LETTER,
@@ -62,32 +62,32 @@ public final class ReportParserConstant {
                         ReportParserFileType.AI, PARSER_AI_LETTER
                 ));
 
-        // 月度报告
-        REPORT_PARSER_BEAN_MAP.put(ReportType.MONTHLY,
-                Map.of(
-                        ReportParserFileType.PDF, PARSER_PDF_MONTHLY,
-//                        ReportParserFileType.EXCEL, PARSER_EXCEL_MONTHLY,
-                        ReportParserFileType.AI, PARSER_AI_MONTHLY,
-                        ReportParserFileType.IMG, PARSER_AI_MONTHLY,
-                        ReportParserFileType.WORD, PARSER_AI_MONTHLY
-                ));
-
-        // 季度报告
-        REPORT_PARSER_BEAN_MAP.put(ReportType.QUARTERLY,
-                Map.of(
-                        ReportParserFileType.PDF, PARSER_PDF_QUARTERLY,
-//                        ReportParserFileType.EXCEL, PARSER_EXCEL_QUARTERLY,
-                        ReportParserFileType.AI, PARSER_AI_QUARTERLY,
-                        ReportParserFileType.WORD, PARSER_AI_QUARTERLY
-                ));
-
-        // 年度报告
-        REPORT_PARSER_BEAN_MAP.put(ReportType.ANNUALLY,
-                Map.of(
-                        ReportParserFileType.PDF, PARSER_PDF_ANNUALLY,
-//                        ReportParserFileType.EXCEL, PARSER_EXCEL_ANNUALLY,
-                        ReportParserFileType.AI, PARSER_AI_ANNUALLY,
-                        ReportParserFileType.WORD, PARSER_AI_ANNUALLY
-                ));
+//        // 月度报告
+//        REPORT_PARSER_BEAN_MAP.put(ReportType.MONTHLY,
+//                Map.of(
+//                        ReportParserFileType.PDF, PARSER_PDF_MONTHLY,
+////                        ReportParserFileType.EXCEL, PARSER_EXCEL_MONTHLY,
+//                        ReportParserFileType.AI, PARSER_AI_MONTHLY,
+//                        ReportParserFileType.IMG, PARSER_AI_MONTHLY,
+//                        ReportParserFileType.WORD, PARSER_AI_MONTHLY
+//                ));
+//
+//        // 季度报告
+//        REPORT_PARSER_BEAN_MAP.put(ReportType.QUARTERLY,
+//                Map.of(
+//                        ReportParserFileType.PDF, PARSER_PDF_QUARTERLY,
+////                        ReportParserFileType.EXCEL, PARSER_EXCEL_QUARTERLY,
+//                        ReportParserFileType.AI, PARSER_AI_QUARTERLY,
+//                        ReportParserFileType.WORD, PARSER_AI_QUARTERLY
+//                ));
+//
+//        // 年度报告
+//        REPORT_PARSER_BEAN_MAP.put(ReportType.ANNUALLY,
+//                Map.of(
+//                        ReportParserFileType.PDF, PARSER_PDF_ANNUALLY,
+////                        ReportParserFileType.EXCEL, PARSER_EXCEL_ANNUALLY,
+//                        ReportParserFileType.AI, PARSER_AI_ANNUALLY,
+//                        ReportParserFileType.WORD, PARSER_AI_ANNUALLY
+//                ));
     }
 }

+ 13 - 13
mo-daq/src/main/java/com/smppw/modaq/application/components/report/parser/ai/AIAnnuallyReportParser.java

@@ -1,13 +1,13 @@
-package com.smppw.modaq.application.components.report.parser.ai;
-
-import com.smppw.modaq.application.components.report.parser.ReportParserConstant;
-import com.smppw.modaq.domain.dto.report.AnnuallyReportData;
-import com.smppw.modaq.domain.mapper.EmailFieldMappingMapper;
-import org.springframework.stereotype.Component;
-
-@Component(ReportParserConstant.PARSER_AI_ANNUALLY)
-public class AIAnnuallyReportParser extends AIQuarterlyReportParser<AnnuallyReportData> {
-    public AIAnnuallyReportParser(EmailFieldMappingMapper fieldMappingMapper) {
-        super(fieldMappingMapper);
-    }
-}
+//package com.smppw.modaq.application.components.report.parser.ai;
+//
+//import com.smppw.modaq.application.components.report.parser.ReportParserConstant;
+//import com.smppw.modaq.domain.dto.report.AnnuallyReportData;
+//import com.smppw.modaq.domain.mapper.EmailFieldMappingMapper;
+//import org.springframework.stereotype.Component;
+//
+//@Component(ReportParserConstant.PARSER_AI_ANNUALLY)
+//public class AIAnnuallyReportParser extends AIQuarterlyReportParser<AnnuallyReportData> {
+//    public AIAnnuallyReportParser(EmailFieldMappingMapper fieldMappingMapper) {
+//        super(fieldMappingMapper);
+//    }
+//}

+ 68 - 68
mo-daq/src/main/java/com/smppw/modaq/application/components/report/parser/ai/AIMonthlyReportParser.java

@@ -1,68 +1,68 @@
-package com.smppw.modaq.application.components.report.parser.ai;
-
-import com.smppw.modaq.application.components.report.parser.ReportParserConstant;
-import com.smppw.modaq.common.exception.ReportParseException;
-import com.smppw.modaq.domain.dto.report.MonthlyReportData;
-import com.smppw.modaq.domain.dto.report.ReportBaseInfoDTO;
-import com.smppw.modaq.domain.dto.report.ReportFundInfoDTO;
-import com.smppw.modaq.domain.dto.report.ReportParserParams;
-import com.smppw.modaq.domain.mapper.EmailFieldMappingMapper;
-import org.springframework.stereotype.Component;
-
-@Component(ReportParserConstant.PARSER_AI_MONTHLY)
-public class AIMonthlyReportParser extends AbstractAIReportParser<MonthlyReportData> {
-    public AIMonthlyReportParser(EmailFieldMappingMapper fieldMappingMapper) {
-        super(fieldMappingMapper);
-    }
-
-    @Override
-    protected boolean isSupportAIParse() {
-        return true;
-    }
-
-    @Override
-    protected String prompt() {
-        return """
-                识别文件中的基金名称、基金管理人、产品代码和报告日期,产品代码的正则表达式是`S[A-Z0-9]{5}`;
-                如果无法识别就返回空字符,结果用json返回,json中不要注释
-                """;
-    }
-
-    @Override
-    protected MonthlyReportData parseExtInfoAndSetData(ReportBaseInfoDTO reportInfo,
-                                                       ReportFundInfoDTO fundInfo) throws ReportParseException {
-//        Object contact = this.allInfoMap.get("联系人信息");
-//        if (ObjUtil.isNotEmpty(contact)) {
-//            // 有联系人就不要净值数据了
-//            reportInfo.setWithContacts(true);
-//        }
-        // AI 就不解析净值数据了
-//        List<ReportNetReportDTO> dtos = ListUtil.list(true);
-//        for (Map.Entry<String, Object> entry : this.allInfoMap.entrySet()) {
-//            Object netInfo = entry.getValue();
-//            if (netInfo == null) {
-//                continue;
-//            }
-//            Map<String, Object> netInfoMap = (Map<String, Object>) netInfo;
-//            ReportNetReportDTO dto = this.buildDto(reportInfo.getFileId(), ReportNetReportDTO.class, netInfoMap);
-//            if (dto == null) {
-//                continue;
-//            }
-//            dto.setLevel(ReportParseUtils.matchFundLevel(entry.getKey()));
-//            dtos.add(dto);
-//        }
-//        reportData.setNetReport(dtos);
-        return new MonthlyReportData(reportInfo, fundInfo);
-    }
-
-    @Override
-    protected ReportFundInfoDTO buildFundInfo(ReportParserParams params) {
-//        // 获取并移除基金概况信息
-//        Object fundInfo = this.allInfoMap.get("基金概况");
-//        if (fundInfo == null) {
-//            throw new ReportParseException(ReportParseStatus.PARSE_FUND_INFO_FAIL, params.getFilename());
-//        }
-//        Map<String, Object> fundInfoMap = (Map<String, Object>) fundInfo;
-        return this.buildDto(params.getFileId(), ReportFundInfoDTO.class, this.allInfoMap);
-    }
-}
+//package com.smppw.modaq.application.components.report.parser.ai;
+//
+//import com.smppw.modaq.application.components.report.parser.ReportParserConstant;
+//import com.smppw.modaq.common.exception.ReportParseException;
+//import com.smppw.modaq.domain.dto.report.MonthlyReportData;
+//import com.smppw.modaq.domain.dto.report.ReportBaseInfoDTO;
+//import com.smppw.modaq.domain.dto.report.ReportFundInfoDTO;
+//import com.smppw.modaq.domain.dto.report.ReportParserParams;
+//import com.smppw.modaq.domain.mapper.EmailFieldMappingMapper;
+//import org.springframework.stereotype.Component;
+//
+//@Component(ReportParserConstant.PARSER_AI_MONTHLY)
+//public class AIMonthlyReportParser extends AbstractAIReportParser<MonthlyReportData> {
+//    public AIMonthlyReportParser(EmailFieldMappingMapper fieldMappingMapper) {
+//        super(fieldMappingMapper);
+//    }
+//
+//    @Override
+//    protected boolean isSupportAIParse() {
+//        return true;
+//    }
+//
+//    @Override
+//    protected String prompt() {
+//        return """
+//                识别文件中的基金名称、基金管理人、产品代码和报告日期,产品代码的正则表达式是`S[A-Z0-9]{5}`;
+//                如果无法识别就返回空字符,结果用json返回,json中不要注释
+//                """;
+//    }
+//
+//    @Override
+//    protected MonthlyReportData parseExtInfoAndSetData(ReportBaseInfoDTO reportInfo,
+//                                                       ReportFundInfoDTO fundInfo) throws ReportParseException {
+////        Object contact = this.allInfoMap.get("联系人信息");
+////        if (ObjUtil.isNotEmpty(contact)) {
+////            // 有联系人就不要净值数据了
+////            reportInfo.setWithContacts(true);
+////        }
+//        // AI 就不解析净值数据了
+////        List<ReportNetReportDTO> dtos = ListUtil.list(true);
+////        for (Map.Entry<String, Object> entry : this.allInfoMap.entrySet()) {
+////            Object netInfo = entry.getValue();
+////            if (netInfo == null) {
+////                continue;
+////            }
+////            Map<String, Object> netInfoMap = (Map<String, Object>) netInfo;
+////            ReportNetReportDTO dto = this.buildDto(reportInfo.getFileId(), ReportNetReportDTO.class, netInfoMap);
+////            if (dto == null) {
+////                continue;
+////            }
+////            dto.setLevel(ReportParseUtils.matchFundLevel(entry.getKey()));
+////            dtos.add(dto);
+////        }
+////        reportData.setNetReport(dtos);
+//        return new MonthlyReportData(reportInfo, fundInfo);
+//    }
+//
+//    @Override
+//    protected ReportFundInfoDTO buildFundInfo(ReportParserParams params) {
+////        // 获取并移除基金概况信息
+////        Object fundInfo = this.allInfoMap.get("基金概况");
+////        if (fundInfo == null) {
+////            throw new ReportParseException(ReportParseStatus.PARSE_FUND_INFO_FAIL, params.getFilename());
+////        }
+////        Map<String, Object> fundInfoMap = (Map<String, Object>) fundInfo;
+//        return this.buildDto(params.getFileId(), ReportFundInfoDTO.class, this.allInfoMap);
+//    }
+//}

+ 45 - 45
mo-daq/src/main/java/com/smppw/modaq/application/components/report/parser/ai/AIOtherReportParser.java

@@ -1,45 +1,45 @@
-package com.smppw.modaq.application.components.report.parser.ai;
-
-import com.smppw.modaq.application.components.report.parser.ReportParserConstant;
-import com.smppw.modaq.common.exception.ReportParseException;
-import com.smppw.modaq.domain.dto.report.*;
-import com.smppw.modaq.domain.mapper.EmailFieldMappingMapper;
-import org.springframework.stereotype.Component;
-
-/**
- * 其他格式的报告(只解析报告基本信息、基金基本信息)
- */
-@Component(ReportParserConstant.PARSER_AI_OTHER)
-public class AIOtherReportParser extends AbstractAIReportParser<ReportData> {
-    public AIOtherReportParser(EmailFieldMappingMapper fieldMappingMapper) {
-        super(fieldMappingMapper);
-    }
-
-    @Override
-    protected String prompt() {
-        return """
-                识别文件中的基金名称、基金管理人、产品代码和报告日期,产品代码的正则表达式是`S[A-Z0-9]{5}`;
-                如果无法识别就返回空字符,结果用json返回,json中不要注释
-                """;
-    }
-
-    @Override
-    protected boolean isSupportAIParse() {
-        return true;
-    }
-
-    @Override
-    protected ReportData parseExtInfoAndSetData(ReportBaseInfoDTO reportInfo,
-                                                ReportFundInfoDTO fundInfo) throws ReportParseException {
-//        Object contact = this.allInfoMap.get("联系人信息");
-//        if (Objects.equals("存在", contact)) {
-//            reportInfo.setWithContacts(true);
-//        }
-        return new MonthlyReportData(reportInfo, fundInfo);
-    }
-
-    @Override
-    protected ReportFundInfoDTO buildFundInfo(ReportParserParams params) {
-        return this.buildDto(params.getFileId(), ReportFundInfoDTO.class, this.allInfoMap);
-    }
-}
+//package com.smppw.modaq.application.components.report.parser.ai;
+//
+//import com.smppw.modaq.application.components.report.parser.ReportParserConstant;
+//import com.smppw.modaq.common.exception.ReportParseException;
+//import com.smppw.modaq.domain.dto.report.*;
+//import com.smppw.modaq.domain.mapper.EmailFieldMappingMapper;
+//import org.springframework.stereotype.Component;
+//
+///**
+// * 其他格式的报告(只解析报告基本信息、基金基本信息)
+// */
+//@Component(ReportParserConstant.PARSER_AI_OTHER)
+//public class AIOtherReportParser extends AbstractAIReportParser<ReportData> {
+//    public AIOtherReportParser(EmailFieldMappingMapper fieldMappingMapper) {
+//        super(fieldMappingMapper);
+//    }
+//
+//    @Override
+//    protected String prompt() {
+//        return """
+//                识别文件中的基金名称、基金管理人、产品代码和报告日期,产品代码的正则表达式是`S[A-Z0-9]{5}`;
+//                如果无法识别就返回空字符,结果用json返回,json中不要注释
+//                """;
+//    }
+//
+//    @Override
+//    protected boolean isSupportAIParse() {
+//        return true;
+//    }
+//
+//    @Override
+//    protected ReportData parseExtInfoAndSetData(ReportBaseInfoDTO reportInfo,
+//                                                ReportFundInfoDTO fundInfo) throws ReportParseException {
+////        Object contact = this.allInfoMap.get("联系人信息");
+////        if (Objects.equals("存在", contact)) {
+////            reportInfo.setWithContacts(true);
+////        }
+//        return new MonthlyReportData(reportInfo, fundInfo);
+//    }
+//
+//    @Override
+//    protected ReportFundInfoDTO buildFundInfo(ReportParserParams params) {
+//        return this.buildDto(params.getFileId(), ReportFundInfoDTO.class, this.allInfoMap);
+//    }
+//}

+ 147 - 147
mo-daq/src/main/java/com/smppw/modaq/application/components/report/parser/ai/AIQuarterlyReportParser.java

@@ -1,147 +1,147 @@
-package com.smppw.modaq.application.components.report.parser.ai;
-
-import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.collection.ListUtil;
-import cn.hutool.core.map.MapUtil;
-import cn.hutool.core.util.StrUtil;
-import com.smppw.modaq.application.components.ReportParseUtils;
-import com.smppw.modaq.application.components.report.parser.ReportParserConstant;
-import com.smppw.modaq.common.enums.ReportParseStatus;
-import com.smppw.modaq.common.exception.ReportParseException;
-import com.smppw.modaq.domain.dto.report.*;
-import com.smppw.modaq.domain.mapper.EmailFieldMappingMapper;
-import org.springframework.stereotype.Component;
-
-import java.util.List;
-import java.util.Map;
-
-@Component(ReportParserConstant.PARSER_AI_QUARTERLY)
-public class AIQuarterlyReportParser<T extends QuarterlyReportData> extends AbstractAIReportParser<T> {
-    public AIQuarterlyReportParser(EmailFieldMappingMapper fieldMappingMapper) {
-        super(fieldMappingMapper);
-    }
-
-    @Override
-    protected boolean isSupportAIParse() {
-        return true;
-    }
-
-    @Override
-    protected String prompt() {
-        return """
-                识别文件中的基金基本情况、投资组合情况,
-                投资组合情况包含期末基金资产组合情况、报告期末按行业分类的股票投资组合,
-                报告期末按行业分类的股票投资组合又包含报告期末按行业分类的境内股票投资组合、报告期末按行业分类的港股通投资股票投资组合,
-                结果用json返回,json中不要注释
-                """;
-    }
-
-    @Override
-    @SuppressWarnings("unchecked")
-    protected T parseExtInfoAndSetData(ReportBaseInfoDTO reportInfo,
-                                       ReportFundInfoDTO fundInfo) throws ReportParseException {
-        QuarterlyReportData reportData = new QuarterlyReportData(reportInfo, fundInfo);
-        // 这俩有分级基金,先不解析
-        reportData.setShareChange(null);
-        reportData.setFinancialIndicators(null);
-        // 资产配置组合
-        Integer fileId = reportInfo.getFileId();
-        String reportName = reportInfo.getReportName();
-        Object assetInfo = this.allInfoMap.get("投资组合情况");
-        if (assetInfo == null) {
-            throw new ReportParseException(ReportParseStatus.PARSE_ASSET_INFO_FAIL, reportName);
-        }
-        Map<String, Object> assetInfoMap = (Map<String, Object>) assetInfo;
-        reportData.setAssetAllocation(this.buildAssetAllocationInfo(fileId, reportName, assetInfoMap));
-        reportData.setInvestmentIndustry(this.buildInvestmentIndustryInfo(fileId, reportName, assetInfoMap));
-        @SuppressWarnings("unchecked")
-        T t = (T) reportData;
-        return t;
-    }
-
-    @Override
-    @SuppressWarnings("unchecked")
-    protected ReportFundInfoDTO buildFundInfo(ReportParserParams params) {
-        // 获取并移除基金基本情况信息
-        Object fundInfo = this.allInfoMap.get("基金基本情况");
-        if (fundInfo == null) {
-            throw new ReportParseException(ReportParseStatus.PARSE_FUND_INFO_FAIL, params.getFilename());
-        }
-        Map<String, Object> fundInfoMap = (Map<String, Object>) fundInfo;
-        return this.buildDto(params.getFileId(), ReportFundInfoDTO.class, fundInfoMap);
-    }
-
-    @SuppressWarnings("unchecked")
-    private List<ReportAssetAllocationDTO> buildAssetAllocationInfo(Integer fileId, String reportName,
-                                                                    Map<String, Object> assetInfoMap) {
-        Object allocationInfo = assetInfoMap.get("期末基金资产组合情况");
-        if (allocationInfo == null) {
-            throw new ReportParseException(ReportParseStatus.PARSE_ASSET_INFO_FAIL, reportName);
-        }
-        List<Map<String, Object>> allocationList = ListUtil.list(false);
-        try {
-            allocationList = (List<Map<String, Object>>) allocationInfo;
-        } catch (Exception ignored) {
-        }
-
-        List<ReportAssetAllocationDTO> dtos = ListUtil.list(false);
-        for (Map<String, Object> allocation : allocationList) {
-            String detail = ReportParseUtils.cleaningValue(allocation.get("子项"));
-            if (StrUtil.isBlank(detail)) {
-                detail = ReportParseUtils.cleaningValue(allocation.get("项目"));
-            }
-            if (!ReportParseUtils.ASSET_ALLOCATION_TYPE_MAPPER.containsKey(detail)) {
-                continue;
-            }
-            String marketValueAndRemark = ReportParseUtils.cleaningValue(allocation.get("金额"), false);
-            // 大类
-            ReportParseUtils.buildAssetAllocation(fileId, detail, marketValueAndRemark, dtos);
-        }
-        return dtos;
-    }
-
-    @SuppressWarnings("unchecked")
-    private List<ReportInvestmentIndustryDTO> buildInvestmentIndustryInfo(Integer fileId, String reportName,
-                                                                          Map<String, Object> assetInfoMap) {
-        Object industryInfo = assetInfoMap.get("报告期末按行业分类的股票投资组合");
-        if (industryInfo == null) {
-            throw new ReportParseException(ReportParseStatus.PARSE_INDUSTRY_INFO_FAIL, reportName);
-        }
-        Map<String, Object> industryMap = MapUtil.empty();
-        try {
-            industryMap = (Map<String, Object>) industryInfo;
-        } catch (Exception ignored) {
-        }
-        List<ReportInvestmentIndustryDTO> dtos = ListUtil.list(false);
-        this.buildIndustryInfo(fileId, 1, industryMap, dtos);
-        this.buildIndustryInfo(fileId, 2, industryMap, dtos);
-        return dtos;
-    }
-
-    @SuppressWarnings("unchecked")
-    private void buildIndustryInfo(Integer fileId, Integer industryType,
-                                   Map<String, Object> industryMap,
-                                   List<ReportInvestmentIndustryDTO> dtos) {
-        String industryKey = industryType == 1 ? "报告期末按行业分类的境内股票投资组合" : "报告期末按行业分类的港股通投资股票投资组合";
-        List<Map<String, Object>> industryList = ListUtil.list(false);
-        try {
-            industryList = (List<Map<String, Object>>) industryMap.get(industryKey);
-        } catch (Exception ignored) {
-        }
-        if (CollUtil.isEmpty(industryList)) {
-            return;
-        }
-        for (Map<String, Object> industry : industryList) {
-            String industryName = ReportParseUtils.cleaningValue(industry.get("行业类别"));
-            if (StrUtil.isBlank(industryName) || !ReportParseUtils.INDUSTRY_COLUMN_NAMES.contains(industryName)) {
-                continue;
-            }
-            ReportInvestmentIndustryDTO dto = new ReportInvestmentIndustryDTO(fileId);
-            dto.setInvestType(industryType);
-            dto.setIndustryName(industryName);
-            dto.setMarketValue(ReportParseUtils.cleaningValue(industry.get("公允价值")));
-            dto.setRatio(ReportParseUtils.cleaningValue(industry.get("占基金资产净值比例(%)")));
-            dtos.add(dto);
-        }
-    }
-}
+//package com.smppw.modaq.application.components.report.parser.ai;
+//
+//import cn.hutool.core.collection.CollUtil;
+//import cn.hutool.core.collection.ListUtil;
+//import cn.hutool.core.map.MapUtil;
+//import cn.hutool.core.util.StrUtil;
+//import com.smppw.modaq.application.components.ReportParseUtils;
+//import com.smppw.modaq.application.components.report.parser.ReportParserConstant;
+//import com.smppw.modaq.common.enums.ReportParseStatus;
+//import com.smppw.modaq.common.exception.ReportParseException;
+//import com.smppw.modaq.domain.dto.report.*;
+//import com.smppw.modaq.domain.mapper.EmailFieldMappingMapper;
+//import org.springframework.stereotype.Component;
+//
+//import java.util.List;
+//import java.util.Map;
+//
+//@Component(ReportParserConstant.PARSER_AI_QUARTERLY)
+//public class AIQuarterlyReportParser<T extends QuarterlyReportData> extends AbstractAIReportParser<T> {
+//    public AIQuarterlyReportParser(EmailFieldMappingMapper fieldMappingMapper) {
+//        super(fieldMappingMapper);
+//    }
+//
+//    @Override
+//    protected boolean isSupportAIParse() {
+//        return true;
+//    }
+//
+//    @Override
+//    protected String prompt() {
+//        return """
+//                识别文件中的基金基本情况、投资组合情况,
+//                投资组合情况包含期末基金资产组合情况、报告期末按行业分类的股票投资组合,
+//                报告期末按行业分类的股票投资组合又包含报告期末按行业分类的境内股票投资组合、报告期末按行业分类的港股通投资股票投资组合,
+//                结果用json返回,json中不要注释
+//                """;
+//    }
+//
+//    @Override
+//    @SuppressWarnings("unchecked")
+//    protected T parseExtInfoAndSetData(ReportBaseInfoDTO reportInfo,
+//                                       ReportFundInfoDTO fundInfo) throws ReportParseException {
+//        QuarterlyReportData reportData = new QuarterlyReportData(reportInfo, fundInfo);
+//        // 这俩有分级基金,先不解析
+//        reportData.setShareChange(null);
+//        reportData.setFinancialIndicators(null);
+//        // 资产配置组合
+//        Integer fileId = reportInfo.getFileId();
+//        String reportName = reportInfo.getReportName();
+//        Object assetInfo = this.allInfoMap.get("投资组合情况");
+//        if (assetInfo == null) {
+//            throw new ReportParseException(ReportParseStatus.PARSE_ASSET_INFO_FAIL, reportName);
+//        }
+//        Map<String, Object> assetInfoMap = (Map<String, Object>) assetInfo;
+//        reportData.setAssetAllocation(this.buildAssetAllocationInfo(fileId, reportName, assetInfoMap));
+//        reportData.setInvestmentIndustry(this.buildInvestmentIndustryInfo(fileId, reportName, assetInfoMap));
+//        @SuppressWarnings("unchecked")
+//        T t = (T) reportData;
+//        return t;
+//    }
+//
+//    @Override
+//    @SuppressWarnings("unchecked")
+//    protected ReportFundInfoDTO buildFundInfo(ReportParserParams params) {
+//        // 获取并移除基金基本情况信息
+//        Object fundInfo = this.allInfoMap.get("基金基本情况");
+//        if (fundInfo == null) {
+//            throw new ReportParseException(ReportParseStatus.PARSE_FUND_INFO_FAIL, params.getFilename());
+//        }
+//        Map<String, Object> fundInfoMap = (Map<String, Object>) fundInfo;
+//        return this.buildDto(params.getFileId(), ReportFundInfoDTO.class, fundInfoMap);
+//    }
+//
+//    @SuppressWarnings("unchecked")
+//    private List<ReportAssetAllocationDTO> buildAssetAllocationInfo(Integer fileId, String reportName,
+//                                                                    Map<String, Object> assetInfoMap) {
+//        Object allocationInfo = assetInfoMap.get("期末基金资产组合情况");
+//        if (allocationInfo == null) {
+//            throw new ReportParseException(ReportParseStatus.PARSE_ASSET_INFO_FAIL, reportName);
+//        }
+//        List<Map<String, Object>> allocationList = ListUtil.list(false);
+//        try {
+//            allocationList = (List<Map<String, Object>>) allocationInfo;
+//        } catch (Exception ignored) {
+//        }
+//
+//        List<ReportAssetAllocationDTO> dtos = ListUtil.list(false);
+//        for (Map<String, Object> allocation : allocationList) {
+//            String detail = ReportParseUtils.cleaningValue(allocation.get("子项"));
+//            if (StrUtil.isBlank(detail)) {
+//                detail = ReportParseUtils.cleaningValue(allocation.get("项目"));
+//            }
+//            if (!ReportParseUtils.ASSET_ALLOCATION_TYPE_MAPPER.containsKey(detail)) {
+//                continue;
+//            }
+//            String marketValueAndRemark = ReportParseUtils.cleaningValue(allocation.get("金额"), false);
+//            // 大类
+//            ReportParseUtils.buildAssetAllocation(fileId, detail, marketValueAndRemark, dtos);
+//        }
+//        return dtos;
+//    }
+//
+//    @SuppressWarnings("unchecked")
+//    private List<ReportInvestmentIndustryDTO> buildInvestmentIndustryInfo(Integer fileId, String reportName,
+//                                                                          Map<String, Object> assetInfoMap) {
+//        Object industryInfo = assetInfoMap.get("报告期末按行业分类的股票投资组合");
+//        if (industryInfo == null) {
+//            throw new ReportParseException(ReportParseStatus.PARSE_INDUSTRY_INFO_FAIL, reportName);
+//        }
+//        Map<String, Object> industryMap = MapUtil.empty();
+//        try {
+//            industryMap = (Map<String, Object>) industryInfo;
+//        } catch (Exception ignored) {
+//        }
+//        List<ReportInvestmentIndustryDTO> dtos = ListUtil.list(false);
+//        this.buildIndustryInfo(fileId, 1, industryMap, dtos);
+//        this.buildIndustryInfo(fileId, 2, industryMap, dtos);
+//        return dtos;
+//    }
+//
+//    @SuppressWarnings("unchecked")
+//    private void buildIndustryInfo(Integer fileId, Integer industryType,
+//                                   Map<String, Object> industryMap,
+//                                   List<ReportInvestmentIndustryDTO> dtos) {
+//        String industryKey = industryType == 1 ? "报告期末按行业分类的境内股票投资组合" : "报告期末按行业分类的港股通投资股票投资组合";
+//        List<Map<String, Object>> industryList = ListUtil.list(false);
+//        try {
+//            industryList = (List<Map<String, Object>>) industryMap.get(industryKey);
+//        } catch (Exception ignored) {
+//        }
+//        if (CollUtil.isEmpty(industryList)) {
+//            return;
+//        }
+//        for (Map<String, Object> industry : industryList) {
+//            String industryName = ReportParseUtils.cleaningValue(industry.get("行业类别"));
+//            if (StrUtil.isBlank(industryName) || !ReportParseUtils.INDUSTRY_COLUMN_NAMES.contains(industryName)) {
+//                continue;
+//            }
+//            ReportInvestmentIndustryDTO dto = new ReportInvestmentIndustryDTO(fileId);
+//            dto.setInvestType(industryType);
+//            dto.setIndustryName(industryName);
+//            dto.setMarketValue(ReportParseUtils.cleaningValue(industry.get("公允价值")));
+//            dto.setRatio(ReportParseUtils.cleaningValue(industry.get("占基金资产净值比例(%)")));
+//            dtos.add(dto);
+//        }
+//    }
+//}

+ 48 - 48
mo-daq/src/main/java/com/smppw/modaq/application/components/report/parser/ai/AIWeeklyReportParser.java

@@ -1,48 +1,48 @@
-package com.smppw.modaq.application.components.report.parser.ai;
-
-import com.smppw.modaq.application.components.report.parser.ReportParserConstant;
-import com.smppw.modaq.common.exception.ReportParseException;
-import com.smppw.modaq.domain.dto.report.ReportBaseInfoDTO;
-import com.smppw.modaq.domain.dto.report.ReportFundInfoDTO;
-import com.smppw.modaq.domain.dto.report.ReportParserParams;
-import com.smppw.modaq.domain.dto.report.WeeklyReportData;
-import com.smppw.modaq.domain.mapper.EmailFieldMappingMapper;
-import org.springframework.stereotype.Component;
-
-/**
- * 管理人周报AI解析器
- */
-@Component(ReportParserConstant.PARSER_AI_WEEKLY)
-public class AIWeeklyReportParser extends AbstractAIReportParser<WeeklyReportData> {
-    public AIWeeklyReportParser(EmailFieldMappingMapper fieldMappingMapper) {
-        super(fieldMappingMapper);
-    }
-
-    @Override
-    protected String prompt() {
-        return """
-                识别文件中的基金名称、基金管理人、产品代码和报告日期,产品代码的正则表达式是`S[A-Z0-9]{5}`;
-                如果无法识别就返回空字符,结果用json返回,json中不要注释
-                """;
-    }
-
-    @Override
-    protected boolean isSupportAIParse() {
-        return true;
-    }
-
-    @Override
-    protected WeeklyReportData parseExtInfoAndSetData(ReportBaseInfoDTO reportInfo,
-                                                      ReportFundInfoDTO fundInfo) throws ReportParseException {
-//        Object contact = this.allInfoMap.get("联系人信息");
-//        if (ObjUtil.isNotEmpty(contact)) {
-//            reportInfo.setWithContacts(true);
-//        }
-        return new WeeklyReportData(reportInfo, fundInfo);
-    }
-
-    @Override
-    protected ReportFundInfoDTO buildFundInfo(ReportParserParams params) {
-        return this.buildDto(params.getFileId(), ReportFundInfoDTO.class, this.allInfoMap);
-    }
-}
+//package com.smppw.modaq.application.components.report.parser.ai;
+//
+//import com.smppw.modaq.application.components.report.parser.ReportParserConstant;
+//import com.smppw.modaq.common.exception.ReportParseException;
+//import com.smppw.modaq.domain.dto.report.ReportBaseInfoDTO;
+//import com.smppw.modaq.domain.dto.report.ReportFundInfoDTO;
+//import com.smppw.modaq.domain.dto.report.ReportParserParams;
+//import com.smppw.modaq.domain.dto.report.WeeklyReportData;
+//import com.smppw.modaq.domain.mapper.EmailFieldMappingMapper;
+//import org.springframework.stereotype.Component;
+//
+///**
+// * 管理人周报AI解析器
+// */
+//@Component(ReportParserConstant.PARSER_AI_WEEKLY)
+//public class AIWeeklyReportParser extends AbstractAIReportParser<WeeklyReportData> {
+//    public AIWeeklyReportParser(EmailFieldMappingMapper fieldMappingMapper) {
+//        super(fieldMappingMapper);
+//    }
+//
+//    @Override
+//    protected String prompt() {
+//        return """
+//                识别文件中的基金名称、基金管理人、产品代码和报告日期,产品代码的正则表达式是`S[A-Z0-9]{5}`;
+//                如果无法识别就返回空字符,结果用json返回,json中不要注释
+//                """;
+//    }
+//
+//    @Override
+//    protected boolean isSupportAIParse() {
+//        return true;
+//    }
+//
+//    @Override
+//    protected WeeklyReportData parseExtInfoAndSetData(ReportBaseInfoDTO reportInfo,
+//                                                      ReportFundInfoDTO fundInfo) throws ReportParseException {
+////        Object contact = this.allInfoMap.get("联系人信息");
+////        if (ObjUtil.isNotEmpty(contact)) {
+////            reportInfo.setWithContacts(true);
+////        }
+//        return new WeeklyReportData(reportInfo, fundInfo);
+//    }
+//
+//    @Override
+//    protected ReportFundInfoDTO buildFundInfo(ReportParserParams params) {
+//        return this.buildDto(params.getFileId(), ReportFundInfoDTO.class, this.allInfoMap);
+//    }
+//}

+ 4 - 5
mo-daq/src/main/java/com/smppw/modaq/application/components/report/parser/ai/AbstractAIReportParser.java

@@ -4,7 +4,6 @@ import cn.hutool.core.exceptions.ExceptionUtil;
 import cn.hutool.core.io.IORuntimeException;
 import cn.hutool.core.map.MapUtil;
 import cn.hutool.core.util.StrUtil;
-import cn.hutool.http.HttpUtil;
 import cn.hutool.json.JSONObject;
 import cn.hutool.json.JSONUtil;
 import com.smppw.modaq.application.components.report.parser.AbstractReportParser;
@@ -16,7 +15,6 @@ import com.smppw.modaq.domain.dto.report.ReportData;
 import com.smppw.modaq.domain.dto.report.ReportParserParams;
 import com.smppw.modaq.domain.mapper.EmailFieldMappingMapper;
 import com.smppw.modaq.infrastructure.util.DateUtils;
-import org.springframework.beans.factory.annotation.Value;
 
 import java.util.Date;
 import java.util.Map;
@@ -27,8 +25,8 @@ import java.util.Map;
  * @param <T> 泛型参数
  */
 public abstract class AbstractAIReportParser<T extends ReportData> extends AbstractReportParser<T> {
-    @Value("${email.report.ai-parser-url}")
-    private String aiParserUrl;
+//    @Value("${email.report.ai-parser-url}")
+//    private String aiParserUrl;
 
     protected String aiFileId;
 
@@ -142,7 +140,8 @@ public abstract class AbstractAIReportParser<T extends ReportData> extends Abstr
         }
         String body = null;
         try {
-            body = HttpUtil.get(this.aiParserUrl, paramsMap);
+            // todo 用java的AI解析
+//            body = HttpUtil.get(this.aiParserUrl, paramsMap);
             JSONObject jsonResult = JSONUtil.parseObj(body);
             this.aiFileId = MapUtil.getStr(jsonResult, "file_id");
             String content = StrUtil.split(jsonResult.getStr("content"), "```").get(1);

+ 148 - 148
mo-daq/src/main/java/com/smppw/modaq/application/components/report/parser/pdf/PDAnnuallyReportParser.java

@@ -1,148 +1,148 @@
-package com.smppw.modaq.application.components.report.parser.pdf;
-
-import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.collection.ListUtil;
-import cn.hutool.core.map.MapUtil;
-import com.smppw.modaq.application.components.ReportParseUtils;
-import com.smppw.modaq.application.components.report.parser.ReportParserConstant;
-import com.smppw.modaq.domain.dto.report.*;
-import com.smppw.modaq.domain.mapper.EmailFieldMappingMapper;
-import org.springframework.stereotype.Component;
-import technology.tabula.Table;
-
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.function.Function;
-
-/**
- * @author wangzaijun
- * @date 2024/10/10 17:34
- * @description 年报解析逻辑:基本信息被拆分为多个表格,财务报表未解析
- */
-@Component(ReportParserConstant.PARSER_PDF_ANNUALLY)
-public class PDAnnuallyReportParser extends PDQuarterlyReportParser<AnnuallyReportData> {
-    private List<Table> fundInfoTables;
-
-    public PDAnnuallyReportParser(EmailFieldMappingMapper fieldMappingMapper) {
-        super(fieldMappingMapper);
-    }
-
-    @Override
-    public String getParser() {
-        return ReportParserConstant.PARSER_PDF_ANNUALLY;
-    }
-
-    @Override
-    protected void init() {
-        super.init();
-        this.fundInfoTables = ListUtil.list(true);
-    }
-
-    @Override
-    protected void initTableInfo(List<Table> tables) {
-        Map<Integer, List<Table>> spanningPageFinancialIndicatorsTableMap = MapUtil.newHashMap(8, true);
-        Map<Integer, List<Table>> spanningPageShareChangeTableMap = MapUtil.newHashMap(8, true);
-        int fi = 0;
-        int sci = 0;
-        for (Table table : tables) {
-            int colCount = table.getColCount();
-            List<String> texts = this.getTableColTexts(table, 0);
-            // 用表格的第一列的数据判断是否主要财务指标数据
-            if (CollUtil.containsAny(texts, ReportParseUtils.FINANCIAL_INDICATORS_COLUMN_NAMES)) {
-                this.splitTables(table, 10, fi, this.financialIndicatorsTables, spanningPageFinancialIndicatorsTableMap);
-                continue;
-            }
-            if (colCount == 2) {
-                // 用表格的第一列的数据判断是否份额变动记录
-                if (CollUtil.containsAny(texts, ReportParseUtils.SHARE_CHANGE_COLUMN_NAMES)) {
-                    this.splitTables(table, 5, sci, this.shareChangeTables, spanningPageShareChangeTableMap);
-                } else if (CollUtil.containsAny(texts, ReportParseUtils.FUND_INFO_COLUMN_NAMES)) {
-                    // 基金基本信息
-                    this.fundInfoTables.add(table);
-                }
-            } else if (colCount == 4) {
-                // 用表格的第二列的数据判断是否行业配置数据(内地)
-                texts = this.getTableColTexts(table, 1);
-                if (CollUtil.containsAny(texts, ReportParseUtils.INDUSTRY_COLUMN_NAMES)) {
-                    this.investmentIndustryTables.add(table);
-                }
-            } else if (colCount == 3) {
-                // 用表格的第一列的数据判断是否行业配置数据(港股通)
-                if (CollUtil.containsAny(texts, ReportParseUtils.INDUSTRY_COLUMN_NAMES)) {
-                    this.investmentIndustryTables.add(table);
-                    continue;
-                }
-                // 资产配置表格识别(兼容跨页的表格)获取表格中第二列的所有文字,判断所有文字中包含"股权投资"等字符串
-                texts = this.getTableColTexts(table, 1);
-                Set<String> keys = ReportParseUtils.ASSET_ALLOCATION_TYPE_MAPPER.keySet();
-                if (CollUtil.containsAny(texts, keys)) {
-                    this.assetAllocationTables.add(table);
-                }
-            }
-        }
-        // 跨页的财务信息记录表(包括表头一共有10行)
-        this.handleSpanningPageTables(this.financialIndicatorsTables, spanningPageFinancialIndicatorsTableMap);
-        // 跨页的份额变动记录表(包括表头一共有5行)
-        this.handleSpanningPageTables(this.shareChangeTables, spanningPageShareChangeTableMap);
-    }
-
-    @Override
-    protected ReportFundInfoDTO buildFundInfo(ReportParserParams params) {
-        Map<String, Object> fundInfoMap = MapUtil.newHashMap(32);
-        for (Table table : this.fundInfoTables) {
-            Map<String, Object> temp = this.parseFundInfo(table);
-            fundInfoMap.putAll(temp);
-        }
-        ReportFundInfoDTO info = new ReportFundInfoDTO(params.getFileId());
-        this.buildInfo(fundInfoMap, info);
-        return info;
-    }
-
-    @Override
-    protected AnnuallyReportData buildReportData(ReportBaseInfoDTO reportInfo,
-                                                 ReportFundInfoDTO fundInfo,
-                                                 List<ReportShareChangeDTO> shareChanges,
-                                                 List<ReportFinancialIndicatorsDTO> financialIndicators,
-                                                 List<ReportAssetAllocationDTO> assetAllocations,
-                                                 List<ReportInvestmentIndustryDTO> investmentIndustries) {
-        AnnuallyReportData reportData = new AnnuallyReportData(reportInfo, fundInfo);
-        reportData.setShareChange(shareChanges);
-        reportData.setFinancialIndicators(financialIndicators);
-        reportData.setAssetAllocation(assetAllocations);
-        reportData.setInvestmentIndustry(investmentIndustries);
-        return reportData;
-    }
-
-    protected List<ReportFinancialIndicatorsDTO> buildFinancialIndicatorsInfo(Integer fileId,
-                                                                              Function<Table, Map<String, Object>> function) {
-        List<ReportFinancialIndicatorsDTO> dtos = ListUtil.list(false);
-        // 分级基金
-        List<String> levels = ReportParseUtils.matchTieredFund(String.join(",", this.textList));
-        // 假设这里可能存在分级基金,不存在表格跨页
-        for (int k = 0; k < this.financialIndicatorsTables.size(); k++) {
-            Table table = this.financialIndicatorsTables.get(k);
-            int colCount = table.getColCount();
-            for (int j = 1; j < colCount; j++) {
-                Map<String, Object> infoMap = MapUtil.newHashMap(16);
-                String year = ReportParseUtils.cleaningValue(table.getCell(0, j).getText());
-                infoMap.put("年度", year);
-                for (int i = 0; i < table.getRowCount(); i++) {
-                    String columnName = ReportParseUtils.cleaningValue(table.getCell(i, 0).getText());
-                    if (columnName == null) {
-                        continue;
-                    }
-                    String value = ReportParseUtils.cleaningValue(table.getCell(i, j).getText());
-                    infoMap.put(columnName, value);
-                }
-                ReportFinancialIndicatorsDTO dto = new ReportFinancialIndicatorsDTO(fileId);
-                this.buildInfo(infoMap, dto);
-                if (levels.size() > k) {
-                    dto.setLevel(levels.get(k));
-                }
-                dtos.add(dto);
-            }
-        }
-        return dtos;
-    }
-}
+//package com.smppw.modaq.application.components.report.parser.pdf;
+//
+//import cn.hutool.core.collection.CollUtil;
+//import cn.hutool.core.collection.ListUtil;
+//import cn.hutool.core.map.MapUtil;
+//import com.smppw.modaq.application.components.ReportParseUtils;
+//import com.smppw.modaq.application.components.report.parser.ReportParserConstant;
+//import com.smppw.modaq.domain.dto.report.*;
+//import com.smppw.modaq.domain.mapper.EmailFieldMappingMapper;
+//import org.springframework.stereotype.Component;
+//import technology.tabula.Table;
+//
+//import java.util.List;
+//import java.util.Map;
+//import java.util.Set;
+//import java.util.function.Function;
+//
+///**
+// * @author wangzaijun
+// * @date 2024/10/10 17:34
+// * @description 年报解析逻辑:基本信息被拆分为多个表格,财务报表未解析
+// */
+//@Component(ReportParserConstant.PARSER_PDF_ANNUALLY)
+//public class PDAnnuallyReportParser extends PDQuarterlyReportParser<AnnuallyReportData> {
+//    private List<Table> fundInfoTables;
+//
+//    public PDAnnuallyReportParser(EmailFieldMappingMapper fieldMappingMapper) {
+//        super(fieldMappingMapper);
+//    }
+//
+//    @Override
+//    public String getParser() {
+//        return ReportParserConstant.PARSER_PDF_ANNUALLY;
+//    }
+//
+//    @Override
+//    protected void init() {
+//        super.init();
+//        this.fundInfoTables = ListUtil.list(true);
+//    }
+//
+//    @Override
+//    protected void initTableInfo(List<Table> tables) {
+//        Map<Integer, List<Table>> spanningPageFinancialIndicatorsTableMap = MapUtil.newHashMap(8, true);
+//        Map<Integer, List<Table>> spanningPageShareChangeTableMap = MapUtil.newHashMap(8, true);
+//        int fi = 0;
+//        int sci = 0;
+//        for (Table table : tables) {
+//            int colCount = table.getColCount();
+//            List<String> texts = this.getTableColTexts(table, 0);
+//            // 用表格的第一列的数据判断是否主要财务指标数据
+//            if (CollUtil.containsAny(texts, ReportParseUtils.FINANCIAL_INDICATORS_COLUMN_NAMES)) {
+//                this.splitTables(table, 10, fi, this.financialIndicatorsTables, spanningPageFinancialIndicatorsTableMap);
+//                continue;
+//            }
+//            if (colCount == 2) {
+//                // 用表格的第一列的数据判断是否份额变动记录
+//                if (CollUtil.containsAny(texts, ReportParseUtils.SHARE_CHANGE_COLUMN_NAMES)) {
+//                    this.splitTables(table, 5, sci, this.shareChangeTables, spanningPageShareChangeTableMap);
+//                } else if (CollUtil.containsAny(texts, ReportParseUtils.FUND_INFO_COLUMN_NAMES)) {
+//                    // 基金基本信息
+//                    this.fundInfoTables.add(table);
+//                }
+//            } else if (colCount == 4) {
+//                // 用表格的第二列的数据判断是否行业配置数据(内地)
+//                texts = this.getTableColTexts(table, 1);
+//                if (CollUtil.containsAny(texts, ReportParseUtils.INDUSTRY_COLUMN_NAMES)) {
+//                    this.investmentIndustryTables.add(table);
+//                }
+//            } else if (colCount == 3) {
+//                // 用表格的第一列的数据判断是否行业配置数据(港股通)
+//                if (CollUtil.containsAny(texts, ReportParseUtils.INDUSTRY_COLUMN_NAMES)) {
+//                    this.investmentIndustryTables.add(table);
+//                    continue;
+//                }
+//                // 资产配置表格识别(兼容跨页的表格)获取表格中第二列的所有文字,判断所有文字中包含"股权投资"等字符串
+//                texts = this.getTableColTexts(table, 1);
+//                Set<String> keys = ReportParseUtils.ASSET_ALLOCATION_TYPE_MAPPER.keySet();
+//                if (CollUtil.containsAny(texts, keys)) {
+//                    this.assetAllocationTables.add(table);
+//                }
+//            }
+//        }
+//        // 跨页的财务信息记录表(包括表头一共有10行)
+//        this.handleSpanningPageTables(this.financialIndicatorsTables, spanningPageFinancialIndicatorsTableMap);
+//        // 跨页的份额变动记录表(包括表头一共有5行)
+//        this.handleSpanningPageTables(this.shareChangeTables, spanningPageShareChangeTableMap);
+//    }
+//
+//    @Override
+//    protected ReportFundInfoDTO buildFundInfo(ReportParserParams params) {
+//        Map<String, Object> fundInfoMap = MapUtil.newHashMap(32);
+//        for (Table table : this.fundInfoTables) {
+//            Map<String, Object> temp = this.parseFundInfo(table);
+//            fundInfoMap.putAll(temp);
+//        }
+//        ReportFundInfoDTO info = new ReportFundInfoDTO(params.getFileId());
+//        this.buildInfo(fundInfoMap, info);
+//        return info;
+//    }
+//
+//    @Override
+//    protected AnnuallyReportData buildReportData(ReportBaseInfoDTO reportInfo,
+//                                                 ReportFundInfoDTO fundInfo,
+//                                                 List<ReportShareChangeDTO> shareChanges,
+//                                                 List<ReportFinancialIndicatorsDTO> financialIndicators,
+//                                                 List<ReportAssetAllocationDTO> assetAllocations,
+//                                                 List<ReportInvestmentIndustryDTO> investmentIndustries) {
+//        AnnuallyReportData reportData = new AnnuallyReportData(reportInfo, fundInfo);
+//        reportData.setShareChange(shareChanges);
+//        reportData.setFinancialIndicators(financialIndicators);
+//        reportData.setAssetAllocation(assetAllocations);
+//        reportData.setInvestmentIndustry(investmentIndustries);
+//        return reportData;
+//    }
+//
+//    protected List<ReportFinancialIndicatorsDTO> buildFinancialIndicatorsInfo(Integer fileId,
+//                                                                              Function<Table, Map<String, Object>> function) {
+//        List<ReportFinancialIndicatorsDTO> dtos = ListUtil.list(false);
+//        // 分级基金
+//        List<String> levels = ReportParseUtils.matchTieredFund(String.join(",", this.textList));
+//        // 假设这里可能存在分级基金,不存在表格跨页
+//        for (int k = 0; k < this.financialIndicatorsTables.size(); k++) {
+//            Table table = this.financialIndicatorsTables.get(k);
+//            int colCount = table.getColCount();
+//            for (int j = 1; j < colCount; j++) {
+//                Map<String, Object> infoMap = MapUtil.newHashMap(16);
+//                String year = ReportParseUtils.cleaningValue(table.getCell(0, j).getText());
+//                infoMap.put("年度", year);
+//                for (int i = 0; i < table.getRowCount(); i++) {
+//                    String columnName = ReportParseUtils.cleaningValue(table.getCell(i, 0).getText());
+//                    if (columnName == null) {
+//                        continue;
+//                    }
+//                    String value = ReportParseUtils.cleaningValue(table.getCell(i, j).getText());
+//                    infoMap.put(columnName, value);
+//                }
+//                ReportFinancialIndicatorsDTO dto = new ReportFinancialIndicatorsDTO(fileId);
+//                this.buildInfo(infoMap, dto);
+//                if (levels.size() > k) {
+//                    dto.setLevel(levels.get(k));
+//                }
+//                dtos.add(dto);
+//            }
+//        }
+//        return dtos;
+//    }
+//}

+ 104 - 104
mo-daq/src/main/java/com/smppw/modaq/application/components/report/parser/pdf/PDMonthlyReportParser.java

@@ -1,104 +1,104 @@
-package com.smppw.modaq.application.components.report.parser.pdf;
-
-import cn.hutool.core.collection.ListUtil;
-import cn.hutool.core.map.MapUtil;
-import cn.hutool.core.util.StrUtil;
-import com.smppw.modaq.application.components.ReportParseUtils;
-import com.smppw.modaq.application.components.report.parser.ReportParserConstant;
-import com.smppw.modaq.domain.dto.report.*;
-import com.smppw.modaq.domain.mapper.EmailFieldMappingMapper;
-import org.springframework.stereotype.Component;
-import technology.tabula.RectangularTextContainer;
-import technology.tabula.Table;
-
-import java.util.List;
-import java.util.Map;
-
-/**
- * @author wangzaijun
- * @date 2024/9/11 16:19
- * @description pdf格式的月报解析
- */
-@Component(ReportParserConstant.PARSER_PDF_MONTHLY)
-public class PDMonthlyReportParser extends AbstractPDReportParser<MonthlyReportData> {
-    private Table fundInfoTable;
-    private List<Table> extNavTables;
-
-    public PDMonthlyReportParser(EmailFieldMappingMapper fieldMappingMapper) {
-        super(fieldMappingMapper);
-    }
-
-    @Override
-    public String getParser() {
-        return ReportParserConstant.PARSER_PDF_MONTHLY;
-    }
-
-    @Override
-    protected void init() {
-        super.init();
-        // 这里初始化
-        this.fundInfoTable = null;
-        this.extNavTables = ListUtil.list(true);
-    }
-
-    @Override
-    protected void initTableInfo(List<Table> tables) {
-        Map<Integer, List<Table>> spanningPageTableMap = MapUtil.newHashMap(8, true);
-        int index = 0;
-        // 一般月报是固定的模板,4列表格是基金基本信息,其他5列的表格是月净值
-        for (Table table : tables) {
-            int colCount = table.getColCount();
-            int rowCount = table.getRowCount();
-            if (colCount == 0 && rowCount == 0) {
-                continue;
-            }
-            if (colCount == 4) {
-                this.fundInfoTable = table;
-            } else if (colCount == 5) {
-                index = this.splitTables(table, 2, index, this.extNavTables, spanningPageTableMap);
-            }
-        }
-        // 跨页的净值记录表(包括表头一共有2行)
-        this.handleSpanningPageTables(this.extNavTables, spanningPageTableMap);
-    }
-
-    @Override
-    protected ReportFundInfoDTO buildFundInfo(ReportParserParams params) {
-        if (this.fundInfoTable == null) {
-            return null;
-        }
-        // 月报的基金基本信息是四列的表格
-        Map<String, Object> baseInfoMap = MapUtil.newHashMap(32);
-        for (int i = 0; i < fundInfoTable.getRows().size(); i++) {
-            @SuppressWarnings("all")
-            List<RectangularTextContainer> cols = fundInfoTable.getRows().get(i);
-            for (int j = 0; j < 2; j++) {
-                baseInfoMap.put(cols.get(j * 2).getText(), cols.get(j * 2 + 1).getText());
-            }
-        }
-        return this.buildDto(params.getFileId(), ReportFundInfoDTO.class, baseInfoMap);
-    }
-
-    @Override
-    protected MonthlyReportData parseExtInfoAndSetData(ReportBaseInfoDTO reportInfo, ReportFundInfoDTO fundInfo) {
-        MonthlyReportData reportData = new MonthlyReportData(reportInfo, fundInfo);
-        // 母基金和分级基金的净值
-        List<ReportNetReportDTO> dtos = this.buildLevelDto(reportInfo.getFileId(), this.extNavTables,
-                ReportNetReportDTO.class, t -> {
-                    Map<String, Object> extInfoMap = MapUtil.newHashMap(16);
-                    // 限制只能两行数据
-                    if (t.getRowCount() != 2) {
-                        return extInfoMap;
-                    }
-                    for (int i = 0; i < t.getColCount(); i++) {
-                        String key = ReportParseUtils.cleaningValue(t.getCell(0, i).getText());
-                        key = StrUtil.subBefore(key, "(", false);
-                        String value = t.getCell(1, i).getText();
-                        extInfoMap.put(key, value);
-                    }
-                    return extInfoMap;
-                });
-        reportData.setNetReport(dtos);
-        return reportData;
-    }
-}
+//package com.smppw.modaq.application.components.report.parser.pdf;
+//
+//import cn.hutool.core.collection.ListUtil;
+//import cn.hutool.core.map.MapUtil;
+//import cn.hutool.core.util.StrUtil;
+//import com.smppw.modaq.application.components.ReportParseUtils;
+//import com.smppw.modaq.application.components.report.parser.ReportParserConstant;
+//import com.smppw.modaq.domain.dto.report.*;
+//import com.smppw.modaq.domain.mapper.EmailFieldMappingMapper;
+//import org.springframework.stereotype.Component;
+//import technology.tabula.RectangularTextContainer;
+//import technology.tabula.Table;
+//
+//import java.util.List;
+//import java.util.Map;
+//
+///**
+// * @author wangzaijun
+// * @date 2024/9/11 16:19
+// * @description pdf格式的月报解析
+// */
+//@Component(ReportParserConstant.PARSER_PDF_MONTHLY)
+//public class PDMonthlyReportParser extends AbstractPDReportParser<MonthlyReportData> {
+//    private Table fundInfoTable;
+//    private List<Table> extNavTables;
+//
+//    public PDMonthlyReportParser(EmailFieldMappingMapper fieldMappingMapper) {
+//        super(fieldMappingMapper);
+//    }
+//
+//    @Override
+//    public String getParser() {
+//        return ReportParserConstant.PARSER_PDF_MONTHLY;
+//    }
+//
+//    @Override
+//    protected void init() {
+//        super.init();
+//        // 这里初始化
+//        this.fundInfoTable = null;
+//        this.extNavTables = ListUtil.list(true);
+//    }
+//
+//    @Override
+//    protected void initTableInfo(List<Table> tables) {
+//        Map<Integer, List<Table>> spanningPageTableMap = MapUtil.newHashMap(8, true);
+//        int index = 0;
+//        // 一般月报是固定的模板,4列表格是基金基本信息,其他5列的表格是月净值
+//        for (Table table : tables) {
+//            int colCount = table.getColCount();
+//            int rowCount = table.getRowCount();
+//            if (colCount == 0 && rowCount == 0) {
+//                continue;
+//            }
+//            if (colCount == 4) {
+//                this.fundInfoTable = table;
+//            } else if (colCount == 5) {
+//                index = this.splitTables(table, 2, index, this.extNavTables, spanningPageTableMap);
+//            }
+//        }
+//        // 跨页的净值记录表(包括表头一共有2行)
+//        this.handleSpanningPageTables(this.extNavTables, spanningPageTableMap);
+//    }
+//
+//    @Override
+//    protected ReportFundInfoDTO buildFundInfo(ReportParserParams params) {
+//        if (this.fundInfoTable == null) {
+//            return null;
+//        }
+//        // 月报的基金基本信息是四列的表格
+//        Map<String, Object> baseInfoMap = MapUtil.newHashMap(32);
+//        for (int i = 0; i < fundInfoTable.getRows().size(); i++) {
+//            @SuppressWarnings("all")
+//            List<RectangularTextContainer> cols = fundInfoTable.getRows().get(i);
+//            for (int j = 0; j < 2; j++) {
+//                baseInfoMap.put(cols.get(j * 2).getText(), cols.get(j * 2 + 1).getText());
+//            }
+//        }
+//        return this.buildDto(params.getFileId(), ReportFundInfoDTO.class, baseInfoMap);
+//    }
+//
+//    @Override
+//    protected MonthlyReportData parseExtInfoAndSetData(ReportBaseInfoDTO reportInfo, ReportFundInfoDTO fundInfo) {
+//        MonthlyReportData reportData = new MonthlyReportData(reportInfo, fundInfo);
+//        // 母基金和分级基金的净值
+//        List<ReportNetReportDTO> dtos = this.buildLevelDto(reportInfo.getFileId(), this.extNavTables,
+//                ReportNetReportDTO.class, t -> {
+//                    Map<String, Object> extInfoMap = MapUtil.newHashMap(16);
+//                    // 限制只能两行数据
+//                    if (t.getRowCount() != 2) {
+//                        return extInfoMap;
+//                    }
+//                    for (int i = 0; i < t.getColCount(); i++) {
+//                        String key = ReportParseUtils.cleaningValue(t.getCell(0, i).getText());
+//                        key = StrUtil.subBefore(key, "(", false);
+//                        String value = t.getCell(1, i).getText();
+//                        extInfoMap.put(key, value);
+//                    }
+//                    return extInfoMap;
+//                });
+//        reportData.setNetReport(dtos);
+//        return reportData;
+//    }
+//}

+ 269 - 269
mo-daq/src/main/java/com/smppw/modaq/application/components/report/parser/pdf/PDQuarterlyReportParser.java

@@ -1,269 +1,269 @@
-package com.smppw.modaq.application.components.report.parser.pdf;
-
-import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.collection.ListUtil;
-import cn.hutool.core.map.MapUtil;
-import cn.hutool.core.util.StrUtil;
-import com.smppw.modaq.application.components.ReportParseUtils;
-import com.smppw.modaq.application.components.report.parser.ReportParserConstant;
-import com.smppw.modaq.common.enums.ReportParseStatus;
-import com.smppw.modaq.common.exception.ReportParseException;
-import com.smppw.modaq.domain.dto.report.*;
-import com.smppw.modaq.domain.mapper.EmailFieldMappingMapper;
-import org.springframework.stereotype.Component;
-import technology.tabula.RectangularTextContainer;
-import technology.tabula.Table;
-
-import java.awt.geom.Rectangle2D;
-import java.util.Comparator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.function.Function;
-
-/**
- * @author wangzaijun
- * @date 2024/9/29 17:53
- * @description pdf格式的季报解析逻辑
- */
-@Component(ReportParserConstant.PARSER_PDF_QUARTERLY)
-public class PDQuarterlyReportParser<T extends QuarterlyReportData> extends AbstractPDReportParser<T> {
-    protected Table fundInfoTable;
-    protected List<Table> financialIndicatorsTables;
-    protected List<Table> shareChangeTables;
-    protected List<Table> assetAllocationTables;
-    protected List<Table> investmentIndustryTables;
-
-    public PDQuarterlyReportParser(EmailFieldMappingMapper fieldMappingMapper) {
-        super(fieldMappingMapper);
-    }
-
-    @Override
-    public String getParser() {
-        return ReportParserConstant.PARSER_PDF_QUARTERLY;
-    }
-
-    @Override
-    protected void init() {
-        super.init();
-        this.fundInfoTable = null;
-        this.financialIndicatorsTables = ListUtil.list(true);
-        this.shareChangeTables = ListUtil.list(true);
-        this.assetAllocationTables = ListUtil.list(true);
-        this.investmentIndustryTables = ListUtil.list(true);
-    }
-
-    @Override
-    protected void initTableInfo(List<Table> tables) {
-        Map<Integer, List<Table>> spanningPageFinancialIndicatorsTableMap = MapUtil.newHashMap(8, true);
-        Map<Integer, List<Table>> spanningPageShareChangeTableMap = MapUtil.newHashMap(8, true);
-        int fi = 0;
-        int sci = 0;
-        for (Table table : tables) {
-            int colCount = table.getColCount();
-            int rowCount = table.getRowCount();
-            if (colCount == 0 && rowCount == 0) {
-                continue;
-            }
-            if (colCount == 2) {
-                // 用表格的第一列的数据判断是否份额变动记录
-                List<String> texts = this.getTableColTexts(table, 0);
-                if (CollUtil.containsAny(texts, ReportParseUtils.FUND_INFO_COLUMN_NAMES)) {
-                    this.fundInfoTable = table;
-                    continue;
-                }
-                // 主要财务指标或份额变动
-                if (CollUtil.containsAny(texts, ReportParseUtils.SHARE_CHANGE_COLUMN_NAMES)) {
-                    sci = this.splitTables(table, 5, sci, this.shareChangeTables, spanningPageShareChangeTableMap);
-                } else if (CollUtil.containsAny(texts, ReportParseUtils.FINANCIAL_INDICATORS_COLUMN_NAMES)) {
-                    fi = this.splitTables(table, 10, fi, this.financialIndicatorsTables, spanningPageFinancialIndicatorsTableMap);
-                }
-            } else if (colCount == 4) {
-                // 行业配置
-                this.investmentIndustryTables.add(table);
-            } else if (colCount == 3) {
-                // 用表格的第一列单元格判断是否资产配置表
-                List<String> texts = this.getTableColTexts(table, 0);
-                if (CollUtil.containsAny(texts, ReportParseUtils.INDUSTRY_COLUMN_NAMES)) {
-                    this.investmentIndustryTables.add(table);
-                } else {
-                    texts = this.getTableColTexts(table, 1);
-                    Set<String> keys = ReportParseUtils.ASSET_ALLOCATION_TYPE_MAPPER.keySet();
-                    if (CollUtil.containsAny(texts, keys)) {
-                        this.assetAllocationTables.add(table);
-                    }
-                }
-            }
-        }
-        // 跨页的财务信息记录表(包括表头一共有10行)
-        this.handleSpanningPageTables(this.financialIndicatorsTables, spanningPageFinancialIndicatorsTableMap);
-        // 跨页的份额变动记录表(包括表头一共有5行)
-        this.handleSpanningPageTables(this.shareChangeTables, spanningPageShareChangeTableMap);
-    }
-
-    @Override
-    protected ReportFundInfoDTO buildFundInfo(ReportParserParams params) {
-        Table fundInfoTable = this.fundInfoTable;
-        if (fundInfoTable == null) {
-            throw new ReportParseException(ReportParseStatus.PARSE_FUND_INFO_FAIL, params.getFilename());
-        }
-        // 基金基本信息映射
-        Map<String, Object> extInfoMap = this.parseFundInfo(fundInfoTable);
-        return this.buildDto(params.getFileId(), ReportFundInfoDTO.class, extInfoMap);
-    }
-
-    protected Map<String, Object> parseFundInfo(Table fundInfoTable) {
-        // 季报和年报的基金基本信息是两列的表格
-        Map<String, Object> baseInfoMap = MapUtil.newHashMap(32);
-        for (int i = 0; i < fundInfoTable.getRows().size(); i++) {
-            @SuppressWarnings("all")
-            List<RectangularTextContainer> cols = fundInfoTable.getRows().get(i);
-            for (int j = 0; j < 1; j++) {
-                String key = ReportParseUtils.cleaningValue(cols.get(j).getText());
-                baseInfoMap.put(key, cols.get(j + 1).getText());
-            }
-        }
-        return baseInfoMap;
-    }
-
-    protected T parseExtInfoAndSetData(ReportBaseInfoDTO reportInfo, ReportFundInfoDTO fundInfo) {
-        Integer fileId = reportInfo.getFileId();
-        // 表格转换数据获取函数
-        Function<Table, Map<String, Object>> function = t -> {
-            Map<String, Object> extInfoMap = MapUtil.newHashMap(16);
-            for (int i = 0; i < t.getRowCount(); i++) {
-                String key = ReportParseUtils.cleaningValue(t.getCell(i, 0).getText());
-                String value = t.getCell(i, 1).getText();
-                extInfoMap.put(key, value);
-            }
-            return extInfoMap;
-        };
-        // 份额变动
-        List<ReportShareChangeDTO> shareChanges = this.buildLevelDto(fileId, this.shareChangeTables,
-                ReportShareChangeDTO.class, function);
-        // 主要财务指标
-        List<ReportFinancialIndicatorsDTO> financialIndicators = this.buildFinancialIndicatorsInfo(fileId, function);
-        // 资产配置
-        List<ReportAssetAllocationDTO> assetAllocations = this.buildAssetAllocationInfo(fileId);
-        // 行业配置
-        List<ReportInvestmentIndustryDTO> investmentIndustries = this.buildInvestmentIndustryInfo(fileId);
-        // 返回数据构建
-        return this.buildReportData(reportInfo, fundInfo, shareChanges, financialIndicators, assetAllocations, investmentIndustries);
-    }
-
-    /**
-     * 主要财务指标数据构建(包括分级基金,并且一个表格可能跨页)
-     *
-     * @param fileId   文件id
-     * @param function 字段映射关系
-     * @return /
-     */
-    protected List<ReportFinancialIndicatorsDTO> buildFinancialIndicatorsInfo(Integer fileId,
-                                                                              Function<Table, Map<String, Object>> function) {
-        return this.buildLevelDto(fileId, this.financialIndicatorsTables, ReportFinancialIndicatorsDTO.class, function);
-    }
-
-    /**
-     * 子类重写,放在cast异常
-     *
-     * @param reportInfo           报告基本信息
-     * @param fundInfo             基金基本信息
-     * @param shareChanges         份额变动
-     * @param financialIndicators  基本财务指标
-     * @param assetAllocations     资产配置
-     * @param investmentIndustries 行业配置
-     * @return /
-     */
-    protected T buildReportData(ReportBaseInfoDTO reportInfo, ReportFundInfoDTO fundInfo,
-                                List<ReportShareChangeDTO> shareChanges,
-                                List<ReportFinancialIndicatorsDTO> financialIndicators,
-                                List<ReportAssetAllocationDTO> assetAllocations,
-                                List<ReportInvestmentIndustryDTO> investmentIndustries) {
-        QuarterlyReportData reportData = new QuarterlyReportData(reportInfo, fundInfo);
-        reportData.setShareChange(shareChanges);
-        reportData.setFinancialIndicators(financialIndicators);
-        reportData.setAssetAllocation(assetAllocations);
-        reportData.setInvestmentIndustry(investmentIndustries);
-        @SuppressWarnings("unchecked")
-        T t = (T) reportData;
-        return t;
-    }
-
-    /**
-     * 构建基金行业配置解析数据
-     *
-     * @return /
-     */
-    private List<ReportInvestmentIndustryDTO> buildInvestmentIndustryInfo(Integer fileId) {
-        List<ReportInvestmentIndustryDTO> dtos = ListUtil.list(false);
-        for (Table table : this.investmentIndustryTables) {
-            int colCount = table.getColCount();
-            // 投资地区: 1-境内, 2-港股通
-            int investType = colCount == 4 ? 1 : 2;
-            int j = colCount == 4 ? 1 : 0;
-            // 按行遍历
-            for (int i = 0; i < table.getRowCount(); i++) {
-                String text = ReportParseUtils.cleaningValue(table.getCell(i, 0).getText());
-                if (StrUtil.containsAny(text, "序号", "行业类别")) {
-                    continue;
-                }
-                String industryName = ReportParseUtils.cleaningValue(table.getCell(i, j).getText());
-                if (StrUtil.isBlank(industryName) || !ReportParseUtils.INDUSTRY_COLUMN_NAMES.contains(industryName)) {
-                    continue;
-                }
-                ReportInvestmentIndustryDTO dto = new ReportInvestmentIndustryDTO(fileId);
-                dto.setInvestType(investType);
-                dto.setIndustryName(industryName);
-                dto.setMarketValue(ReportParseUtils.cleaningValue(table.getCell(i, j + 1).getText()));
-                dto.setRatio(ReportParseUtils.cleaningValue(table.getCell(i, j + 2).getText()));
-                dtos.add(dto);
-            }
-        }
-        return dtos;
-    }
-
-    /**
-     * 构建基金资产配置解析数据
-     *
-     * @param fileId 文件id
-     * @return /
-     */
-    private List<ReportAssetAllocationDTO> buildAssetAllocationInfo(Integer fileId) {
-        List<ReportAssetAllocationDTO> dtos = ListUtil.list(false);
-        for (Table table : this.assetAllocationTables) {
-            // 按行遍历
-            for (@SuppressWarnings("all") List<RectangularTextContainer> row : table.getRows()) {
-                // x坐标升序(防止部分行乱序问题)
-                row.sort(Comparator.comparing(Rectangle2D.Float::getX));
-                // 金额、市值,有时是 “备注#金额”的格式
-                String marketValueAndRemark = ReportParseUtils.cleaningValue(row.get(2).getText(), false);
-                // 资产明细
-                String detail = ReportParseUtils.cleaningValue(row.get(1).getText(), false);
-                if (!ReportParseUtils.ASSET_ALLOCATION_TYPE_MAPPER.containsKey(detail)) {
-                    continue;
-                }
-                // 大类
-                ReportParseUtils.buildAssetAllocation(fileId, detail, marketValueAndRemark, dtos);
-            }
-        }
-        return dtos;
-    }
-
-    /**
-     * 获取表格指定列的所有文字内容
-     *
-     * @param table 表格
-     * @param col   指定列
-     * @return /
-     */
-    protected List<String> getTableColTexts(Table table, Integer col) {
-        List<String> details = ListUtil.list(false);
-        for (@SuppressWarnings("all") List<RectangularTextContainer> row : table.getRows()) {
-            String detail = ReportParseUtils.cleaningValue(row.get(col).getText(), false);
-            if (StrUtil.isNotBlank(detail)) {
-                details.add(detail);
-            }
-        }
-        return details;
-    }
-}
+//package com.smppw.modaq.application.components.report.parser.pdf;
+//
+//import cn.hutool.core.collection.CollUtil;
+//import cn.hutool.core.collection.ListUtil;
+//import cn.hutool.core.map.MapUtil;
+//import cn.hutool.core.util.StrUtil;
+//import com.smppw.modaq.application.components.ReportParseUtils;
+//import com.smppw.modaq.application.components.report.parser.ReportParserConstant;
+//import com.smppw.modaq.common.enums.ReportParseStatus;
+//import com.smppw.modaq.common.exception.ReportParseException;
+//import com.smppw.modaq.domain.dto.report.*;
+//import com.smppw.modaq.domain.mapper.EmailFieldMappingMapper;
+//import org.springframework.stereotype.Component;
+//import technology.tabula.RectangularTextContainer;
+//import technology.tabula.Table;
+//
+//import java.awt.geom.Rectangle2D;
+//import java.util.Comparator;
+//import java.util.List;
+//import java.util.Map;
+//import java.util.Set;
+//import java.util.function.Function;
+//
+///**
+// * @author wangzaijun
+// * @date 2024/9/29 17:53
+// * @description pdf格式的季报解析逻辑
+// */
+//@Component(ReportParserConstant.PARSER_PDF_QUARTERLY)
+//public class PDQuarterlyReportParser<T extends QuarterlyReportData> extends AbstractPDReportParser<T> {
+//    protected Table fundInfoTable;
+//    protected List<Table> financialIndicatorsTables;
+//    protected List<Table> shareChangeTables;
+//    protected List<Table> assetAllocationTables;
+//    protected List<Table> investmentIndustryTables;
+//
+//    public PDQuarterlyReportParser(EmailFieldMappingMapper fieldMappingMapper) {
+//        super(fieldMappingMapper);
+//    }
+//
+//    @Override
+//    public String getParser() {
+//        return ReportParserConstant.PARSER_PDF_QUARTERLY;
+//    }
+//
+//    @Override
+//    protected void init() {
+//        super.init();
+//        this.fundInfoTable = null;
+//        this.financialIndicatorsTables = ListUtil.list(true);
+//        this.shareChangeTables = ListUtil.list(true);
+//        this.assetAllocationTables = ListUtil.list(true);
+//        this.investmentIndustryTables = ListUtil.list(true);
+//    }
+//
+//    @Override
+//    protected void initTableInfo(List<Table> tables) {
+//        Map<Integer, List<Table>> spanningPageFinancialIndicatorsTableMap = MapUtil.newHashMap(8, true);
+//        Map<Integer, List<Table>> spanningPageShareChangeTableMap = MapUtil.newHashMap(8, true);
+//        int fi = 0;
+//        int sci = 0;
+//        for (Table table : tables) {
+//            int colCount = table.getColCount();
+//            int rowCount = table.getRowCount();
+//            if (colCount == 0 && rowCount == 0) {
+//                continue;
+//            }
+//            if (colCount == 2) {
+//                // 用表格的第一列的数据判断是否份额变动记录
+//                List<String> texts = this.getTableColTexts(table, 0);
+//                if (CollUtil.containsAny(texts, ReportParseUtils.FUND_INFO_COLUMN_NAMES)) {
+//                    this.fundInfoTable = table;
+//                    continue;
+//                }
+//                // 主要财务指标或份额变动
+//                if (CollUtil.containsAny(texts, ReportParseUtils.SHARE_CHANGE_COLUMN_NAMES)) {
+//                    sci = this.splitTables(table, 5, sci, this.shareChangeTables, spanningPageShareChangeTableMap);
+//                } else if (CollUtil.containsAny(texts, ReportParseUtils.FINANCIAL_INDICATORS_COLUMN_NAMES)) {
+//                    fi = this.splitTables(table, 10, fi, this.financialIndicatorsTables, spanningPageFinancialIndicatorsTableMap);
+//                }
+//            } else if (colCount == 4) {
+//                // 行业配置
+//                this.investmentIndustryTables.add(table);
+//            } else if (colCount == 3) {
+//                // 用表格的第一列单元格判断是否资产配置表
+//                List<String> texts = this.getTableColTexts(table, 0);
+//                if (CollUtil.containsAny(texts, ReportParseUtils.INDUSTRY_COLUMN_NAMES)) {
+//                    this.investmentIndustryTables.add(table);
+//                } else {
+//                    texts = this.getTableColTexts(table, 1);
+//                    Set<String> keys = ReportParseUtils.ASSET_ALLOCATION_TYPE_MAPPER.keySet();
+//                    if (CollUtil.containsAny(texts, keys)) {
+//                        this.assetAllocationTables.add(table);
+//                    }
+//                }
+//            }
+//        }
+//        // 跨页的财务信息记录表(包括表头一共有10行)
+//        this.handleSpanningPageTables(this.financialIndicatorsTables, spanningPageFinancialIndicatorsTableMap);
+//        // 跨页的份额变动记录表(包括表头一共有5行)
+//        this.handleSpanningPageTables(this.shareChangeTables, spanningPageShareChangeTableMap);
+//    }
+//
+//    @Override
+//    protected ReportFundInfoDTO buildFundInfo(ReportParserParams params) {
+//        Table fundInfoTable = this.fundInfoTable;
+//        if (fundInfoTable == null) {
+//            throw new ReportParseException(ReportParseStatus.PARSE_FUND_INFO_FAIL, params.getFilename());
+//        }
+//        // 基金基本信息映射
+//        Map<String, Object> extInfoMap = this.parseFundInfo(fundInfoTable);
+//        return this.buildDto(params.getFileId(), ReportFundInfoDTO.class, extInfoMap);
+//    }
+//
+//    protected Map<String, Object> parseFundInfo(Table fundInfoTable) {
+//        // 季报和年报的基金基本信息是两列的表格
+//        Map<String, Object> baseInfoMap = MapUtil.newHashMap(32);
+//        for (int i = 0; i < fundInfoTable.getRows().size(); i++) {
+//            @SuppressWarnings("all")
+//            List<RectangularTextContainer> cols = fundInfoTable.getRows().get(i);
+//            for (int j = 0; j < 1; j++) {
+//                String key = ReportParseUtils.cleaningValue(cols.get(j).getText());
+//                baseInfoMap.put(key, cols.get(j + 1).getText());
+//            }
+//        }
+//        return baseInfoMap;
+//    }
+//
+//    protected T parseExtInfoAndSetData(ReportBaseInfoDTO reportInfo, ReportFundInfoDTO fundInfo) {
+//        Integer fileId = reportInfo.getFileId();
+//        // 表格转换数据获取函数
+//        Function<Table, Map<String, Object>> function = t -> {
+//            Map<String, Object> extInfoMap = MapUtil.newHashMap(16);
+//            for (int i = 0; i < t.getRowCount(); i++) {
+//                String key = ReportParseUtils.cleaningValue(t.getCell(i, 0).getText());
+//                String value = t.getCell(i, 1).getText();
+//                extInfoMap.put(key, value);
+//            }
+//            return extInfoMap;
+//        };
+//        // 份额变动
+//        List<ReportShareChangeDTO> shareChanges = this.buildLevelDto(fileId, this.shareChangeTables,
+//                ReportShareChangeDTO.class, function);
+//        // 主要财务指标
+//        List<ReportFinancialIndicatorsDTO> financialIndicators = this.buildFinancialIndicatorsInfo(fileId, function);
+//        // 资产配置
+//        List<ReportAssetAllocationDTO> assetAllocations = this.buildAssetAllocationInfo(fileId);
+//        // 行业配置
+//        List<ReportInvestmentIndustryDTO> investmentIndustries = this.buildInvestmentIndustryInfo(fileId);
+//        // 返回数据构建
+//        return this.buildReportData(reportInfo, fundInfo, shareChanges, financialIndicators, assetAllocations, investmentIndustries);
+//    }
+//
+//    /**
+//     * 主要财务指标数据构建(包括分级基金,并且一个表格可能跨页)
+//     *
+//     * @param fileId   文件id
+//     * @param function 字段映射关系
+//     * @return /
+//     */
+//    protected List<ReportFinancialIndicatorsDTO> buildFinancialIndicatorsInfo(Integer fileId,
+//                                                                              Function<Table, Map<String, Object>> function) {
+//        return this.buildLevelDto(fileId, this.financialIndicatorsTables, ReportFinancialIndicatorsDTO.class, function);
+//    }
+//
+//    /**
+//     * 子类重写,放在cast异常
+//     *
+//     * @param reportInfo           报告基本信息
+//     * @param fundInfo             基金基本信息
+//     * @param shareChanges         份额变动
+//     * @param financialIndicators  基本财务指标
+//     * @param assetAllocations     资产配置
+//     * @param investmentIndustries 行业配置
+//     * @return /
+//     */
+//    protected T buildReportData(ReportBaseInfoDTO reportInfo, ReportFundInfoDTO fundInfo,
+//                                List<ReportShareChangeDTO> shareChanges,
+//                                List<ReportFinancialIndicatorsDTO> financialIndicators,
+//                                List<ReportAssetAllocationDTO> assetAllocations,
+//                                List<ReportInvestmentIndustryDTO> investmentIndustries) {
+//        QuarterlyReportData reportData = new QuarterlyReportData(reportInfo, fundInfo);
+//        reportData.setShareChange(shareChanges);
+//        reportData.setFinancialIndicators(financialIndicators);
+//        reportData.setAssetAllocation(assetAllocations);
+//        reportData.setInvestmentIndustry(investmentIndustries);
+//        @SuppressWarnings("unchecked")
+//        T t = (T) reportData;
+//        return t;
+//    }
+//
+//    /**
+//     * 构建基金行业配置解析数据
+//     *
+//     * @return /
+//     */
+//    private List<ReportInvestmentIndustryDTO> buildInvestmentIndustryInfo(Integer fileId) {
+//        List<ReportInvestmentIndustryDTO> dtos = ListUtil.list(false);
+//        for (Table table : this.investmentIndustryTables) {
+//            int colCount = table.getColCount();
+//            // 投资地区: 1-境内, 2-港股通
+//            int investType = colCount == 4 ? 1 : 2;
+//            int j = colCount == 4 ? 1 : 0;
+//            // 按行遍历
+//            for (int i = 0; i < table.getRowCount(); i++) {
+//                String text = ReportParseUtils.cleaningValue(table.getCell(i, 0).getText());
+//                if (StrUtil.containsAny(text, "序号", "行业类别")) {
+//                    continue;
+//                }
+//                String industryName = ReportParseUtils.cleaningValue(table.getCell(i, j).getText());
+//                if (StrUtil.isBlank(industryName) || !ReportParseUtils.INDUSTRY_COLUMN_NAMES.contains(industryName)) {
+//                    continue;
+//                }
+//                ReportInvestmentIndustryDTO dto = new ReportInvestmentIndustryDTO(fileId);
+//                dto.setInvestType(investType);
+//                dto.setIndustryName(industryName);
+//                dto.setMarketValue(ReportParseUtils.cleaningValue(table.getCell(i, j + 1).getText()));
+//                dto.setRatio(ReportParseUtils.cleaningValue(table.getCell(i, j + 2).getText()));
+//                dtos.add(dto);
+//            }
+//        }
+//        return dtos;
+//    }
+//
+//    /**
+//     * 构建基金资产配置解析数据
+//     *
+//     * @param fileId 文件id
+//     * @return /
+//     */
+//    private List<ReportAssetAllocationDTO> buildAssetAllocationInfo(Integer fileId) {
+//        List<ReportAssetAllocationDTO> dtos = ListUtil.list(false);
+//        for (Table table : this.assetAllocationTables) {
+//            // 按行遍历
+//            for (@SuppressWarnings("all") List<RectangularTextContainer> row : table.getRows()) {
+//                // x坐标升序(防止部分行乱序问题)
+//                row.sort(Comparator.comparing(Rectangle2D.Float::getX));
+//                // 金额、市值,有时是 “备注#金额”的格式
+//                String marketValueAndRemark = ReportParseUtils.cleaningValue(row.get(2).getText(), false);
+//                // 资产明细
+//                String detail = ReportParseUtils.cleaningValue(row.get(1).getText(), false);
+//                if (!ReportParseUtils.ASSET_ALLOCATION_TYPE_MAPPER.containsKey(detail)) {
+//                    continue;
+//                }
+//                // 大类
+//                ReportParseUtils.buildAssetAllocation(fileId, detail, marketValueAndRemark, dtos);
+//            }
+//        }
+//        return dtos;
+//    }
+//
+//    /**
+//     * 获取表格指定列的所有文字内容
+//     *
+//     * @param table 表格
+//     * @param col   指定列
+//     * @return /
+//     */
+//    protected List<String> getTableColTexts(Table table, Integer col) {
+//        List<String> details = ListUtil.list(false);
+//        for (@SuppressWarnings("all") List<RectangularTextContainer> row : table.getRows()) {
+//            String detail = ReportParseUtils.cleaningValue(row.get(col).getText(), false);
+//            if (StrUtil.isNotBlank(detail)) {
+//                details.add(detail);
+//            }
+//        }
+//        return details;
+//    }
+//}

+ 14 - 14
mo-daq/src/main/java/com/smppw/modaq/application/components/report/writer/AnnuallyReportWriter.java

@@ -1,14 +1,14 @@
-package com.smppw.modaq.application.components.report.writer;
-
-import com.smppw.modaq.domain.dto.report.AnnuallyReportData;
-import com.smppw.modaq.domain.mapper.report.*;
-import org.springframework.stereotype.Component;
-
-@Component(ReportWriterConstant.WRITER_ANNUALLY)
-public class AnnuallyReportWriter extends QuarterlyReportWriter<AnnuallyReportData> {
-    public AnnuallyReportWriter(ReportBaseInfoMapper baseInfoMapper, ReportFundInfoMapper fundInfoMapper,
-                                ReportShareChangeMapper shareChangeMapper, ReportAssetAllocationMapper assetAllocationMapper,
-                                ReportInvestmentIndustryMapper investmentIndustryMapper, ReportFinancialIndicatorMapper financialIndicatorMapper) {
-        super(baseInfoMapper, fundInfoMapper, shareChangeMapper, assetAllocationMapper, investmentIndustryMapper, financialIndicatorMapper);
-    }
-}
+//package com.smppw.modaq.application.components.report.writer;
+//
+//import com.smppw.modaq.domain.dto.report.AnnuallyReportData;
+//import com.smppw.modaq.domain.mapper.report.*;
+//import org.springframework.stereotype.Component;
+//
+//@Component(ReportWriterConstant.WRITER_ANNUALLY)
+//public class AnnuallyReportWriter extends QuarterlyReportWriter<AnnuallyReportData> {
+//    public AnnuallyReportWriter(ReportBaseInfoMapper baseInfoMapper, ReportFundInfoMapper fundInfoMapper,
+//                                ReportShareChangeMapper shareChangeMapper, ReportAssetAllocationMapper assetAllocationMapper,
+//                                ReportInvestmentIndustryMapper investmentIndustryMapper, ReportFinancialIndicatorMapper financialIndicatorMapper) {
+//        super(baseInfoMapper, fundInfoMapper, shareChangeMapper, assetAllocationMapper, investmentIndustryMapper, financialIndicatorMapper);
+//    }
+//}

+ 35 - 35
mo-daq/src/main/java/com/smppw/modaq/application/components/report/writer/MonthlyReportWriter.java

@@ -1,35 +1,35 @@
-package com.smppw.modaq.application.components.report.writer;
-
-import cn.hutool.core.collection.CollUtil;
-import com.smppw.modaq.domain.dto.report.MonthlyReportData;
-import com.smppw.modaq.domain.dto.report.ReportNetReportDTO;
-import com.smppw.modaq.domain.entity.report.ReportNetReportDO;
-import com.smppw.modaq.domain.mapper.report.ReportBaseInfoMapper;
-import com.smppw.modaq.domain.mapper.report.ReportFundInfoMapper;
-import com.smppw.modaq.domain.mapper.report.ReportNetReportMapper;
-import org.springframework.stereotype.Component;
-
-import java.util.List;
-import java.util.stream.Collectors;
-
-@Component(ReportWriterConstant.WRITER_MONTHLY)
-public class MonthlyReportWriter extends AbstractReportWriter<MonthlyReportData> {
-    private final ReportNetReportMapper netReportMapper;
-
-    public MonthlyReportWriter(ReportBaseInfoMapper baseInfoMapper,
-                               ReportFundInfoMapper fundInfoMapper,
-                               ReportNetReportMapper netReportMapper) {
-        super(baseInfoMapper, fundInfoMapper);
-        this.netReportMapper = netReportMapper;
-    }
-
-    @Override
-    protected void writeExtData(MonthlyReportData reportData) {
-        List<ReportNetReportDTO> netReport = reportData.getNetReport();
-        if (CollUtil.isNotEmpty(netReport)) {
-            List<ReportNetReportDO> entityList = netReport.stream()
-                    .map(ReportNetReportDTO::toEntity).collect(Collectors.toList());
-            this.netReportMapper.insert(entityList);
-        }
-    }
-}
+//package com.smppw.modaq.application.components.report.writer;
+//
+//import cn.hutool.core.collection.CollUtil;
+//import com.smppw.modaq.domain.dto.report.MonthlyReportData;
+//import com.smppw.modaq.domain.dto.report.ReportNetReportDTO;
+//import com.smppw.modaq.domain.entity.report.ReportNetReportDO;
+//import com.smppw.modaq.domain.mapper.report.ReportBaseInfoMapper;
+//import com.smppw.modaq.domain.mapper.report.ReportFundInfoMapper;
+//import com.smppw.modaq.domain.mapper.report.ReportNetReportMapper;
+//import org.springframework.stereotype.Component;
+//
+//import java.util.List;
+//import java.util.stream.Collectors;
+//
+//@Component(ReportWriterConstant.WRITER_MONTHLY)
+//public class MonthlyReportWriter extends AbstractReportWriter<MonthlyReportData> {
+//    private final ReportNetReportMapper netReportMapper;
+//
+//    public MonthlyReportWriter(ReportBaseInfoMapper baseInfoMapper,
+//                               ReportFundInfoMapper fundInfoMapper,
+//                               ReportNetReportMapper netReportMapper) {
+//        super(baseInfoMapper, fundInfoMapper);
+//        this.netReportMapper = netReportMapper;
+//    }
+//
+//    @Override
+//    protected void writeExtData(MonthlyReportData reportData) {
+//        List<ReportNetReportDTO> netReport = reportData.getNetReport();
+//        if (CollUtil.isNotEmpty(netReport)) {
+//            List<ReportNetReportDO> entityList = netReport.stream()
+//                    .map(ReportNetReportDTO::toEntity).collect(Collectors.toList());
+//            this.netReportMapper.insert(entityList);
+//        }
+//    }
+//}

+ 18 - 18
mo-daq/src/main/java/com/smppw/modaq/application/components/report/writer/OtherReportWriter.java

@@ -1,18 +1,18 @@
-package com.smppw.modaq.application.components.report.writer;
-
-import com.smppw.modaq.domain.dto.report.ReportData;
-import com.smppw.modaq.domain.mapper.report.ReportBaseInfoMapper;
-import com.smppw.modaq.domain.mapper.report.ReportFundInfoMapper;
-import org.springframework.stereotype.Component;
-
-@Component(ReportWriterConstant.WRITER_OTHER)
-public class OtherReportWriter extends AbstractReportWriter<ReportData> {
-    public OtherReportWriter(ReportBaseInfoMapper baseInfoMapper, ReportFundInfoMapper fundInfoMapper) {
-        super(baseInfoMapper, fundInfoMapper);
-    }
-
-    @Override
-    protected void writeExtData(ReportData reportData) {
-        // 没有数据要保存
-    }
-}
+//package com.smppw.modaq.application.components.report.writer;
+//
+//import com.smppw.modaq.domain.dto.report.ReportData;
+//import com.smppw.modaq.domain.mapper.report.ReportBaseInfoMapper;
+//import com.smppw.modaq.domain.mapper.report.ReportFundInfoMapper;
+//import org.springframework.stereotype.Component;
+//
+//@Component(ReportWriterConstant.WRITER_OTHER)
+//public class OtherReportWriter extends AbstractReportWriter<ReportData> {
+//    public OtherReportWriter(ReportBaseInfoMapper baseInfoMapper, ReportFundInfoMapper fundInfoMapper) {
+//        super(baseInfoMapper, fundInfoMapper);
+//    }
+//
+//    @Override
+//    protected void writeExtData(ReportData reportData) {
+//        // 没有数据要保存
+//    }
+//}

+ 62 - 62
mo-daq/src/main/java/com/smppw/modaq/application/components/report/writer/QuarterlyReportWriter.java

@@ -1,62 +1,62 @@
-package com.smppw.modaq.application.components.report.writer;
-
-import cn.hutool.core.collection.CollUtil;
-import com.smppw.modaq.domain.dto.report.*;
-import com.smppw.modaq.domain.entity.report.ReportAssetAllocationDO;
-import com.smppw.modaq.domain.entity.report.ReportFinancialIndicatorsDO;
-import com.smppw.modaq.domain.entity.report.ReportInvestmentIndustryDO;
-import com.smppw.modaq.domain.entity.report.ReportShareChangeDO;
-import com.smppw.modaq.domain.mapper.report.*;
-import org.springframework.stereotype.Component;
-
-import java.util.List;
-import java.util.stream.Collectors;
-
-@Component(ReportWriterConstant.WRITER_QUARTERLY)
-public class QuarterlyReportWriter<T extends QuarterlyReportData> extends AbstractReportWriter<T> {
-    private final ReportShareChangeMapper shareChangeMapper;
-    private final ReportAssetAllocationMapper assetAllocationMapper;
-    private final ReportInvestmentIndustryMapper investmentIndustryMapper;
-    private final ReportFinancialIndicatorMapper financialIndicatorMapper;
-
-    public QuarterlyReportWriter(ReportBaseInfoMapper baseInfoMapper, ReportFundInfoMapper fundInfoMapper,
-                                 ReportShareChangeMapper shareChangeMapper, ReportAssetAllocationMapper assetAllocationMapper,
-                                 ReportInvestmentIndustryMapper investmentIndustryMapper, ReportFinancialIndicatorMapper financialIndicatorMapper) {
-        super(baseInfoMapper, fundInfoMapper);
-        this.shareChangeMapper = shareChangeMapper;
-        this.assetAllocationMapper = assetAllocationMapper;
-        this.investmentIndustryMapper = investmentIndustryMapper;
-        this.financialIndicatorMapper = financialIndicatorMapper;
-    }
-
-    @Override
-    protected void writeExtData(QuarterlyReportData reportData) {
-        List<ReportShareChangeDTO> shareChange = reportData.getShareChange();
-        if (CollUtil.isNotEmpty(shareChange)) {
-            List<ReportShareChangeDO> entityList = shareChange.stream()
-                    .map(ReportShareChangeDTO::toEntity).collect(Collectors.toList());
-            this.shareChangeMapper.insert(entityList);
-        }
-
-        List<ReportAssetAllocationDTO> assetAllocation = reportData.getAssetAllocation();
-        if (CollUtil.isNotEmpty(assetAllocation)) {
-            List<ReportAssetAllocationDO> entityList = assetAllocation.stream()
-                    .map(ReportAssetAllocationDTO::toEntity).collect(Collectors.toList());
-            this.assetAllocationMapper.insert(entityList);
-        }
-
-        List<ReportFinancialIndicatorsDTO> financialIndicators = reportData.getFinancialIndicators();
-        if (CollUtil.isNotEmpty(financialIndicators)) {
-            List<ReportFinancialIndicatorsDO> entityList = financialIndicators.stream()
-                    .map(ReportFinancialIndicatorsDTO::toEntity).collect(Collectors.toList());
-            this.financialIndicatorMapper.insert(entityList);
-        }
-
-        List<ReportInvestmentIndustryDTO> investmentIndustry = reportData.getInvestmentIndustry();
-        if (CollUtil.isNotEmpty(investmentIndustry)) {
-            List<ReportInvestmentIndustryDO> entityList = investmentIndustry.stream()
-                    .map(ReportInvestmentIndustryDTO::toEntity).collect(Collectors.toList());
-            this.investmentIndustryMapper.insert(entityList);
-        }
-    }
-}
+//package com.smppw.modaq.application.components.report.writer;
+//
+//import cn.hutool.core.collection.CollUtil;
+//import com.smppw.modaq.domain.dto.report.*;
+//import com.smppw.modaq.domain.entity.report.ReportAssetAllocationDO;
+//import com.smppw.modaq.domain.entity.report.ReportFinancialIndicatorsDO;
+//import com.smppw.modaq.domain.entity.report.ReportInvestmentIndustryDO;
+//import com.smppw.modaq.domain.entity.report.ReportShareChangeDO;
+//import com.smppw.modaq.domain.mapper.report.*;
+//import org.springframework.stereotype.Component;
+//
+//import java.util.List;
+//import java.util.stream.Collectors;
+//
+//@Component(ReportWriterConstant.WRITER_QUARTERLY)
+//public class QuarterlyReportWriter<T extends QuarterlyReportData> extends AbstractReportWriter<T> {
+//    private final ReportShareChangeMapper shareChangeMapper;
+//    private final ReportAssetAllocationMapper assetAllocationMapper;
+//    private final ReportInvestmentIndustryMapper investmentIndustryMapper;
+//    private final ReportFinancialIndicatorMapper financialIndicatorMapper;
+//
+//    public QuarterlyReportWriter(ReportBaseInfoMapper baseInfoMapper, ReportFundInfoMapper fundInfoMapper,
+//                                 ReportShareChangeMapper shareChangeMapper, ReportAssetAllocationMapper assetAllocationMapper,
+//                                 ReportInvestmentIndustryMapper investmentIndustryMapper, ReportFinancialIndicatorMapper financialIndicatorMapper) {
+//        super(baseInfoMapper, fundInfoMapper);
+//        this.shareChangeMapper = shareChangeMapper;
+//        this.assetAllocationMapper = assetAllocationMapper;
+//        this.investmentIndustryMapper = investmentIndustryMapper;
+//        this.financialIndicatorMapper = financialIndicatorMapper;
+//    }
+//
+//    @Override
+//    protected void writeExtData(QuarterlyReportData reportData) {
+//        List<ReportShareChangeDTO> shareChange = reportData.getShareChange();
+//        if (CollUtil.isNotEmpty(shareChange)) {
+//            List<ReportShareChangeDO> entityList = shareChange.stream()
+//                    .map(ReportShareChangeDTO::toEntity).collect(Collectors.toList());
+//            this.shareChangeMapper.insert(entityList);
+//        }
+//
+//        List<ReportAssetAllocationDTO> assetAllocation = reportData.getAssetAllocation();
+//        if (CollUtil.isNotEmpty(assetAllocation)) {
+//            List<ReportAssetAllocationDO> entityList = assetAllocation.stream()
+//                    .map(ReportAssetAllocationDTO::toEntity).collect(Collectors.toList());
+//            this.assetAllocationMapper.insert(entityList);
+//        }
+//
+//        List<ReportFinancialIndicatorsDTO> financialIndicators = reportData.getFinancialIndicators();
+//        if (CollUtil.isNotEmpty(financialIndicators)) {
+//            List<ReportFinancialIndicatorsDO> entityList = financialIndicators.stream()
+//                    .map(ReportFinancialIndicatorsDTO::toEntity).collect(Collectors.toList());
+//            this.financialIndicatorMapper.insert(entityList);
+//        }
+//
+//        List<ReportInvestmentIndustryDTO> investmentIndustry = reportData.getInvestmentIndustry();
+//        if (CollUtil.isNotEmpty(investmentIndustry)) {
+//            List<ReportInvestmentIndustryDO> entityList = investmentIndustry.stream()
+//                    .map(ReportInvestmentIndustryDTO::toEntity).collect(Collectors.toList());
+//            this.investmentIndustryMapper.insert(entityList);
+//        }
+//    }
+//}

+ 11 - 11
mo-daq/src/main/java/com/smppw/modaq/application/components/report/writer/ReportWriterConstant.java

@@ -8,25 +8,25 @@ import java.util.Map;
 public final class ReportWriterConstant {
     public static final Map<ReportType, String> REPORT_TYPE_BEAN_MAP = MapUtil.newHashMap(8);
 
-    static final String WRITER_OTHER = "report-writer:other";
+//    static final String WRITER_OTHER = "report-writer:other";
 
-    static final String WRITER_WEEKLY = "report-writer:weekly";
+//    static final String WRITER_WEEKLY = "report-writer:weekly";
 
     static final String WRITER_LETTER = "report-writer:letter";
 
-    static final String WRITER_MONTHLY = "report-writer:monthly";
-    static final String WRITER_QUARTERLY = "report-writer:quarterly";
-    static final String WRITER_ANNUALLY = "report-writer:annually";
+//    static final String WRITER_MONTHLY = "report-writer:monthly";
+//    static final String WRITER_QUARTERLY = "report-writer:quarterly";
+//    static final String WRITER_ANNUALLY = "report-writer:annually";
 
     static {
-        REPORT_TYPE_BEAN_MAP.put(ReportType.OTHER, WRITER_OTHER);
-
-        REPORT_TYPE_BEAN_MAP.put(ReportType.WEEKLY, WRITER_WEEKLY);
+//        REPORT_TYPE_BEAN_MAP.put(ReportType.OTHER, WRITER_OTHER);
+//
+//        REPORT_TYPE_BEAN_MAP.put(ReportType.WEEKLY, WRITER_WEEKLY);
 
         REPORT_TYPE_BEAN_MAP.put(ReportType.LETTER, WRITER_LETTER);
 
-        REPORT_TYPE_BEAN_MAP.put(ReportType.MONTHLY, WRITER_MONTHLY);
-        REPORT_TYPE_BEAN_MAP.put(ReportType.QUARTERLY, WRITER_QUARTERLY);
-        REPORT_TYPE_BEAN_MAP.put(ReportType.ANNUALLY, WRITER_ANNUALLY);
+//        REPORT_TYPE_BEAN_MAP.put(ReportType.MONTHLY, WRITER_MONTHLY);
+//        REPORT_TYPE_BEAN_MAP.put(ReportType.QUARTERLY, WRITER_QUARTERLY);
+//        REPORT_TYPE_BEAN_MAP.put(ReportType.ANNUALLY, WRITER_ANNUALLY);
     }
 }

+ 18 - 18
mo-daq/src/main/java/com/smppw/modaq/application/components/report/writer/WeeklyReportWriter.java

@@ -1,18 +1,18 @@
-package com.smppw.modaq.application.components.report.writer;
-
-import com.smppw.modaq.domain.dto.report.WeeklyReportData;
-import com.smppw.modaq.domain.mapper.report.ReportBaseInfoMapper;
-import com.smppw.modaq.domain.mapper.report.ReportFundInfoMapper;
-import org.springframework.stereotype.Component;
-
-@Component(ReportWriterConstant.WRITER_WEEKLY)
-public class WeeklyReportWriter extends AbstractReportWriter<WeeklyReportData> {
-    public WeeklyReportWriter(ReportBaseInfoMapper baseInfoMapper, ReportFundInfoMapper fundInfoMapper) {
-        super(baseInfoMapper, fundInfoMapper);
-    }
-
-    @Override
-    protected void writeExtData(WeeklyReportData reportData) {
-        // 没有数据要保存
-    }
-}
+//package com.smppw.modaq.application.components.report.writer;
+//
+//import com.smppw.modaq.domain.dto.report.WeeklyReportData;
+//import com.smppw.modaq.domain.mapper.report.ReportBaseInfoMapper;
+//import com.smppw.modaq.domain.mapper.report.ReportFundInfoMapper;
+//import org.springframework.stereotype.Component;
+//
+//@Component(ReportWriterConstant.WRITER_WEEKLY)
+//public class WeeklyReportWriter extends AbstractReportWriter<WeeklyReportData> {
+//    public WeeklyReportWriter(ReportBaseInfoMapper baseInfoMapper, ReportFundInfoMapper fundInfoMapper) {
+//        super(baseInfoMapper, fundInfoMapper);
+//    }
+//
+//    @Override
+//    protected void writeExtData(WeeklyReportData reportData) {
+//        // 没有数据要保存
+//    }
+//}

+ 109 - 109
mo-daq/src/main/java/com/smppw/modaq/application/task/ParseSchedulerTask.java

@@ -1,116 +1,116 @@
-package com.smppw.modaq.application.task;
-
-import cn.hutool.core.collection.ListUtil;
-import cn.hutool.core.date.DateUtil;
-import cn.hutool.core.exceptions.ExceptionUtil;
-import com.smppw.modaq.application.service.EmailParseApiService;
-import com.smppw.modaq.common.conts.EmailTypeConst;
-import com.smppw.modaq.domain.entity.TaskRecordDO;
-import com.smppw.modaq.domain.service.TaskRecordService;
-import jakarta.annotation.PostConstruct;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.scheduling.annotation.Scheduled;
-import org.springframework.stereotype.Component;
-
-import java.util.Date;
-
-@Component
-public class ParseSchedulerTask {
-    private final Logger logger = LoggerFactory.getLogger(this.getClass());
-
-    private final EmailParseApiService emailParseApiService;
-    private final TaskRecordService taskRecordService;
-
-    public ParseSchedulerTask(EmailParseApiService emailParseApiService, TaskRecordService taskRecordService) {
-        this.emailParseApiService = emailParseApiService;
-        this.taskRecordService = taskRecordService;
-    }
-
-    @PostConstruct
-    public void executeOnStartup() {
+//package com.smppw.modaq.application.task;
+//
+//import cn.hutool.core.collection.ListUtil;
+//import cn.hutool.core.date.DateUtil;
+//import cn.hutool.core.exceptions.ExceptionUtil;
+//import com.smppw.modaq.application.service.EmailParseApiService;
+//import com.smppw.modaq.common.conts.EmailTypeConst;
+//import com.smppw.modaq.domain.entity.TaskRecordDO;
+//import com.smppw.modaq.domain.service.TaskRecordService;
+//import jakarta.annotation.PostConstruct;
+//import org.slf4j.Logger;
+//import org.slf4j.LoggerFactory;
+//import org.springframework.scheduling.annotation.Scheduled;
+//import org.springframework.stereotype.Component;
+//
+//import java.util.Date;
+//
+//@Component
+//public class ParseSchedulerTask {
+//    private final Logger logger = LoggerFactory.getLogger(this.getClass());
+//
+//    private final EmailParseApiService emailParseApiService;
+//    private final TaskRecordService taskRecordService;
+//
+//    public ParseSchedulerTask(EmailParseApiService emailParseApiService, TaskRecordService taskRecordService) {
+//        this.emailParseApiService = emailParseApiService;
+//        this.taskRecordService = taskRecordService;
+//    }
+//
+//    @PostConstruct
+//    public void executeOnStartup() {
+////        try {
+////            // 定期报告从 其他文件夹/报告公告 文件夹获取邮件
+////            this.emailParseApiService.parseEmail(
+////                    DateUtil.parseDateTime("2025-06-06 18:00:00"),
+////                    DateUtil.parseDateTime("2025-06-06 18:10:01"),
+////                    ListUtil.of("其他文件夹/报告公告"), EmailTypeConst.REPORT_EMAIL_TYPES);
+////        } catch (Exception e) {
+////            logger.error(ExceptionUtil.getMessage(e));
+////        }
+////
+////        try {
+////            // 确认函从 INBOX 文件夹获取邮件
+////            this.emailParseApiService.parseEmail(
+////                    DateUtil.parseDateTime("2025-06-03 18:50:00"),
+////                    DateUtil.parseDateTime("2025-06-03 19:56:00"),
+////                    null, ListUtil.of(EmailTypeConst.REPORT_LETTER_EMAIL_TYPE));
+////        } catch (Exception e) {
+////            logger.error(ExceptionUtil.getMessage(e));
+////        }
+//    }
+//
+//    /**
+//     * 定时任务每11分钟执行一次
+//     */
+//    @Scheduled(cron = "0 */11 * * * ?")
+//    public void letter() {
+//        String taskKey = "mo_email_parse_letter_task";
+//        TaskRecordDO task = this.taskRecordService.getTaskRecord(taskKey, 11 * 2 * 60);
+//        if (task == null) {
+//            return;
+//        }
+//        long start = System.currentTimeMillis();
+//        Date now = new Date();
 //        try {
-//            // 定期报告从 其他文件夹/报告公告 文件夹获取邮件
-//            this.emailParseApiService.parseEmail(
-//                    DateUtil.parseDateTime("2025-06-06 18:00:00"),
-//                    DateUtil.parseDateTime("2025-06-06 18:10:01"),
-//                    ListUtil.of("其他文件夹/报告公告"), EmailTypeConst.REPORT_EMAIL_TYPES);
+//            // 尽可能往前找11分钟覆盖可能遗漏的邮件
+//            Date startTime = DateUtil.offsetMinute(task.getStartTime(), -11);
+//            // 确认单从 INBOX 默认文件夹获取邮件
+//            this.emailParseApiService.parseEmail(startTime, now,
+//                    null, ListUtil.of(EmailTypeConst.REPORT_LETTER_EMAIL_TYPE));
+//            task.setStatus(1);
 //        } catch (Exception e) {
-//            logger.error(ExceptionUtil.getMessage(e));
+//            task.setStatus(2);
+//            task.setErrMsg(ExceptionUtil.stacktraceToString(e));
+//            this.logger.error("任务{} 执行错误:{}", taskKey, ExceptionUtil.stacktraceToString(e));
+//        } finally {
+//            task.setEndTime(now);
+//            this.taskRecordService.updateStatus(task);
+//            if (this.logger.isInfoEnabled()) {
+//                this.logger.info("任务{} 执行完成,耗时:{}ms", taskKey, System.currentTimeMillis() - start);
+//            }
 //        }
+//    }
 //
+//    /**
+//     * 定时任务每小时的15分和45分执行一次
+//     */
+//    @Scheduled(cron = "0 15,45 * * * ?")
+//    public void report() {
+//        String taskKey = "mo_email_parser_report_task";
+//        TaskRecordDO task = this.taskRecordService.getTaskRecord(taskKey, 60 * 2 * 60);
+//        if (task == null) {
+//            return;
+//        }
+//        long start = System.currentTimeMillis();
+//        Date now = new Date();
 //        try {
-//            // 确认函从 INBOX 文件夹获取邮件
-//            this.emailParseApiService.parseEmail(
-//                    DateUtil.parseDateTime("2025-06-03 18:50:00"),
-//                    DateUtil.parseDateTime("2025-06-03 19:56:00"),
-//                    null, ListUtil.of(EmailTypeConst.REPORT_LETTER_EMAIL_TYPE));
+//            // 尽可能往前找60分钟覆盖可能遗漏的邮件
+//            Date startTime = DateUtil.offsetMinute(task.getStartTime(), -60);
+//            // 定期报告从 我的文件夹.报告公告 文件夹获取邮件
+//            this.emailParseApiService.parseEmail(startTime, now,
+//                    ListUtil.of("其他文件夹/报告公告"), EmailTypeConst.REPORT_EMAIL_TYPES);
+//            task.setStatus(1);
 //        } catch (Exception e) {
-//            logger.error(ExceptionUtil.getMessage(e));
+//            task.setStatus(2);
+//            task.setErrMsg(ExceptionUtil.stacktraceToString(e));
+//            this.logger.error("定期报告解析任务{} 执行错误:{}", taskKey, ExceptionUtil.stacktraceToString(e));
+//        } finally {
+//            task.setEndTime(now);
+//            this.taskRecordService.updateStatus(task);
+//            if (this.logger.isInfoEnabled()) {
+//                this.logger.info("定期报告解析任务{} 执行完成,耗时:{}ms", taskKey, System.currentTimeMillis() - start);
+//            }
 //        }
-    }
-
-    /**
-     * 定时任务每11分钟执行一次
-     */
-    @Scheduled(cron = "0 */11 * * * ?")
-    public void letter() {
-        String taskKey = "mo_email_parse_letter_task";
-        TaskRecordDO task = this.taskRecordService.getTaskRecord(taskKey, 11 * 2 * 60);
-        if (task == null) {
-            return;
-        }
-        long start = System.currentTimeMillis();
-        Date now = new Date();
-        try {
-            // 尽可能往前找11分钟覆盖可能遗漏的邮件
-            Date startTime = DateUtil.offsetMinute(task.getStartTime(), -11);
-            // 确认单从 INBOX 默认文件夹获取邮件
-            this.emailParseApiService.parseEmail(startTime, now,
-                    null, ListUtil.of(EmailTypeConst.REPORT_LETTER_EMAIL_TYPE));
-            task.setStatus(1);
-        } catch (Exception e) {
-            task.setStatus(2);
-            task.setErrMsg(ExceptionUtil.stacktraceToString(e));
-            this.logger.error("任务{} 执行错误:{}", taskKey, ExceptionUtil.stacktraceToString(e));
-        } finally {
-            task.setEndTime(now);
-            this.taskRecordService.updateStatus(task);
-            if (this.logger.isInfoEnabled()) {
-                this.logger.info("任务{} 执行完成,耗时:{}ms", taskKey, System.currentTimeMillis() - start);
-            }
-        }
-    }
-
-    /**
-     * 定时任务每小时的15分和45分执行一次
-     */
-    @Scheduled(cron = "0 15,45 * * * ?")
-    public void report() {
-        String taskKey = "mo_email_parser_report_task";
-        TaskRecordDO task = this.taskRecordService.getTaskRecord(taskKey, 60 * 2 * 60);
-        if (task == null) {
-            return;
-        }
-        long start = System.currentTimeMillis();
-        Date now = new Date();
-        try {
-            // 尽可能往前找60分钟覆盖可能遗漏的邮件
-            Date startTime = DateUtil.offsetMinute(task.getStartTime(), -60);
-            // 定期报告从 我的文件夹.报告公告 文件夹获取邮件
-            this.emailParseApiService.parseEmail(startTime, now,
-                    ListUtil.of("其他文件夹/报告公告"), EmailTypeConst.REPORT_EMAIL_TYPES);
-            task.setStatus(1);
-        } catch (Exception e) {
-            task.setStatus(2);
-            task.setErrMsg(ExceptionUtil.stacktraceToString(e));
-            this.logger.error("定期报告解析任务{} 执行错误:{}", taskKey, ExceptionUtil.stacktraceToString(e));
-        } finally {
-            task.setEndTime(now);
-            this.taskRecordService.updateStatus(task);
-            if (this.logger.isInfoEnabled()) {
-                this.logger.info("定期报告解析任务{} 执行完成,耗时:{}ms", taskKey, System.currentTimeMillis() - start);
-            }
-        }
-    }
-}
+//    }
+//}

+ 2 - 2
mo-daq/src/main/java/com/smppw/modaq/common/enums/ReportParserFileType.java

@@ -14,8 +14,8 @@ import java.util.Arrays;
 @Getter
 public enum ReportParserFileType {
     PDF(Constants.FILE_PDF),
-    WORD(Constants.FILE_DOCX),
-    IMG(Constants.FILE_PNG + "," + Constants.FILE_JPG),
+//    WORD(Constants.FILE_DOCX),
+//    IMG(Constants.FILE_PNG + "," + Constants.FILE_JPG),
 //    EXCEL("xlsx,xls"),
 //    PYTHON("python");
     AI("ai");

+ 19 - 19
mo-daq/src/main/java/com/smppw/modaq/common/enums/ReportType.java

@@ -4,30 +4,30 @@ import lombok.Getter;
 
 @Getter
 public enum ReportType {
-    // 最后识别的类型
-    OTHER(-2, "其他报告",
-            new String[]{"公告", "通知", "告知函", "意见征询函", "说明函", "简报",
-                    "清算报告", "邀请函", "观点", "预警", "投研报告", "公示", "回顾",
-                    "风险提示函", "说明", "合同变更", "生效函"}),
+//    // 最后识别的类型
+//    OTHER(-2, "其他报告",
+//            new String[]{"公告", "通知", "告知函", "意见征询函", "说明函", "简报",
+//                    "清算报告", "邀请函", "观点", "预警", "投研报告", "公示", "回顾",
+//                    "风险提示函", "说明", "合同变更", "生效函"}),
 
     LETTER(-1, "交易流水确认函",
             new String[]{"确认单", "确认函", "交易确认数据",
                     "赎回确认", "申购确认", "分红确认", "确认表", "交易确认", "确认"}),
 
-    /**
-     * 月报识别规则(单独的“月”字不绑定到月度报告中,防止影响其他报告)
-     */
-    MONTHLY(0, "月",
-            new String[]{"月度报告", "月报", "月度"}),
-
-    QUARTERLY(1, "季",
-            new String[]{"季度报告", "季报", "季度"}),
-
-    ANNUALLY(2, "年",
-            new String[]{"年度", "年报", "年度报告"}),
-
-    WEEKLY(3, "周",
-            new String[]{"周报", "周度报告", "周度", "周总结"}),
+//    /**
+//     * 月报识别规则(单独的“月”字不绑定到月度报告中,防止影响其他报告)
+//     */
+//    MONTHLY(0, "月",
+//            new String[]{"月度报告", "月报", "月度"}),
+//
+//    QUARTERLY(1, "季",
+//            new String[]{"季度报告", "季报", "季度"}),
+//
+//    ANNUALLY(2, "年",
+//            new String[]{"年度", "年报", "年度报告"}),
+//
+//    WEEKLY(3, "周",
+//            new String[]{"周报", "周度报告", "周度", "周总结"}),
     ;
 
     private final int type;

+ 134 - 135
mo-daq/src/main/java/com/smppw/modaq/domain/service/EmailParseService.java

@@ -8,7 +8,6 @@ import cn.hutool.core.io.FileUtil;
 import cn.hutool.core.map.MapUtil;
 import cn.hutool.core.util.IdUtil;
 import cn.hutool.core.util.StrUtil;
-import com.smppw.modaq.application.components.OCRReportParser;
 import com.smppw.modaq.application.components.ReportParseUtils;
 import com.smppw.modaq.application.components.report.parser.ReportParser;
 import com.smppw.modaq.application.components.report.parser.ReportParserFactory;
@@ -26,7 +25,6 @@ import com.smppw.modaq.common.enums.ReportType;
 import com.smppw.modaq.common.exception.NotSupportReportException;
 import com.smppw.modaq.common.exception.ReportParseException;
 import com.smppw.modaq.domain.dto.*;
-import com.smppw.modaq.domain.dto.report.OCRParseData;
 import com.smppw.modaq.domain.dto.report.ParseResult;
 import com.smppw.modaq.domain.dto.report.ReportData;
 import com.smppw.modaq.domain.dto.report.ReportParserParams;
@@ -93,8 +91,8 @@ public class EmailParseService {
     @Value("${email.file.path}")
     private String path;
 
-    @Value("${email.report.ocr-parser-url}")
-    private String ocrParserUrl;
+//    @Value("${email.report.ocr-parser-url}")
+//    private String ocrParserUrl;
 
     @Value("${email.read-write-seen:true}")
     private boolean readWriteSeen;
@@ -177,9 +175,9 @@ public class EmailParseService {
                 Integer type = EmailUtil.getEmailTypeBySubject(emailTitle + emailFile.getFilename());
                 // 特殊月报
                 if ((Objects.equals(EmailTypeConst.NAV_EMAIL_TYPE, type)
-                          || Objects.equals(EmailTypeConst.REPORT_OTHER_TYPE, type))
+                        || Objects.equals(EmailTypeConst.REPORT_OTHER_TYPE, type))
                         && (ReportParseUtils.containsAny(emailTitle, ReportParseUtils.MANAGER_KEYWORDS)
-                          || emailTitle.contains("定期报告"))) {
+                        || emailTitle.contains("定期报告"))) {
                     type = EmailTypeConst.REPORT_EMAIL_TYPE;
                 }
                 // 其他报告
@@ -519,16 +517,16 @@ public class EmailParseService {
             return new ParseResult<>(ReportParseStatus.NOT_A_REPORT, null, fileName);
         }
 
-        // docx转pdf
-        if (Objects.equals(ReportParserFileType.WORD, fileType)) {
-            try {
-                String outputFile = FileUtil.getParent(filepath, 1) + File.separator + FileUtil.mainName(fileName) + ".pdf";
-                PdfUtil.convertDocxToPdf(filepath, outputFile);
-                filepath = outputFile;
-            } catch (Exception e) {
-                log.warn("报告{} 转换为pdf失败:{}", fileName, ExceptionUtil.stacktraceToString(e));
-            }
-        }
+//        // docx转pdf
+//        if (Objects.equals(ReportParserFileType.WORD, fileType)) {
+//            try {
+//                String outputFile = FileUtil.getParent(filepath, 1) + File.separator + FileUtil.mainName(fileName) + ".pdf";
+//                PdfUtil.convertDocxToPdf(filepath, outputFile);
+//                filepath = outputFile;
+//            } catch (Exception e) {
+//                log.warn("报告{} 转换为pdf失败:{}", fileName, ExceptionUtil.stacktraceToString(e));
+//            }
+//        }
         // 首页和尾页转为png图片,首页用来识别基金名称和基金代码、尾页用来识别印章和联系人
         List<String> images = ListUtil.list(true);
         if (Objects.equals(ReportParserFileType.PDF, fileType)) {
@@ -542,22 +540,23 @@ public class EmailParseService {
             } catch (Exception e) {
                 log.warn("报告{} 生成图片失败:{}", fileName, ExceptionUtil.stacktraceToString(e));
             }
-        } else if (Objects.equals(ReportParserFileType.IMG, fileType)) {
-            try {
-                String outputFile = PdfUtil.compressAndSave(filepath);
-                images.add(outputFile);
-            } catch (IOException e) {
-                log.error("报告{} 图片压缩失败,{}", fileName, ExceptionUtil.stacktraceToString(e));
-            }
+//        } else if (Objects.equals(ReportParserFileType.IMG, fileType)) {
+//            try {
+//                String outputFile = PdfUtil.compressAndSave(filepath);
+//                images.add(outputFile);
+//            } catch (IOException e) {
+//                log.error("报告{} 图片压缩失败,{}", fileName, ExceptionUtil.stacktraceToString(e));
+//            }
         }
 
         // ocr识别月报是否管理人版或协会版
         ReportMonthlyType monthlyType = ReportMonthlyType.NO_NEED;
-        if (ReportType.MONTHLY == reportType) {
-            monthlyType = this.determineReportType(emailTitle, fileName, filepath, images);
-        }
-        boolean isAmac = reportType == ReportType.ANNUALLY || reportType == ReportType.QUARTERLY
-                || (reportType == ReportType.MONTHLY && ReportMonthlyType.AMAC == monthlyType);
+//        if (ReportType.MONTHLY == reportType) {
+//            monthlyType = this.determineReportType(emailTitle, fileName, filepath, images);
+//        }
+//        boolean isAmac = reportType == ReportType.ANNUALLY || reportType == ReportType.QUARTERLY
+//                || (reportType == ReportType.MONTHLY && ReportMonthlyType.AMAC == monthlyType);
+        boolean isAmac = false;
         // 不支持解析的格式文件
         boolean notSupportFile = false;
         // 解析报告
@@ -604,8 +603,8 @@ public class EmailParseService {
             if (log.isInfoEnabled()) {
                 log.info("报告{} 用ocr补充解析结果。补充前的结果是:\n{}", fileName, reportData);
             }
-            // ocr信息提取(印章、联系人、基金名称和产品代码)
-            this.ocrReportData(reportType, reportData, fileName, images);
+//            // ocr信息提取(印章、联系人、基金名称和产品代码)
+//            this.ocrReportData(reportType, reportData, fileName, images);
             // 设置月报类型
             if (reportData != null && reportData.getBaseInfo() != null) {
                 reportData.getBaseInfo().setMonthlyType(monthlyType.getType());
@@ -619,114 +618,114 @@ public class EmailParseService {
         return result;
     }
 
-    /**
-     * 判断月报类型(管理人版还是协会版)
-     *
-     * @param emailTitle 邮件主题
-     * @param fileName   报告名称
-     * @param filepath   报告路径
-     * @param images     报告的第一页和尾页图片地址(主要用于ocr提取关键信息)
-     */
-    public ReportMonthlyType determineReportType(String emailTitle, String fileName,
-                                                 String filepath, List<String> images) {
-        // 1. 优先根据文件名判断
-        if (ReportParseUtils.containsAny(fileName, AMAC_KEYWORDS)) {
-            return ReportMonthlyType.AMAC;
-        }
-        if (ReportParseUtils.containsAny(fileName, ReportParseUtils.MANAGER_KEYWORDS)) {
-            return ReportMonthlyType.MANAGER;
-        }
-//        if (StrUtil.isNotBlank(ReportParseUtils.matchFundCode(fileName))) {
+//    /**
+//     * 判断月报类型(管理人版还是协会版)
+//     *
+//     * @param emailTitle 邮件主题
+//     * @param fileName   报告名称
+//     * @param filepath   报告路径
+//     * @param images     报告的第一页和尾页图片地址(主要用于ocr提取关键信息)
+//     */
+//    public ReportMonthlyType determineReportType(String emailTitle, String fileName,
+//                                                 String filepath, List<String> images) {
+//        // 1. 优先根据文件名判断
+//        if (ReportParseUtils.containsAny(fileName, AMAC_KEYWORDS)) {
 //            return ReportMonthlyType.AMAC;
 //        }
-        // 2. 根据文件路径判断
-        List<String> pathSegments = StrUtil.split(filepath, File.separator);
-        for (String segment : pathSegments) {
-            boolean isExcluded = ReportParseUtils.containsAny(segment, EXCLUDE_PATH_KEYWORDS);
-            if (!isExcluded && ReportParseUtils.containsAny(segment, AMAC_KEYWORDS)) {
-                return ReportMonthlyType.AMAC;
-            }
-            if (!isExcluded && ReportParseUtils.containsAny(segment, ReportParseUtils.MANAGER_KEYWORDS)) {
-                return ReportMonthlyType.MANAGER;
-            }
-        }
-        // 3. 根据邮件主题判断
-        boolean isAmacEmail = ReportParseUtils.containsAny(emailTitle, AMAC_KEYWORDS)
-                && !emailTitle.contains("公司及协会版");
-        if (isAmacEmail) {
-            return ReportMonthlyType.AMAC;
-        }
-        if (ReportParseUtils.containsAny(emailTitle, ReportParseUtils.MANAGER_KEYWORDS)) {
-            return ReportMonthlyType.MANAGER;
-        }
-        // 4.ocr 提取“曲线”、“基金份额”等关键字,如果有曲线则是管理人,如果有估值日期则是协会
-        if (CollUtil.isNotEmpty(images)) {
-            try {
-                return new OCRReportParser().parseMonthlyType(fileName, this.ocrParserUrl, images.get(0));
-            } catch (Exception ignored) {
-                return ReportMonthlyType.FAILED;
-            }
-        }
-        return ReportMonthlyType.FAILED;
-    }
+//        if (ReportParseUtils.containsAny(fileName, ReportParseUtils.MANAGER_KEYWORDS)) {
+//            return ReportMonthlyType.MANAGER;
+//        }
+////        if (StrUtil.isNotBlank(ReportParseUtils.matchFundCode(fileName))) {
+////            return ReportMonthlyType.AMAC;
+////        }
+//        // 2. 根据文件路径判断
+//        List<String> pathSegments = StrUtil.split(filepath, File.separator);
+//        for (String segment : pathSegments) {
+//            boolean isExcluded = ReportParseUtils.containsAny(segment, EXCLUDE_PATH_KEYWORDS);
+//            if (!isExcluded && ReportParseUtils.containsAny(segment, AMAC_KEYWORDS)) {
+//                return ReportMonthlyType.AMAC;
+//            }
+//            if (!isExcluded && ReportParseUtils.containsAny(segment, ReportParseUtils.MANAGER_KEYWORDS)) {
+//                return ReportMonthlyType.MANAGER;
+//            }
+//        }
+//        // 3. 根据邮件主题判断
+//        boolean isAmacEmail = ReportParseUtils.containsAny(emailTitle, AMAC_KEYWORDS)
+//                && !emailTitle.contains("公司及协会版");
+//        if (isAmacEmail) {
+//            return ReportMonthlyType.AMAC;
+//        }
+//        if (ReportParseUtils.containsAny(emailTitle, ReportParseUtils.MANAGER_KEYWORDS)) {
+//            return ReportMonthlyType.MANAGER;
+//        }
+//        // 4.ocr 提取“曲线”、“基金份额”等关键字,如果有曲线则是管理人,如果有估值日期则是协会
+//        if (CollUtil.isNotEmpty(images)) {
+//            try {
+//                return new OCRReportParser().parseMonthlyType(fileName, this.ocrParserUrl, images.get(0));
+//            } catch (Exception ignored) {
+//                return ReportMonthlyType.FAILED;
+//            }
+//        }
+//        return ReportMonthlyType.FAILED;
+//    }
 
-    /**
-     * ocr 提取信息(包括首页的基金名称或报告日期,尾页的印章或联系人等信息)
-     *
-     * @param reportData 报告解析结果
-     * @param fileName   报告名称
-     * @param images     报告的收益和尾页png图片
-     */
-    private void ocrReportData(ReportType reportType,
-                               ReportData reportData,
-                               String fileName,
-                               List<String> images) {
-        if (reportData == null || CollUtil.isEmpty(images)) {
-            return;
-        }
-        OCRParseData parseRes = null;
-        // 报告才识别尾页的印章和联系人,确认单不识别尾页
-        if (ReportType.LETTER != reportType) {
-            try {
-                // 首页和尾页相等时只读首页
-                String imageUrl = images.size() == 1 ? images.get(0) : images.get(1);
-                parseRes = new OCRReportParser().parse(fileName, this.ocrParserUrl, imageUrl);
-            } catch (Exception e) {
-                log.error("报告{} OCR识别印章和联系人出错:{}", fileName, e.getMessage());
-            }
-            // ocr识别尾页是否包含印章和联系人信息
-            if (parseRes != null) {
-                if (reportData.getBaseInfo() != null) {
-                    reportData.getBaseInfo().setWithSeals(parseRes.getWithSeals());
-                    reportData.getBaseInfo().setWithContacts(parseRes.getWithContacts());
-                    if (fileName.contains("用印") && !Objects.equals(true, reportData.getBaseInfo().getWithSeals())) {
-                        reportData.getBaseInfo().setWithSeals(true);
-                    }
-                }
-            }
-        }
-        // 首页和尾页不相等时解析首页的数据
-        if (images.size() != 1) {
-            try {
-                parseRes = new OCRReportParser().parse(fileName, this.ocrParserUrl, images.get(0));
-            } catch (Exception e) {
-                log.error("报告{} OCR识别首页基金名称和报告日期出错:{}", fileName, e.getMessage());
-            }
-        }
-        // 用首页识别基金名称、产品代码和基金管理人
-        if (reportData.getFundInfo() != null && parseRes != null) {
-            if (StrUtil.isBlank(reportData.getFundInfo().getFundName())) {
-                reportData.getFundInfo().setFundName(parseRes.getFundName());
-            }
-            if (StrUtil.isBlank(reportData.getFundInfo().getFundCode())) {
-                reportData.getFundInfo().setFundCode(parseRes.getFundCode());
-            }
-            if (StrUtil.isBlank(reportData.getFundInfo().getCompanyName())
-                    || !reportData.getFundInfo().getCompanyName().contains("有限公司")) {
-                reportData.getFundInfo().setCompanyName(parseRes.getCompanyName());
-            }
-        }
-    }
+//    /**
+//     * ocr 提取信息(包括首页的基金名称或报告日期,尾页的印章或联系人等信息)
+//     *
+//     * @param reportData 报告解析结果
+//     * @param fileName   报告名称
+//     * @param images     报告的收益和尾页png图片
+//     */
+//    private void ocrReportData(ReportType reportType,
+//                               ReportData reportData,
+//                               String fileName,
+//                               List<String> images) {
+//        if (reportData == null || CollUtil.isEmpty(images)) {
+//            return;
+//        }
+//        OCRParseData parseRes = null;
+//        // 报告才识别尾页的印章和联系人,确认单不识别尾页
+//        if (ReportType.LETTER != reportType) {
+//            try {
+//                // 首页和尾页相等时只读首页
+//                String imageUrl = images.size() == 1 ? images.get(0) : images.get(1);
+//                parseRes = new OCRReportParser().parse(fileName, this.ocrParserUrl, imageUrl);
+//            } catch (Exception e) {
+//                log.error("报告{} OCR识别印章和联系人出错:{}", fileName, e.getMessage());
+//            }
+//            // ocr识别尾页是否包含印章和联系人信息
+//            if (parseRes != null) {
+//                if (reportData.getBaseInfo() != null) {
+//                    reportData.getBaseInfo().setWithSeals(parseRes.getWithSeals());
+//                    reportData.getBaseInfo().setWithContacts(parseRes.getWithContacts());
+//                    if (fileName.contains("用印") && !Objects.equals(true, reportData.getBaseInfo().getWithSeals())) {
+//                        reportData.getBaseInfo().setWithSeals(true);
+//                    }
+//                }
+//            }
+//        }
+//        // 首页和尾页不相等时解析首页的数据
+//        if (images.size() != 1) {
+//            try {
+//                parseRes = new OCRReportParser().parse(fileName, this.ocrParserUrl, images.get(0));
+//            } catch (Exception e) {
+//                log.error("报告{} OCR识别首页基金名称和报告日期出错:{}", fileName, e.getMessage());
+//            }
+//        }
+//        // 用首页识别基金名称、产品代码和基金管理人
+//        if (reportData.getFundInfo() != null && parseRes != null) {
+//            if (StrUtil.isBlank(reportData.getFundInfo().getFundName())) {
+//                reportData.getFundInfo().setFundName(parseRes.getFundName());
+//            }
+//            if (StrUtil.isBlank(reportData.getFundInfo().getFundCode())) {
+//                reportData.getFundInfo().setFundCode(parseRes.getFundCode());
+//            }
+//            if (StrUtil.isBlank(reportData.getFundInfo().getCompanyName())
+//                    || !reportData.getFundInfo().getCompanyName().contains("有限公司")) {
+//                reportData.getFundInfo().setCompanyName(parseRes.getCompanyName());
+//            }
+//        }
+//    }
 
     /**
      * 保存报告解析结果

+ 14 - 14
mo-daq/src/main/java/com/smppw/modaq/infrastructure/util/PdfUtil.java

@@ -6,9 +6,9 @@ import org.apache.pdfbox.Loader;
 import org.apache.pdfbox.io.RandomAccessReadBufferedFile;
 import org.apache.pdfbox.pdmodel.PDDocument;
 import org.apache.pdfbox.rendering.PDFRenderer;
-import org.docx4j.Docx4J;
-import org.docx4j.openpackaging.packages.OpcPackage;
-import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
+//import org.docx4j.Docx4J;
+//import org.docx4j.openpackaging.packages.OpcPackage;
+//import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
 
 import javax.imageio.ImageIO;
 import java.awt.*;
@@ -47,17 +47,17 @@ public class PdfUtil {
         }
     }
 
-    public static void convertDocxToPdf(String input, String output) throws Exception {
-        validateDocx(input);
-        try (OutputStream os = new FileOutputStream(output)) {
-            OpcPackage opc = OpcPackage.load(new File(input));
-            if (opc instanceof WordprocessingMLPackage) {
-                Docx4J.toPDF((WordprocessingMLPackage) opc, os);
-            } else {
-                throw new Exception("不是WordprocessingML文档");
-            }
-        }
-    }
+//    public static void convertDocxToPdf(String input, String output) throws Exception {
+//        validateDocx(input);
+//        try (OutputStream os = new FileOutputStream(output)) {
+//            OpcPackage opc = OpcPackage.load(new File(input));
+//            if (opc instanceof WordprocessingMLPackage) {
+//                Docx4J.toPDF((WordprocessingMLPackage) opc, os);
+//            } else {
+//                throw new Exception("不是WordprocessingML文档");
+//            }
+//        }
+//    }
 
     /**
      * 将 PDF 的首页和尾页转换为 PNG 图片

+ 5 - 5
mo-daq/src/main/resources/application.yml

@@ -50,10 +50,10 @@ spring:
 email:
   file:
     path: /home/wwwroot/mo_report_file
-  report:
-    # ai解析远程地址
-    ai-parser-url: http://localhost:8088/upload-filepath
-    # ocr文字识别接口地址
-    ocr-parser-url: http://localhost:8088/parse-img
+#  report:
+#    # ai解析远程地址
+#    ai-parser-url: http://localhost:8088/upload-filepath
+#    # ocr文字识别接口地址
+#    ocr-parser-url: http://localhost:8088/parse-img
   # 读写 seen 标记
   read-write-seen: false