package com.simuwang.manage.task; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.ListUtil; import cn.hutool.core.date.DateUtil; import cn.hutool.core.exceptions.ExceptionUtil; import cn.hutool.core.util.StrUtil; import com.alibaba.excel.EasyExcel; import com.simuwang.base.common.conts.DateConst; import com.simuwang.base.common.util.EmailUtil; import com.simuwang.base.config.CompetitionConfig; import com.simuwang.base.mapper.RcCompetitionCalcDateMapper; import com.simuwang.base.mapper.RcCompetitionTaskDateMapper; import com.simuwang.base.pojo.dos.RcCompetitionCalcDateDO; import com.simuwang.base.pojo.dos.RcCompetitionTaskDateDO; import com.simuwang.base.pojo.dto.FundNavDataDTO; import com.simuwang.base.pojo.dto.FundNavDeletionDTO; import com.simuwang.base.pojo.dto.MailboxInfoDTO; import com.simuwang.base.pojo.dto.competition.CompetitionBaseResultDTO; import com.simuwang.manage.service.EmailSystemConfigService; import com.simuwang.manage.service.competition.FundNavService; import com.simuwang.task.CompetitionIndicatorCalcTask; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.stereotype.Component; import java.io.File; import java.util.Date; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @Component public class CompetitionTask { private static final Logger log = LoggerFactory.getLogger(CompetitionTask.class); private final FundNavService fundNavService; private final CompetitionConfig competitionConfig; private final EmailSystemConfigService emailSystemConfigService; private final RcCompetitionTaskDateMapper competitionTaskDateMapper; private final RcCompetitionCalcDateMapper competitionCalcDateMapper; private final FundDeletionTask fundDeletionTask; private final CompetitionIndicatorCalcTask competitionIndicatorCalcTask; private final ThreadPoolTaskExecutor asyncExecutor; public CompetitionTask(FundNavService fundNavService, CompetitionConfig competitionConfig, EmailSystemConfigService emailSystemConfigService, RcCompetitionTaskDateMapper competitionTaskDateMapper, RcCompetitionCalcDateMapper competitionCalcDateMapper, FundDeletionTask fundDeletionTask, CompetitionIndicatorCalcTask competitionIndicatorCalcTask, @Qualifier("asyncExecutor") ThreadPoolTaskExecutor asyncExecutor) { this.fundNavService = fundNavService; this.competitionConfig = competitionConfig; this.emailSystemConfigService = emailSystemConfigService; this.competitionTaskDateMapper = competitionTaskDateMapper; this.competitionCalcDateMapper = competitionCalcDateMapper; this.fundDeletionTask = fundDeletionTask; this.competitionIndicatorCalcTask = competitionIndicatorCalcTask; this.asyncExecutor = asyncExecutor; } public String getResult(Integer type, Integer competitionId, String period) { asyncExecutor.execute(() -> { if (type == 1) { outputFundNavDetail(competitionId, period); } else if (type == 2) { outputFundNavDeletion(competitionId, period, true); } else if (type == 3) { List calcDateDOList = competitionCalcDateMapper.queryByPriod(ListUtil.toList(period), competitionId); if (CollUtil.isNotEmpty(calcDateDOList)) { outputCompetitionResult(competitionId, period, calcDateDOList.get(0)); } } }); return "操作成功,请等到结果输出..."; } /** * 输出基金净值采集结果明细任务 * 每天10:00,15:00执行任务 */ @Scheduled(cron = "0 0 10,15 * * ?") public void fundNavDataTask() { Integer competitionId = competitionConfig.getId(); String date = DateUtil.format(new Date(), DateConst.YYYY_MM_DD); List taskDateDOList = competitionTaskDateMapper.queryByNavDetailDate(date, competitionId); if (CollUtil.isEmpty(taskDateDOList)) { return; } for (RcCompetitionTaskDateDO taskDateDO : taskDateDOList) { String period = taskDateDO.getPriod(); outputFundNavDetail(competitionId, period); } } /** * 输出基金净值缺失明细任务 * 每天10:00,15:00执行任务 */ @Scheduled(cron = "0 0 10,15 * * ?") public void navDeletionTask() { Integer competitionId = competitionConfig.getId(); // 输出之前 -> 执行净值缺失检测 fundDeletionTask.computeDeletion(); String period = DateUtil.format(new Date(), DateConst.YYYY_MM); outputFundNavDeletion(competitionId, period, false); } /** * 输出基金净值衍生指标及排名结果明细任务 * 每天10:00,15:00执行任务 */ @Scheduled(cron = "0 0 10,15 * * ?") public void competitionResultTask() { Integer competitionId = competitionConfig.getId(); String date = DateUtil.format(new Date(), DateConst.YYYY_MM_DD); List taskDateDOList = competitionTaskDateMapper.queryByPriodDate(date, competitionId); if (CollUtil.isEmpty(taskDateDOList)) { return; } // 输出榜单之前 -> 执行净值缺失检测(确保净值不全的基金不参与榜单) fundDeletionTask.computeDeletion(); List periodList = taskDateDOList.stream().map(RcCompetitionTaskDateDO::getPriod).distinct().collect(Collectors.toList()); List calcDateDOList = competitionCalcDateMapper.queryByPriod(periodList, competitionId); Map periodCalcDataDoMap = calcDateDOList.stream().collect(Collectors.toMap(RcCompetitionCalcDateDO::getPriod, v -> v)); for (RcCompetitionTaskDateDO taskDateDO : taskDateDOList) { String period = taskDateDO.getPriod(); RcCompetitionCalcDateDO calcDateDO = periodCalcDataDoMap.get(period); outputCompetitionResult(competitionId, period, calcDateDO); } } public void outputFundNavDetail(Integer competitionId, String period) { List navDataDTOList = fundNavService.getFungNavData(competitionId); if (CollUtil.isEmpty(navDataDTOList)) { return; } String filePath = competitionConfig.getDirectory() + competitionConfig.getName() + "_" + period + "_基金净值采集结果明细_" + DateUtil.format(new Date(), DateConst.YYYYMMDD) + ".xlsx"; EasyExcel.write(filePath, FundNavDataDTO.class) .sheet("基金净值采集结果明细") .doWrite(navDataDTOList); log.info("基金净值采集结果明细表格已输出 -> 文件:{}", filePath); // 通过邮件发送"基金净值采集结果明细表格" if (competitionConfig.getMethod() == 1) { MailboxInfoDTO mailboxInfoDTO = emailSystemConfigService.getFromEmailInfo(); String receivingMailbox = emailSystemConfigService.getRecipientEmail(); if (mailboxInfoDTO == null || StrUtil.isBlank(receivingMailbox)) { log.info("未配置发件箱和收件箱,无法发送基金净值采集结果明细邮件"); return; } try { EmailUtil.senEmail(mailboxInfoDTO, receivingMailbox, new File(filePath), "基金净值采集结果明细", "", period + "_基金净值采集结果明细"); log.info("基金净值采集结果明细表 -> 邮件已发送"); } catch (Exception e) { log.error("邮件发送基金净值采集结果明细表异常 -> 堆栈信息:{}", ExceptionUtil.stacktraceToString(e)); } } } private void outputFundNavDeletion(Integer competitionId, String period, boolean isComputeDeletion) { String endDate = DateUtil.format(new Date(), DateConst.YYYY_MM_DD); // 输出榜单之前 -> 执行净值缺失检测(确保净值不全的基金不参与榜单) if (isComputeDeletion) { // fundDeletionTask.computeDeletion(); } List navDeletionDTOList = fundNavService.getFundNavDeletion(competitionId, endDate); if (CollUtil.isEmpty(navDeletionDTOList)) { return; } String filePath = competitionConfig.getDirectory() + competitionConfig.getName() + "_" + period + "_基金净值缺失明细_" + DateUtil.format(new Date(), DateConst.YYYYMMDD) + ".xlsx"; EasyExcel.write(filePath, FundNavDeletionDTO.class) .sheet("基金净值缺失明细") .doWrite(navDeletionDTOList); log.info("基金净值缺失明细表格已输出 -> 文件:{}", filePath); // 通过邮件发送"基金净值采集结果明细表格" if (competitionConfig.getMethod() == 1) { MailboxInfoDTO mailboxInfoDTO = emailSystemConfigService.getFromEmailInfo(); String receivingMailbox = emailSystemConfigService.getRecipientEmail(); if (mailboxInfoDTO == null || StrUtil.isBlank(receivingMailbox)) { log.info("未配置发件箱和收件箱,无法发送基金净值缺失明细邮件"); return; } try { EmailUtil.senEmail(mailboxInfoDTO, receivingMailbox, new File(filePath), "基金净值缺失明细", "", period + "_基金净值缺失明细"); log.info("基金净值缺失明细表 -> 邮件已发送"); } catch (Exception e) { log.error("邮件发送基金净值缺失明细表异常 -> 堆栈信息:{}", ExceptionUtil.stacktraceToString(e)); } } } private void outputCompetitionResult(Integer competitionId, String period, RcCompetitionCalcDateDO calcDateDO) { long startTime = System.currentTimeMillis(); // 输出榜单之前 -> 执行基金净值指标计算 competitionIndicatorCalcTask.calculateIndicator(competitionId, calcDateDO); List competitionResultDTOList = fundNavService.getCompetitionResult(competitionId, period); if (CollUtil.isEmpty(competitionResultDTOList)) { log.info("当前榜单:{}无结果数据", period); return; } Class aClass = competitionResultDTOList.get(0).getClass(); String filePath = competitionConfig.getDirectory() + competitionConfig.getName() + "_" + period + "_基金净值衍生指标及排名结果明细_" + DateUtil.format(new Date(), DateConst.YYYYMMDD) + ".xlsx"; EasyExcel.write(filePath, aClass) .sheet("基金净值衍生指标及排名结果明细") .doWrite(competitionResultDTOList); log.info("基金净值衍生指标及排名结果明细表已输出 -> 文件:{},耗时:{}", filePath, (System.currentTimeMillis() - startTime)); Integer method = competitionConfig.getMethod(); // 通过邮件发送"基金净值采集结果明细表格" if (method == 1) { MailboxInfoDTO mailboxInfoDTO = emailSystemConfigService.getFromEmailInfo(); String receivingMailbox = emailSystemConfigService.getRecipientEmail(); if (mailboxInfoDTO == null || StrUtil.isBlank(receivingMailbox)) { log.info("未配置发件箱和收件箱,无法发送基金净值衍生指标及排名结果明细邮件"); return; } try { String emailTitle = period + "_基金净值衍生指标及排名结果明细"; EmailUtil.senEmail(mailboxInfoDTO, receivingMailbox, new File(filePath), emailTitle, "", emailTitle); log.info("基金净值衍生指标及排名结果明细表 -> 邮件已发送"); } catch (Exception e) { log.error("邮件发送基金净值衍生指标及排名结果明细表异常 -> 堆栈信息:{}", ExceptionUtil.stacktraceToString(e)); } } } }