package com.ycwl.basic.task; import cn.hutool.core.date.DateUtil; import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2DTO; import com.ycwl.basic.mapper.ScenicDeviceStatsMapper; import com.ycwl.basic.mapper.StatisticsMapper; import com.ycwl.basic.model.mobile.statistic.req.CommonQueryReq; import com.ycwl.basic.model.mobile.statistic.resp.AppStatisticsFunnelVO; import com.ycwl.basic.model.pc.scenic.req.ScenicReqQuery; import com.ycwl.basic.model.pc.scenicDeviceStats.entity.ScenicDeviceStatsEntity; import com.ycwl.basic.repository.ScenicRepository; import com.ycwl.basic.service.mobile.AppStatisticsService; import com.ycwl.basic.utils.ApiResponse; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Profile; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import java.util.Date; import java.util.List; @Slf4j @Component @EnableScheduling @Profile("prod") public class ScenicStatsTask { @Autowired private ScenicDeviceStatsMapper mapper; @Autowired private StatisticsMapper statisticsMapper; @Autowired private AppStatisticsService statisticsService; @Autowired private ScenicRepository scenicRepository; @Autowired private RedisTemplate redisTemplate; @Scheduled(cron = "0 1 0 * * *") public void countDeviceStats() { Date yesterdayStart = DateUtil.beginOfDay(DateUtil.yesterday()); Date yesterdayEnd = DateUtil.endOfDay(yesterdayStart); Date twoDaysBeforeStart = DateUtil.beginOfDay(DateUtil.offsetDay(DateUtil.yesterday(), -1)); Date twoDaysBeforeEnd = DateUtil.endOfDay(twoDaysBeforeStart); // 前天的数据 List list = mapper.countDeviceStats(twoDaysBeforeStart, twoDaysBeforeEnd); if (!list.isEmpty()) { list.forEach(stats -> { stats.setDate(twoDaysBeforeStart); mapper.insert(stats); }); } list = mapper.countDeviceStats(yesterdayStart, yesterdayEnd); if (!list.isEmpty()) { list.forEach(stats -> { stats.setDate(yesterdayStart); mapper.insert(stats); }); } } @Scheduled(cron = "0 0 2 * * *") public void countScenicStats() { log.info("开始执行景区统计任务,统计前7天至昨天的数据"); // 获取所有景区列表 ScenicReqQuery query = new ScenicReqQuery(); query.setPageSize(1000); List scenicList = scenicRepository.list(query); // 循环统计前7天(至昨天)的数据 for (int daysAgo = 1; daysAgo <= 7; daysAgo++) { Date targetDate = DateUtil.offsetDay(new Date(), -daysAgo); Date startTime = DateUtil.beginOfDay(targetDate); Date endTime = DateUtil.endOfDay(targetDate); log.info("正在统计第{}天前的数据,日期: {}", daysAgo, DateUtil.formatDate(startTime)); scenicList.forEach((scenic) -> { try { CommonQueryReq commonQueryReq = new CommonQueryReq(); Long scenicId = Long.valueOf(scenic.getId()); commonQueryReq.setScenicId(scenicId); commonQueryReq.setStartTime(startTime); commonQueryReq.setEndTime(endTime); commonQueryReq.setRealtime(true); // 执行统计查询 ApiResponse resp = statisticsService.userConversionFunnel(commonQueryReq); AppStatisticsFunnelVO data = resp.getData(); // 写入数据库(REPLACE INTO 会自动更新已存在的记录) statisticsMapper.insertStat(scenicId, startTime, data); // 删除该景区的缓存,确保下次查询时获取最新数据 invalidateStatisticsCache(scenicId); } catch (Exception e) { log.error("统计景区 {} 在日期 {} 的数据时发生错误", scenic.getId(), DateUtil.formatDate(startTime), e); } }); log.info("第{}天前的数据统计完成,日期: {}", daysAgo, DateUtil.formatDate(startTime)); } log.info("景区统计任务执行完成"); } /** * 删除景区统计缓存 * @param scenicId 景区ID */ private void invalidateStatisticsCache(Long scenicId) { String redisKey = "statistics:tmp_cache:" + scenicId; redisTemplate.delete(redisKey); } }