wangzaijun 7 달 전
부모
커밋
9f1691dc0d
52개의 변경된 파일1793개의 추가작업 그리고 302개의 파일을 삭제
  1. 11 2
      service-base/src/main/java/com/simuwang/base/common/conts/ApplicationRuleFileConst.java
  2. 25 0
      service-base/src/main/java/com/simuwang/base/common/conts/EmailDataDirectionConst.java
  3. 0 2
      service-base/src/main/java/com/simuwang/base/common/util/EmailUtil.java
  4. 102 2
      service-base/src/main/java/com/simuwang/base/common/util/ExcelUtil.java
  5. 35 0
      service-base/src/main/java/com/simuwang/base/common/util/NavDataUtil.java
  6. 1 1
      service-base/src/main/java/com/simuwang/base/mapper/EmailFundAssetMapper.java
  7. 1 1
      service-base/src/main/java/com/simuwang/base/mapper/EmailFundNavMapper.java
  8. 8 0
      service-base/src/main/java/com/simuwang/base/mapper/EmailTemplateApplicationRuleMapper.java
  9. 5 0
      service-base/src/main/java/com/simuwang/base/mapper/EmailTemplateDataRuleMapper.java
  10. 14 0
      service-base/src/main/java/com/simuwang/base/mapper/EmailTemplateInfoMapper.java
  11. 12 1
      service-base/src/main/java/com/simuwang/base/mapper/EmailTemplateMappingMapper.java
  12. 5 0
      service-base/src/main/java/com/simuwang/base/pojo/dos/EmailFundNavDO.java
  13. 11 1
      service-base/src/main/java/com/simuwang/base/pojo/dos/EmailTemplateDataRuleDO.java
  14. 29 2
      service-base/src/main/java/com/simuwang/base/pojo/dos/EmailTemplateInfoDO.java
  15. 18 0
      service-base/src/main/java/com/simuwang/base/pojo/dos/EmailTemplateMappingDO.java
  16. 5 0
      service-base/src/main/java/com/simuwang/base/pojo/dos/FundAliasDO.java
  17. 21 0
      service-base/src/main/java/com/simuwang/base/pojo/dto/EmailFileContentDTO.java
  18. 23 0
      service-base/src/main/java/com/simuwang/base/pojo/dto/EmailFundNavDTO.java
  19. 31 0
      service-base/src/main/java/com/simuwang/base/pojo/dto/TemplateDataRuleDTO.java
  20. 18 5
      service-base/src/main/java/com/simuwang/base/pojo/dto/TemplateDetailDTO.java
  21. 48 0
      service-base/src/main/java/com/simuwang/base/pojo/dto/query/EmailTemplateInfoPageQuery.java
  22. 72 0
      service-base/src/main/java/com/simuwang/base/pojo/dto/query/EmailTemplateSettingPageQuery.java
  23. 41 0
      service-base/src/main/java/com/simuwang/base/pojo/vo/EmailTemplateApplicationRuleVO.java
  24. 45 0
      service-base/src/main/java/com/simuwang/base/pojo/vo/EmailTemplateDataRuleVO.java
  25. 44 0
      service-base/src/main/java/com/simuwang/base/pojo/vo/EmailTemplateInfoVO.java
  26. 40 0
      service-base/src/main/java/com/simuwang/base/pojo/vo/EmailTemplateMappingVO.java
  27. 28 0
      service-base/src/main/java/com/simuwang/base/pojo/vo/SaveTemplateInfoVO.java
  28. 1 1
      service-base/src/main/resources/mapper/EmailFileInfoMapper.xml
  29. 6 1
      service-base/src/main/resources/mapper/EmailFundAssetMapper.xml
  30. 8 2
      service-base/src/main/resources/mapper/EmailFundNavMapper.xml
  31. 1 1
      service-base/src/main/resources/mapper/EmailParseInfoMapper.xml
  32. 38 0
      service-base/src/main/resources/mapper/EmailTemplateApplicationRuleMapper.xml
  33. 34 0
      service-base/src/main/resources/mapper/EmailTemplateDataRuleMapper.xml
  34. 47 0
      service-base/src/main/resources/mapper/EmailTemplateInfoMapper.xml
  35. 68 3
      service-base/src/main/resources/mapper/EmailTemplateMappingMapper.xml
  36. 6 0
      service-base/src/main/resources/mapper/FundAliasMapper.xml
  37. 2 19
      service-daq/src/main/java/com/simuwang/daq/service/AbstractEmailParser.java
  38. 1 0
      service-daq/src/main/java/com/simuwang/daq/service/EmailParseApiServiceImpl.java
  39. 30 11
      service-daq/src/main/java/com/simuwang/daq/service/EmailParseService.java
  40. 364 53
      service-daq/src/main/java/com/simuwang/daq/service/EmailTemplateService.java
  41. 2 2
      service-daq/src/main/java/com/simuwang/daq/service/FundService.java
  42. 29 182
      service-daq/src/main/java/com/simuwang/daq/service/NavEmailParser.java
  43. 0 2
      service-deploy/src/main/resources/application.yml
  44. 1 1
      service-deploy/src/test/java/com/simuwang/ApplicationTest.java
  45. 78 0
      service-manage/src/main/java/com/simuwang/manage/api/template/TemplateController.java
  46. 69 0
      service-manage/src/main/java/com/simuwang/manage/api/template/TemplateSettingController.java
  47. 23 0
      service-manage/src/main/java/com/simuwang/manage/service/EmailTemplateInfoService.java
  48. 20 0
      service-manage/src/main/java/com/simuwang/manage/service/EmailTemplateMappingService.java
  49. 1 1
      service-manage/src/main/java/com/simuwang/manage/service/impl/DeletionServiceImpl.java
  50. 195 0
      service-manage/src/main/java/com/simuwang/manage/service/impl/EmailTemplateInfoServiceImpl.java
  51. 73 0
      service-manage/src/main/java/com/simuwang/manage/service/impl/EmailTemplateMappingServiceImpl.java
  52. 3 6
      service-manage/src/main/java/com/simuwang/manage/service/impl/FundAliasServiceImpl.java

+ 11 - 2
service-base/src/main/java/com/simuwang/base/common/conts/ApplicationRuleFileConst.java

@@ -1,16 +1,25 @@
 package com.simuwang.base.common.conts;
 
 public class ApplicationRuleFileConst {
+
     /**
      * 邮件标题
      */
     public final static Integer EMAIL_TITLE_FILE = 1;
+
+    /**
+     * 邮件正文
+     */
+    public final static Integer EMAIL_CONTENT_FILE = 2;
+
     /**
      * 附件名称
      */
-    public final static Integer EMAIL_FILE_NAME_FILE = 2;
+    public final static Integer EMAIL_FILE_NAME_FILE = 3;
+
     /**
      * 表格内容
      */
-    public final static Integer EMAIL_EXCEL_CONTENT_FILE = 3;
+    public final static Integer EMAIL_EXCEL_CONTENT_FILE = 4;
+
 }

+ 25 - 0
service-base/src/main/java/com/simuwang/base/common/conts/EmailDataDirectionConst.java

@@ -0,0 +1,25 @@
+package com.simuwang.base.common.conts;
+
+public class EmailDataDirectionConst {
+
+    /**
+     * 数据行方向
+     */
+    public static final Integer ROW_DIRECTION_TYPE = 1;
+
+    /**
+     * 数据列方向
+     */
+    public static final Integer COLUMN_DIRECTION_TYPE = 2;
+
+    /**
+     * 其他方向
+     */
+    public static final Integer OTHER_DIRECTION_TYPE = 3;
+
+    /**
+     * 最大行数或最大列数
+     */
+    public static final Integer MAX_ROW_COLUMN = 2;
+
+}

+ 0 - 2
service-base/src/main/java/com/simuwang/base/common/util/EmailUtil.java

@@ -161,7 +161,6 @@ public class EmailUtil {
         EmailContentInfoDTO emailContentInfoDTO = new EmailContentInfoDTO();
         try {
             if ((part.getContentType().contains("text/html") || part.getContentType().contains("TEXT/HTML"))) {
-                if (partContent.toString().contains("<table")) {
                     emailContentInfoDTO.setEmailContent(partContent.toString());
                     String savePath = filePath + fileName;
                     File saveFile = new File(savePath);
@@ -174,7 +173,6 @@ public class EmailUtil {
                     }
                     emailContentInfoDTO.setFileName(fileName);
                     emailContentInfoDTO.setFilePath(savePath);
-                }
             }
         } catch (MessagingException e) {
             logger.info("邮件正文采集失败 -> 文件名:{}, 报错堆栈:{}", fileName, ExceptionUtil.stacktraceToString(e));

+ 102 - 2
service-base/src/main/java/com/simuwang/base/common/util/ExcelUtil.java

@@ -3,17 +3,26 @@ package com.simuwang.base.common.util;
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.exceptions.ExceptionUtil;
+import cn.hutool.core.lang.Pair;
 import cn.hutool.core.util.StrUtil;
 import com.simuwang.base.common.conts.DateConst;
+import com.simuwang.base.common.conts.EmailDataDirectionConst;
+import com.simuwang.base.pojo.dto.EmailContentInfoDTO;
+import org.apache.pdfbox.Loader;
+import org.apache.pdfbox.pdmodel.PDDocument;
 import org.apache.poi.hssf.usermodel.*;
 import org.apache.poi.ss.usermodel.*;
 import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.jsoup.Jsoup;
+import org.jsoup.nodes.Document;
 import org.jsoup.nodes.Element;
 import org.jsoup.select.Elements;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.io.*;
+import java.nio.file.Files;
+import java.nio.file.Paths;
 import java.text.NumberFormat;
 import java.util.Date;
 import java.util.List;
@@ -23,6 +32,11 @@ import org.apache.commons.compress.archivers.ArchiveEntry;
 import org.apache.commons.compress.archivers.ArchiveInputStream;
 import org.apache.commons.compress.archivers.ArchiveStreamFactory;
 import org.apache.commons.compress.utils.IOUtils;
+import technology.tabula.ObjectExtractor;
+import technology.tabula.Page;
+import technology.tabula.PageIterator;
+import technology.tabula.RectangularTextContainer;
+import technology.tabula.extractors.SpreadsheetExtractionAlgorithm;
 
 public class ExcelUtil {
 
@@ -43,6 +57,7 @@ public class ExcelUtil {
     public static boolean isHTML(String fileName) {
         return StrUtil.isNotBlank(fileName) && fileName.endsWith("html");
     }
+
     public static Sheet getSheet(File file, int sheetIndex) {
         if (file == null || !file.exists()) {
             return null;
@@ -326,12 +341,97 @@ public class ExcelUtil {
     }
 
     public static Sheet getFirstSheet(String filePath) {
+        if (StrUtil.isBlank(filePath)) {
+            return null;
+        }
         try {
             File file = new File(filePath);
             return ExcelUtil.getSheet(file, 0);
-        }catch (Exception e) {
-            logger.error("获取文件的sheet错误 -> 文件路径:{},堆栈信息为:{}",filePath, ExceptionUtil.stacktraceToString(e));
+        } catch (Exception e) {
+            logger.error("获取文件的sheet错误 -> 文件路径:{},堆栈信息为:{}", filePath, ExceptionUtil.stacktraceToString(e));
         }
         return null;
     }
+
+    public static String pdfConvertToExcel(String filePath, String excelFilePath) {
+        File savefile = new File(excelFilePath);
+        if (!savefile.exists()) {
+            if (!savefile.getParentFile().exists()) {
+                savefile.getParentFile().mkdirs();
+                savefile.getParentFile().setExecutable(true);
+            }
+        }
+        try (OutputStream outputStream = Files.newOutputStream(Paths.get(excelFilePath))) {
+            PDDocument document = Loader.loadPDF(new File(filePath));
+            PageIterator extract = new ObjectExtractor(document).extract();
+            Workbook workbook = new XSSFWorkbook();
+            Sheet sheet = workbook.createSheet("Sheet1");
+            while (extract.hasNext()) {
+                Page next = extract.next();
+                List<technology.tabula.Table> tableList = new SpreadsheetExtractionAlgorithm().extract(next);
+                for (technology.tabula.Table table : tableList) {
+                    List<List<RectangularTextContainer>> rows = table.getRows();
+                    for (int rowNum = 0; rowNum < rows.size(); rowNum++) {
+                        Row sheetRow = sheet.createRow(rowNum);
+                        List<RectangularTextContainer> textContainerList = rows.get(rowNum);
+                        for (int cellNum = 0; cellNum < textContainerList.size(); cellNum++) {
+                            Cell cell = sheetRow.createCell(cellNum);
+                            RectangularTextContainer textContainer = textContainerList.get(cellNum);
+                            if (textContainer != null) {
+                                cell.setCellValue(textContainer.getText());
+                            }
+                        }
+                    }
+                }
+            }
+            // 将Excel工作簿写入输出流
+            workbook.write(outputStream);
+        } catch (Exception e) {
+            logger.error("解析邮件pdf附件报错 -> 堆栈信息:{}", ExceptionUtil.stacktraceToString(e));
+            return null;
+        }
+        return excelFilePath;
+    }
+
+    public static String contentConvertToExcel(String emailContent, String excelFilePath) {
+        Elements rows;
+        try {
+            Document doc = Jsoup.parse(emailContent);
+            Element table = doc.select("table").first();
+            rows = table.select("tr");
+        } catch (Exception e) {
+            return null;
+        }
+        File saveFile = new File(excelFilePath);
+        if (!saveFile.exists()) {
+            if (!saveFile.getParentFile().exists()) {
+                saveFile.getParentFile().mkdirs();
+                saveFile.getParentFile().setExecutable(true);
+            }
+        }
+        try (OutputStream outputStream = new FileOutputStream(saveFile)) {
+            // 创建一个新的Excel工作簿
+            Workbook workbook = new XSSFWorkbook();
+            Sheet sheet = workbook.createSheet("Sheet1");
+            ExcelUtil.writeDataToSheet(sheet, rows);
+            // 将Excel工作簿写入输出流
+            workbook.write(outputStream);
+        } catch (Exception e) {
+            logger.error("邮件正文转换成excel报错 -> 堆栈信息:{}", ExceptionUtil.stacktraceToString(e));
+            return null;
+        }
+        return excelFilePath;
+    }
+
+    /**
+     * 通过表头所在位置判断是行数据还是列数据
+     *
+     * @param fieldPositionMap excel中表头所在的位置
+     * @return 行方向-1,,列方向-2
+     */
+    public static Integer detectDataDirection(Map<String, Pair<Integer, Integer>> fieldPositionMap) {
+        long count = fieldPositionMap.values().stream().map(Pair::getValue).distinct().count();
+        return count == 1 ? EmailDataDirectionConst.COLUMN_DIRECTION_TYPE : EmailDataDirectionConst.ROW_DIRECTION_TYPE;
+    }
+
 }

+ 35 - 0
service-base/src/main/java/com/simuwang/base/common/util/NavDataUtil.java

@@ -0,0 +1,35 @@
+package com.simuwang.base.common.util;
+
+import cn.hutool.core.util.StrUtil;
+import com.simuwang.base.pojo.dto.EmailFundNavDTO;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NavDataUtil {
+
+    private static final Logger log = LoggerFactory.getLogger(NavDataUtil.class);
+
+    public static boolean navDataFormatCheck(EmailFundNavDTO fundNavDTO) {
+        // 净值日期格式校验
+        boolean isvalidDate = StringUtil.isValidDate(fundNavDTO.getPriceDate());
+        if (!isvalidDate) {
+            log.warn("净值日期格式不正确 -> 解析到的数据:{}", fundNavDTO);
+            return false;
+        }
+        if(StrUtil.isBlank(fundNavDTO.getFundName()) && StrUtil.isBlank(fundNavDTO.getRegisterNumber())){
+            log.warn("备案编码和基金名称都为空-> 解析到的数据:{}", fundNavDTO);
+            return false;
+        }
+        // 单位净值,累计单位净值,资产净值,资产份额数字格式校验
+        boolean isvalidNumericFormat = (StrUtil.isBlank(fundNavDTO.getNav()) || StringUtil.isNumeric(fundNavDTO.getNav()))
+                && (StrUtil.isBlank(fundNavDTO.getCumulativeNavWithdrawal()) || StringUtil.isNumeric(fundNavDTO.getCumulativeNavWithdrawal()))
+                && (StrUtil.isBlank(fundNavDTO.getAssetNet()) || StringUtil.isNumeric(fundNavDTO.getAssetNet()))
+                && (StrUtil.isBlank(fundNavDTO.getAssetShare()) || StringUtil.isNumeric(fundNavDTO.getAssetShare()));
+        if (!isvalidNumericFormat) {
+            log.warn("单位净值或累计净值或资产净值或资产份额格式不正确 -> 解析到的数据:{}", fundNavDTO);
+            return false;
+        }
+        log.info("数据格式验证通过 -> {}", fundNavDTO);
+        return true;
+    }
+}

+ 1 - 1
service-base/src/main/java/com/simuwang/base/mapper/EmailFundAssetMapper.java

@@ -17,7 +17,7 @@ public interface EmailFundAssetMapper {
 
     long countAssetDetail(ParseDetailPageQuery parseDetailPageQuery);
 
-    Integer countNoStoreAsset(String sourceFundName);
+    Integer countNoStoreAsset(@Param("fundName") String sourceFundName,@Param("registerNumber")String registerNumber);
 
     void deleteByFileId(@Param("fileId") Integer fileId);
 

+ 1 - 1
service-base/src/main/java/com/simuwang/base/mapper/EmailFundNavMapper.java

@@ -18,7 +18,7 @@ public interface EmailFundNavMapper {
 
     long countNavDetail(ParseDetailPageQuery parseDetailPageQuery);
 
-    Integer countNoStoreNav(@Param("fundName") String sourceFundName);
+    Integer countNoStoreNav(@Param("fundName") String sourceFundName,@Param("registerNumber") String registerNumber);
 
     List<Integer> selectFileIdByFundName(@Param("fundName") String sourceFundName);
 

+ 8 - 0
service-base/src/main/java/com/simuwang/base/mapper/EmailTemplateApplicationRuleMapper.java

@@ -10,4 +10,12 @@ import java.util.List;
 public interface EmailTemplateApplicationRuleMapper {
 
     List<EmailTemplateApplicationRuleDO> queryByTemplateId(@Param("templateIdList") List<Integer> templateIdList);
+
+    void batchInsert(@Param("itemDoList") List<EmailTemplateApplicationRuleDO> templateApplicationRuleDOList);
+
+    void batchUpdate(@Param("itemDoList") List<EmailTemplateApplicationRuleDO> editList);
+
+    void deleteByTemplateId(@Param("templateIdList")List<Integer> idList,@Param("userId") Integer userId);
+
+    void deleteByIdList(@Param("idList") List<Integer> idList,@Param("userId") Integer userId);
 }

+ 5 - 0
service-base/src/main/java/com/simuwang/base/mapper/EmailTemplateDataRuleMapper.java

@@ -11,4 +11,9 @@ public interface EmailTemplateDataRuleMapper {
 
     List<EmailTemplateDataRuleDO> queryByTemplateId(@Param("templateIdList") List<Integer> templateIdList);
 
+    void batchInsert(@Param("itemDoList") List<EmailTemplateDataRuleDO> emailTemplateDataRuleDOList);
+
+    void batchUpdate(@Param("itemDoList")List<EmailTemplateDataRuleDO> editList);
+
+    void deleteByTemplateId(@Param("templateIdList")List<Integer> idList,@Param("userId") Integer userId);
 }

+ 14 - 0
service-base/src/main/java/com/simuwang/base/mapper/EmailTemplateInfoMapper.java

@@ -1,8 +1,22 @@
 package com.simuwang.base.mapper;
 
+import com.simuwang.base.pojo.dos.EmailTemplateInfoDO;
+import com.simuwang.base.pojo.dto.query.EmailTemplateInfoPageQuery;
 import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
 
 @Mapper
 public interface EmailTemplateInfoMapper {
 
+    List<EmailTemplateInfoDO> searchTemplateList(EmailTemplateInfoPageQuery emailTemplateInfoPageQuery);
+
+    long countTemplateList(EmailTemplateInfoPageQuery emailTemplateInfoPageQuery);
+
+    void deleteTemplateList(@Param("idList") List<Integer> idList,@Param("userId")Integer userId);
+
+    Integer saveTemplateInfo(EmailTemplateInfoDO emailDeletionInfoDO);
+
+    void updateTemplateInfo(EmailTemplateInfoDO emailDeletionInfoDO);
 }

+ 12 - 1
service-base/src/main/java/com/simuwang/base/mapper/EmailTemplateMappingMapper.java

@@ -1,6 +1,8 @@
 package com.simuwang.base.mapper;
 
 import com.simuwang.base.pojo.dos.EmailTemplateInfoDO;
+import com.simuwang.base.pojo.dos.EmailTemplateMappingDO;
+import com.simuwang.base.pojo.dto.query.EmailTemplateSettingPageQuery;
 import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Param;
 
@@ -9,6 +11,15 @@ import java.util.List;
 @Mapper
 public interface EmailTemplateMappingMapper {
 
-    List<EmailTemplateInfoDO> queryByEmail(@Param("email") String email);
+    List<EmailTemplateInfoDO> queryByEmail(@Param("email") String email, @Param("type") Integer type);
 
+    List<EmailTemplateMappingDO> searchTemplateSettingList(EmailTemplateSettingPageQuery emailTemplateSettingPageQuery);
+
+    long countTemplateSettingList(EmailTemplateSettingPageQuery emailTemplateSettingPageQuery);
+
+    void deleteTemplateSetting(@Param("idList") List<Integer> idList, @Param("userId") Integer userId);
+
+    void updateEmailTemplateMappingDO(EmailTemplateMappingDO emailTemplateMappingDO);
+
+    void saveEmailTemplateMappingDO(EmailTemplateMappingDO emailTemplateMappingDO);
 }

+ 5 - 0
service-base/src/main/java/com/simuwang/base/pojo/dos/EmailFundNavDO.java

@@ -65,6 +65,11 @@ public class EmailFundNavDO {
     @TableField(value = "exception_status")
     private Integer exceptionStatus;
     /**
+     * 模板id(0-通用模板)
+     */
+    @TableField(value = "template_id")
+    private Integer templateId;
+    /**
      * 记录的有效性;1-有效;0-无效;
      */
     @TableField(value = "isvalid")

+ 11 - 1
service-base/src/main/java/com/simuwang/base/pojo/dos/EmailTemplateDataRuleDO.java

@@ -26,6 +26,11 @@ public class EmailTemplateDataRuleDO {
     @TableId(value = "field_name")
     private Integer fieldName;
     /**
+     * 提取位置:1-正文,2-正文表格
+     */
+    @TableId(value = "position")
+    private Integer position;
+    /**
      * 表格行
      */
     @TableId(value = "row")
@@ -39,7 +44,12 @@ public class EmailTemplateDataRuleDO {
      * 提取规则
      */
     @TableId(value = "field_rule")
-    private Integer fieldRule;
+    private String fieldRule;
+    /**
+     * 单位转换
+     */
+    @TableId(value = "unit_convert")
+    private Integer unitConvert;
     /**
      * 是否有效:0-无效,1-有效
      */

+ 29 - 2
service-base/src/main/java/com/simuwang/base/pojo/dos/EmailTemplateInfoDO.java

@@ -1,8 +1,10 @@
 package com.simuwang.base.pojo.dos;
 
+import com.baomidou.mybatisplus.annotation.IdType;
 import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
+import com.simuwang.base.pojo.vo.EmailTemplateInfoVO;
 import lombok.Data;
 
 import java.util.Date;
@@ -13,7 +15,7 @@ public class EmailTemplateInfoDO {
     /**
      * 主键Id
      */
-    @TableId(value = "id")
+    @TableId(value = "id",type = IdType.AUTO)
     private Integer id;
     /**
      * 模板名称
@@ -21,11 +23,26 @@ public class EmailTemplateInfoDO {
     @TableId(value = "name")
     private String name;
     /**
-     * 模版方向:1-行,2-列
+     * 模板类型:1-excel类型,2-正文类型
+     */
+    @TableId(value = "type")
+    private Integer type;
+    /**
+     * 模版方向:1-行,2-列,-1其他
      */
     @TableId(value = "direction")
     private Integer direction;
     /**
+     * 循环开始数字或者字母
+     */
+    @TableId(value = "start_index")
+    private String startIndex;
+    /**
+     * 循环结束数字或者字母
+     */
+    @TableId(value = "end_index")
+    private String endIndex;
+    /**
      * 模版备注
      */
     @TableId(value = "description")
@@ -60,4 +77,14 @@ public class EmailTemplateInfoDO {
      */
     @TableField(value = "updatetime")
     private Date updateTime;
+
+    public EmailTemplateInfoVO toVO() {
+        EmailTemplateInfoVO vo = new EmailTemplateInfoVO();
+        vo.setName(this.name);
+        vo.setId(this.id);
+        vo.setStatus(this.status);
+        vo.setDescription(this.description);
+        vo.setType(this.type);
+        return vo;
+    }
 }

+ 18 - 0
service-base/src/main/java/com/simuwang/base/pojo/dos/EmailTemplateMappingDO.java

@@ -3,6 +3,7 @@ package com.simuwang.base.pojo.dos;
 import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
+import com.simuwang.base.pojo.vo.EmailTemplateMappingVO;
 import lombok.Data;
 
 import java.util.Date;
@@ -70,4 +71,21 @@ public class EmailTemplateMappingDO {
      */
     @TableField(value = "updatetime")
     private Date updateTime;
+
+    /**
+     * 模版名称
+     */
+    private String templateName;
+
+    public EmailTemplateMappingVO toVO() {
+        EmailTemplateMappingVO vo = new EmailTemplateMappingVO();
+        vo.setTemplateId(this.templateId);
+        vo.setId(this.id);
+        vo.setCompanyName(this.companyName);
+        vo.setTitle(this.title);
+        vo.setTemplateName(this.templateName);
+        vo.setStatus(this.status);
+        vo.setEmail(this.email);
+        return vo;
+    }
 }

+ 5 - 0
service-base/src/main/java/com/simuwang/base/pojo/dos/FundAliasDO.java

@@ -35,6 +35,10 @@ public class FundAliasDO {
      */
     private String targetRegisterNumber;
     /**
+     * 匹配的源备案编码
+     */
+    private String companyName;
+    /**
      * 记录的有效性;1-有效;0-无效;
      */
     private Integer isvalid;
@@ -63,6 +67,7 @@ public class FundAliasDO {
         fundAliasVO.setTargetFundId(this.targetFundId);
         fundAliasVO.setTargetFundName(this.targetFundName);
         fundAliasVO.setTargetRegisterNumber(this.targetRegisterNumber);
+        fundAliasVO.setCompanyName(this.companyName);
         return fundAliasVO;
     }
 }

+ 21 - 0
service-base/src/main/java/com/simuwang/base/pojo/dto/EmailFileContentDTO.java

@@ -0,0 +1,21 @@
+package com.simuwang.base.pojo.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class EmailFileContentDTO {
+
+    /**
+     * 文件路径(excel路径)
+     */
+    private String filePath;
+
+    /**
+     * 邮件正文
+     */
+    private String content;
+}

+ 23 - 0
service-base/src/main/java/com/simuwang/base/pojo/dto/EmailFundNavDTO.java

@@ -3,6 +3,7 @@ package com.simuwang.base.pojo.dto;
 import lombok.Data;
 
 import java.util.List;
+import java.util.Objects;
 
 @Data
 public class EmailFundNavDTO {
@@ -39,6 +40,10 @@ public class EmailFundNavDTO {
      */
     private String assetNet;
     /**
+     * 模板id(0-通用模板)
+     */
+    private Integer templateId;
+    /**
      * 匹配上的基金id
      */
     private List<String> fundIdList;
@@ -46,4 +51,22 @@ public class EmailFundNavDTO {
      * 解析状态:1-成功,2-净值缺失,3-未匹配基金,4-净值<=0,5-资产净值<=0
      */
     private Integer parseStatus;
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        EmailFundNavDTO that = (EmailFundNavDTO) o;
+        return Objects.equals(fundName, that.fundName) && Objects.equals(registerNumber, that.registerNumber) && Objects.equals(priceDate, that.priceDate)
+                && Objects.equals(nav, that.nav) && Objects.equals(cumulativeNavWithdrawal, that.cumulativeNavWithdrawal) && Objects.equals(assetShare, that.assetShare) && Objects.equals(assetNet, that.assetNet);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(fundName, registerNumber, priceDate, nav, cumulativeNavWithdrawal, assetShare, assetNet);
+    }
 }

+ 31 - 0
service-base/src/main/java/com/simuwang/base/pojo/dto/TemplateDataRuleDTO.java

@@ -0,0 +1,31 @@
+package com.simuwang.base.pojo.dto;
+
+import lombok.Data;
+
+@Data
+public class TemplateDataRuleDTO {
+    /**
+     * 字段名称:1-备案编码,2-基金名称,3-净值日期,4-单位净值,5-累计净值,6-资产份额,7-资产净值
+     */
+    private Integer fieldName;
+    /**
+     * 提取位置:1-正文,2-正文表格
+     */
+    private Integer position;
+    /**
+     * 表格行
+     */
+    private Integer row;
+    /**
+     * 表格列
+     */
+    private String column;
+    /**
+     * 提取规则
+     */
+    private String fieldRule;
+    /**
+     * 单位转换
+     */
+    private Integer unitConvert;
+}

+ 18 - 5
service-base/src/main/java/com/simuwang/base/pojo/dto/TemplateDetailDTO.java

@@ -1,15 +1,14 @@
 package com.simuwang.base.pojo.dto;
 
-import cn.hutool.core.lang.Pair;
 import lombok.Data;
 
-import java.util.Map;
+import java.util.List;
 
 @Data
 public class TemplateDetailDTO {
 
     /**
-     * 模板idi
+     * 模板id
      */
     private Integer templateId;
     /**
@@ -18,7 +17,21 @@ public class TemplateDetailDTO {
     private Integer direction;
 
     /**
-     * 字段所在表格中的位置
+     * 模板类型:1-excel类型,2-正文类型
      */
-    private Map<String, Pair<Integer, Integer>> fieldPositionMap;
+    private Integer type;
+
+    /**
+     * 循环开始数字或者字母
+     */
+    private String startIndex;
+
+    /**
+     * 循环结束数字或者字母
+     */
+    private String endIndex;
+    /**
+     * 数据提取规则明细
+     */
+    private List<TemplateDataRuleDTO> dataRuleDetailList;
 }

+ 48 - 0
service-base/src/main/java/com/simuwang/base/pojo/dto/query/EmailTemplateInfoPageQuery.java

@@ -0,0 +1,48 @@
+package com.simuwang.base.pojo.dto.query;
+
+import com.simuwang.base.common.support.query.PageQuery;
+
+/**
+ * FileName: EmailTemplateInfoPageQuery
+ * Author:   chenjianhua
+ * Date:     2024/9/25 18:48
+ * Description: ${DESCRIPTION}
+ */
+public class EmailTemplateInfoPageQuery extends PageQuery {
+    /**
+     * 模版名称
+     */
+    private String name;
+    /**
+     * 模板类型:1-excel类型,2-正文类型
+     */
+    private Integer type;
+    /**
+     * 状态:0-关闭,1-开启
+     */
+    private Integer status;
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public Integer getType() {
+        return type;
+    }
+
+    public void setType(Integer type) {
+        this.type = type;
+    }
+
+    public Integer getStatus() {
+        return status;
+    }
+
+    public void setStatus(Integer status) {
+        this.status = status;
+    }
+}

+ 72 - 0
service-base/src/main/java/com/simuwang/base/pojo/dto/query/EmailTemplateSettingPageQuery.java

@@ -0,0 +1,72 @@
+package com.simuwang.base.pojo.dto.query;
+
+import com.simuwang.base.common.support.query.PageQuery;
+
+/**
+ * FileName: EmailTemplateSettingPageQuery
+ * Author:   chenjianhua
+ * Date:     2024/9/25 20:26
+ * Description: ${DESCRIPTION}
+ */
+public class EmailTemplateSettingPageQuery extends PageQuery {
+    /**
+     * 模版名称(email_template_info.name)
+     */
+    private String templateName;
+    /**
+     * 标题名称
+     */
+    private String title;
+    /**
+     * 来源邮箱地址
+     */
+    private String email;
+    /**
+     * 公司名称
+     */
+    private String companyName;
+    /**
+     * 状态:0-关闭,1-开启
+     */
+    private Integer status;
+
+    public String getTemplateName() {
+        return templateName;
+    }
+
+    public void setTemplateName(String templateName) {
+        this.templateName = templateName;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    public String getEmail() {
+        return email;
+    }
+
+    public void setEmail(String email) {
+        this.email = email;
+    }
+
+    public String getCompanyName() {
+        return companyName;
+    }
+
+    public void setCompanyName(String companyName) {
+        this.companyName = companyName;
+    }
+
+    public Integer getStatus() {
+        return status;
+    }
+
+    public void setStatus(Integer status) {
+        this.status = status;
+    }
+}

+ 41 - 0
service-base/src/main/java/com/simuwang/base/pojo/vo/EmailTemplateApplicationRuleVO.java

@@ -0,0 +1,41 @@
+package com.simuwang.base.pojo.vo;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.util.Date;
+
+@Data
+public class EmailTemplateApplicationRuleVO {
+    /**
+     * 主键Id
+     */
+    private Integer id;
+    /**
+     * 模版id(email_template_info.id)
+     */
+    private Integer templateId;
+    /**
+     * 字段类型:1-邮件标题,2-附件名称,3-表格内容
+     */
+    private Integer type;
+    /**
+     * 表格行
+     */
+    private Integer row;
+    /**
+     * 表格列
+     */
+    private String column;
+    /**
+     * 包含关键字(多个以英文逗号隔开)
+     */
+    private String containKeyword;
+    /**
+     * 不包含关键字(多个以英文逗号隔开)
+     */
+    private String notContainKeyword;
+
+}

+ 45 - 0
service-base/src/main/java/com/simuwang/base/pojo/vo/EmailTemplateDataRuleVO.java

@@ -0,0 +1,45 @@
+package com.simuwang.base.pojo.vo;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.util.Date;
+
+@Data
+public class EmailTemplateDataRuleVO {
+    /**
+     * 主键Id
+     */
+    private Integer id;
+    /**
+     * 模版id(email_template_info.id)
+     */
+    private Integer templateId;
+    /**
+     * 字段名称:1-备案编码,2-基金名称,3-净值日期,4-单位净值,5-累计净值,6-资产份额,7-资产净值
+     */
+    private Integer fieldName;
+    /**
+     * 提取位置:1-正文,2-正文表格
+     */
+    private Integer position;
+    /**
+     * 表格行
+     */
+    private Integer row;
+    /**
+     * 表格列
+     */
+    private String column;
+    /**
+     * 提取规则
+     */
+    private String fieldRule;
+    /**
+     * 单位转换
+     */
+    private Integer unitConvert;
+
+}

+ 44 - 0
service-base/src/main/java/com/simuwang/base/pojo/vo/EmailTemplateInfoVO.java

@@ -0,0 +1,44 @@
+package com.simuwang.base.pojo.vo;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.util.Date;
+
+@Data
+public class EmailTemplateInfoVO {
+    /**
+     * 主键Id
+     */
+    private Integer id;
+    /**
+     * 模板名称
+     */
+    private String name;
+    /**
+     * 模板类型:1-excel类型,2-正文类型
+     */
+    private Integer type;
+    /**
+     * 模版方向:1-行,2-列,-1其他
+     */
+    private Integer direction;
+    /**
+     * 循环开始数字或者字母
+     */
+    private String startIndex;
+    /**
+     * 循环结束数字或者字母
+     */
+    private String endIndex;
+    /**
+     * 模版备注
+     */
+    private String description;
+    /**
+     * 状态:0-关闭,1-开启
+     */
+    private Integer status;
+}

+ 40 - 0
service-base/src/main/java/com/simuwang/base/pojo/vo/EmailTemplateMappingVO.java

@@ -0,0 +1,40 @@
+package com.simuwang.base.pojo.vo;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.util.Date;
+
+@Data
+public class EmailTemplateMappingVO {
+    /**
+     * 主键Id
+     */
+    private Integer id;
+    /**
+     * 模版id(email_template_info.id)
+     */
+    private Integer templateId;
+    /**
+     * 模版名称(email_template_info.name)
+     */
+    private String templateName;
+    /**
+     * 标题名称
+     */
+    private String title;
+    /**
+     * 邮箱地址
+     */
+    private String email;
+    /**
+     * 公司名称
+     */
+    private String companyName;
+    /**
+     * 状态:0-关闭,1-开启
+     */
+    private Integer status;
+}

+ 28 - 0
service-base/src/main/java/com/simuwang/base/pojo/vo/SaveTemplateInfoVO.java

@@ -0,0 +1,28 @@
+package com.simuwang.base.pojo.vo;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * FileName: SaveTemplateInfoVO
+ * Author:   chenjianhua
+ * Date:     2024/9/25 19:06
+ * Description: ${DESCRIPTION}
+ */
+@Data
+public class SaveTemplateInfoVO {
+    /**
+     * 模版基本信息
+     */
+    private EmailTemplateInfoVO emailTemplateInfoVO;
+    /**
+     * 适用规则信息
+     */
+    private List<EmailTemplateApplicationRuleVO> emailTemplateApplicationRuleVOList;
+    /**
+     * 字段匹配位置信息
+     */
+    private List<EmailTemplateDataRuleVO> emailTemplateDataRuleVOList;
+
+}

+ 1 - 1
service-base/src/main/resources/mapper/EmailFileInfoMapper.xml

@@ -32,7 +32,7 @@
             parameterType="java.lang.Integer">
         select id ,email_id, file_name, file_path,
                isvalid, creatorid, createtime, updaterid, updatetime
-        from PPW_EMAIL.email_file_info where email_id=#{emailId} and isvalid=1 and file_name not like '%html'
+        from PPW_EMAIL.email_file_info where email_id=#{emailId} and isvalid=1
     </select>
 
     <select id="queryByEmailId" resultMap="BaseResultMap">

+ 6 - 1
service-base/src/main/resources/mapper/EmailFundAssetMapper.xml

@@ -164,7 +164,12 @@
         select count(id)
         from PPW_EMAIL.email_fund_asset
         where isvalid =1 and exception_status=3
-          and fund_name=#{fundName}
+        <if test="fundName != null and fundName !=''">
+            and fund_name=#{fundName}
+        </if>
+        <if test="registerNumber != null and registerNumber !=''">
+            and register_number=#{registerNumber}
+        </if>
     </select>
     <select id="selectNotMappingAsset" resultMap="BaseResultMap"
             parameterType="java.lang.String">

+ 8 - 2
service-base/src/main/resources/mapper/EmailFundNavMapper.xml

@@ -12,6 +12,7 @@
         <result column="cumulative_nav_withdrawal" property="cumulativeNavWithdrawal"/>
         <result column="is_stored" property="isStored"/>
         <result column="exception_status" property="exceptionStatus"/>
+        <result column="template_id" property="templateId"/>
         <result column="isvalid" property="isvalid"/>
         <result column="creatorid" property="creatorId"/>
         <result column="createtime" property="createTime"/>
@@ -24,12 +25,12 @@
 
     <insert id="batchInsert" parameterType="com.simuwang.base.pojo.dos.EmailFundNavDO">
         insert into PPW_EMAIL.email_fund_nav(file_id, fund_id, fund_name,register_number,price_date,
-                                              nav,cumulative_nav_withdrawal,is_stored,exception_status,
+                                              nav,cumulative_nav_withdrawal,is_stored,exception_status,template_id,
                                               isvalid, creatorid, createtime, updaterid, updatetime)
         values
         <foreach collection="itemDoList" item="itemDo" index="index" separator=",">
             (#{itemDo.fileId},#{itemDo.fundId},#{itemDo.fundName},#{itemDo.registerNumber},#{itemDo.priceDate},
-             #{itemDo.nav},#{itemDo.cumulativeNavWithdrawal},#{itemDo.isStored},#{itemDo.exceptionStatus},
+             #{itemDo.nav},#{itemDo.cumulativeNavWithdrawal},#{itemDo.isStored},#{itemDo.exceptionStatus},#{itemDo.templateId},
             #{itemDo.isvalid}, #{itemDo.creatorId}, #{itemDo.createTime}, #{itemDo.updaterId}, #{itemDo.updateTime})
         </foreach>
     </insert>
@@ -166,7 +167,12 @@
         select count(nav.id)
         from PPW_EMAIL.email_fund_nav nav
         where nav.isvalid =1 and nav.exception_status=3
+        <if test="fundName != null and fundName != ''">
             and nav.fund_name=#{fundName}
+        </if>
+        <if test="registerNumber != null and registerNumber != ''">
+            and nav.register_number=#{registerNumber}
+        </if>
     </select>
     <select id="selectFileIdByFundName" resultType="java.lang.Integer" parameterType="java.lang.String">
         select distinct nav.file_id from PPW_EMAIL.email_fund_nav nav where nav.isvalid =1 and nav.exception_status=3

+ 1 - 1
service-base/src/main/resources/mapper/EmailParseInfoMapper.xml

@@ -114,7 +114,7 @@
     </select>
 
     <select id="queryById" resultMap="BaseResultMap">
-        select id, email, email_date, parse_date, email_title, email_type
+        select id, email, email_date, parse_date, email_title, email_type, sender_email
         from PPW_EMAIL.email_parse_info
         where isvalid = 1
           and id = #{id}

+ 38 - 0
service-base/src/main/resources/mapper/EmailTemplateApplicationRuleMapper.xml

@@ -15,6 +15,44 @@
         <result column="updaterid" property="updaterId"/>
         <result column="updatetime" property="updateTime"/>
     </resultMap>
+    <insert id="batchInsert">
+        insert into PPW_EMAIL.email_template_application_rule(template_id,type,row,column,contain_keyword,not_contain_keyword,isvalid,creatorid,createtime,updaterid,updatetime)
+        values
+        <foreach collection="itemDoList" item="itemDo" index="index" separator=",">
+            (#{itemDo.templateId},#{itemDo.type},#{itemDo.row},#{itemDo.column},#{itemDo.containKeyword},#{itemDo.notContainKeyword},
+            #{itemDo.isvalid}, #{itemDo.creatorId}, #{itemDo.createTime}, #{itemDo.updaterId}, #{itemDo.updateTime})
+        </foreach>
+    </insert>
+    <update id="batchUpdate">
+        <foreach collection="itemDoList" item="itemDo" index="index" open="" close="" separator=";">
+            update PPW_EMAIL.email_template_application_rule
+            <set>
+                template_id=#{itemDo.templateId},
+                type = #{itemDo.type},
+                row=#{itemDo.row},
+                column=#{itemDo.column},
+                contain_keyword=#{itemDo.containKeyword},
+                not_contain_keyword=#{itemDo.notContainKeyword},
+                updatetime=#{itemDo.updateTime},
+                updaterid=#{itemDo.updaterId}
+            </set>
+            where isvalid = 1 and id=#{itemDo.id}
+        </foreach>
+    </update>
+    <update id="deleteByTemplateId">
+        update PPW_EMAIL.email_template_application_rule set isvalid=0,updatetime=sysdate(),updaterid=#{userId}
+        and template_id in
+        <foreach collection="templateIdList" index="index" item="templateId" open="(" separator="," close=")">
+            #{templateId}
+        </foreach>
+    </update>
+    <delete id="deleteByIdList">
+        update PPW_EMAIL.email_template_application_rule set isvalid=0,updatetime=sysdate(),updaterid=#{userId}
+        where isvalid = 1 and id in
+        <foreach collection="idList" index="index" item="id" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </delete>
 
     <select id="queryByTemplateId" resultMap="BaseResultMap">
         select *

+ 34 - 0
service-base/src/main/resources/mapper/EmailTemplateDataRuleMapper.xml

@@ -5,15 +5,49 @@
         <id column="id" property="id"/>
         <result column="template_id" property="templateId"/>
         <result column="field_name" property="fieldName"/>
+        <result column="position" property="position"/>
         <result column="row" property="row"/>
         <result column="column" property="column"/>
         <result column="field_rule" property="fieldRule"/>
+        <result column="unit_convert" property="unitConvert"/>
         <result column="isvalid" property="isvalid"/>
         <result column="creatorid" property="creatorId"/>
         <result column="createtime" property="createTime"/>
         <result column="updaterid" property="updaterId"/>
         <result column="updatetime" property="updateTime"/>
     </resultMap>
+    <insert id="batchInsert">
+        insert into PPW_EMAIL.email_template_data_rule(template_id,field_name,position,row,column,field_rule,unit_convert,isvalid,creatorid,createtime,updaterid,updatetime)
+        values
+        <foreach collection="itemDoList" item="itemDo" index="index" separator=",">
+            (#{itemDo.templateId},#{itemDo.fieldName},#{itemDo.position},#{itemDo.row},#{itemDo.column},#{itemDo.fieldRule},#{itemDo.unitConvert},
+            #{itemDo.isvalid}, #{itemDo.creatorId}, #{itemDo.createTime}, #{itemDo.updaterId}, #{itemDo.updateTime})
+        </foreach>
+    </insert>
+    <update id="batchUpdate">
+        <foreach collection="itemDoList" item="itemDo" index="index" open="" close="" separator=";">
+            update PPW_EMAIL.email_template_data_rule
+            <set>
+                template_id=#{itemDo.templateId},
+                field_name = #{itemDo.fieldName},
+                position=#{itemDo.position},
+                row=#{itemDo.row},
+                column=#{itemDo.column},
+                field_rule=#{itemDo.fieldRule},
+                unit_convert=#{itemDo.unitConvert},
+                updatetime=#{itemDo.updateTime},
+                updaterid=#{itemDo.updaterId}
+            </set>
+            where isvalid = 1 and id=#{itemDo.id}
+        </foreach>
+    </update>
+    <update id="deleteByTemplateId">
+        update PPW_EMAIL.email_template_data_rule set isvalid=0,updatetime=sysdate(),updaterid=#{userId}
+        where isvalid=1 and template_id in
+        <foreach collection="templateIdList" index="index" item="templateId" open="(" separator="," close=")">
+            #{templateId}
+        </foreach>
+    </update>
 
     <select id="queryByTemplateId" resultMap="BaseResultMap">
         select *

+ 47 - 0
service-base/src/main/resources/mapper/EmailTemplateInfoMapper.xml

@@ -4,7 +4,10 @@
     <resultMap id="BaseResultMap" type="com.simuwang.base.pojo.dos.EmailTemplateInfoDO">
         <id column="id" property="id"/>
         <result column="name" property="name"/>
+        <result column="type" property="type"/>
         <result column="direction" property="direction"/>
+        <result column="start_index" property="startIndex"/>
+        <result column="end_index" property="endIndex"/>
         <result column="description" property="description"/>
         <result column="status" property="status"/>
         <result column="isvalid" property="isvalid"/>
@@ -13,6 +16,50 @@
         <result column="updaterid" property="updaterId"/>
         <result column="updatetime" property="updateTime"/>
     </resultMap>
+    <insert id="saveTemplateInfo"  useGeneratedKeys="true" keyProperty="id">
+        insert into PPW_EMAIL.email_template_info(name,type,direction,start_index,end_index,description,status,isvalid,creatorid,createtime,updaterid,updatetime)
+        values
+            (#{name},#{type},#{direction},#{startIndex},#{endIndex},#{description},#{status},#{isvalid},#{creatorId},#{createTime},#{updaterId},#{updateTime})
+    </insert>
+    <update id="deleteTemplateList">
+        update PPW_EMAIL.email_template_info set isvalid=0,updatetime=sysdate(),updaterid=#{userId} where isvalid=1
+        and id in
+        <foreach item="id" collection="idList" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </update>
+    <update id="updateTemplateInfo">
+        update PPW_EMAIL.email_template_info set name=#{name},type=#{type},description=#{description},status=#{status},updatetime=#{updateTime},updaterid=#{updaterId}
+        where id=#{id} and isvalid=1
+    </update>
+    <select id="searchTemplateList" resultMap="BaseResultMap">
+        select id,name,type,direction,start_index,end_index,description,status,isvalid,creatorid,createtime,updaterid,updatetime
+        from PPW_EMAIL.email_template_info where isvalid=1
+        <if test="name != null and name !=''">
+            and name =#{name}
+        </if>
+        <if test="type != null">
+            and type =#{type}
+        </if>
+        <if test="status != null">
+            and status =#{status}
+        </if>
+        order by updatetime desc
+        limit #{offset},#{pageSize}
+    </select>
+    <select id="countTemplateList" resultType="java.lang.Long">
+        select count(1)
+        from PPW_EMAIL.email_template_info where isvalid=1
+        <if test="name != null and name !=''">
+            and name =#{name}
+        </if>
+        <if test="type != null">
+            and type =#{type}
+        </if>
+        <if test="status != null">
+            and status =#{status}
+        </if>
+    </select>
 
 
 </mapper>

+ 68 - 3
service-base/src/main/resources/mapper/EmailTemplateMappingMapper.xml

@@ -7,23 +7,88 @@
         <result column="title" property="title"/>
         <result column="email" property="email"/>
         <result column="company_name" property="companyName"/>
-        <result column="description" property="description"/>
         <result column="status" property="status"/>
         <result column="isvalid" property="isvalid"/>
         <result column="creatorid" property="creatorId"/>
         <result column="createtime" property="createTime"/>
         <result column="updaterid" property="updaterId"/>
         <result column="updatetime" property="updateTime"/>
+        <result column="template_name" property="templateName"/>
     </resultMap>
+    <insert id="saveEmailTemplateMappingDO">
+        insert into PPW_EMAIL.email_template_mapping(template_id,title,email,company_name,status,isvalid,creatorid,createtime,updaterid,updatetime)
+        values
+            (#{templateId},#{title},#{email},#{companyName},#{status},#{isvalid},#{creatorId},#{createTime},#{updaterId},#{updateTime})
+    </insert>
+    <update id="deleteTemplateSetting">
+        update  PPW_EMAIL.email_template_mapping set isvalid=0,updatetime=sysdate(),updaterid=#{userId}
+        where isvalid=1 and id in
+        <foreach item="id" collection="idList" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </update>
+    <update id="updateEmailTemplateMappingDO">
+        update PPW_EMAIL.email_template_mapping set template_id=#{templateId},title=#{title},email=#{email},company_name=#{companyName},
+                                                    status=#{status},updatetime=#{updateTime},updaterid=#{updaterId}
+        where isvalid=1 and id=#{id}
+    </update>
 
     <select id="queryByEmail" resultType="com.simuwang.base.pojo.dos.EmailTemplateInfoDO">
         select t1.template_id as id,
-               t2.direction as direction
+               t2.direction as direction,
+               t2.type as type,
+               t2.start_index as startIndex,
+               t2.end_index as endIndex
         from PPW_EMAIL.email_template_mapping t1
-            join PPW_EMAIL.email_template_info t2 on t2.id = t1.template_id and t2.isvalid = 1
+            join PPW_EMAIL.email_template_info t2 on t2.id = t1.template_id and t2.isvalid = 1 and t2.status = 1
         where t1.email = #{email}
+          and t2.type = #{type}
           and t1.isvalid = 1
           and t2.status = 1
     </select>
+    <select id="searchTemplateSettingList" resultMap="BaseResultMap">
+        select mapping.id,mapping.template_id,mapping.title,mapping.email,mapping.company_name,mapping.status,
+        t.name as template_name
+        from PPW_EMAIL.email_template_mapping mapping
+            join PPW_EMAIL.email_template_info t on t.id = mapping.template_id and t.isvalid = 1 and t.status = 1
+        where mapping.isvalid=1
+        <if test="title != null and title != ''">
+            mapping.title like concat('%',#{title},'%')
+        </if>
+        <if test="email != null and email != ''">
+            mapping.email like concat('%',#{email},'%')
+        </if>
+        <if test="companyName != null and companyName != ''">
+            mapping.company_name like concat('%',#{companyName},'%')
+        </if>
+        <if test="templateName != null and templateName != ''">
+            t.name like concat('%',#{templateName},'%')
+        </if>
+        <if test="status != null">
+            mapping.status=#{status}
+        </if>
+        limit #{offset},#{pageSize}
+    </select>
+    <select id="countTemplateSettingList" resultType="java.lang.Long">
+        select count(mapping.id)
+        from PPW_EMAIL.email_template_mapping mapping
+        join PPW_EMAIL.email_template_info t on t.id = mapping.template_id and t.isvalid = 1 and t.status = 1
+        where mapping.isvalid=1
+        <if test="title != null and title != ''">
+            mapping.title like concat('%',#{title},'%')
+        </if>
+        <if test="email != null and email != ''">
+            mapping.email like concat('%',#{email},'%')
+        </if>
+        <if test="companyName != null and companyName != ''">
+            mapping.company_name like concat('%',#{companyName},'%')
+        </if>
+        <if test="templateName != null and templateName != ''">
+            t.name like concat('%',#{templateName},'%')
+        </if>
+        <if test="status != null">
+            mapping.status=#{status}
+        </if>
+    </select>
 
 </mapper>

+ 6 - 0
service-base/src/main/resources/mapper/FundAliasMapper.xml

@@ -8,6 +8,7 @@
         <result column="target_fund_id" property="targetFundId"/>
         <result column="target_fund_name" property="targetFundName"/>
         <result column="target_register_number" property="targetRegisterNumber"/>
+        <result column="company_name" property="companyName"/>
         <result column="isvalid" property="isvalid"/>
         <result column="creatorid" property="creatorId"/>
         <result column="createtime" property="createTime"/>
@@ -89,6 +90,7 @@
         alias.target_fund_id,
         info.fund_name as target_fund_name,
         info.register_number as target_register_number,
+        c.company_name as company_name,
         alias.isvalid,
         alias.creatorid,
         alias.createtime,
@@ -97,6 +99,8 @@
         from PPW_EMAIL.fund_alias alias
         left join PPW_EMAIL.pvn_fund_info info
         on alias.target_fund_id = info.fund_id and info.isvalid=1
+        left join PPW_EMAIL.pvn_company_info c
+        on c.company_id = info.trust_id and c.isvalid=1
         where alias.isvalid=1
         <if test="fundName != null and fundName !=''">
             and (alias.source_fund_name like concat('%',#{fundName},'%') or alias.source_register_number like concat('%',#{fundName},'%') )
@@ -118,6 +122,8 @@
         select count(1) from PPW_EMAIL.fund_alias alias
         left join PPW_EMAIL.pvn_fund_info info
         on alias.target_fund_id = info.fund_id and info.isvalid=1
+        left join PPW_EMAIL.pvn_company_info c
+        on c.company_id = info.trust_id and c.isvalid=1
         where alias.isvalid=1
         <if test="fundName != null and fundName !=''">
             and (alias.source_fund_name like concat('%',#{fundName},'%') or alias.source_register_number like concat('%',#{fundName},'%') )

+ 2 - 19
service-daq/src/main/java/com/simuwang/daq/service/AbstractEmailParser.java

@@ -1,6 +1,7 @@
 package com.simuwang.daq.service;
 
 import cn.hutool.core.util.StrUtil;
+import com.simuwang.base.common.util.NavDataUtil;
 import com.simuwang.base.common.util.StringUtil;
 import com.simuwang.base.pojo.dto.EmailContentInfoDTO;
 import com.simuwang.base.pojo.dto.EmailFundNavDTO;
@@ -12,8 +13,6 @@ import java.util.Map;
 
 public abstract class AbstractEmailParser {
 
-    private static final Logger log = LoggerFactory.getLogger(AbstractEmailParser.class);
-
     public boolean isSupport(Integer emailType) {
         return false;
     }
@@ -21,22 +20,6 @@ public abstract class AbstractEmailParser {
     public abstract List<EmailFundNavDTO> parse(EmailContentInfoDTO emailContentInfoDTO, Map<String, List<String>> emailFieldMap);
 
     public boolean dataFormat(EmailFundNavDTO fundNavDTO) {
-        // 净值日期格式校验
-        boolean isvalidDate = StringUtil.isValidDate(fundNavDTO.getPriceDate());
-        if (!isvalidDate) {
-            log.warn("净值日期格式不正确 -> 解析到的数据:{}", fundNavDTO);
-            return false;
-        }
-        // 单位净值,累计单位净值,资产净值,资产份额数字格式校验
-        boolean isvalidNumericFormat = (StrUtil.isBlank(fundNavDTO.getNav()) || StringUtil.isNumeric(fundNavDTO.getNav()))
-                && (StrUtil.isBlank(fundNavDTO.getCumulativeNavWithdrawal()) || StringUtil.isNumeric(fundNavDTO.getCumulativeNavWithdrawal()))
-                && (StrUtil.isBlank(fundNavDTO.getAssetNet()) || StringUtil.isNumeric(fundNavDTO.getAssetNet()))
-                && (StrUtil.isBlank(fundNavDTO.getAssetShare()) || StringUtil.isNumeric(fundNavDTO.getAssetShare()));
-        if (!isvalidNumericFormat) {
-            log.warn("单位净值或累计净值或资产净值或资产份额格式不正确 -> 解析到的数据:{}", fundNavDTO);
-            return false;
-        }
-        log.info("数据格式验证通过 -> {}", fundNavDTO);
-        return true;
+        return NavDataUtil.navDataFormatCheck(fundNavDTO);
     }
 }

+ 1 - 0
service-daq/src/main/java/com/simuwang/daq/service/EmailParseApiServiceImpl.java

@@ -155,6 +155,7 @@ public class EmailParseApiServiceImpl implements EmailParseApiService {
             EmailContentInfoDTO contentInfoDTO = new EmailContentInfoDTO();
             contentInfoDTO.setEmailId(emailId);
             contentInfoDTO.setFileId(fileInfoDO.getId());
+            contentInfoDTO.setSenderEmail(emailParseInfoDO.getSenderEmail());
             contentInfoDTO.setEmailAddress(emailParseInfoDO.getEmail());
             contentInfoDTO.setEmailDate(emailDate);
             contentInfoDTO.setEmailTitle(emailParseInfoDO.getEmailTitle());

+ 30 - 11
service-daq/src/main/java/com/simuwang/daq/service/EmailParseService.java

@@ -229,7 +229,7 @@ public class EmailParseService {
         List<EmailFundNavDO> emailFundNavDOList = fundNavDTOList.stream()
                 .map(e -> buildEmailFundNavDo(fileId, e, parseDate)).filter(CollUtil::isNotEmpty).flatMap(List::stream).collect(Collectors.toList());
         if (CollUtil.isNotEmpty(emailFundNavDOList)) {
-            // 先删除文件id下的净值数据(考虑到重新解析的需求,如果是首次解析,那么fiel_id下不存在净值数据)
+            // 先删除文件id下的净值数据(考虑到重新解析的需求,如果是首次解析,那么file_id下不存在净值数据)
             emailFundNavMapper.deleteByFileId(fileId);
             emailFundNavMapper.batchInsert(emailFundNavDOList);
             List<NavDO> navDOList = emailFundNavDOList.stream().filter(e -> StrUtil.isNotBlank(e.getFundId()))
@@ -261,7 +261,13 @@ public class EmailParseService {
             List<NavDO> updateNavDoList = navDOS.stream().filter(e -> dateList.contains(DateUtil.format(e.getPriceDate(), DateConst.YYYY_MM_DD))).collect(Collectors.toList());
             List<NavDO> insertNavDoList = navDOS.stream().filter(e -> !dateList.contains(DateUtil.format(e.getPriceDate(), DateConst.YYYY_MM_DD))).collect(Collectors.toList());
             if (CollUtil.isNotEmpty(insertNavDoList)) {
-                navMapper.batchInsert(insertNavDoList);
+                Map<Date, List<NavDO>> priceDateNavDoListMap = insertNavDoList.stream().collect(Collectors.groupingBy(NavDO::getPriceDate));
+                boolean hasDuplicationDateData = priceDateNavDoListMap.values().stream().map(List::size).anyMatch(e -> e > 1);
+                if (!hasDuplicationDateData) {
+                    navMapper.batchInsert(insertNavDoList);
+                }
+                // 要插入的数据中存在相同日期的数据 -> 只能一条一条的插入数据了
+                insertNavDoList.forEach(e -> saveNavDo(ListUtil.toList(e)));
             }
             if (CollUtil.isNotEmpty(updateNavDoList)) {
                 navMapper.batchUpdate(updateNavDoList);
@@ -281,7 +287,13 @@ public class EmailParseService {
             List<AssetDO> updateAssetDoList = assetDOS.stream().filter(e -> dateList.contains(DateUtil.format(e.getPriceDate(), DateConst.YYYY_MM_DD))).collect(Collectors.toList());
             List<AssetDO> insertAssetDoList = assetDOS.stream().filter(e -> !dateList.contains(DateUtil.format(e.getPriceDate(), DateConst.YYYY_MM_DD))).collect(Collectors.toList());
             if (CollUtil.isNotEmpty(insertAssetDoList)) {
-                assetMapper.batchInsert(insertAssetDoList);
+                Map<Date, List<AssetDO>> priceDateAssetDoListMap = insertAssetDoList.stream().collect(Collectors.groupingBy(AssetDO::getPriceDate));
+                boolean hasDuplicationDateData = priceDateAssetDoListMap.values().stream().map(List::size).anyMatch(e -> e > 1);
+                if (!hasDuplicationDateData) {
+                    assetMapper.batchInsert(insertAssetDoList);
+                }
+                // 要插入的数据中存在相同日期的数据 -> 只能一条一条的插入数据了
+                insertAssetDoList.forEach(e -> saveAssetDo(ListUtil.toList(e)));
             }
             if (CollUtil.isNotEmpty(updateAssetDoList)) {
                 assetMapper.batchUpdate(updateAssetDoList);
@@ -360,6 +372,7 @@ public class EmailParseService {
                 emailFundNavDO.setFundName(fundNavDTO.getFundName());
                 emailFundNavDO.setRegisterNumber(fundNavDTO.getRegisterNumber());
                 emailFundNavDO.setExceptionStatus(fundNavDTO.getParseStatus());
+                emailFundNavDO.setTemplateId(fundNavDTO.getTemplateId());
                 emailFundNavDO.setIsvalid(1);
                 emailFundNavDO.setCreatorId(0);
                 emailFundNavDO.setCreateTime(parseDate);
@@ -376,6 +389,7 @@ public class EmailParseService {
             emailFundNavDO.setFundName(fundNavDTO.getFundName());
             emailFundNavDO.setRegisterNumber(fundNavDTO.getRegisterNumber());
             emailFundNavDO.setExceptionStatus(fundNavDTO.getParseStatus());
+            emailFundNavDO.setTemplateId(fundNavDTO.getTemplateId());
             emailFundNavDO.setIsStored(isStored);
             emailFundNavDO.setIsvalid(1);
             emailFundNavDO.setCreatorId(0);
@@ -467,21 +481,25 @@ public class EmailParseService {
             fundAliasDOList = fundAliasMapper.queryFundIdByName(fundName);
         }
 
-        // 说明未匹配基金已写入别名表
-        if(CollUtil.isEmpty(fundIdList) && CollUtil.isNotEmpty(fundAliasDOList)){
+        // 未匹配基金已写入别名表
+        if (CollUtil.isEmpty(fundIdList) && CollUtil.isNotEmpty(fundAliasDOList)) {
             return;
         }
-
+        // 未匹配基金且未写入别名表
+        if (CollUtil.isEmpty(fundIdList) && CollUtil.isEmpty(fundAliasDOList)) {
+            fundAliasMapper.batchInsert(ListUtil.toList(buildFundAliasDO(fundName, registerNumber, null)));
+            log.info("写入别名表 -> 基金名称:{},备案编码:{},基金id:{}", fundName, registerNumber, fundIdList);
+            return;
+        }
+        // 匹配上基金 -> 需要判断此时基金id是否已经在别名管理表
         if (CollUtil.isNotEmpty(fundAliasDOList)) {
             List<String> collect = fundAliasDOList.stream().filter(Objects::nonNull).map(FundAliasDO::getTargetFundId).filter(Objects::nonNull).distinct().toList();
             fundIdList = fundIdList.stream().filter(e -> !collect.contains(e)).toList();
         }
-
-        log.info("写入别名表 -> 基金名称:{},备案编码:{},基金id:{}", fundName, registerNumber, fundIdList);
-        List<FundAliasDO> fundAliasDOS = CollUtil.isNotEmpty(fundIdList) ? ListUtil.toList(buildFundAliasDO(fundName, registerNumber, null))
-                : fundIdList.stream().map(e -> buildFundAliasDO(fundName, registerNumber, e)).toList();
-        if(CollUtil.isNotEmpty(fundAliasDOS)){
+        List<FundAliasDO> fundAliasDOS = CollUtil.isNotEmpty(fundIdList) ? fundIdList.stream().map(e -> buildFundAliasDO(fundName, registerNumber, e)).toList() : null;
+        if (CollUtil.isNotEmpty(fundAliasDOS)) {
             fundAliasMapper.batchInsert(fundAliasDOS);
+            log.info("写入别名表 -> 基金名称:{},备案编码:{},基金id:{}", fundName, registerNumber, fundIdList);
         }
     }
 
@@ -640,6 +658,7 @@ public class EmailParseService {
 
         // 正则表达式匹配邮件地址
         Pattern pattern = Pattern.compile("<(\\S+)>");
+
         Matcher matcher = pattern.matcher(address);
         if (matcher.find()) {
             return matcher.group(1);

+ 364 - 53
service-daq/src/main/java/com/simuwang/daq/service/EmailTemplateService.java

@@ -1,33 +1,54 @@
 package com.simuwang.daq.service;
 
+import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.exceptions.ExceptionUtil;
 import cn.hutool.core.lang.Pair;
+import cn.hutool.core.map.MapUtil;
 import cn.hutool.core.util.StrUtil;
 import com.simuwang.base.common.conts.ApplicationRuleFileConst;
+import com.simuwang.base.common.conts.EmailDataDirectionConst;
 import com.simuwang.base.common.conts.EmailFieldConst;
 import com.simuwang.base.common.util.ExcelUtil;
+import com.simuwang.base.common.util.NavDataUtil;
 import com.simuwang.base.mapper.EmailTemplateApplicationRuleMapper;
 import com.simuwang.base.mapper.EmailTemplateDataRuleMapper;
 import com.simuwang.base.mapper.EmailTemplateMappingMapper;
+import com.simuwang.base.pojo.dto.EmailFileContentDTO;
 import com.simuwang.base.pojo.dos.EmailTemplateApplicationRuleDO;
 import com.simuwang.base.pojo.dos.EmailTemplateDataRuleDO;
 import com.simuwang.base.pojo.dos.EmailTemplateInfoDO;
 import com.simuwang.base.pojo.dto.EmailContentInfoDTO;
+import com.simuwang.base.pojo.dto.EmailFundNavDTO;
+import com.simuwang.base.pojo.dto.TemplateDataRuleDTO;
 import com.simuwang.base.pojo.dto.TemplateDetailDTO;
 import org.apache.poi.ss.usermodel.Cell;
 import org.apache.poi.ss.usermodel.Row;
 import org.apache.poi.ss.usermodel.Sheet;
+import org.jsoup.Jsoup;
+import org.jsoup.nodes.Document;
+import org.jsoup.nodes.Element;
+import org.jsoup.select.Elements;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Service;
 
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.io.File;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 
+/**
+ * @author mozuwen
+ * @date 2024-09-23
+ * @description 净值模板解析
+ */
 @Service
 public class EmailTemplateService {
 
+    private static final Logger log = LoggerFactory.getLogger(EmailTemplateService.class);
+
     private final EmailTemplateMappingMapper emailTemplateMappingMapper;
     private final EmailTemplateApplicationRuleMapper emailTemplateApplicationRuleMapper;
     private final EmailTemplateDataRuleMapper emailTemplateDataRuleMapper;
@@ -51,19 +72,230 @@ public class EmailTemplateService {
         this.emailTemplateDataRuleMapper = emailTemplateDataRuleMapper;
     }
 
-    public List<TemplateDetailDTO> getTemplateDetail(EmailContentInfoDTO emailContentInfoDTO, String filePath) {
+
+    public List<EmailFundNavDTO> parseUsingTemplate(EmailContentInfoDTO emailContentInfoDTO) {
+        // 考虑文件为PDF,html,zip等情况 -> 将正文html和pdf文件转成Excel
+        List<EmailFileContentDTO> emailFileContentDTOList = getRealFilePath(emailContentInfoDTO.getFilePath(), emailContentInfoDTO.getEmailContent());
+        if (CollUtil.isEmpty(emailFileContentDTOList)) {
+            return CollUtil.newArrayList();
+        }
+        List<EmailFundNavDTO> emailFundNavDTOList = CollUtil.newArrayList();
+        for (EmailFileContentDTO emailFileContentDTO : emailFileContentDTOList) {
+            String filePath = emailFileContentDTO.getFilePath();
+            String textContent = emailFileContentDTO.getContent();
+            List<TemplateDetailDTO> templateDetailDTOList = getTemplateDetail(emailContentInfoDTO, textContent, filePath);
+            if (CollUtil.isEmpty(templateDetailDTOList)) {
+                return CollUtil.newArrayList();
+            }
+            // 按照模板分别进行解析
+            for (TemplateDetailDTO templateDetailDTO : templateDetailDTOList) {
+                try {
+                    // 按照模板配置规则解析
+                    List<EmailFundNavDTO> fundNavDTOList = extraFundNav(filePath, textContent, templateDetailDTO);
+                    fundNavDTOList = fundNavDTOList.stream().filter(NavDataUtil::navDataFormatCheck).toList();
+                    if (CollUtil.isNotEmpty(fundNavDTOList)) {
+                        fundNavDTOList.forEach(e->e.setTemplateId(templateDetailDTO.getTemplateId()));
+                        emailFundNavDTOList.addAll(fundNavDTOList);
+                    }
+                } catch (Exception e) {
+                    log.error("净值模板解析报错 -> 模板id:{},文件:{},堆栈信息:{}", templateDetailDTO.getTemplateId(), filePath, ExceptionUtil.stacktraceToString(e));
+                }
+            }
+        }
+        // 过滤掉相同的数据
+        return emailFundNavDTOList.stream().distinct().toList();
+    }
+
+    private List<EmailFundNavDTO> extraFundNav(String filePath, String textContent, TemplateDetailDTO templateDetailDTO) {
+        List<TemplateDataRuleDTO> dataRuleDetailList = templateDetailDTO.getDataRuleDetailList();
+        Map<String, String> fieldValueMap = MapUtil.newHashMap(8);
+        List<Map<String, String>> fieldValueMapList = CollUtil.newArrayList();
+        boolean hasParsedTableData = false;
+        Integer direction = templateDetailDTO.getDirection();
+
+        for (TemplateDataRuleDTO templateDataRuleDTO : dataRuleDetailList) {
+            Integer fieldName = templateDataRuleDTO.getFieldName();
+            Integer position = templateDataRuleDTO.getPosition();
+            if (position == 1) {
+                String valueByPattern = getValueByPattern(textContent, templateDataRuleDTO.getFieldRule());
+                fieldValueMap.put(FILE_TYPE_MAP.get(fieldName), valueByPattern);
+            }
+            if (position == 2 && !hasParsedTableData) {
+                hasParsedTableData = true;
+                List<TemplateDataRuleDTO> dataRuleDTOS = dataRuleDetailList.stream().filter(e -> e.getPosition() == 2).toList();
+                fieldValueMapList = parsedTableData(filePath, direction, dataRuleDTOS);
+            }
+        }
+        return buildEmailFundNavDTO(fieldValueMap, fieldValueMapList);
+    }
+
+    private List<Map<String, String>> parsedTableData(String filePath, Integer direction, List<TemplateDataRuleDTO> dataRuleDTOS) {
+        if (StrUtil.isBlank(filePath) || CollUtil.isEmpty(dataRuleDTOS)) {
+            return CollUtil.newArrayList();
+        }
+        Sheet sheet = ExcelUtil.getFirstSheet(filePath);
+        if (sheet == null) {
+            return CollUtil.newArrayList();
+        }
+
+        List<Map<String, String>> fieldValueMapList = CollUtil.newArrayList();
+        Map<String, Pair<Integer, Integer>> fieldPositionMap = MapUtil.newHashMap();
+        Map<String, String> fieldPatternMap = MapUtil.newHashMap();
+        for (TemplateDataRuleDTO dataRuleDTO : dataRuleDTOS) {
+            Integer row = dataRuleDTO.getRow() - 1;
+            int column = columnLetterToIndex(dataRuleDTO.getColumn());
+            Pair<Integer, Integer> pair = new Pair<>(row, column);
+            fieldPositionMap.put(FILE_TYPE_MAP.get(dataRuleDTO.getFieldName()), pair);
+            if (StrUtil.isNotBlank(dataRuleDTO.getFieldRule())) {
+                fieldPatternMap.put(FILE_TYPE_MAP.get(dataRuleDTO.getFieldName()), dataRuleDTO.getFieldRule());
+            }
+        }
+        if (direction.equals(EmailDataDirectionConst.ROW_DIRECTION_TYPE)) {
+            int startRow = fieldPositionMap.values().stream().map(Pair::getKey).min(Integer::compareTo).orElse(0);
+            for (int i = startRow + 1; i <= sheet.getLastRowNum(); i++) {
+                Map<String, String> fieldValueMap = MapUtil.newHashMap(8);
+                Row row = sheet.getRow(i);
+                if (row == null) {
+                    continue;
+                }
+                for (Map.Entry<String, Pair<Integer, Integer>> fieldEntry : fieldPositionMap.entrySet()) {
+                    String fieldName = fieldEntry.getKey();
+                    String fieldRule = fieldPatternMap.get(fieldName);
+                    int columnIndex = fieldEntry.getValue().getValue();
+                    Cell cell = row.getCell(columnIndex);
+                    String cellValue = getValueByPattern(ExcelUtil.getCellValue(cell), fieldRule);
+                    fieldValueMap.put(fieldName, cellValue);
+                }
+                fieldValueMapList.add(fieldValueMap);
+            }
+        }
+        if (direction.equals(EmailDataDirectionConst.COLUMN_DIRECTION_TYPE)) {
+            int startColumn = fieldPositionMap.values().stream().map(Pair::getValue).min(Integer::compareTo).orElse(0);
+            for (int columnNum = startColumn + 1; columnNum < EmailDataDirectionConst.MAX_ROW_COLUMN; columnNum++) {
+                Map<String, String> fieldValueMap = MapUtil.newHashMap();
+                for (Map.Entry<String, Pair<Integer, Integer>> fieldEntry : fieldPositionMap.entrySet()) {
+                    String fieldName = fieldEntry.getKey();
+                    String fieldRule = fieldPatternMap.get(fieldName);
+                    Integer rowIndex = fieldEntry.getValue().getKey();
+                    Integer columnIndex = fieldEntry.getValue().getValue();
+                    Row row = sheet.getRow(rowIndex);
+                    if (row == null) {
+                        continue;
+                    }
+                    Cell cell = row.getCell(columnIndex);
+                    String cellValue = getValueByPattern(ExcelUtil.getCellValue(cell), fieldRule);
+                    fieldValueMap.put(fieldName, cellValue);
+                }
+                fieldValueMapList.add(fieldValueMap);
+            }
+        }
+        // 表头和数据在同一个单元格
+        if (direction.equals(EmailDataDirectionConst.OTHER_DIRECTION_TYPE)) {
+            Map<String, String> fieldValueMap = MapUtil.newHashMap();
+            for (Map.Entry<String, Pair<Integer, Integer>> fieldEntry : fieldPositionMap.entrySet()) {
+                String fieldName = fieldEntry.getKey();
+                String fieldRule = fieldPatternMap.get(fieldName);
+                Integer rowIndex = fieldEntry.getValue().getKey();
+                Integer columnIndex = fieldEntry.getValue().getValue();
+                Row row = sheet.getRow(rowIndex);
+                if (row == null) {
+                    continue;
+                }
+                Cell cell = row.getCell(columnIndex);
+                String cellValue = getValueByPattern(ExcelUtil.getCellValue(cell), fieldRule);
+                fieldValueMap.put(fieldName, cellValue);
+            }
+            fieldValueMapList.add(fieldValueMap);
+        }
+
+        return fieldValueMapList;
+    }
+
+    /**
+     * 根据正则表达式提取内容
+     *
+     * @param text      文本
+     * @param fieldRule 正则表达式
+     * @return 内容
+     */
+    private String getValueByPattern(String text, String fieldRule) {
+        if (StrUtil.isBlank(text) || StrUtil.isBlank(fieldRule)) {
+            return text;
+        }
+        Pattern pattern = Pattern.compile(fieldRule);
+        Matcher matcher = pattern.matcher(text);
+        while (matcher.find()) {
+            return matcher.group(1);
+        }
+        return null;
+    }
+
+    /**
+     * 封装解析的数据为净值数据
+     *
+     * @param textFieldValueMap      从正文表格中解析到的数据
+     * @param excelFieldValueMapList 从正文文本中解析到的数据
+     * @return 净值数据
+     */
+    private List<EmailFundNavDTO> buildEmailFundNavDTO(Map<String, String> textFieldValueMap, List<Map<String, String>> excelFieldValueMapList) {
+        if (MapUtil.isEmpty(textFieldValueMap) && CollUtil.isEmpty(excelFieldValueMapList)) {
+            return CollUtil.newArrayList();
+        }
+        List<EmailFundNavDTO> fundNavDTOList = CollUtil.newArrayList();
+        if (CollUtil.isNotEmpty(excelFieldValueMapList)) {
+            for (Map<String, String> excelFieldValueMap : excelFieldValueMapList) {
+                fundNavDTOList.add(buildEmailFundNavDTO(excelFieldValueMap, textFieldValueMap));
+            }
+        }
+        if (MapUtil.isNotEmpty(textFieldValueMap) && CollUtil.isEmpty(excelFieldValueMapList)) {
+            fundNavDTOList.add(buildEmailFundNavDTO(null, textFieldValueMap));
+        }
+        return fundNavDTOList;
+    }
+
+    private EmailFundNavDTO buildEmailFundNavDTO(Map<String, String> excelFieldValueMap, Map<String, String> textFieldValueMap) {
+        EmailFundNavDTO fundNavDTO = new EmailFundNavDTO();
+        String registerNumber = MapUtil.isNotEmpty(excelFieldValueMap) && StrUtil.isNotBlank(excelFieldValueMap.get(EmailFieldConst.REGISTER_NUMBER))
+                ? excelFieldValueMap.get(EmailFieldConst.REGISTER_NUMBER) : MapUtil.isNotEmpty(textFieldValueMap) ? textFieldValueMap.get(EmailFieldConst.REGISTER_NUMBER) : null;
+        String fundName = MapUtil.isNotEmpty(excelFieldValueMap) && StrUtil.isNotBlank(excelFieldValueMap.get(EmailFieldConst.FUND_NAME))
+                ? excelFieldValueMap.get(EmailFieldConst.FUND_NAME) : MapUtil.isNotEmpty(textFieldValueMap) ? textFieldValueMap.get(EmailFieldConst.FUND_NAME) : null;
+        String priceDate = MapUtil.isNotEmpty(excelFieldValueMap) && StrUtil.isNotBlank(excelFieldValueMap.get(EmailFieldConst.PRICE_DATE))
+                ? excelFieldValueMap.get(EmailFieldConst.PRICE_DATE) : MapUtil.isNotEmpty(textFieldValueMap) ? textFieldValueMap.get(EmailFieldConst.PRICE_DATE) : null;
+        String nav = MapUtil.isNotEmpty(excelFieldValueMap) && StrUtil.isNotBlank(excelFieldValueMap.get(EmailFieldConst.NAV))
+                ? excelFieldValueMap.get(EmailFieldConst.NAV) : MapUtil.isNotEmpty(textFieldValueMap) ? textFieldValueMap.get(EmailFieldConst.NAV) : null;
+        String cumulativeNavWithdrawal = MapUtil.isNotEmpty(excelFieldValueMap) && StrUtil.isNotBlank(excelFieldValueMap.get(EmailFieldConst.CUMULATIVE_NAV_WITHDRAWAL))
+                ? excelFieldValueMap.get(EmailFieldConst.CUMULATIVE_NAV_WITHDRAWAL) : MapUtil.isNotEmpty(textFieldValueMap) ? textFieldValueMap.get(EmailFieldConst.CUMULATIVE_NAV_WITHDRAWAL) : null;
+        String assetShare = MapUtil.isNotEmpty(excelFieldValueMap) && StrUtil.isNotBlank(excelFieldValueMap.get(EmailFieldConst.ASSET_SHARE))
+                ? excelFieldValueMap.get(EmailFieldConst.ASSET_SHARE) : MapUtil.isNotEmpty(textFieldValueMap) ? textFieldValueMap.get(EmailFieldConst.ASSET_SHARE) : null;
+        String assetNet = MapUtil.isNotEmpty(excelFieldValueMap) && StrUtil.isNotBlank(excelFieldValueMap.get(EmailFieldConst.ASSET_NET))
+                ? excelFieldValueMap.get(EmailFieldConst.ASSET_NET) : MapUtil.isNotEmpty(textFieldValueMap) ? textFieldValueMap.get(EmailFieldConst.ASSET_NET) : null;
+
+        fundNavDTO.setRegisterNumber(registerNumber);
+        fundNavDTO.setFundName(fundName);
+        fundNavDTO.setPriceDate(priceDate);
+        fundNavDTO.setNav(nav);
+        fundNavDTO.setCumulativeNavWithdrawal(cumulativeNavWithdrawal);
+        fundNavDTO.setAssetShare(assetShare);
+        fundNavDTO.setAssetNet(assetNet);
+        return fundNavDTO;
+    }
+
+
+    public List<TemplateDetailDTO> getTemplateDetail(EmailContentInfoDTO emailContentInfoDTO, String textContent, String filePath) {
         List<TemplateDetailDTO> templateDetailDTOList = CollUtil.newArrayList();
         String senderEmail = emailContentInfoDTO.getSenderEmail();
-        if (StrUtil.isBlank(senderEmail) || StrUtil.isBlank(filePath)) {
+        if (StrUtil.isBlank(senderEmail)) {
             return templateDetailDTOList;
         }
+        // 1-excel类型,2-正文类型
+        int type = StrUtil.isNotBlank(emailContentInfoDTO.getFilePath()) && ExcelUtil.isHTML(emailContentInfoDTO.getFilePath()) ? 2 : 1;
         // 查询邮箱配置的模板Id
-        List<EmailTemplateInfoDO> emailTemplateInfoDOList = emailTemplateMappingMapper.queryByEmail(senderEmail);
+        List<EmailTemplateInfoDO> emailTemplateInfoDOList = emailTemplateMappingMapper.queryByEmail(senderEmail, type);
         List<Integer> templateIdList = emailTemplateInfoDOList.stream().map(EmailTemplateInfoDO::getId).collect(Collectors.toList());
         if (CollUtil.isEmpty(templateIdList)) {
             return templateDetailDTOList;
         }
-        Map<Integer, Integer> templateIdDirectionMap = emailTemplateInfoDOList.stream().collect(Collectors.toMap(EmailTemplateInfoDO::getId, EmailTemplateInfoDO::getDirection));
+        Map<Integer, EmailTemplateInfoDO> templateIdDirectionMap = emailTemplateInfoDOList.stream().collect(Collectors.toMap(EmailTemplateInfoDO::getId, v -> v));
         // 查询模版适用性规则 -> 判断邮件是否满足模板适用性规则
         List<EmailTemplateApplicationRuleDO> templateApplicationRuleDOList = emailTemplateApplicationRuleMapper.queryByTemplateId(templateIdList);
         if (CollUtil.isEmpty(templateApplicationRuleDOList)) {
@@ -78,66 +310,111 @@ public class EmailTemplateService {
             Integer templateId = templateIdApplicationRule.getKey();
             List<EmailTemplateApplicationRuleDO> applicationRuleDOList = templateIdApplicationRule.getValue();
             // 判断是否满足模板适用性规则
-            boolean isMatchTemplate = isMatchTemplate(emailContentInfoDTO.getEmailTitle(), emailContentInfoDTO.getFileName(), filePath, applicationRuleDOList);
+            boolean isMatchTemplate = isMatchTemplate(textContent, emailContentInfoDTO.getEmailTitle(), emailContentInfoDTO.getFileName(), filePath, applicationRuleDOList);
             if (!isMatchTemplate) {
                 continue;
             }
             TemplateDetailDTO templateDetailDTO = new TemplateDetailDTO();
             templateDetailDTO.setTemplateId(templateId);
-            // 模板的数据行方向:默认为行
-            Integer directionOrDefault = templateIdDirectionMap.getOrDefault(templateId, 1);
-            templateDetailDTO.setDirection(directionOrDefault);
-            Map<String, Pair<Integer, Integer>> fieldPositionMap = getFieldPosition(templateIdDataRuleMap.get(templateId));
-            templateDetailDTO.setFieldPositionMap(fieldPositionMap);
+            EmailTemplateInfoDO emailTemplateInfoDO = templateIdDirectionMap.get(templateId);
+            templateDetailDTO.setDirection(emailTemplateInfoDO.getDirection());
+            templateDetailDTO.setType(emailTemplateInfoDO.getType());
+            templateDetailDTO.setStartIndex(emailTemplateInfoDO.getStartIndex());
+            templateDetailDTO.setEndIndex(emailTemplateInfoDO.getEndIndex());
+
+            List<EmailTemplateDataRuleDO> dataRuleDOList = templateIdDataRuleMap.get(templateId);
+            List<TemplateDataRuleDTO> dataRuleDetailList = dataRuleDOList.stream().map(e -> BeanUtil.copyProperties(e, TemplateDataRuleDTO.class)).toList();
+            templateDetailDTO.setDataRuleDetailList(dataRuleDetailList);
             templateDetailDTOList.add(templateDetailDTO);
         }
         return templateDetailDTOList;
     }
 
-    private Map<String, Pair<Integer, Integer>> getFieldPosition(List<EmailTemplateDataRuleDO> emailTemplateDataRuleDOList) {
-        Map<String, Pair<Integer, Integer>> fieldPositionMap = new HashMap<>();
-        for (EmailTemplateDataRuleDO templateDataRuleDO : emailTemplateDataRuleDOList) {
-            Integer fieldName = templateDataRuleDO.getFieldName();
-            String fieldValue = FILE_TYPE_MAP.get(fieldName);
-            int column = columnLetterToIndex(templateDataRuleDO.getColumn());
-            Pair<Integer, Integer> pair = new Pair<>(templateDataRuleDO.getRow() - 1, column);
-            fieldPositionMap.put(fieldValue, pair);
+    public List<EmailFileContentDTO> getRealFilePath(String filePath, String content) {
+        List<EmailFileContentDTO> emailFileContentDTOList = CollUtil.newArrayList();
+        if (StrUtil.isBlank(filePath)) {
+            return emailFileContentDTOList;
         }
-        return fieldPositionMap;
-    }
+        if (ExcelUtil.isExcel(filePath)) {
+            emailFileContentDTOList.add(new EmailFileContentDTO(filePath, null));
+        } else if (ExcelUtil.isHTML(filePath)) {
+            String excelFilePath = filePath.replace(".html", ".xlsx");
+            excelFilePath = ExcelUtil.contentConvertToExcel(content, excelFilePath);
+            emailFileContentDTOList.add(new EmailFileContentDTO(excelFilePath, getTextFromHtml(content)));
+        } else if (ExcelUtil.isPdf(filePath)) {
+            String excelFilePath = filePath.replace(".pdf", ".xlsx").replace(".PDF", ".xlsx");
+            excelFilePath = ExcelUtil.pdfConvertToExcel(filePath, excelFilePath);
+            emailFileContentDTOList.add(new EmailFileContentDTO(excelFilePath, null));
+        } else if (ExcelUtil.isZip(filePath)) {
 
-    private boolean isMatchTemplate(String emailTitle, String fileName, String filePath, List<EmailTemplateApplicationRuleDO> applicationRuleDOList) {
-        int notMatchCount = 0;
-        for (EmailTemplateApplicationRuleDO applicationRuleDO : applicationRuleDOList) {
-            if (!isMathApplicationRule(applicationRuleDO, emailTitle, fileName, filePath)) {
-                notMatchCount++;
+            String destPath = filePath.replaceAll(".zip", "").replaceAll(".ZIP", "");
+            List<String> dir = ExcelUtil.extractCompressedFiles(filePath, destPath);
+            for (String zipFilePath : dir) {
+                File file = new File(zipFilePath);
+                if (file.isDirectory()) {
+                    for (String navFilePath : Objects.requireNonNull(file.list())) {
+                        Optional.ofNullable(getRealFilePath(navFilePath, null)).ifPresent(emailFileContentDTOList::addAll);
+                    }
+                } else {
+                    Optional.ofNullable(getRealFilePath(zipFilePath, null)).ifPresent(emailFileContentDTOList::addAll);
+                }
             }
         }
-        return notMatchCount == 0;
+        return emailFileContentDTOList;
+    }
+
+    private String getTextFromHtml(String htmlContent) {
+        if (StrUtil.isBlank(htmlContent)) {
+            return null;
+        }
+        Document doc = Jsoup.parse(htmlContent);
+        if (doc == null) {
+            return htmlContent;
+        }
+        Elements allElements = doc.getAllElements();
+        String textContent = allElements.stream().map(Element::ownText).collect(Collectors.joining("\n"));
+
+        return textContent.trim();
+    }
+
+    /**
+     * 判断邮件是否满足模板的适用性规则
+     *
+     * @param emailContent          邮件正文内容(已转成纯文本,以换行符分割每行内容)
+     * @param emailTitle            邮件主题
+     * @param fileName              附件名称
+     * @param filePath              文件路径(邮件正文html转成)
+     * @param applicationRuleDOList 模板配置的适用性规则列表
+     * @return true or false
+     */
+    private boolean isMatchTemplate(String emailContent, String emailTitle, String fileName,
+                                    String filePath, List<EmailTemplateApplicationRuleDO> applicationRuleDOList) {
+        return applicationRuleDOList.stream()
+                .allMatch(e -> isMathApplicationRule(e, emailContent, emailTitle, fileName, filePath));
     }
 
-    private boolean isMathApplicationRule(EmailTemplateApplicationRuleDO applicationRuleDO, String emailTitle, String fileName, String filePath) {
+    /**
+     * 判断邮件是否满足模板的某条适用性规则
+     *
+     * @param applicationRuleDO 适用性规则
+     * @param emailContent      邮件正文内容(可为空)
+     * @param emailTitle        邮件主题
+     * @param fileName          附件名称
+     * @param filePath          文件路径(邮件正文html转成)
+     * @return true or false
+     */
+    private boolean isMathApplicationRule(EmailTemplateApplicationRuleDO applicationRuleDO, String emailContent, String emailTitle, String fileName, String filePath) {
         boolean isMatch = true;
         Integer type = applicationRuleDO.getType();
         String containKeyword = applicationRuleDO.getContainKeyword();
         String notContainKeyword = applicationRuleDO.getNotContainKeyword();
         if (ApplicationRuleFileConst.EMAIL_TITLE_FILE.equals(type)) {
-            if (StrUtil.isNotBlank(containKeyword)) {
-                isMatch = Arrays.stream(containKeyword.split(",")).allMatch(emailTitle::contains);
-            }
-            if (StrUtil.isNotBlank(notContainKeyword)) {
-                isMatch = Arrays.stream(notContainKeyword.split(",")).noneMatch(emailTitle::contains) && isMatch;
-            }
-        }
-        if (ApplicationRuleFileConst.EMAIL_FILE_NAME_FILE.equals(type)) {
-            if (StrUtil.isNotBlank(containKeyword)) {
-                isMatch = Arrays.stream(containKeyword.split(",")).allMatch(fileName::contains);
-            }
-            if (StrUtil.isNotBlank(notContainKeyword)) {
-                isMatch = Arrays.stream(notContainKeyword.split(",")).noneMatch(fileName::contains) && isMatch;
-            }
-        }
-        if (ApplicationRuleFileConst.EMAIL_EXCEL_CONTENT_FILE.equals(type)) {
+            isMatch = iskeywordMatch(emailTitle, containKeyword, notContainKeyword);
+        } else if (ApplicationRuleFileConst.EMAIL_CONTENT_FILE.equals(type)) {
+            isMatch = iskeywordMatch(emailContent, containKeyword, notContainKeyword);
+        } else if (ApplicationRuleFileConst.EMAIL_FILE_NAME_FILE.equals(type)) {
+            isMatch = iskeywordMatch(fileName, containKeyword, notContainKeyword);
+        } else if (ApplicationRuleFileConst.EMAIL_EXCEL_CONTENT_FILE.equals(type)) {
             if (StrUtil.isNotBlank(fileName) && ExcelUtil.isExcel(fileName)) {
                 if (applicationRuleDO.getRow() == null || StrUtil.isBlank(applicationRuleDO.getColumn())) {
                     return false;
@@ -159,17 +436,30 @@ public class EmailTemplateService {
                 if (StrUtil.isBlank(cellValue)) {
                     return false;
                 }
-                if (StrUtil.isNotBlank(containKeyword)) {
-                    isMatch = Arrays.stream(containKeyword.split(",")).allMatch(cellValue::contains);
-                }
-                if (StrUtil.isNotBlank(notContainKeyword)) {
-                    isMatch = Arrays.stream(notContainKeyword.split(",")).noneMatch(cellValue::contains) && isMatch;
-                }
+                isMatch = iskeywordMatch(cellValue, containKeyword, notContainKeyword);
             }
         }
         return isMatch;
     }
 
+    private Map<String, Pair<Integer, Integer>> getFieldPosition(List<EmailTemplateDataRuleDO> emailTemplateDataRuleDOList) {
+        Map<String, Pair<Integer, Integer>> fieldPositionMap = new HashMap<>();
+        for (EmailTemplateDataRuleDO templateDataRuleDO : emailTemplateDataRuleDOList) {
+            Integer fieldName = templateDataRuleDO.getFieldName();
+            String fieldValue = FILE_TYPE_MAP.get(fieldName);
+            int column = columnLetterToIndex(templateDataRuleDO.getColumn());
+            Pair<Integer, Integer> pair = new Pair<>(templateDataRuleDO.getRow() - 1, column);
+            fieldPositionMap.put(fieldValue, pair);
+        }
+        return fieldPositionMap;
+    }
+
+    /**
+     * 将数据列转成数字型索引
+     *
+     * @param columnName 数据列名:如A,B,....
+     * @return 数据列数字型索引
+     */
     public static int columnLetterToIndex(String columnName) {
         int columnIndex = 0;
         int columnLength = columnName.length();
@@ -184,4 +474,25 @@ public class EmailTemplateService {
         return columnIndex;
     }
 
+    /**
+     * 判断字符串是否包含指定的关键词列表,并且不包含指定的排除关键词列表。
+     *
+     * @param emailTitle        要检查的字符串
+     * @param containKeyword    逗号分隔的必须包含的关键词列表
+     * @param notContainKeyword 逗号分隔的必须不包含的关键词列表
+     * @return true or false
+     */
+    public boolean iskeywordMatch(String emailTitle, String containKeyword, String notContainKeyword) {
+        boolean isMatch = true;
+        if (StrUtil.isNotBlank(containKeyword)) {
+            isMatch &= Arrays.stream(containKeyword.split(","))
+                    .allMatch(emailTitle::contains);
+        }
+        if (StrUtil.isNotBlank(notContainKeyword)) {
+            isMatch &= Arrays.stream(notContainKeyword.split(","))
+                    .noneMatch(emailTitle::contains);
+        }
+        return isMatch;
+    }
+
 }

+ 2 - 2
service-daq/src/main/java/com/simuwang/daq/service/FundService.java

@@ -55,7 +55,7 @@ public class FundService {
             }
         }
         // 备案编码匹配
-        if (StrUtil.isNotBlank(registerNumber)) {
+        if (StrUtil.isNotBlank(registerNumber) && StrUtil.isBlank(fundName)) {
             List<FundInfoDO> fundInfos = fundInfoMapper.queryFundByRegisterNumber(registerNumber);
             if (CollUtil.isNotEmpty(fundInfos)) {
                 return fundInfos;
@@ -66,7 +66,7 @@ public class FundService {
             }
         }
         // 基金名称匹配
-        if (StrUtil.isNotBlank(fundName)) {
+        if (StrUtil.isBlank(registerNumber) && StrUtil.isNotBlank(fundName)) {
             List<FundInfoDO> fundInfos = fundInfoMapper.queryFundByName(fundName);
             if (CollUtil.isNotEmpty(fundInfos)) {
                 return fundInfos;

+ 29 - 182
service-daq/src/main/java/com/simuwang/daq/service/NavEmailParser.java

@@ -2,11 +2,11 @@ package com.simuwang.daq.service;
 
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.date.DateUtil;
-import cn.hutool.core.exceptions.ExceptionUtil;
 import cn.hutool.core.lang.Pair;
 import cn.hutool.core.map.MapUtil;
 import cn.hutool.core.util.StrUtil;
 import com.simuwang.base.common.conts.DateConst;
+import com.simuwang.base.common.conts.EmailDataDirectionConst;
 import com.simuwang.base.common.conts.EmailFieldConst;
 import com.simuwang.base.common.conts.EmailTypeConst;
 import com.simuwang.base.common.util.ExcelUtil;
@@ -14,30 +14,15 @@ import com.simuwang.base.common.util.StringUtil;
 import com.simuwang.base.pojo.dto.EmailContentInfoDTO;
 import com.simuwang.base.pojo.dto.EmailFundNavDTO;
 import com.simuwang.base.pojo.dto.FieldPositionDTO;
-import com.simuwang.base.pojo.dto.TemplateDetailDTO;
-import org.apache.pdfbox.Loader;
-import org.apache.pdfbox.pdmodel.PDDocument;
 import org.apache.poi.ss.usermodel.Cell;
 import org.apache.poi.ss.usermodel.Row;
 import org.apache.poi.ss.usermodel.Sheet;
-import org.apache.poi.ss.usermodel.Workbook;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-import org.jsoup.Jsoup;
-import org.jsoup.nodes.Document;
-import org.jsoup.nodes.Element;
-import org.jsoup.select.Elements;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Component;
-import technology.tabula.*;
-import technology.tabula.extractors.SpreadsheetExtractionAlgorithm;
 
 import java.io.File;
-import java.io.FileOutputStream;
-import java.io.OutputStream;
-import java.nio.file.Files;
-import java.nio.file.Paths;
 import java.util.*;
 import java.util.stream.Collectors;
 
@@ -54,14 +39,9 @@ public class NavEmailParser extends AbstractEmailParser {
     @Value("${email.file.path}")
     private String path;
 
-    @Value("${email.force-template.enable}")
-    private boolean forceTemplateEnable;
-
     private final ValuationEmailParser valuationEmailParser;
     private final EmailTemplateService emailTemplateService;
 
-    private static final Integer ROW_DIRECTION_TYPE = 1;
-    private static final Integer COLUMN_DIRECTION_TYPE = 2;
     private static final int MAX_COLUMN = 20;
 
     public NavEmailParser(ValuationEmailParser valuationEmailParser, EmailTemplateService emailTemplateService) {
@@ -79,8 +59,9 @@ public class NavEmailParser extends AbstractEmailParser {
         List<EmailFundNavDTO> emailFundNavDTOList = CollUtil.newArrayList();
         String emailContent = emailContentInfoDTO.getEmailContent();
         // 1.解析邮件正文
-        if (StrUtil.isNotBlank(emailContent)) {
-            emailFundNavDTOList = parseEmailContent(emailContentInfoDTO, emailContent, emailFieldMap);
+        if (StrUtil.isNotBlank(emailContentInfoDTO.getFilePath()) && ExcelUtil.isHTML(emailContentInfoDTO.getFileName())) {
+            String excelFilePath = emailContentInfoDTO.getFilePath().replace(".html", ".xlsx");
+            emailFundNavDTOList = parseEmailContent(emailContent, excelFilePath, emailFieldMap);
         }
         // 2.解析邮件excel附件
         if (StrUtil.isNotBlank(emailContentInfoDTO.getFilePath()) && ExcelUtil.isExcel(emailContentInfoDTO.getFileName())) {
@@ -108,10 +89,14 @@ public class NavEmailParser extends AbstractEmailParser {
                 emailFundNavDTOList = valuationEmailParser.parse(emailContentInfoDTO, emailFieldMap);
             }
         }
+        // email_fund_nav增加template_id字段
+        if (CollUtil.isEmpty(emailFundNavDTOList)) {
+            emailFundNavDTOList.forEach(e -> e.setTemplateId(0));
+        }
 
         // 通用模版解析 -> 根据配置的模板进行解析
-        if (CollUtil.isEmpty(emailFundNavDTOList) || forceTemplateEnable) {
-            emailFundNavDTOList = parseUsingTemplate(emailContentInfoDTO);
+        if (CollUtil.isEmpty(emailFundNavDTOList)) {
+            emailFundNavDTOList = emailTemplateService.parseUsingTemplate(emailContentInfoDTO);
         }
         return emailFundNavDTOList;
     }
@@ -149,55 +134,14 @@ public class NavEmailParser extends AbstractEmailParser {
         return fundNavDTOList;
     }
 
-
     private List<EmailFundNavDTO> parsePdfFile(String filePath, String excelFilePath, Map<String, List<String>> emailFieldMap) {
-        excelFilePath = pdfConvertToExcel(filePath, excelFilePath);
+        excelFilePath = ExcelUtil.pdfConvertToExcel(filePath, excelFilePath);
         if (StrUtil.isBlank(excelFilePath)) {
             return CollUtil.newArrayList();
         }
         return parseExcelFile(excelFilePath, emailFieldMap);
     }
 
-    private String pdfConvertToExcel(String filePath, String excelFilePath) {
-        File savefile = new File(excelFilePath);
-        if (!savefile.exists()) {
-            if (!savefile.getParentFile().exists()) {
-                savefile.getParentFile().mkdirs();
-                savefile.getParentFile().setExecutable(true);
-            }
-        }
-        try (OutputStream outputStream = Files.newOutputStream(Paths.get(excelFilePath))) {
-            PDDocument document = Loader.loadPDF(new File(filePath));
-            PageIterator extract = new ObjectExtractor(document).extract();
-            Workbook workbook = new XSSFWorkbook();
-            Sheet sheet = workbook.createSheet("Sheet1");
-            while (extract.hasNext()) {
-                Page next = extract.next();
-                List<Table> tableList = new SpreadsheetExtractionAlgorithm().extract(next);
-                for (Table table : tableList) {
-                    List<List<RectangularTextContainer>> rows = table.getRows();
-                    for (int rowNum = 0; rowNum < rows.size(); rowNum++) {
-                        Row sheetRow = sheet.createRow(rowNum);
-                        List<RectangularTextContainer> textContainerList = rows.get(rowNum);
-                        for (int cellNum = 0; cellNum < textContainerList.size(); cellNum++) {
-                            Cell cell = sheetRow.createCell(cellNum);
-                            RectangularTextContainer textContainer = textContainerList.get(cellNum);
-                            if (textContainer != null) {
-                                cell.setCellValue(textContainer.getText());
-                            }
-                        }
-                    }
-                }
-            }
-            // 将Excel工作簿写入输出流
-            workbook.write(outputStream);
-        } catch (Exception e) {
-            log.error("解析邮件pdf附件报错 -> 堆栈信息:{}", ExceptionUtil.stacktraceToString(e));
-            return null;
-        }
-        return excelFilePath;
-    }
-
     /**
      * 解析邮件excel附件
      *
@@ -207,6 +151,10 @@ public class NavEmailParser extends AbstractEmailParser {
      */
     private List<EmailFundNavDTO> parseExcelFile(String filePath, Map<String, List<String>> emailFieldMap) {
         Sheet sheet = ExcelUtil.getFirstSheet(filePath);
+        if (sheet == null) {
+            log.info("获取不到有效的sheet页面,文件路径:{}", filePath);
+            return CollUtil.newArrayList();
+        }
         // 1.找到表头所在位置
         Map<String, Pair<Integer, Integer>> fieldPositionMap = getFieldPosition(sheet, emailFieldMap);
         if (MapUtil.isEmpty(fieldPositionMap)) {
@@ -225,110 +173,18 @@ public class NavEmailParser extends AbstractEmailParser {
     /**
      * 解析邮件正文
      *
-     * @param emailContentInfoDTO 邮件信息
-     * @param emailContent        正文内容
-     * @param emailFieldMap       邮件字段识别规则映射表
+     * @param emailContent  正文内容
+     * @param emailFieldMap 邮件字段识别规则映射表
      * @return 解析到的净值数据
      */
-    private List<EmailFundNavDTO> parseEmailContent(EmailContentInfoDTO emailContentInfoDTO, String emailContent, Map<String, List<String>> emailFieldMap) {
-        String excelFilePath = contentConvertToExcel(emailContentInfoDTO);
+    private List<EmailFundNavDTO> parseEmailContent(String emailContent, String excelFilePath, Map<String, List<String>> emailFieldMap) {
+        excelFilePath = ExcelUtil.contentConvertToExcel(emailContent, excelFilePath);
         if (StrUtil.isBlank(excelFilePath)) {
             return CollUtil.newArrayList();
         }
         return parseExcelFile(excelFilePath, emailFieldMap);
     }
 
-    public String contentConvertToExcel(EmailContentInfoDTO emailContentInfoDTO) {
-        Document doc = Jsoup.parse(emailContentInfoDTO.getEmailContent());
-        Element table = doc.select("table").first();
-        Elements rows = table.select("tr");
-        String excelFilePath = path + "/content/" + emailContentInfoDTO.getEmailAddress() + "/" + emailContentInfoDTO.getEmailDate().substring(0, 10).replaceAll("-", "") + "/"
-                + emailContentInfoDTO.getFileName().replace(".html", ".xlsx");
-        File saveFile = new File(excelFilePath);
-        if (!saveFile.exists()) {
-            if (!saveFile.getParentFile().exists()) {
-                saveFile.getParentFile().mkdirs();
-                saveFile.getParentFile().setExecutable(true);
-            }
-        }
-        try (OutputStream outputStream = new FileOutputStream(saveFile)) {
-            // 创建一个新的Excel工作簿
-            Workbook workbook = new XSSFWorkbook();
-            Sheet sheet = workbook.createSheet("Sheet1");
-            ExcelUtil.writeDataToSheet(sheet, rows);
-            // 将Excel工作簿写入输出流
-            workbook.write(outputStream);
-        } catch (Exception e) {
-            log.error("解析正文报错 -> 邮件主题:{},邮件日期:{},堆栈信息:{}", emailContentInfoDTO.getEmailTitle(), emailContentInfoDTO.getEmailDate(), ExceptionUtil.stacktraceToString(e));
-            return null;
-        }
-        return excelFilePath;
-    }
-
-    private List<EmailFundNavDTO> parseUsingTemplate(EmailContentInfoDTO emailContentInfoDTO) {
-        // 考虑文件为PDF,html,zip等情况 -> 将相关文件转成Excel
-        List<String> filePathList = getRealFilePath(emailContentInfoDTO.getFilePath(), emailContentInfoDTO);
-        if (CollUtil.isEmpty(filePathList)) {
-            return CollUtil.newArrayList();
-        }
-        List<EmailFundNavDTO> emailFundNavDTOList = CollUtil.newArrayList();
-        for (String filePath : filePathList) {
-            List<TemplateDetailDTO> templateDetailDTOList = emailTemplateService.getTemplateDetail(emailContentInfoDTO, filePath);
-            if (CollUtil.isEmpty(templateDetailDTOList) || ExcelUtil.getFirstSheet(filePath) == null) {
-                return CollUtil.newArrayList();
-            }
-            // 获取文件的sheet页
-            Sheet sheet = ExcelUtil.getFirstSheet(filePath);
-            // 按照模板分别进行解析 -> 只要有一个模板解析到数据就停止
-            for (TemplateDetailDTO templateDetailDTO : templateDetailDTOList) {
-                try {
-                    Integer direction = templateDetailDTO.getDirection();
-                    Map<String, Pair<Integer, Integer>> fieldPositionMap = templateDetailDTO.getFieldPositionMap();
-                    List<EmailFundNavDTO> fundNavDTOList = parseSheetData(sheet, fieldPositionMap, direction);
-                    fundNavDTOList = fundNavDTOList.stream().filter(super::dataFormat).collect(Collectors.toList());
-                    if (CollUtil.isNotEmpty(fundNavDTOList)) {
-                        emailFundNavDTOList.addAll(fundNavDTOList);
-                        break;
-                    }
-                } catch (Exception e) {
-                    log.error("净值模板解析报错 -> 模板id:{},文件:{},堆栈信息:{}", templateDetailDTO.getTemplateId(), filePath, ExceptionUtil.stacktraceToString(e));
-                }
-            }
-        }
-        return emailFundNavDTOList;
-    }
-
-    private List<String> getRealFilePath(String filePath, EmailContentInfoDTO emailContentInfoDTO) {
-        List<String> filePathList = CollUtil.newArrayList();
-        if (StrUtil.isBlank(filePath)) {
-            return filePathList;
-        }
-        if (ExcelUtil.isExcel(filePath)) {
-            filePathList.add(filePath);
-        } else if (ExcelUtil.isHTML(filePath)) {
-            String excelFilePath = contentConvertToExcel(emailContentInfoDTO);
-            Optional.ofNullable(excelFilePath).ifPresent(filePathList::add);
-        } else if (ExcelUtil.isPdf(filePath)) {
-            String excelFilePath = filePath.replace(".pdf", ".xlsx").replace(".PDF", ".xlsx");
-            excelFilePath = pdfConvertToExcel(filePath, excelFilePath);
-            Optional.ofNullable(excelFilePath).ifPresent(filePathList::add);
-        } else if (ExcelUtil.isZip(filePath)) {
-            String destPath = filePath.replaceAll(".zip", "").replaceAll(".ZIP", "");
-            List<String> dir = ExcelUtil.extractCompressedFiles(filePath, destPath);
-            for (String zipFilePath : dir) {
-                File file = new File(zipFilePath);
-                if (file.isDirectory()) {
-                    for (String navFilePath : Objects.requireNonNull(file.list())) {
-                        Optional.ofNullable(getRealFilePath(navFilePath, emailContentInfoDTO)).ifPresent(filePathList::addAll);
-                    }
-                } else {
-                    Optional.ofNullable(getRealFilePath(zipFilePath, emailContentInfoDTO)).ifPresent(filePathList::addAll);
-                }
-            }
-        }
-        return filePathList;
-    }
-
     /**
      * 根据字段所在表格的位置提取净值数据
      *
@@ -340,12 +196,12 @@ public class NavEmailParser extends AbstractEmailParser {
     private List<EmailFundNavDTO> parseSheetData(Sheet sheet, Map<String, Pair<Integer, Integer>> fieldPositionMap, Integer direction) {
         List<EmailFundNavDTO> fundNavDTOList = CollUtil.newArrayList();
         // 通过表头所在位置判断是行数据还是列数据
-        Integer dataDirectionType = direction != null ? direction : detectDataDirection(fieldPositionMap);
+        Integer dataDirectionType = direction != null ? direction : ExcelUtil.detectDataDirection(fieldPositionMap);
         // 数据起始行,起始列
-        int initRow = dataDirectionType.equals(ROW_DIRECTION_TYPE) ? fieldPositionMap.values().stream().map(Pair::getKey).max(Integer::compareTo).orElse(0)
+        int initRow = dataDirectionType.equals(EmailDataDirectionConst.ROW_DIRECTION_TYPE) ? fieldPositionMap.values().stream().map(Pair::getKey).max(Integer::compareTo).orElse(0)
                 : fieldPositionMap.values().stream().map(Pair::getKey).min(Integer::compareTo).orElse(0);
         int initColumn = fieldPositionMap.values().stream().map(Pair::getValue).min(Integer::compareTo).orElse(0);
-        if (dataDirectionType.equals(ROW_DIRECTION_TYPE)) {
+        if (dataDirectionType.equals(EmailDataDirectionConst.ROW_DIRECTION_TYPE)) {
             // 表头字段-列号映射关系
             Map<String, Integer> fieldColumnMap = getFieldRow(fieldPositionMap);
             int lastRowNum = sheet.getLastRowNum();
@@ -355,12 +211,12 @@ public class NavEmailParser extends AbstractEmailParser {
                 Optional.ofNullable(readSheetRowData(sheetRow, fieldColumnMap)).ifPresent(fundNavDTOList::addAll);
             }
         }
-        if (dataDirectionType.equals(COLUMN_DIRECTION_TYPE)) {
+        if (dataDirectionType.equals(EmailDataDirectionConst.COLUMN_DIRECTION_TYPE)) {
             // 表头字段-行号映射关系
             Map<Integer, String> fieldRowMap = getRowField(fieldPositionMap);
             int lastRow = fieldPositionMap.values().stream().map(Pair::getKey).max(Integer::compareTo).orElse(0);
             // 遍历每一列
-            for (int columnNum = initColumn + 1; columnNum < MAX_COLUMN; columnNum++) {
+            for (int columnNum = initColumn + 1; columnNum < EmailDataDirectionConst.MAX_ROW_COLUMN; columnNum++) {
                 Map<String, String> fieldValueMap = MapUtil.newHashMap();
                 for (int rowNum = initRow; rowNum <= lastRow; rowNum++) {
                     Row row = sheet.getRow(rowNum);
@@ -561,17 +417,6 @@ public class NavEmailParser extends AbstractEmailParser {
     }
 
     /**
-     * 通过表头所在位置判断是行数据还是列数据
-     *
-     * @param fieldPositionMap excel中表头所在的位置
-     * @return 行方向-1,,列方向-2
-     */
-    private Integer detectDataDirection(Map<String, Pair<Integer, Integer>> fieldPositionMap) {
-        long count = fieldPositionMap.values().stream().map(Pair::getValue).distinct().count();
-        return count == 1 ? COLUMN_DIRECTION_TYPE : ROW_DIRECTION_TYPE;
-    }
-
-    /**
      * 找出excel中表头所在的位置
      *
      * @param sheet         表格工作簿
@@ -636,9 +481,11 @@ public class NavEmailParser extends AbstractEmailParser {
         // 母基金缺少代码的情况
         if (hasParentField && fieldPositionMap.get(EmailFieldConst.PARENT_REGISTER_NUMBER) == null) {
             List<FieldPositionDTO> fieldPositionDTOS = tempFieldPositionMap.get(EmailFieldConst.REGISTER_NUMBER);
-            Pair<Integer, Integer> parentRegisterNumberPair = fieldPositionDTOS.stream()
-                    .filter(e -> e.getFieldValue().contains("协会") || e.getFieldValue().contains("备案")).map(FieldPositionDTO::getPair).findFirst().orElse(null);
-            fieldPositionMap.put(EmailFieldConst.PARENT_REGISTER_NUMBER, parentRegisterNumberPair);
+            if (CollUtil.isNotEmpty(fieldPositionDTOS)) {
+                Pair<Integer, Integer> parentRegisterNumberPair = fieldPositionDTOS.stream()
+                        .filter(e -> e.getFieldValue().contains("协会") || e.getFieldValue().contains("备案")).map(FieldPositionDTO::getPair).findFirst().orElse(null);
+                fieldPositionMap.put(EmailFieldConst.PARENT_REGISTER_NUMBER, parentRegisterNumberPair);
+            }
         }
         return fieldPositionMap;
     }

+ 0 - 2
service-deploy/src/main/resources/application.yml

@@ -70,8 +70,6 @@ email-rule:
 email:
   file:
     path: /data/file/nav
-  force-template:
-    enable: true
 
 # 配置
 simuwang:

+ 1 - 1
service-deploy/src/test/java/com/simuwang/ApplicationTest.java

@@ -48,7 +48,7 @@ public class ApplicationTest {
 
     @Test
     public void testReparseEmail() {
-        emailParseApiService.reparseEmail(7);
+        emailParseApiService.reparseEmail(593);
     }
 
     @Test

+ 78 - 0
service-manage/src/main/java/com/simuwang/manage/api/template/TemplateController.java

@@ -0,0 +1,78 @@
+package com.simuwang.manage.api.template;
+
+import com.simuwang.base.common.support.MybatisPage;
+import com.simuwang.base.pojo.dto.query.DeletionPageQuery;
+import com.simuwang.base.pojo.dto.query.EmailTemplateInfoPageQuery;
+import com.simuwang.base.pojo.vo.*;
+import com.simuwang.logging.SystemLog;
+import com.simuwang.manage.service.EmailTemplateInfoService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * 模版管理
+ * Author:   chenjianhua
+ * Date:     2024/9/25 18:46
+ * Description: ${DESCRIPTION}
+ */
+@SystemLog(value = "模版管理")
+@RestController
+@RequestMapping("/v1/template")
+public class TemplateController {
+
+    @Autowired
+    private EmailTemplateInfoService emailTemplateInfoService;
+
+    /**
+     * 模版详情页面展示数据
+     * @param emailTemplateInfoPageQuery
+     * @return
+     */
+    @SystemLog(value = "模版详情页面展示数据")
+    @RequestMapping("search-template-list")
+    public MybatisPage<EmailTemplateInfoVO> searchTemplateList(EmailTemplateInfoPageQuery emailTemplateInfoPageQuery){
+        MybatisPage<EmailTemplateInfoVO> result = emailTemplateInfoService.searchTemplateList(emailTemplateInfoPageQuery);
+        return result;
+    }
+
+
+    /**
+     * 批量删除模版
+     * @param idListVO
+     * @return
+     */
+    @SystemLog(value = "批量删除模版")
+    @RequestMapping("delete-template-list")
+    public boolean deleteTemplateList(@RequestBody IdListVO idListVO){
+        emailTemplateInfoService.deleteTemplateList(idListVO);
+        return true;
+    }
+
+
+    /**
+     * 保存模版
+     * @param saveTemplateInfoVO
+     * @return
+     */
+    @SystemLog(value = "保存模版信息")
+    @RequestMapping("save-template-list")
+    public boolean saveTemplateList(@RequestBody SaveTemplateInfoVO saveTemplateInfoVO){
+        emailTemplateInfoService.saveTemplateList(saveTemplateInfoVO);
+        return true;
+    }
+
+    /**
+     * 批量删除适用规则
+     * @param idListVO
+     * @return
+     */
+    @SystemLog(value = "批量删除适用规则")
+    @RequestMapping("delete-application-rule")
+    public boolean deleteApplicationRuleList(@RequestBody IdListVO idListVO){
+        emailTemplateInfoService.deleteApplicationRuleList(idListVO);
+        return true;
+    }
+
+}

+ 69 - 0
service-manage/src/main/java/com/simuwang/manage/api/template/TemplateSettingController.java

@@ -0,0 +1,69 @@
+package com.simuwang.manage.api.template;
+
+import com.simuwang.base.common.support.MybatisPage;
+import com.simuwang.base.pojo.dto.query.EmailTemplateInfoPageQuery;
+import com.simuwang.base.pojo.dto.query.EmailTemplateSettingPageQuery;
+import com.simuwang.base.pojo.vo.EmailTemplateInfoVO;
+import com.simuwang.base.pojo.vo.EmailTemplateMappingVO;
+import com.simuwang.base.pojo.vo.IdListVO;
+import com.simuwang.base.pojo.vo.SaveTemplateInfoVO;
+import com.simuwang.logging.SystemLog;
+import com.simuwang.manage.service.EmailTemplateInfoService;
+import com.simuwang.manage.service.EmailTemplateMappingService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * 模版设置
+ * Author:   chenjianhua
+ * Date:     2024/9/25 18:46
+ * Description: ${DESCRIPTION}
+ */
+@SystemLog(value = "模版管理")
+@RestController
+@RequestMapping("/v1/template-setting")
+public class TemplateSettingController {
+
+    @Autowired
+    private EmailTemplateMappingService emailTemplateMappingService;
+
+    /**
+     * 模版设置页面展示数据
+     * @param emailTemplateSettingPageQuery
+     * @return
+     */
+    @SystemLog(value = "模版设置页面展示数据")
+    @RequestMapping("search-template-setting-list")
+    public MybatisPage<EmailTemplateMappingVO> searchTemplateSettingList(EmailTemplateSettingPageQuery emailTemplateSettingPageQuery){
+        MybatisPage<EmailTemplateMappingVO> result = emailTemplateMappingService.searchTemplateSettingList(emailTemplateSettingPageQuery);
+        return result;
+    }
+
+
+    /**
+     * 批量删除模版设置
+     * @param idListVO
+     * @return
+     */
+    @SystemLog(value = "批量删除模版设置")
+    @RequestMapping("delete-template-setting")
+    public boolean deleteTemplateSetting(@RequestBody IdListVO idListVO){
+        emailTemplateMappingService.deleteTemplateSetting(idListVO);
+        return true;
+    }
+
+
+    /**
+     * 保存模版设置
+     * @param emailTemplateMappingVO
+     * @return
+     */
+    @SystemLog(value = "保存模版设置")
+    @RequestMapping("save-template-setting")
+    public boolean saveTemplateSetting(@RequestBody EmailTemplateMappingVO emailTemplateMappingVO){
+        emailTemplateMappingService.saveTemplateSetting(emailTemplateMappingVO);
+        return true;
+    }
+}

+ 23 - 0
service-manage/src/main/java/com/simuwang/manage/service/EmailTemplateInfoService.java

@@ -0,0 +1,23 @@
+package com.simuwang.manage.service;
+
+import com.simuwang.base.common.support.MybatisPage;
+import com.simuwang.base.pojo.dto.query.EmailTemplateInfoPageQuery;
+import com.simuwang.base.pojo.vo.EmailTemplateInfoVO;
+import com.simuwang.base.pojo.vo.IdListVO;
+import com.simuwang.base.pojo.vo.SaveTemplateInfoVO;
+
+/**
+ * FileName: EmailTemplateInfoService
+ * Author:   chenjianhua
+ * Date:     2024/9/25 18:50
+ * Description: ${DESCRIPTION}
+ */
+public interface EmailTemplateInfoService {
+    MybatisPage<EmailTemplateInfoVO> searchTemplateList(EmailTemplateInfoPageQuery emailTemplateInfoPageQuery);
+
+    void deleteTemplateList(IdListVO idListVO);
+
+    void saveTemplateList(SaveTemplateInfoVO saveTemplateInfoVO);
+
+    void deleteApplicationRuleList(IdListVO idListVO);
+}

+ 20 - 0
service-manage/src/main/java/com/simuwang/manage/service/EmailTemplateMappingService.java

@@ -0,0 +1,20 @@
+package com.simuwang.manage.service;
+
+import com.simuwang.base.common.support.MybatisPage;
+import com.simuwang.base.pojo.dto.query.EmailTemplateSettingPageQuery;
+import com.simuwang.base.pojo.vo.EmailTemplateMappingVO;
+import com.simuwang.base.pojo.vo.IdListVO;
+
+/**
+ * FileName: EmailTemplateMappingService
+ * Author:   chenjianhua
+ * Date:     2024/9/25 20:25
+ * Description: ${DESCRIPTION}
+ */
+public interface EmailTemplateMappingService {
+    MybatisPage<EmailTemplateMappingVO> searchTemplateSettingList(EmailTemplateSettingPageQuery emailTemplateSettingPageQuery);
+
+    void deleteTemplateSetting(IdListVO idListVO);
+
+    void saveTemplateSetting(EmailTemplateMappingVO emailTemplateMappingVO);
+}

+ 1 - 1
service-manage/src/main/java/com/simuwang/manage/service/impl/DeletionServiceImpl.java

@@ -179,7 +179,7 @@ public class DeletionServiceImpl implements DeletionService {
             if(sumDistribute == null){
                 sumDistribute = new BigDecimal(0);
             }
-            //不存在分红的时候,判断当前的差值是否符合要求
+            //判断当前的差值是否符合要求
             BigDecimal difference = cumulativeNavWithdrawal.subtract(nav.add(sumDistribute));
             if(difference.compareTo(threshold) > 0){
                 //存在缺失

+ 195 - 0
service-manage/src/main/java/com/simuwang/manage/service/impl/EmailTemplateInfoServiceImpl.java

@@ -0,0 +1,195 @@
+package com.simuwang.manage.service.impl;
+
+import com.simuwang.base.common.support.MybatisPage;
+import com.simuwang.base.common.util.DateUtils;
+import com.simuwang.base.common.util.StringUtil;
+import com.simuwang.base.mapper.EmailTemplateApplicationRuleMapper;
+import com.simuwang.base.mapper.EmailTemplateDataRuleMapper;
+import com.simuwang.base.mapper.EmailTemplateInfoMapper;
+import com.simuwang.base.pojo.dos.EmailTemplateApplicationRuleDO;
+import com.simuwang.base.pojo.dos.EmailTemplateDataRuleDO;
+import com.simuwang.base.pojo.dos.EmailTemplateInfoDO;
+import com.simuwang.base.pojo.dto.query.EmailTemplateInfoPageQuery;
+import com.simuwang.base.pojo.vo.*;
+import com.simuwang.manage.service.EmailTemplateInfoService;
+import com.simuwang.shiro.utils.UserUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * FileName: EmailTemplateInfoServiceImpl
+ * Author:   chenjianhua
+ * Date:     2024/9/25 18:50
+ * Description: ${DESCRIPTION}
+ */
+@Service
+public class EmailTemplateInfoServiceImpl implements EmailTemplateInfoService {
+
+    @Autowired
+    private EmailTemplateInfoMapper emailTemplateInfoMapper;
+
+    @Autowired
+    private EmailTemplateDataRuleMapper emailTemplateDataRuleMapper;
+
+    @Autowired
+    private EmailTemplateApplicationRuleMapper emailTemplateApplicationRuleMapper;
+
+    @Override
+    public MybatisPage<EmailTemplateInfoVO> searchTemplateList(EmailTemplateInfoPageQuery emailTemplateInfoPageQuery) {
+        List<EmailTemplateInfoDO> emailTemplateInfoDOList = emailTemplateInfoMapper.searchTemplateList(emailTemplateInfoPageQuery);
+        List<EmailTemplateInfoVO> emailTemplateInfoVOList = emailTemplateInfoDOList.stream().map(EmailTemplateInfoDO::toVO).collect(Collectors.toList());
+        long total = emailTemplateInfoMapper.countTemplateList(emailTemplateInfoPageQuery);
+        return MybatisPage.of(total,emailTemplateInfoVOList);
+    }
+
+    @Override
+    public void deleteTemplateList(IdListVO idListVO) {
+        Integer userId = UserUtils.getLoginUser().getUserId();
+        List<Integer> idList = idListVO.getIdList();
+        emailTemplateInfoMapper.deleteTemplateList(idList,userId);
+        emailTemplateApplicationRuleMapper.deleteByTemplateId(idList,userId);
+        emailTemplateDataRuleMapper.deleteByTemplateId(idList,userId);
+    }
+
+    @Override
+    public void saveTemplateList(SaveTemplateInfoVO saveTemplateInfoVO) {
+        EmailTemplateInfoVO emailTemplateInfoVO = saveTemplateInfoVO.getEmailTemplateInfoVO();
+        EmailTemplateInfoDO emailDeletionInfoDO = toEmailTemplateInfoDO(emailTemplateInfoVO);
+        Integer templateId;
+        if(StringUtil.isNull(emailDeletionInfoDO.getId())){
+            //保存
+            templateId = emailTemplateInfoMapper.saveTemplateInfo(emailDeletionInfoDO);
+            List<EmailTemplateDataRuleVO> emailTemplateDataRuleVOList = saveTemplateInfoVO.getEmailTemplateDataRuleVOList();
+            if(emailTemplateDataRuleVOList.size() > 0){
+                emailTemplateDataRuleVOList.forEach(e -> e.setTemplateId(templateId));
+                List<EmailTemplateDataRuleDO> emailTemplateDataRuleDOList = new ArrayList<>();
+                for(EmailTemplateDataRuleVO dataRuleVO : emailTemplateDataRuleVOList){
+                    EmailTemplateDataRuleDO emailTemplateDataRuleDO = toEmailTemplateDataRuleDO(dataRuleVO);
+                    emailTemplateDataRuleDOList.add(emailTemplateDataRuleDO);
+                }
+                emailTemplateDataRuleMapper.batchInsert(emailTemplateDataRuleDOList);
+            }
+            List<EmailTemplateApplicationRuleVO> emailTemplateApplicationRuleVOList = saveTemplateInfoVO.getEmailTemplateApplicationRuleVOList();
+            if(emailTemplateApplicationRuleVOList.size() > 0){
+                emailTemplateApplicationRuleVOList.forEach(e -> e.setTemplateId(templateId));
+                List<EmailTemplateApplicationRuleDO> templateApplicationRuleDOList = new ArrayList<>();
+                for(EmailTemplateApplicationRuleVO applicationRuleVO : emailTemplateApplicationRuleVOList){
+                    EmailTemplateApplicationRuleDO applicationRuleDO = toEmailTemplateApplicationRuleDO(applicationRuleVO);
+                    templateApplicationRuleDOList.add(applicationRuleDO);
+                }
+                emailTemplateApplicationRuleMapper.batchInsert(templateApplicationRuleDOList);
+            }
+        }else{
+            templateId = emailDeletionInfoDO.getId();
+            emailTemplateInfoMapper.updateTemplateInfo(emailDeletionInfoDO);
+            List<EmailTemplateDataRuleVO> emailTemplateDataRuleVOList = saveTemplateInfoVO.getEmailTemplateDataRuleVOList();
+            if(emailTemplateDataRuleVOList.size() > 0){
+                emailTemplateDataRuleVOList.forEach(e -> e.setTemplateId(templateId));
+                List<EmailTemplateDataRuleDO> addList = new ArrayList<>();
+                List<EmailTemplateDataRuleDO> editList = new ArrayList<>();
+                for(EmailTemplateDataRuleVO dataRuleVO : emailTemplateDataRuleVOList){
+                    EmailTemplateDataRuleDO emailTemplateDataRuleDO = toEmailTemplateDataRuleDO(dataRuleVO);
+                    if(StringUtil.isNull(emailTemplateDataRuleDO.getId())){
+                        addList.add(emailTemplateDataRuleDO);
+                    }else{
+                        addList.add(emailTemplateDataRuleDO);
+                    }
+                }
+                if(addList.size() > 0){
+                    emailTemplateDataRuleMapper.batchInsert(addList);
+                }
+                if(editList.size() > 0){
+                    emailTemplateDataRuleMapper.batchUpdate(editList);
+                }
+            }
+            List<EmailTemplateApplicationRuleVO> emailTemplateApplicationRuleVOList = saveTemplateInfoVO.getEmailTemplateApplicationRuleVOList();
+            if(emailTemplateApplicationRuleVOList.size() > 0){
+                emailTemplateApplicationRuleVOList.forEach(e -> e.setTemplateId(templateId));
+                List<EmailTemplateApplicationRuleDO> addList = new ArrayList<>();
+                List<EmailTemplateApplicationRuleDO> editList = new ArrayList<>();
+                for(EmailTemplateApplicationRuleVO applicationRuleVO : emailTemplateApplicationRuleVOList){
+                    EmailTemplateApplicationRuleDO applicationRuleDO = toEmailTemplateApplicationRuleDO(applicationRuleVO);
+                    if(StringUtil.isNull(applicationRuleDO.getId())){
+                        addList.add(applicationRuleDO);
+                    }else{
+                        editList.add(applicationRuleDO);
+                    }
+                }
+                if(addList.size() > 0){
+                    emailTemplateApplicationRuleMapper.batchInsert(addList);
+                }
+                if(editList.size() > 0){
+                    emailTemplateApplicationRuleMapper.batchUpdate(editList);
+                }
+            }
+
+        }
+    }
+
+    @Override
+    public void deleteApplicationRuleList(IdListVO idListVO) {
+        Integer userId = UserUtils.getLoginUser().getUserId();
+        emailTemplateApplicationRuleMapper.deleteByIdList(idListVO.getIdList(),userId);
+    }
+
+    private EmailTemplateApplicationRuleDO toEmailTemplateApplicationRuleDO(EmailTemplateApplicationRuleVO applicationRuleVO) {
+        Integer userId = UserUtils.getLoginUser().getUserId();
+        EmailTemplateApplicationRuleDO applicationRuleDO = new EmailTemplateApplicationRuleDO();
+        applicationRuleDO.setId(applicationRuleVO.getId());
+        applicationRuleDO.setTemplateId(applicationRuleVO.getTemplateId());
+        applicationRuleDO.setColumn(applicationRuleVO.getColumn());
+        applicationRuleDO.setRow(applicationRuleVO.getRow());
+        applicationRuleDO.setContainKeyword(applicationRuleVO.getContainKeyword());
+        applicationRuleDO.setNotContainKeyword(applicationRuleVO.getNotContainKeyword());
+        applicationRuleDO.setIsvalid(1);
+        applicationRuleDO.setType(applicationRuleVO.getType());
+        applicationRuleDO.setUpdaterId(userId);
+        applicationRuleDO.setUpdateTime(DateUtils.getNowDate());
+        if(StringUtil.isNull(applicationRuleDO.getId())){
+            applicationRuleDO.setCreateTime(DateUtils.getNowDate());
+            applicationRuleDO.setCreatorId(userId);
+        }
+        return applicationRuleDO;
+    }
+
+    private EmailTemplateDataRuleDO toEmailTemplateDataRuleDO(EmailTemplateDataRuleVO dataRuleVO) {
+        Integer userId = UserUtils.getLoginUser().getUserId();
+        EmailTemplateDataRuleDO emailTemplateDataRuleDO = new EmailTemplateDataRuleDO();
+        emailTemplateDataRuleDO.setTemplateId(dataRuleVO.getTemplateId());
+        emailTemplateDataRuleDO.setId(dataRuleVO.getId());
+        emailTemplateDataRuleDO.setFieldRule(dataRuleVO.getFieldRule());
+        emailTemplateDataRuleDO.setColumn(dataRuleVO.getColumn());
+        emailTemplateDataRuleDO.setRow(dataRuleVO.getRow());
+        emailTemplateDataRuleDO.setPosition(dataRuleVO.getPosition());
+        emailTemplateDataRuleDO.setUnitConvert(dataRuleVO.getUnitConvert());
+        emailTemplateDataRuleDO.setIsvalid(1);
+        emailTemplateDataRuleDO.setUpdaterId(userId);
+        emailTemplateDataRuleDO.setUpdateTime(DateUtils.getNowDate());
+        if(StringUtil.isNull(dataRuleVO.getId())){
+            emailTemplateDataRuleDO.setCreateTime(DateUtils.getNowDate());
+            emailTemplateDataRuleDO.setCreatorId(userId);
+        }
+        return emailTemplateDataRuleDO;
+    }
+
+    private EmailTemplateInfoDO toEmailTemplateInfoDO(EmailTemplateInfoVO emailTemplateInfoVO) {
+        Integer userId = UserUtils.getLoginUser().getUserId();
+        EmailTemplateInfoDO emailDeletionInfoDO = new EmailTemplateInfoDO();
+        emailDeletionInfoDO.setId(emailTemplateInfoVO.getId());
+        emailDeletionInfoDO.setName(emailTemplateInfoVO.getName());
+        emailDeletionInfoDO.setStatus(emailTemplateInfoVO.getStatus());
+        emailDeletionInfoDO.setDescription(emailTemplateInfoVO.getDescription());
+        emailDeletionInfoDO.setIsvalid(1);
+        emailDeletionInfoDO.setUpdateTime(DateUtils.getNowDate());
+        emailDeletionInfoDO.setUpdaterId(userId);
+        if(StringUtil.isNull(emailTemplateInfoVO.getId())){
+            emailDeletionInfoDO.setCreateTime(DateUtils.getNowDate());
+            emailDeletionInfoDO.setCreatorId(userId);
+        }
+        return emailDeletionInfoDO;
+    }
+}

+ 73 - 0
service-manage/src/main/java/com/simuwang/manage/service/impl/EmailTemplateMappingServiceImpl.java

@@ -0,0 +1,73 @@
+package com.simuwang.manage.service.impl;
+
+import com.simuwang.base.common.support.MybatisPage;
+import com.simuwang.base.common.util.DateUtils;
+import com.simuwang.base.common.util.StringUtil;
+import com.simuwang.base.mapper.EmailTemplateMappingMapper;
+import com.simuwang.base.pojo.dos.EmailTemplateMappingDO;
+import com.simuwang.base.pojo.dto.query.EmailTemplateSettingPageQuery;
+import com.simuwang.base.pojo.vo.EmailTemplateMappingVO;
+import com.simuwang.base.pojo.vo.IdListVO;
+import com.simuwang.manage.service.EmailTemplateMappingService;
+import com.simuwang.shiro.utils.UserUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * FileName: EmailTemplateMappingServiceImpl
+ * Author:   chenjianhua
+ * Date:     2024/9/25 20:25
+ * Description: ${DESCRIPTION}
+ */
+@Service
+public class EmailTemplateMappingServiceImpl implements EmailTemplateMappingService {
+    @Autowired
+    private EmailTemplateMappingMapper emailTemplateMappingMapper;
+
+    @Override
+    public MybatisPage<EmailTemplateMappingVO> searchTemplateSettingList(EmailTemplateSettingPageQuery emailTemplateSettingPageQuery) {
+        List<EmailTemplateMappingDO> emailTemplateMappingDOList = emailTemplateMappingMapper.searchTemplateSettingList(emailTemplateSettingPageQuery);
+        List<EmailTemplateMappingVO> emailTemplateMappingVOList = emailTemplateMappingDOList.stream().map(EmailTemplateMappingDO::toVO).collect(Collectors.toList());
+        long total = emailTemplateMappingMapper.countTemplateSettingList(emailTemplateSettingPageQuery);
+        return MybatisPage.of(total,emailTemplateMappingVOList);
+    }
+
+    @Override
+    public void deleteTemplateSetting(IdListVO idListVO) {
+        Integer userId = UserUtils.getLoginUser().getUserId();
+        emailTemplateMappingMapper.deleteTemplateSetting(idListVO.getIdList(),userId);
+    }
+
+    @Override
+    public void saveTemplateSetting(EmailTemplateMappingVO emailTemplateMappingVO) {
+        EmailTemplateMappingDO emailTemplateMappingDO = toEmailTemplateMappingDO(emailTemplateMappingVO);
+        if(StringUtil.isNull(emailTemplateMappingDO.getId())){
+            emailTemplateMappingMapper.updateEmailTemplateMappingDO(emailTemplateMappingDO);
+        }else{
+            emailTemplateMappingMapper.saveEmailTemplateMappingDO(emailTemplateMappingDO);
+        }
+    }
+
+    private EmailTemplateMappingDO toEmailTemplateMappingDO(EmailTemplateMappingVO vo) {
+        Integer userId = UserUtils.getLoginUser().getUserId();
+        EmailTemplateMappingDO emailTemplateMappingDO = new EmailTemplateMappingDO();
+        emailTemplateMappingDO.setEmail(vo.getEmail());
+        emailTemplateMappingDO.setId(vo.getId());
+        emailTemplateMappingDO.setTemplateId(vo.getTemplateId());
+        emailTemplateMappingDO.setTemplateName(vo.getTemplateName());
+        emailTemplateMappingDO.setStatus(vo.getStatus());
+        emailTemplateMappingDO.setTitle(vo.getTitle());
+        emailTemplateMappingDO.setCompanyName(vo.getCompanyName());
+        emailTemplateMappingDO.setUpdateTime(DateUtils.getNowDate());
+        emailTemplateMappingDO.setIsvalid(1);
+        emailTemplateMappingDO.setUpdaterId(userId);
+        if(StringUtil.isNull(emailTemplateMappingDO.getId())){
+            emailTemplateMappingDO.setCreateTime(DateUtils.getNowDate());
+            emailTemplateMappingDO.setCreatorId(userId);
+        }
+        return emailTemplateMappingDO;
+    }
+}

+ 3 - 6
service-manage/src/main/java/com/simuwang/manage/service/impl/FundAliasServiceImpl.java

@@ -18,6 +18,7 @@ import com.simuwang.shiro.utils.UserUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
+import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
 import java.util.stream.Collectors;
@@ -57,15 +58,11 @@ public class FundAliasServiceImpl implements FundAliasService {
         List<FundAliasVO> fundAliasVOList =  fundAliasDOList.stream().map(FundAliasDO::toVo).collect(Collectors.toList());
         for(FundAliasVO vo : fundAliasVOList){
             //异常净值数量
-            Integer navTotal = emailFundNavMapper.countNoStoreNav(vo.getSourceFundName());
+            Integer navTotal = emailFundNavMapper.countNoStoreNav(vo.getSourceFundName(),vo.getSourceRegisterNumber());
             vo.setNavTotal(navTotal);
             //异常净值数量
-            Integer assetTotal = emailFundAssetMapper.countNoStoreAsset(vo.getSourceFundName());
+            Integer assetTotal = emailFundAssetMapper.countNoStoreAsset(vo.getSourceFundName(),vo.getSourceRegisterNumber());
             vo.setAssetTotal(assetTotal);
-            //管理人
-            if(vo.getTargetFundId() !=null){
-                vo.setCompanyName(companyInformationMapper.getCompanyNameByFundId(vo.getTargetFundId()));
-            }
             //最新净值日期
             vo.setPriceDate(emailFundNavMapper.getMaxPriceDate(vo.getSourceFundName()));
         }