diff --git a/ruoyi-cai/src/main/java/com/ruoyi/cai/lottery/LotteryService.java b/ruoyi-cai/src/main/java/com/ruoyi/cai/lottery/LotteryService.java index 4c91352e..c0efa391 100644 --- a/ruoyi-cai/src/main/java/com/ruoyi/cai/lottery/LotteryService.java +++ b/ruoyi-cai/src/main/java/com/ruoyi/cai/lottery/LotteryService.java @@ -138,19 +138,36 @@ public class LotteryService { } // 步骤3:执行抽奖规则(保底→最低抽数过滤→概率抽奖) PrizeOnline winPrize = null; + boolean isResetContinuousDraws = false; // 是否需要重置累计抽数 + // 3.1 保底规则判断(优先触发) winPrize = checkGuaranteeRule(validPrizes, newContinuousDraws); + if (winPrize != null) { + // 触发保底中奖,需要重置累计抽数 + isResetContinuousDraws = true; + log.info("用户{}触发保底,中得奖品{},累计抽数将重置", userId, winPrize.getPrizeName()); + } + // 3.2 未触发保底,执行概率抽奖(含最低中奖抽数过滤) if (winPrize == null) { winPrize = executeProbabilityDraw(validPrizes, newContinuousDraws); + if (winPrize != null) { + // 概率抽奖中奖,需要重置累计抽数 + isResetContinuousDraws = true; + log.info("用户{}概率抽奖中得奖品{},累计抽数将重置", userId, winPrize.getPrizeName()); + } } - // 步骤4:处理中奖结果,确定最终奖品ID和累计抽数重置 - if(winPrize == null){ - winPrize = new PrizeOnline(); // TODO 谢谢惠顾 + + // 3.3 未中奖,使用谢谢惠顾 + if (winPrize == null) { + winPrize = thankPrize; + // 谢谢惠顾不重置累计抽数 + log.info("用户{}未中奖,谢谢惠顾,累计抽数继续累加到{}", userId, newContinuousDraws); } - // 步骤5:持久化抽奖记录+更新缓存 - winPrizeAfter(winPrize, user, drawPoint, newContinuousDraws); - // 步骤6:返回中奖奖品 + + // 步骤4:持久化抽奖记录+更新缓存 + winPrizeAfter(winPrize, user, drawPoint, newContinuousDraws, isResetContinuousDraws); + // 步骤5:返回中奖奖品 return winPrize; } @@ -162,11 +179,14 @@ public class LotteryService { */ private PrizeOnline checkGuaranteeRule(List validPrizes, int currentDraws) { // 按保底抽数升序排序,优先触发保底抽数小的奖品 - validPrizes.sort(Comparator.comparingInt(PrizeOnline::getGuaranteeDraws)); - for (PrizeOnline prize : validPrizes) { + List sortedPrizes = new ArrayList<>(validPrizes); + sortedPrizes.sort(Comparator.comparingInt(PrizeOnline::getGuaranteeDraws)); + + for (PrizeOnline prize : sortedPrizes) { int guaranteeDraws = prize.getGuaranteeDraws(); if (guaranteeDraws > 0 && currentDraws >= guaranteeDraws) { - log.info("触发保底规则,用户抽中奖品:{}", prize.getPrizeName()); + log.info("触发保底规则,累计抽数{} >= 保底抽数{},用户抽中奖品:{}", + currentDraws, guaranteeDraws, prize.getPrizeName()); return prize; } } @@ -183,9 +203,12 @@ public class LotteryService { // 步骤1:过滤出满足最低中奖抽数的奖品 List filterPrizes = filterByMinWinDraws(validPrizes, currentDraws); if (filterPrizes.isEmpty()) { - log.info("无满足最低中奖抽数的奖品,返回谢谢惠顾"); + log.info("累计抽数{}:无满足最低中奖抽数的奖品,返回谢谢惠顾", currentDraws); return null; } + + log.info("累计抽数{}:满足最低中奖抽数的奖品有{}个", currentDraws, filterPrizes.size()); + // 步骤2:计算奖品的概率总和(放大为整数,提升精度) double totalProbability = 0.0; Map prizeProbMap = new LinkedHashMap<>(); // 保留顺序 @@ -201,7 +224,7 @@ public class LotteryService { // 步骤3:若总概率为0,直接返回null if (totalProbability <= 0) { - log.info("满足条件的奖品总中奖率为0,返回谢谢惠顾"); + log.info("累计抽数{}:满足条件的奖品总中奖率为0,返回谢谢惠顾", currentDraws); return null; } @@ -216,10 +239,13 @@ public class LotteryService { int probInt = (int) (prob * RANDOM_MAX); currentNum += probInt; if (randomNum < currentNum) { - log.info("概率抽奖抽中奖品:{}", prize.getPrizeName()); + log.info("累计抽数{}:概率抽奖抽中奖品{}(中奖率:{})", + currentDraws, prize.getPrizeName(), prob); return prize; } } + // 理论上不会走到这里,因为randomNum在totalProbability范围内 + log.warn("累计抽数{}:概率抽奖未匹配到任何奖品,返回谢谢惠顾", currentDraws); return null; } @@ -229,8 +255,12 @@ public class LotteryService { private List filterByMinWinDraws(List prizes, int currentDraws) { List filterList = new ArrayList<>(); for (PrizeOnline prize : prizes) { - if (currentDraws >= prize.getMinWinDraws()) { + int minWinDraws = prize.getMinWinDraws(); + if (currentDraws >= minWinDraws) { filterList.add(prize); + log.debug("奖品{}满足最低中奖抽数条件:{} >= {}", prize.getPrizeName(), currentDraws, minWinDraws); + } else { + log.debug("奖品{}不满足最低中奖抽数条件:{} < {}", prize.getPrizeName(), currentDraws, minWinDraws); } } return filterList; @@ -260,16 +290,20 @@ public class LotteryService { * 保存抽奖记录(事务控制) */ @Transactional(rollbackFor = Exception.class) - public void winPrizeAfter(PrizeOnline prizeOnline, User user,Integer drawPoint, int continuousDraws) { + public void winPrizeAfter(PrizeOnline prizeOnline, User user,Integer drawPoint, + int continuousDraws, boolean isResetContinuousDraws) { // 扣减积分 String traceId = IdManager.nextIdStr(); PointChangeLog pointChangeLog = pointManager.drawPoint(prizeOnline, user, drawPoint, traceId); // 记录用户抽奖记录 prizeWinningRecordService.winningRecord(pointChangeLog, prizeOnline, user, drawPoint); - // 更新缓存 + // 更新缓存(根据是否中奖决定是否重置累计抽数) String cacheKey = String.format(USER_DRAW_COUNT_KEY, user.getId()); RBucket bucket = redissonClient.getBucket(cacheKey); - bucket.set(continuousDraws, USER_DRAW_COUNT_EXPIRE, java.util.concurrent.TimeUnit.SECONDS); + int finalContinuousDraws = isResetContinuousDraws ? 0 : continuousDraws; + bucket.set(finalContinuousDraws); + log.info("用户{}抽奖完成,最终累计抽数:{}(中奖重置:{})", + user.getId(), finalContinuousDraws, isResetContinuousDraws); } /**