123
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user