TicketBoxTask.java 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. package com.qs.mp.quartz.task;
  2. import com.alibaba.fastjson.JSONArray;
  3. import com.alibaba.fastjson.JSONObject;
  4. import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
  5. import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
  6. import com.qs.mp.admin.domain.Ticket;
  7. import com.qs.mp.admin.domain.TicketAwards;
  8. import com.qs.mp.admin.domain.TicketBox;
  9. import com.qs.mp.admin.service.ITicketAwardsService;
  10. import com.qs.mp.admin.service.ITicketBoxService;
  11. import com.qs.mp.admin.service.ITicketService;
  12. import com.qs.mp.common.annotation.Log;
  13. import com.qs.mp.common.core.domain.AjaxResult;
  14. import com.qs.mp.common.enums.TicketTypeEnum;
  15. import com.qs.mp.common.enums.UserTicketOrderStatusEnum;
  16. import com.qs.mp.common.utils.DateUtils;
  17. import com.qs.mp.common.utils.LogUtil;
  18. import com.qs.mp.common.utils.RSAUtil;
  19. import com.qs.mp.user.domain.UserTicketOrder;
  20. import com.qs.mp.user.service.IUserTicketOrderService;
  21. import java.math.BigDecimal;
  22. import java.math.RoundingMode;
  23. import java.util.ArrayList;
  24. import java.util.Comparator;
  25. import java.util.HashMap;
  26. import java.util.List;
  27. import java.util.Map;
  28. import java.util.TreeMap;
  29. import java.util.stream.Collectors;
  30. import org.slf4j.Logger;
  31. import org.slf4j.LoggerFactory;
  32. import org.springframework.beans.factory.annotation.Autowired;
  33. import org.springframework.stereotype.Component;
  34. import org.springframework.util.Assert;
  35. /**
  36. * 检查票组出奖率
  37. * @author zhongcp
  38. * @Date 2022/3/17
  39. */
  40. @Component("ticketBoxTask")
  41. public class TicketBoxTask {
  42. protected final Logger logger = LoggerFactory.getLogger(this.getClass().getSimpleName());
  43. @Autowired
  44. private ITicketService ticketService;
  45. @Autowired
  46. private ITicketAwardsService ticketAwardsService;
  47. @Autowired
  48. private ITicketBoxService ticketBoxService;
  49. private final int PAGE_SIZE = 100;
  50. /**
  51. * 检查票组中奖分布任务
  52. */
  53. public void checkPrize(String boxId) {
  54. LogUtil.info(logger, "...票组奖品分布检测任务开始...");
  55. TicketBox ticketBox = ticketBoxService.getById(boxId);
  56. List<TicketAwards> ticketAwardsList = ticketAwardsService.list(new LambdaQueryWrapper<TicketAwards>().eq(TicketAwards::getBoxId, boxId));
  57. Map<String, TicketAwards> ticketAwardsMap = new HashMap<>();
  58. for (TicketAwards ticketAward : ticketAwardsList) {
  59. ticketAwardsMap.put(ticketAward.getName(), ticketAward);
  60. }
  61. List<Ticket> listAll = new ArrayList<Ticket>();
  62. // 首先查询要导出的数据总数
  63. LambdaQueryWrapper<Ticket> queryWrapper = new LambdaQueryWrapper<Ticket>();
  64. queryWrapper.eq(Ticket::getBoxId, boxId);
  65. int totalSize = ticketService.count(queryWrapper);
  66. if (totalSize == 0) {
  67. LogUtil.info(logger, "票组票数为0,boxId:{0}", boxId);
  68. }
  69. if(totalSize > PAGE_SIZE) {
  70. int totalPage = totalSize%PAGE_SIZE == 0 ? totalSize/PAGE_SIZE : totalSize/PAGE_SIZE+1;
  71. for (int i = 0; i < totalPage; i++) {
  72. LambdaQueryWrapper<Ticket> pageQueryWrapper = new LambdaQueryWrapper<Ticket>();
  73. pageQueryWrapper.select(Ticket::getSerialNo, Ticket::getDrawNum, Ticket::getCipherLuckyNum, Ticket::getPkgId);
  74. pageQueryWrapper.eq(Ticket::getBoxId, boxId);
  75. pageQueryWrapper.last("limit "+ (i*PAGE_SIZE) +", " + PAGE_SIZE);
  76. List<Ticket> list = ticketService.list(pageQueryWrapper);
  77. if(null != list && list.size() > 0 ) {
  78. listAll.addAll(list);
  79. }
  80. }
  81. }else {
  82. listAll = ticketService.list(queryWrapper);
  83. }
  84. HashMap<String, HashMap<String, Integer>> pkgAwardsMap = new HashMap<>();
  85. if(null != listAll && listAll.size() > 0 ) {
  86. listAll.sort(Comparator.comparing(Ticket::getSerialNo));
  87. for (Ticket ticket : listAll) {
  88. JSONArray jsonArray = JSONArray.parseArray(ticket.getDrawNum());
  89. for (int i = 0; i < jsonArray.size(); i++) {
  90. JSONObject jo = jsonArray.getJSONObject(i);
  91. String luckyNum = RSAUtil.decrypt(ticket.getCipherLuckyNum());
  92. // LogUtil.info(logger, "num:{0},luckyNum:{1}", new Object[]{jo.get("num"), luckyNum});
  93. if (jo.get("num") == Integer.valueOf(luckyNum)) {
  94. HashMap<String, Integer> awardsMap = pkgAwardsMap.get(ticket.getPkgId());
  95. if (awardsMap == null) {
  96. awardsMap = new HashMap<>();
  97. pkgAwardsMap.put(ticket.getPkgId(), awardsMap);
  98. }
  99. Integer awardsNum = awardsMap.get(jo.getString("name"));
  100. if (null == awardsNum) {
  101. awardsNum = 0;
  102. }
  103. awardsNum += 1;
  104. awardsMap.put(jo.getString("name"), awardsNum);
  105. }
  106. }
  107. }
  108. }
  109. LogUtil.info(logger, "票包奖品分布:{0}", JSONObject.toJSONString(pkgAwardsMap));
  110. // 奖级累计中奖数量
  111. Map<String, Integer> totalAwardsMap = new HashMap<>();
  112. for (String key : pkgAwardsMap.keySet()) {
  113. HashMap<String, Integer> awardsMap = pkgAwardsMap.get(key);
  114. int sumAwardsNum = 0;
  115. for (String subKey : awardsMap.keySet()) {
  116. sumAwardsNum += awardsMap.get(subKey);
  117. Integer totalAwardsNum = totalAwardsMap.get(subKey);
  118. if (totalAwardsNum == null) {
  119. totalAwardsNum = 0;
  120. }
  121. totalAwardsNum += awardsMap.get(subKey);
  122. totalAwardsMap.put(subKey, totalAwardsNum);
  123. }
  124. Assert.isTrue(sumAwardsNum == ticketBox.getPkgUnit(), "票包的中奖数和票包张数不匹配。总中奖数:" + sumAwardsNum + ",票包张数:" + ticketBox.getPkgUnit());
  125. // 检查票包每个奖项的中奖率是否和整体票组中奖率一致
  126. for (String subKey : awardsMap.keySet()) {
  127. BigDecimal hitRate = new BigDecimal(awardsMap.get(subKey) * 100).divide(new BigDecimal(sumAwardsNum), 4, RoundingMode.DOWN);
  128. // 误差率
  129. BigDecimal misRate = ticketAwardsMap.get(subKey).getHitRate().subtract(hitRate).divide(hitRate, 2, RoundingMode.HALF_UP);
  130. if (misRate.abs().compareTo(new BigDecimal(0.01)) > 0) {
  131. LogUtil.error(logger, "中奖率与整个票组的中奖率误差大于0.01,pkgId:{0},票包奖项:{1},数量:{2},票包中奖率:{3},票组中奖率:{4}",
  132. new Object[]{key, subKey, awardsMap.get(subKey), hitRate, ticketAwardsMap.get(subKey).getHitRate()});
  133. }
  134. }
  135. Map<String, Integer> treeMap = new TreeMap<>((str1, str2) -> str1.compareTo(str2));
  136. treeMap.putAll(awardsMap);
  137. LogUtil.info(logger, "票包{0}奖级分布情况:{1}", new Object[]{key, treeMap});
  138. }
  139. // 排序
  140. Map<String, Integer> resultMap = new TreeMap<>((str1, str2) -> str1.compareTo(str2));
  141. resultMap.putAll(totalAwardsMap);
  142. for (String key : resultMap.keySet()) {
  143. int realNum = resultMap.get(key);
  144. LogUtil.info(logger, "奖级{0}数量为{1}", new Object[]{key, realNum});
  145. if(realNum != ticketAwardsMap.get(key).getQuantity()) {
  146. LogUtil.error(logger, "实际中奖数(" + realNum + ")和票组中奖数(" + ticketAwardsMap.get(key).getQuantity() + ")不等" );
  147. }
  148. }
  149. LogUtil.info(logger, "...票组奖品分布检测任务结束...");
  150. }
  151. }