diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/LotteryDrawExe.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/LotteryDrawExe.java index 4b1bf234..45df7313 100644 --- a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/LotteryDrawExe.java +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/LotteryDrawExe.java @@ -22,6 +22,7 @@ import com.red.circle.other.infra.database.rds.service.activity.LotteryTicketSer import com.red.circle.other.infra.database.rds.service.activity.LotteryUserCountService; import com.red.circle.other.infra.database.rds.service.activity.LotteryUserProgressService; import com.red.circle.other.infra.database.rds.service.activity.LotteryDeviceRecordService; +import com.red.circle.other.infra.database.rds.service.activity.UserActivityRechargeService; import com.red.circle.other.infra.database.rds.entity.activity.LotteryDeviceRecord; import com.red.circle.other.infra.database.rds.service.user.device.LatestMobileDeviceService; import com.red.circle.other.infra.utils.ZonedDateTimeUtils; @@ -66,6 +67,7 @@ public class LotteryDrawExe { private final RedisService redisService; private final LatestMobileDeviceService latestMobileDeviceService; private final LotteryDeviceRecordService lotteryDeviceRecordService; + private final UserActivityRechargeService userActivityRechargeService; @Transactional(rollbackFor = Exception.class) public LotteryDrawResultCO execute(LotteryDrawCmd cmd) { @@ -81,16 +83,20 @@ public class LotteryDrawExe { // 3. 校验抽奖次数限制 validateDrawCount(userId, activityId, activity); - // 4. 校验并扣除抽奖券(如果需要) + + // 4. 查询用户充值金额(用于过滤美元奖励) + BigDecimal userRechargeAmount = getUserRechargeAmount(userId, activityId); + + // 5. 校验并扣除抽奖券(如果需要) deductTicket(userId, activity.getTicketCost()); - // 5. 获取或创建用户进度(用于动态概率) + // 6. 获取或创建用户进度(用于动态概率) LotteryUserProgress progress = getOrCreateUserProgress(userId, activityId); - // 6. 执行抽奖算法(动态概率) - LotteryPrize prize = drawPrizeWithDynamicProbability(activityId, activity, progress); + // 7. 执行抽奖算法(动态概率) + LotteryPrize prize = drawPrizeWithDynamicProbability(activityId, activity, progress, userRechargeAmount); - // 7. 扣减奖品库存(使用悲观锁防止超卖) + // 8. 扣减奖品库存(使用悲观锁防止超卖) if (prize != null) { boolean deductSuccess = deductPrizeStock(prize.getId()); if (!deductSuccess) { @@ -99,24 +105,24 @@ public class LotteryDrawExe { } } - // 8. 保存抽奖记录 + // 9. 保存抽奖记录 LotteryRecord record = saveDrawRecord(userId, activityId, prize, now, null, 1); - // 9. 发放奖励 + // 10. 发放奖励 if (prize != null) { lotteryPrizeGrantService.grantPrize(userId, prize, record.getRecordNo()); } - // 10. 更新用户抽奖次数 + // 11. 更新用户抽奖次数 updateUserDrawCount(userId, activityId); - // 11. 更新用户进度(累加金额和次数) + // 12. 更新用户进度(累加金额和次数) updateUserProgress(progress, prize); - // 12. 记录设备信息(首次抽奖时) + // 13. 记录设备信息(首次抽奖时) recordDeviceAfterDraw(activityId, userId); - // 13. 组装返回结果 + // 14. 组装返回结果 return convertToResultCO(record, prize); } @@ -215,14 +221,28 @@ public class LotteryDrawExe { return progress; } + /** + * 查询用户充值金额. + */ + private BigDecimal getUserRechargeAmount(Long userId, Long activityId) { + try { + BigDecimal amount = userActivityRechargeService.getUserTotalAmount(userId, activityId); + return amount != null ? amount : BigDecimal.ZERO; + } catch (Exception e) { + log.error("Failed to get user recharge amount, userId: {}, activityId: {}", userId, activityId, e); + return BigDecimal.ZERO; + } + } + /** * 动态概率抽奖. */ - private LotteryPrize drawPrizeWithDynamicProbability(Long activityId, LotteryActivity activity, LotteryUserProgress progress) { + private LotteryPrize drawPrizeWithDynamicProbability(Long activityId, LotteryActivity activity, + LotteryUserProgress progress, BigDecimal userRechargeAmount) { // 判断是否启用动态概率 if (activity.getEnableDynamicProbability() == null || activity.getEnableDynamicProbability() != 1) { // 未启用动态概率,使用普通抽奖 - return drawPrizeNormal(activityId, progress.getUserId()); + return drawPrizeNormal(activityId, progress.getUserId(), userRechargeAmount); } // 1. 判断用户所处阶段 @@ -236,20 +256,23 @@ public class LotteryDrawExe { // 3. 过滤用户已中过的BADGE类型奖品 prizes = filterAlreadyWonBadgePrizes(prizes, progress.getUserId()); - // 4. 过滤会超过提现门槛的大奖 + // 4. 过滤美元奖励(充值金额为0的用户不能抽到) + prizes = filterMoneyPrizes(prizes, userRechargeAmount); + + // 5. 过滤会超过提现门槛的大奖 prizes = filterOverThresholdPrizes(prizes, progress, activity.getWithdrawThreshold()); if (prizes.isEmpty()) { return null; } - // 5. 动态调整概率 + // 6. 动态调整概率 adjustProbability(prizes, progress, activity.getWithdrawThreshold()); - // 6. 执行抽奖 + // 7. 执行抽奖 LotteryPrize selectedPrize = randomSelectByProbability(prizes); - // 7. 如果抽中了BADGE类型奖品,记录到Redis + // 8. 如果抽中了BADGE类型奖品,记录到Redis if (selectedPrize != null && "BADGE".equals(selectedPrize.getPrizeType())) { markBadgePrizeAsWon(progress.getUserId(), selectedPrize.getId()); } @@ -260,7 +283,7 @@ public class LotteryDrawExe { /** * 普通抽奖(不使用动态概率). */ - private LotteryPrize drawPrizeNormal(Long activityId, Long userId) { + private LotteryPrize drawPrizeNormal(Long activityId, Long userId, BigDecimal userRechargeAmount) { List prizes = lotteryPrizeService.query() .eq(LotteryPrize::getActivityId, activityId) .gt(LotteryPrize::getRemainingStock, 0) @@ -274,6 +297,9 @@ public class LotteryDrawExe { // 过滤用户已中过的BADGE类型奖品 prizes = filterAlreadyWonBadgePrizes(prizes, userId); + // 过滤美元奖励(充值金额为0的用户不能抽到) + prizes = filterMoneyPrizes(prizes, userRechargeAmount); + if (prizes.isEmpty()) { return null; } @@ -621,6 +647,41 @@ public class LotteryDrawExe { .collect(Collectors.toList()); } + /** + * 过滤美元奖励(充值金额为0的用户不能抽到). + * + * @param prizes 奖品列表 + * @param userRechargeAmount 用户充值金额 + * @return 过滤后的奖品列表 + */ + private List filterMoneyPrizes(List prizes, BigDecimal userRechargeAmount) { + if (prizes == null || prizes.isEmpty()) { + return prizes; + } + + // 如果用户充值金额>0,不需要过滤 + if (userRechargeAmount.compareTo(BigDecimal.ZERO) > 0) { + return prizes; + } + + // 充值金额为0,过滤掉MONEY类型奖品 + List filtered = prizes.stream() + .filter(prize -> { + if ("MONEY".equals(prize.getPrizeType())) { + log.info("User has no recharge, filtering MONEY prize. userId: {}, prizeId: {}, prizeName: {}", + userRechargeAmount, prize.getId(), prize.getPrizeName()); + return false; + } + return true; + }) + .collect(Collectors.toList()); + + log.info("Filter MONEY prizes completed. userRechargeAmount: {}, beforeCount: {}, afterCount: {}", + userRechargeAmount, prizes.size(), filtered.size()); + + return filtered; + } + /** * 标记用户已中BADGE类型奖品(永久记录). *