增加徽章只中将一次处理
This commit is contained in:
parent
71cddc71fc
commit
783534636d
@ -1,5 +1,6 @@
|
||||
package com.red.circle.other.app.command.activity;
|
||||
|
||||
import com.red.circle.component.redis.service.RedisService;
|
||||
import com.red.circle.framework.core.asserts.ResponseAssert;
|
||||
import com.red.circle.other.app.dto.clientobject.activity.LotteryDrawResultCO;
|
||||
import com.red.circle.other.app.dto.clientobject.activity.LotteryPrizeCO;
|
||||
@ -55,6 +56,7 @@ public class LotteryDrawExe {
|
||||
private final LotteryUserCountService lotteryUserCountService;
|
||||
private final LotteryUserProgressService lotteryUserProgressService;
|
||||
private final LotteryPrizeGrantService lotteryPrizeGrantService;
|
||||
private final RedisService redisService;
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public LotteryDrawResultCO execute(LotteryDrawCmd cmd) {
|
||||
@ -171,7 +173,7 @@ public class LotteryDrawExe {
|
||||
// 判断是否启用动态概率
|
||||
if (activity.getEnableDynamicProbability() == null || activity.getEnableDynamicProbability() != 1) {
|
||||
// 未启用动态概率,使用普通抽奖
|
||||
return drawPrizeNormal(activityId);
|
||||
return drawPrizeNormal(activityId, progress.getUserId());
|
||||
}
|
||||
|
||||
// 1. 判断用户所处阶段
|
||||
@ -182,24 +184,34 @@ public class LotteryDrawExe {
|
||||
// 2. 查询对应奖品池的奖品
|
||||
List<LotteryPrize> prizes = getPrizesByPool(activityId, stage);
|
||||
|
||||
// 3. 过滤会超过提现门槛的大奖
|
||||
// 3. 过滤用户已中过的BADGE类型奖品
|
||||
prizes = filterAlreadyWonBadgePrizes(prizes, progress.getUserId());
|
||||
|
||||
// 4. 过滤会超过提现门槛的大奖
|
||||
prizes = filterOverThresholdPrizes(prizes, progress, activity.getWithdrawThreshold());
|
||||
|
||||
if (prizes.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 4. 动态调整概率
|
||||
// 5. 动态调整概率
|
||||
adjustProbability(prizes, progress, activity.getWithdrawThreshold());
|
||||
|
||||
// 5. 执行抽奖
|
||||
return randomSelectByProbability(prizes);
|
||||
// 6. 执行抽奖
|
||||
LotteryPrize selectedPrize = randomSelectByProbability(prizes);
|
||||
|
||||
// 7. 如果抽中了BADGE类型奖品,记录到Redis
|
||||
if (selectedPrize != null && "BADGE".equals(selectedPrize.getPrizeType())) {
|
||||
markBadgePrizeAsWon(progress.getUserId(), selectedPrize.getId());
|
||||
}
|
||||
|
||||
return selectedPrize;
|
||||
}
|
||||
|
||||
/**
|
||||
* 普通抽奖(不使用动态概率).
|
||||
*/
|
||||
private LotteryPrize drawPrizeNormal(Long activityId) {
|
||||
private LotteryPrize drawPrizeNormal(Long activityId, Long userId) {
|
||||
List<LotteryPrize> prizes = lotteryPrizeService.query()
|
||||
.eq(LotteryPrize::getActivityId, activityId)
|
||||
.gt(LotteryPrize::getRemainingStock, 0)
|
||||
@ -210,7 +222,21 @@ public class LotteryDrawExe {
|
||||
return null;
|
||||
}
|
||||
|
||||
return randomSelectByProbability(prizes);
|
||||
// 过滤用户已中过的BADGE类型奖品
|
||||
prizes = filterAlreadyWonBadgePrizes(prizes, userId);
|
||||
|
||||
if (prizes.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
LotteryPrize selectedPrize = randomSelectByProbability(prizes);
|
||||
|
||||
// 如果抽中了BADGE类型奖品,记录到Redis
|
||||
if (selectedPrize != null && "BADGE".equals(selectedPrize.getPrizeType())) {
|
||||
markBadgePrizeAsWon(userId, selectedPrize.getId());
|
||||
}
|
||||
|
||||
return selectedPrize;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -522,6 +548,53 @@ public class LotteryDrawExe {
|
||||
String.format("%06d", ThreadLocalRandom.current().nextInt(1000000));
|
||||
}
|
||||
|
||||
/**
|
||||
* 过滤用户已中过的BADGE类型奖品.
|
||||
*
|
||||
* @param prizes 奖品列表
|
||||
* @param userId 用户ID
|
||||
* @return 过滤后的奖品列表
|
||||
*/
|
||||
private List<LotteryPrize> filterAlreadyWonBadgePrizes(List<LotteryPrize> prizes, Long userId) {
|
||||
if (prizes == null || prizes.isEmpty()) {
|
||||
return prizes;
|
||||
}
|
||||
|
||||
return prizes.stream()
|
||||
.filter(prize -> {
|
||||
// 如果不是BADGE类型,直接通过
|
||||
if (!"BADGE".equals(prize.getPrizeType())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 检查用户是否已经中过这个BADGE
|
||||
String redisKey = "lottery:badge:won:" + userId + ":" + prize.getId();
|
||||
String won = redisService.getString(redisKey);
|
||||
|
||||
if (won != null) {
|
||||
log.info("User already won this BADGE prize, filtering it out. userId: {}, prizeId: {}, prizeName: {}",
|
||||
userId, prize.getId(), prize.getPrizeName());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 标记用户已中BADGE类型奖品(永久记录).
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param prizeId 奖品ID
|
||||
*/
|
||||
private void markBadgePrizeAsWon(Long userId, Long prizeId) {
|
||||
String redisKey = "lottery:badge:won:" + userId + ":" + prizeId;
|
||||
// 永久存储,表示该用户已经中过这个BADGE
|
||||
redisService.setString(redisKey, "1");
|
||||
log.info("Mark BADGE prize as won. userId: {}, prizeId: {}", userId, prizeId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为结果CO.
|
||||
*/
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package com.red.circle.other.app.command.activity;
|
||||
|
||||
import com.red.circle.component.redis.service.RedisService;
|
||||
import com.red.circle.framework.core.asserts.ResponseAssert;
|
||||
import com.red.circle.other.app.dto.clientobject.activity.LotteryDrawResultCO;
|
||||
import com.red.circle.other.app.dto.clientobject.activity.LotteryMultiDrawResultCO;
|
||||
@ -56,6 +57,7 @@ public class LotteryMultiDrawExe {
|
||||
private final LotteryUserCountService lotteryUserCountService;
|
||||
private final LotteryUserProgressService lotteryUserProgressService;
|
||||
private final LotteryPrizeGrantService lotteryPrizeGrantService;
|
||||
private final RedisService redisService;
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public LotteryMultiDrawResultCO execute(LotteryMultiDrawCmd cmd) {
|
||||
@ -202,12 +204,16 @@ public class LotteryMultiDrawExe {
|
||||
|
||||
private LotteryPrize drawPrizeWithDynamicProbability(Long activityId, LotteryActivity activity, LotteryUserProgress progress) {
|
||||
if (activity.getEnableDynamicProbability() == null || activity.getEnableDynamicProbability() != 1) {
|
||||
return drawPrizeWithMultiProbability(activityId);
|
||||
return drawPrizeWithMultiProbability(activityId, progress.getUserId());
|
||||
}
|
||||
String stage = determinePrizePool(progress, activity);
|
||||
log.debug("Multi-draw stage: {}, userId: {}, drawCount: {}, totalAmount: {}",
|
||||
stage, progress.getUserId(), progress.getTotalDrawCount(), progress.getTotalAmount());
|
||||
List<LotteryPrize> prizes = getPrizesByPool(activityId, stage);
|
||||
|
||||
// 过滤用户已中过的BADGE类型奖品
|
||||
prizes = filterAlreadyWonBadgePrizes(prizes, progress.getUserId());
|
||||
|
||||
prizes = filterOverThresholdPrizes(prizes, progress, activity.getWithdrawThreshold());
|
||||
if (prizes.isEmpty()) {
|
||||
return null;
|
||||
@ -218,7 +224,14 @@ public class LotteryMultiDrawExe {
|
||||
}
|
||||
}
|
||||
adjustProbability(prizes, progress, activity.getWithdrawThreshold());
|
||||
return randomSelectByProbability(prizes);
|
||||
LotteryPrize selectedPrize = randomSelectByProbability(prizes);
|
||||
|
||||
// 如果抽中了BADGE类型奖品,记录到Redis
|
||||
if (selectedPrize != null && "BADGE".equals(selectedPrize.getPrizeType())) {
|
||||
markBadgePrizeAsWon(progress.getUserId(), selectedPrize.getId());
|
||||
}
|
||||
|
||||
return selectedPrize;
|
||||
}
|
||||
|
||||
private String determinePrizePool(LotteryUserProgress progress, LotteryActivity activity) {
|
||||
@ -302,7 +315,7 @@ public class LotteryMultiDrawExe {
|
||||
return prizes.get(prizes.size() - 1);
|
||||
}
|
||||
|
||||
private LotteryPrize drawPrizeWithMultiProbability(Long activityId) {
|
||||
private LotteryPrize drawPrizeWithMultiProbability(Long activityId, Long userId) {
|
||||
List<LotteryPrize> prizes = lotteryPrizeService.query()
|
||||
.eq(LotteryPrize::getActivityId, activityId)
|
||||
.gt(LotteryPrize::getRemainingStock, 0)
|
||||
@ -311,6 +324,14 @@ public class LotteryMultiDrawExe {
|
||||
if (prizes.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 过滤用户已中过的BADGE类型奖品
|
||||
prizes = filterAlreadyWonBadgePrizes(prizes, userId);
|
||||
|
||||
if (prizes.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
BigDecimal totalProbability = prizes.stream()
|
||||
.map(prize -> prize.getMultiDrawProbability() != null ? prize.getMultiDrawProbability() : prize.getProbability())
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
@ -320,10 +341,20 @@ public class LotteryMultiDrawExe {
|
||||
BigDecimal probability = prize.getMultiDrawProbability() != null ? prize.getMultiDrawProbability() : prize.getProbability();
|
||||
cumulative += probability.doubleValue();
|
||||
if (randomValue <= cumulative) {
|
||||
// 如果抽中了BADGE类型奖品,记录到Redis
|
||||
if ("BADGE".equals(prize.getPrizeType())) {
|
||||
markBadgePrizeAsWon(userId, prize.getId());
|
||||
}
|
||||
return prize;
|
||||
}
|
||||
}
|
||||
return prizes.get(prizes.size() - 1);
|
||||
|
||||
LotteryPrize lastPrize = prizes.get(prizes.size() - 1);
|
||||
// 如果抽中了BADGE类型奖品,记录到Redis
|
||||
if (lastPrize != null && "BADGE".equals(lastPrize.getPrizeType())) {
|
||||
markBadgePrizeAsWon(userId, lastPrize.getId());
|
||||
}
|
||||
return lastPrize;
|
||||
}
|
||||
|
||||
private void replaceWithGuaranteePrize(List<LotteryDrawResultCO> results, LotteryActivity activity, Long userId, Long activityId, Timestamp now, String batchNo, LotteryUserProgress progress) {
|
||||
@ -495,4 +526,51 @@ public class LotteryMultiDrawExe {
|
||||
return "LT" + System.currentTimeMillis() + String.format("%06d", ThreadLocalRandom.current().nextInt(1000000));
|
||||
}
|
||||
|
||||
/**
|
||||
* 过滤用户已中过的BADGE类型奖品.
|
||||
*
|
||||
* @param prizes 奖品列表
|
||||
* @param userId 用户ID
|
||||
* @return 过滤后的奖品列表
|
||||
*/
|
||||
private List<LotteryPrize> filterAlreadyWonBadgePrizes(List<LotteryPrize> prizes, Long userId) {
|
||||
if (prizes == null || prizes.isEmpty()) {
|
||||
return prizes;
|
||||
}
|
||||
|
||||
return prizes.stream()
|
||||
.filter(prize -> {
|
||||
// 如果不是BADGE类型,直接通过
|
||||
if (!"BADGE".equals(prize.getPrizeType())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 检查用户是否已经中过这个BADGE
|
||||
String redisKey = "lottery:badge:won:" + userId + ":" + prize.getId();
|
||||
String won = redisService.getString(redisKey);
|
||||
|
||||
if (won != null) {
|
||||
log.info("User already won this BADGE prize in multi-draw, filtering it out. userId: {}, prizeId: {}, prizeName: {}",
|
||||
userId, prize.getId(), prize.getPrizeName());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 标记用户已中BADGE类型奖品(永久记录).
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param prizeId 奖品ID
|
||||
*/
|
||||
private void markBadgePrizeAsWon(Long userId, Long prizeId) {
|
||||
String redisKey = "lottery:badge:won:" + userId + ":" + prizeId;
|
||||
// 永久存储,表示该用户已经中过这个BADGE
|
||||
redisService.setString(redisKey, "1");
|
||||
log.info("Mark BADGE prize as won in multi-draw. userId: {}, prizeId: {}", userId, prizeId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user