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 ticketAwardsList = ticketAwardsService.list(new LambdaQueryWrapper().eq(TicketAwards::getBoxId, boxId)); Map ticketAwardsMap = new HashMap<>(); for (TicketAwards ticketAward : ticketAwardsList) { ticketAwardsMap.put(ticketAward.getName(), ticketAward); } List listAll = new ArrayList(); // 首先查询要导出的数据总数 LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper(); 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 pageQueryWrapper = new LambdaQueryWrapper(); pageQueryWrapper.select(Ticket::getSerialNo, Ticket::getDrawNum, Ticket::getCipherLuckyNum, Ticket::getPkgId); pageQueryWrapper.eq(Ticket::getBoxId, boxId); pageQueryWrapper.last("limit "+ (i*PAGE_SIZE) +", " + PAGE_SIZE); List list = ticketService.list(pageQueryWrapper); if(null != list && list.size() > 0 ) { listAll.addAll(list); } } }else { listAll = ticketService.list(queryWrapper); } HashMap> 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 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 totalAwardsMap = new HashMap<>(); for (String key : pkgAwardsMap.keySet()) { HashMap 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 treeMap = new TreeMap<>((str1, str2) -> str1.compareTo(str2)); treeMap.putAll(awardsMap); LogUtil.info(logger, "票包{0}奖级分布情况:{1}", new Object[]{key, treeMap}); } // 排序 Map 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, "...票组奖品分布检测任务结束..."); } }