You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

410 lines
19 KiB

2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
  1. package com.example.demo.serviceImpl;
  2. import com.example.demo.domain.entity.Statistics;
  3. import com.example.demo.domain.entity.UserGoldRecord;
  4. import com.example.demo.mapper.StatisticsMapper;
  5. import com.example.demo.service.GeneralService;
  6. import com.example.demo.service.StatisticsService;
  7. import com.example.demo.service.WorkbenchService;
  8. import org.slf4j.Logger;
  9. import org.slf4j.LoggerFactory;
  10. import org.springframework.beans.factory.annotation.Autowired;
  11. import org.springframework.scheduling.annotation.Scheduled;
  12. import org.springframework.stereotype.Service;
  13. import java.time.LocalDate;
  14. import java.time.LocalDateTime;
  15. import java.time.LocalTime;
  16. import java.time.ZoneId;
  17. import java.time.format.DateTimeFormatter;
  18. import java.util.*;
  19. /**
  20. * @program: gold-java
  21. * @ClassName StatisticsServiceImpl
  22. * @description: 统计相关
  23. * @author: Ethan
  24. * @create: 202506-18 12:00
  25. * @Version 1.0
  26. **/
  27. @Service
  28. public class StatisticsServiceImpl implements StatisticsService {
  29. private static final Logger log = LoggerFactory.getLogger(StatisticsServiceImpl.class);
  30. @Autowired
  31. private StatisticsMapper statisticsMapper;
  32. @Autowired
  33. private GeneralService generalService;
  34. @Autowired
  35. private WorkbenchService workbenchService;
  36. /*
  37. 每小时第十分执行定时任务更新当天part1数据
  38. */
  39. @Override
  40. @Scheduled(cron = "0 10 * * * ?") // 每小时执行一次
  41. public void runHourlyTaskPart1() {
  42. Date today = new Date(); //取当天日期
  43. for(String market : generalService.getMarket()){
  44. saveStatisticsPart1(market,today);
  45. }
  46. }
  47. /*
  48. 每小时执行定时任务更新当天part2数据
  49. */
  50. @Override
  51. @Scheduled(cron = "0 10 * * * ?") // 每小时执行一次
  52. public void runHourlyTaskPart2() {
  53. Date today = new Date(); //取当天日期
  54. for(String market : generalService.getMarket()){
  55. saveStatisticsPart2(market,today);
  56. }
  57. }
  58. /*
  59. 每小时执行定时任务更新年度数据
  60. */
  61. @Override
  62. @Scheduled(cron = "0 10 * * * ?") // 每小时执行一次
  63. public void runHourlyTaskYear() {
  64. Date today = new Date();
  65. // 获取当前日期
  66. LocalDate today1 = LocalDate.now();
  67. // 获取当前年份的第一天
  68. LocalDate firstDayOfYear = today1.withDayOfYear(1);
  69. // 将年份的第一天日期转换为Date类型
  70. Date yearlyStartDate=Date.from(firstDayOfYear.atStartOfDay(ZoneId.systemDefault()).toInstant());
  71. for(String market : generalService.getMarket()){
  72. saveStatisticsYear(market,yearlyStartDate,today);
  73. }
  74. }
  75. /*
  76. 0点执行定时任务更新近一周part2数据
  77. */
  78. @Override
  79. @Scheduled(cron = "0 30 0 * * ?") // 修改为每天 00:30 执行
  80. public void runDailyTaskPart2() {
  81. Calendar cal = Calendar.getInstance();
  82. cal.add(Calendar.DAY_OF_YEAR, -7); // 一周前
  83. Date startDate = cal.getTime();
  84. Date yesterday = generalService.getYesterday(); // 昨天
  85. // 获取 Calendar 实例并设置为昨天的日期
  86. Calendar calendar = Calendar.getInstance();
  87. calendar.setTime(yesterday);
  88. // 设置时间为昨天的23:59:55
  89. calendar.set(Calendar.HOUR_OF_DAY, 23);
  90. calendar.set(Calendar.MINUTE, 59);
  91. calendar.set(Calendar.SECOND, 55);
  92. //把yesterday的结束时间设为结束时间
  93. Date endDate= calendar.getTime();
  94. //近一周的日期列表
  95. List<Date> dateList =generalService.getAllDatesBetween(startDate, endDate);
  96. for (Date date : dateList) {
  97. for (String market : generalService.getMarket()) {
  98. saveStatisticsPart2(market, date);
  99. }
  100. }
  101. }
  102. /*
  103. 查询某地区某天已存在的统计数据
  104. */
  105. @Override
  106. public Statistics getExistStatistics(String market, Date date) {
  107. LocalDateTime startTime = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime().with(LocalTime.MIN);
  108. LocalDateTime endTime= startTime.plusDays(1).minusSeconds(1);
  109. return statisticsMapper.selectByMarketAndDate(market,
  110. Date.from(startTime.atZone(ZoneId.systemDefault()).toInstant()),
  111. Date.from(endTime.atZone(ZoneId.systemDefault()).toInstant()));
  112. }
  113. /*
  114. 新增或更新或不修改某地区某天part1统计数据
  115. */
  116. @Override
  117. public void saveStatisticsPart1(String market, Date date) {
  118. //获取该地区该日期part1(余量属性)统计数据
  119. Statistics newStats=getStatisticsPart1(market,date);
  120. //获取该地区该日期已存在的数据
  121. Statistics existStats = getExistStatistics(market, date);
  122. //判断是否存在已存在的数据
  123. if(existStats==null){
  124. //没有记录,新增
  125. statisticsMapper.insertPart1(newStats );
  126. }else {
  127. //判断新旧数据part1部分(余量属性)是否一致
  128. if (!isSameStatisticsPart1(existStats,newStats)){
  129. statisticsMapper.updatePart1(newStats);
  130. }else{
  131. System.out.println("数据未发生改变");
  132. }
  133. }
  134. }
  135. /*
  136. 新增或更新或不修改某地区某天年度统计数据
  137. */
  138. @Override
  139. public void saveStatisticsYear(String market,Date yearlyStartDate, Date date) {
  140. //获取该地区该日期年度统计数据
  141. Statistics newStats=getYearlyStatistics(market,yearlyStartDate,date);
  142. //获取该地区该日期已存在的数据
  143. Statistics existStats = getExistStatistics(market, date);
  144. //判断是否存在已存在的数据
  145. if(existStats==null){
  146. //没有记录,新增
  147. statisticsMapper.insertYear(newStats );
  148. }else {
  149. //判断新旧数据年度部分是否一致
  150. if (!isSameStatisticsYear(existStats,newStats)){
  151. statisticsMapper.updateYear(newStats);
  152. }else{
  153. System.out.println("数据未发生改变");
  154. }
  155. }
  156. }
  157. /*
  158. 新增或更新或不修改某地区某天part2统计数据
  159. */
  160. @Override
  161. public void saveStatisticsPart2(String market, Date date){
  162. //获取该地区该日期part2(余量外属性)统计数据
  163. Statistics newStats=getStatisticsPart2(market,date);
  164. //获取该地区该日期已存在的数据
  165. Statistics existStats = getExistStatistics(market, date);
  166. //判断是否存在已存在的数据
  167. if(existStats==null){
  168. //没有记录,新增
  169. statisticsMapper.insertPart2(newStats );
  170. }else {
  171. //判断新旧数据part2部分(余量外属性)是否一致
  172. if (!isSameStatisticsPart2(existStats,newStats)){
  173. statisticsMapper.updatePart2(newStats);
  174. }else{
  175. // existStats.setUpdateTime(date);
  176. // statisticsMapper.updatePart2(existStats);
  177. System.out.println("数据未发生改变");
  178. }
  179. }
  180. }
  181. @Override
  182. public Statistics getStatisticsPart1(String market, Date date) {
  183. //获取日期
  184. LocalDate localDate=date.toInstant()
  185. .atZone(ZoneId.of("Asia/Shanghai")) // 使用系统默认时区
  186. .toLocalDate();
  187. //初始化Statistics对象
  188. Statistics statistics = new Statistics();
  189. statistics.setMarket(market);
  190. statistics.setCurrentDatetime(localDate);
  191. //计算属性
  192. //当前金币余量
  193. Integer currentGold = statisticsMapper.sumCurrentPermanentGold(market)+
  194. statisticsMapper.sumCurrentFreeJune( market)+
  195. statisticsMapper.sumCurrentFreeDecember(market)+
  196. statisticsMapper.sumCurrentTaskGold( market);
  197. statistics.setCurrentGold(currentGold);
  198. //较前一日变化
  199. Date yesterday =generalService.getYesterday();
  200. //把yesterday改为昨天的开始时间和结束时间
  201. LocalDateTime startTime = yesterday.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime().with(LocalTime.MIN);
  202. LocalDateTime endTime= startTime.plusDays(1).minusSeconds(1);
  203. //昨天金币余量
  204. Statistics ydayStats = statisticsMapper.selectByMarketAndDate(market, Date.from(startTime.atZone(ZoneId.systemDefault()).toInstant()),
  205. Date.from(endTime.atZone(ZoneId.systemDefault()).toInstant()));
  206. Integer yesterdayGold=0;
  207. if (ydayStats != null) {
  208. yesterdayGold = ydayStats.getCurrentGold();
  209. }
  210. Integer dailyChange = currentGold - yesterdayGold;
  211. statistics.setDailyChange(dailyChange);
  212. //当前永久金币
  213. Integer currentPermanent = statisticsMapper.sumCurrentPermanentGold(market);
  214. statistics.setCurrentPermanent(currentPermanent);
  215. //当前免费六月金币
  216. Integer currentFreeJune = statisticsMapper.sumCurrentFreeJune(market);
  217. statistics.setCurrentFreeJune(currentFreeJune);
  218. //当前免费十二月金币
  219. Integer currentFreeDecember = statisticsMapper.sumCurrentFreeDecember(market);
  220. statistics.setCurrentFreeDecember(currentFreeDecember);
  221. //当前任务金币
  222. Integer currentTask = statisticsMapper.sumCurrentTaskGold(market);
  223. statistics.setCurrentTask(currentTask);
  224. return statistics;
  225. }
  226. /*
  227. 根据地区与日期获取part2(余量外属性)统计数据
  228. */
  229. @Override
  230. public Statistics getStatisticsPart2(String market, Date date) {
  231. //获取日期
  232. LocalDate localDate=date.toInstant()
  233. .atZone(ZoneId.of("Asia/Shanghai")) // 使用系统默认时区
  234. .toLocalDate();
  235. //把date改为当天的开始时间和结束时间
  236. LocalDateTime startTime = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime().with(LocalTime.MIN);
  237. LocalDateTime endTime= startTime.plusDays(1).minusSeconds(1);
  238. //定义审核状态列表
  239. List<Integer> auditStatusList = new ArrayList<>();
  240. auditStatusList.add(1); // 审核通过
  241. auditStatusList.add(3); // 外部传入默认通过
  242. //查询当天该地区审核通过的所有数据
  243. List<UserGoldRecord> records = statisticsMapper.findByMarketAndAuditStatus(market, auditStatusList,
  244. Date.from(startTime.atZone(ZoneId.systemDefault()).toInstant()),Date.from(endTime.atZone(ZoneId.systemDefault()).toInstant()));
  245. //初始化Statistics对象
  246. Statistics statistics = new Statistics();
  247. statistics.setMarket(market);
  248. statistics.setCurrentDatetime(localDate);
  249. //计算属性
  250. //充值相关-当日充值(永久+免费)
  251. Integer recharge = records.stream()
  252. .filter(record -> record.getType() == 0) // 类型为充值
  253. .mapToInt(record -> record.getPermanentGold() + record.getFreeJune() + record.getFreeDecember() + record.getTaskGold())
  254. .sum();
  255. statistics.setRecharge(recharge);
  256. //充值相关-当日金额(永久)
  257. Integer money = records.stream()
  258. .filter(record -> record.getType() == 0) // 类型为充值
  259. .mapToInt(UserGoldRecord::getPermanentGold)
  260. .sum();
  261. statistics.setMoney(money);
  262. //消费相关-当日新增消费(永久)
  263. Integer consumePermanent = records.stream()
  264. .filter(record -> record.getType() == 1) // 类型为消费
  265. .mapToInt(UserGoldRecord::getPermanentGold)
  266. .sum();
  267. statistics.setConsumePermanent(Math.abs(consumePermanent));
  268. //消费相关-当日新增消费(六月免费)
  269. Integer consumeFreeJune = records.stream()
  270. .filter(record -> record.getType() == 1) // 类型为消费
  271. .mapToInt(UserGoldRecord::getFreeJune)
  272. .sum();
  273. statistics.setConsumeFreeJune(Math.abs(consumeFreeJune));
  274. //消费相关-当日新增消费(十二月免费)
  275. Integer consumeFreeDecember = records.stream()
  276. .filter(record -> record.getType() == 1) // 类型为消费
  277. .mapToInt(UserGoldRecord::getFreeDecember)
  278. .sum();
  279. statistics.setConsumeFreeDecember(Math.abs(consumeFreeDecember));
  280. //消费相关-当日新增消费(任务)
  281. Integer consumeTask = records.stream()
  282. .filter(record -> record.getType() == 1) // 类型为消费
  283. .mapToInt(UserGoldRecord::getTaskGold)
  284. .sum();
  285. statistics.setConsumeTask(Math.abs(consumeTask)); // 使用 Math.abs 确保为正数
  286. //退款相关-当日退款(永久)
  287. Integer refundPermanent = records.stream()
  288. .filter(record -> record.getType() == 2) // 类型为退款
  289. .mapToInt(UserGoldRecord::getPermanentGold)
  290. .sum();
  291. statistics.setRefundPermanent(refundPermanent);
  292. //退款相关-当日退款(六月免费)
  293. Integer refundFreeJune = records.stream()
  294. .filter(record -> record.getType() == 2) // 类型为退款
  295. .mapToInt(UserGoldRecord::getFreeJune)
  296. .sum();
  297. statistics.setRefundFreeJune(refundFreeJune);
  298. //退款相关-当日退款(十二月免费)
  299. Integer refundFreeDecember = records.stream()
  300. .filter(record -> record.getType() == 2) // 类型为退款
  301. .mapToInt(UserGoldRecord::getFreeDecember)
  302. .sum();
  303. statistics.setRefundFreeDecember(refundFreeDecember);
  304. //退款相关-当日退款(任务)
  305. Integer refundTask = records.stream()
  306. .filter(record -> record.getType() == 2) // 类型为退款
  307. .mapToInt(UserGoldRecord::getTaskGold)
  308. .sum();
  309. statistics.setRefundTask(refundTask);
  310. //充值人数
  311. int rechargeNum= statisticsMapper.countRechargeNum(market,Date.from(startTime.atZone(ZoneId.systemDefault()).toInstant()),Date.from(endTime.atZone(ZoneId.systemDefault()).toInstant()));
  312. statistics.setRechargeNum(rechargeNum);
  313. //首充人数
  314. int firstRecharge= statisticsMapper.countFirstRecharge(market,Date.from(startTime.atZone(ZoneId.systemDefault()).toInstant()),Date.from(endTime.atZone(ZoneId.systemDefault()).toInstant()));
  315. statistics.setFirstRecharge(firstRecharge);
  316. return statistics;
  317. }
  318. @Override
  319. public Statistics getYearlyStatistics(String market,Date yearlyStartDate, Date date) {
  320. //获取日期
  321. LocalDate localDate=date.toInstant()
  322. .atZone(ZoneId.of("Asia/Shanghai")) // 使用系统默认时区
  323. .toLocalDate();
  324. // 一次性获取全年统计数据(从年初到今天)
  325. Map<String, Integer> yearlyStats = workbenchService.calculateAllSum(market, yearlyStartDate, date);
  326. //初始化Statistics对象
  327. Statistics statistics = new Statistics();
  328. statistics.setMarket(market);
  329. statistics.setCurrentDatetime(localDate);
  330. statistics.setYearlyRecharge(yearlyStats.getOrDefault("recharge", 0)); // 充值-全年累计充值
  331. statistics.setYearlyMoney(yearlyStats.getOrDefault("money", 0)); // 充值-全年累计金额(永久)//充值-全年累计金额(永久)
  332. statistics.setYearlyConsume(yearlyStats.getOrDefault("consume", 0)); // 年累计消费
  333. statistics.setYearlyRefund(yearlyStats.getOrDefault("refund", 0)); // 年累计退款
  334. statistics.setYearlyRechargeNum(yearlyStats.getOrDefault("rechargeNum", 0));//年累计充值人数
  335. return statistics;
  336. }
  337. /*
  338. * 判断两个统计对象part1(余量属性)是否相同
  339. */
  340. private boolean isSameStatisticsPart1(Statistics oldStats, Statistics newStats) {
  341. return Objects.equals(oldStats.getCurrentGold(), newStats.getCurrentGold()) &&
  342. Objects.equals(oldStats.getCurrentPermanent(), newStats.getCurrentPermanent()) &&
  343. Objects.equals(oldStats.getCurrentFreeJune(), newStats.getCurrentFreeJune()) &&
  344. Objects.equals(oldStats.getCurrentFreeDecember(), newStats.getCurrentFreeDecember()) &&
  345. Objects.equals(oldStats.getCurrentTask(), newStats.getCurrentTask()) &&
  346. Objects.equals(oldStats.getDailyChange(), newStats.getDailyChange()) ;
  347. }
  348. /*
  349. * 判断两个统计对象part2(余量外属性)是否相同
  350. */
  351. private boolean isSameStatisticsPart2(Statistics oldStats, Statistics newStats) {
  352. return Objects.equals(oldStats.getRecharge(), newStats.getRecharge()) &&
  353. Objects.equals(oldStats.getMoney(), newStats.getMoney()) &&
  354. Objects.equals(oldStats.getConsumePermanent(), newStats.getConsumePermanent()) &&
  355. Objects.equals(oldStats.getConsumeFreeJune(), newStats.getConsumeFreeJune()) &&
  356. Objects.equals(oldStats.getConsumeFreeDecember(), newStats.getConsumeFreeDecember()) &&
  357. Objects.equals(oldStats.getConsumeTask(), newStats.getConsumeTask()) &&
  358. Objects.equals(oldStats.getRefundPermanent(), newStats.getRefundPermanent()) &&
  359. Objects.equals(oldStats.getRefundFreeJune(), newStats.getRefundFreeJune()) &&
  360. Objects.equals(oldStats.getRefundFreeDecember(), newStats.getRefundFreeDecember()) &&
  361. Objects.equals(oldStats.getRefundTask(), newStats.getRefundTask()) &&
  362. Objects.equals(oldStats.getRechargeNum(), newStats.getRechargeNum()) &&
  363. Objects.equals(oldStats.getFirstRecharge(), newStats.getFirstRecharge()) &&
  364. Objects.equals(oldStats.getCurrentGold(), newStats.getCurrentGold()) &&
  365. Objects.equals(oldStats.getDailyChange(), newStats.getDailyChange()) &&
  366. Objects.equals(oldStats.getCurrentPermanent(), newStats.getCurrentPermanent()) &&
  367. Objects.equals(oldStats.getCurrentFreeJune(), newStats.getCurrentFreeJune()) &&
  368. Objects.equals(oldStats.getCurrentFreeDecember(), newStats.getCurrentFreeDecember()) &&
  369. Objects.equals(oldStats.getCurrentTask(), newStats.getCurrentTask());
  370. }
  371. /*
  372. * 判断两个统计对象年度统计是否相同
  373. */
  374. private boolean isSameStatisticsYear(Statistics oldStats, Statistics newStats) {
  375. return Objects.equals(oldStats.getYearlyRecharge(), newStats.getYearlyRecharge()) &&
  376. Objects.equals(oldStats.getYearlyMoney(), newStats.getYearlyMoney()) &&
  377. Objects.equals(oldStats.getYearlyConsume(), newStats.getYearlyConsume()) &&
  378. Objects.equals(oldStats.getYearlyRefund(), newStats.getYearlyRefund()) &&
  379. Objects.equals(oldStats.getYearlyRechargeNum(), newStats.getYearlyRechargeNum()) ;}
  380. }