This commit is contained in:
777
2026-01-14 17:45:39 +08:00
parent 235059c96a
commit 27edbd9cf6

View File

@@ -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<PrizeOnline> validPrizes, int currentDraws) {
// 按保底抽数升序排序,优先触发保底抽数小的奖品
validPrizes.sort(Comparator.comparingInt(PrizeOnline::getGuaranteeDraws));
for (PrizeOnline prize : validPrizes) {
List<PrizeOnline> 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<PrizeOnline> 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<PrizeOnline, Double> 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<PrizeOnline> filterByMinWinDraws(List<PrizeOnline> prizes, int currentDraws) {
List<PrizeOnline> 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<Integer> 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);
}
/**