|
@@ -0,0 +1,164 @@
|
|
|
+package com.qs.mp.quartz.task;
|
|
|
+
|
|
|
+import com.alibaba.fastjson.JSONArray;
|
|
|
+import com.alibaba.fastjson.JSONObject;
|
|
|
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
|
|
+import com.qs.mp.admin.domain.Ticket;
|
|
|
+import com.qs.mp.admin.domain.TicketAwards;
|
|
|
+import com.qs.mp.admin.domain.TicketBox;
|
|
|
+import com.qs.mp.admin.service.ITicketAwardsService;
|
|
|
+import com.qs.mp.admin.service.ITicketBoxService;
|
|
|
+import com.qs.mp.admin.service.ITicketService;
|
|
|
+import com.qs.mp.common.annotation.Log;
|
|
|
+import com.qs.mp.common.core.domain.AjaxResult;
|
|
|
+import com.qs.mp.common.enums.TicketTypeEnum;
|
|
|
+import com.qs.mp.common.enums.UserTicketOrderStatusEnum;
|
|
|
+import com.qs.mp.common.utils.DateUtils;
|
|
|
+import com.qs.mp.common.utils.LogUtil;
|
|
|
+import com.qs.mp.common.utils.RSAUtil;
|
|
|
+import com.qs.mp.user.domain.UserTicketOrder;
|
|
|
+import com.qs.mp.user.service.IUserTicketOrderService;
|
|
|
+import java.math.BigDecimal;
|
|
|
+import java.math.RoundingMode;
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.Comparator;
|
|
|
+import java.util.HashMap;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+import java.util.TreeMap;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+import org.slf4j.Logger;
|
|
|
+import org.slf4j.LoggerFactory;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.stereotype.Component;
|
|
|
+import org.springframework.util.Assert;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 检查票组出奖率
|
|
|
+ * @author zhongcp
|
|
|
+ * @Date 2022/3/17
|
|
|
+ */
|
|
|
+@Component("ticketBoxTask")
|
|
|
+public class TicketBoxTask {
|
|
|
+
|
|
|
+ protected final Logger logger = LoggerFactory.getLogger(this.getClass().getSimpleName());
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private ITicketService ticketService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private ITicketAwardsService ticketAwardsService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private ITicketBoxService ticketBoxService;
|
|
|
+
|
|
|
+ private final int PAGE_SIZE = 100;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 检查票组中奖分布任务
|
|
|
+ */
|
|
|
+ public void checkPrize(String boxId) {
|
|
|
+ LogUtil.info(logger, "...票组奖品分布检测任务开始...");
|
|
|
+
|
|
|
+ TicketBox ticketBox = ticketBoxService.getById(boxId);
|
|
|
+ List<TicketAwards> ticketAwardsList = ticketAwardsService.list(new LambdaQueryWrapper<TicketAwards>().eq(TicketAwards::getBoxId, boxId));
|
|
|
+ Map<String, TicketAwards> ticketAwardsMap = new HashMap<>();
|
|
|
+ for (TicketAwards ticketAward : ticketAwardsList) {
|
|
|
+ ticketAwardsMap.put(ticketAward.getName(), ticketAward);
|
|
|
+ }
|
|
|
+
|
|
|
+ List<Ticket> listAll = new ArrayList<Ticket>();
|
|
|
+ // 首先查询要导出的数据总数
|
|
|
+ LambdaQueryWrapper<Ticket> queryWrapper = new LambdaQueryWrapper<Ticket>();
|
|
|
+ queryWrapper.eq(Ticket::getBoxId, boxId);
|
|
|
+ int totalSize = ticketService.count(queryWrapper);
|
|
|
+ if (totalSize == 0) {
|
|
|
+ LogUtil.info(logger, "票组票数为0,boxId:{0}", boxId);
|
|
|
+ }
|
|
|
+
|
|
|
+ if(totalSize > PAGE_SIZE) {
|
|
|
+ int totalPage = totalSize%PAGE_SIZE == 0 ? totalSize/PAGE_SIZE : totalSize/PAGE_SIZE+1;
|
|
|
+ for (int i = 0; i < totalPage; i++) {
|
|
|
+ LambdaQueryWrapper<Ticket> pageQueryWrapper = new LambdaQueryWrapper<Ticket>();
|
|
|
+ pageQueryWrapper.select(Ticket::getSerialNo, Ticket::getDrawNum, Ticket::getCipherLuckyNum, Ticket::getPkgId);
|
|
|
+ pageQueryWrapper.eq(Ticket::getBoxId, boxId);
|
|
|
+ pageQueryWrapper.last("limit "+ (i*PAGE_SIZE) +", " + PAGE_SIZE);
|
|
|
+ List<Ticket> list = ticketService.list(pageQueryWrapper);
|
|
|
+ if(null != list && list.size() > 0 ) {
|
|
|
+ listAll.addAll(list);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }else {
|
|
|
+ listAll = ticketService.list(queryWrapper);
|
|
|
+ }
|
|
|
+
|
|
|
+ HashMap<String, HashMap<String, Integer>> pkgAwardsMap = new HashMap<>();
|
|
|
+ if(null != listAll && listAll.size() > 0 ) {
|
|
|
+ listAll.sort(Comparator.comparing(Ticket::getSerialNo));
|
|
|
+ for (Ticket ticket : listAll) {
|
|
|
+ JSONArray jsonArray = JSONArray.parseArray(ticket.getDrawNum());
|
|
|
+ for (int i = 0; i < jsonArray.size(); i++) {
|
|
|
+ JSONObject jo = jsonArray.getJSONObject(i);
|
|
|
+ String luckyNum = RSAUtil.decrypt(ticket.getCipherLuckyNum());
|
|
|
+// LogUtil.info(logger, "num:{0},luckyNum:{1}", new Object[]{jo.get("num"), luckyNum});
|
|
|
+ if (jo.get("num") == Integer.valueOf(luckyNum)) {
|
|
|
+ HashMap<String, Integer> awardsMap = pkgAwardsMap.get(ticket.getPkgId());
|
|
|
+ if (awardsMap == null) {
|
|
|
+ awardsMap = new HashMap<>();
|
|
|
+ pkgAwardsMap.put(ticket.getPkgId(), awardsMap);
|
|
|
+ }
|
|
|
+ Integer awardsNum = awardsMap.get(jo.getString("name"));
|
|
|
+ if (null == awardsNum) {
|
|
|
+ awardsNum = 0;
|
|
|
+ }
|
|
|
+ awardsNum += 1;
|
|
|
+ awardsMap.put(jo.getString("name"), awardsNum);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ LogUtil.info(logger, "票包奖品分布:{0}", JSONObject.toJSONString(pkgAwardsMap));
|
|
|
+ // 奖级累计中奖数量
|
|
|
+ Map<String, Integer> totalAwardsMap = new HashMap<>();
|
|
|
+ for (String key : pkgAwardsMap.keySet()) {
|
|
|
+ HashMap<String, Integer> awardsMap = pkgAwardsMap.get(key);
|
|
|
+
|
|
|
+ int sumAwardsNum = 0;
|
|
|
+ for (String subKey : awardsMap.keySet()) {
|
|
|
+ sumAwardsNum += awardsMap.get(subKey);
|
|
|
+ Integer totalAwardsNum = totalAwardsMap.get(subKey);
|
|
|
+ if (totalAwardsNum == null) {
|
|
|
+ totalAwardsNum = 0;
|
|
|
+ }
|
|
|
+ totalAwardsNum += awardsMap.get(subKey);
|
|
|
+ totalAwardsMap.put(subKey, totalAwardsNum);
|
|
|
+ }
|
|
|
+ Assert.isTrue(sumAwardsNum == ticketBox.getPkgUnit(), "票包的中奖数和票包张数不匹配。总中奖数:" + sumAwardsNum + ",票包张数:" + ticketBox.getPkgUnit());
|
|
|
+ // 检查票包每个奖项的中奖率是否和整体票组中奖率一致
|
|
|
+ for (String subKey : awardsMap.keySet()) {
|
|
|
+ BigDecimal hitRate = new BigDecimal(awardsMap.get(subKey) * 100).divide(new BigDecimal(sumAwardsNum), 4, RoundingMode.DOWN);
|
|
|
+ // 误差率
|
|
|
+ BigDecimal misRate = ticketAwardsMap.get(subKey).getHitRate().subtract(hitRate).divide(hitRate, 2, RoundingMode.HALF_UP);
|
|
|
+ if (misRate.abs().compareTo(new BigDecimal(0.01)) > 0) {
|
|
|
+ LogUtil.error(logger, "中奖率与整个票组的中奖率误差大于0.01,pkgId:{0},票包奖项:{1},数量:{2},票包中奖率:{3},票组中奖率:{4}",
|
|
|
+ new Object[]{key, subKey, awardsMap.get(subKey), hitRate, ticketAwardsMap.get(subKey).getHitRate()});
|
|
|
+ }
|
|
|
+ }
|
|
|
+ Map<String, Integer> treeMap = new TreeMap<>((str1, str2) -> str1.compareTo(str2));
|
|
|
+ treeMap.putAll(awardsMap);
|
|
|
+ LogUtil.info(logger, "票包{0}奖级分布情况:{1}", new Object[]{key, treeMap});
|
|
|
+ }
|
|
|
+ // 排序
|
|
|
+ Map<String, Integer> resultMap = new TreeMap<>((str1, str2) -> str1.compareTo(str2));
|
|
|
+ resultMap.putAll(totalAwardsMap);
|
|
|
+ for (String key : resultMap.keySet()) {
|
|
|
+ int realNum = resultMap.get(key);
|
|
|
+ LogUtil.info(logger, "奖级{0}数量为{1}", new Object[]{key, realNum});
|
|
|
+ if(realNum != ticketAwardsMap.get(key).getQuantity()) {
|
|
|
+ LogUtil.error(logger, "实际中奖数(" + realNum + ")和票组中奖数(" + ticketAwardsMap.get(key).getQuantity() + ")不等" );
|
|
|
+ }
|
|
|
+ }
|
|
|
+ LogUtil.info(logger, "...票组奖品分布检测任务结束...");
|
|
|
+ }
|
|
|
+}
|