新增 幸运&魔法礼物&游戏 赢得金币发送抽奖券

This commit is contained in:
tianfeng 2026-02-10 15:10:15 +08:00
parent 865461657a
commit 78c9b31280
9 changed files with 150 additions and 3 deletions

View File

@ -29,6 +29,7 @@ import com.red.circle.other.app.dto.cmd.game.GameLxwlUpdateBalanceCmd;
import com.red.circle.other.app.dto.cmd.game.GameLxwlUserInfoCmd;
import com.red.circle.other.app.enums.violation.GameOriginEnum;
import com.red.circle.other.app.enums.violation.ViolationTypeEnum;
import com.red.circle.other.app.service.activity.ActivityRechargeTicketService;
import com.red.circle.other.app.service.activity.RankingActivityService;
import com.red.circle.other.app.service.game.GameActivityService;
import com.red.circle.other.app.util.DateTimeAsiaRiyadhUtils;
@ -91,6 +92,7 @@ public class GameHkysRestController {
private final RankingActivityService rankingActivityService;
private final GameActivityService gameActivityService;
private final RedisService redisService;
private final ActivityRechargeTicketService activityRechargeTicketService;
@IgnoreResultResponse
@PostMapping("/getUserInfo")
@ -192,6 +194,9 @@ public class GameHkysRestController {
//处理游戏获得任务
if (cmd.getType() == 2) {
gameActivityService.handleGameSpendTask(userId, cmd.getCoin());
// 累加用户获得的金币并发送抽奖券
activityRechargeTicketService.accumulatedRechargeAndAddTicket(userId, Math.abs(cmd.getCoin()));
}

View File

@ -12,6 +12,7 @@ import com.red.circle.other.infra.database.rds.dto.activity.ActivityRechargeRank
import com.red.circle.other.inner.model.dto.user.OwnSpecialIdDTO;
import com.red.circle.other.inner.model.dto.user.UserProfileDTO;
import com.red.circle.tool.core.collection.CollectionUtils;
import com.red.circle.tool.core.num.NumUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
@ -30,6 +31,11 @@ public class ActivityRechargeRankExe {
private final UserProfileGateway userProfileGateway;
private final UserProfileAppConvertor userProfileAppConvertor;
/**
* 2026春节游戏礼物活动
*/
private static final Long FIXED_ACTIVITY_ID = 2007771533988204877L;
public ActivityRechargeRankCO execute(ActivityRechargeRankCmd cmd) {
Page<ActivityRechargeRankDTO> page = new Page<>(cmd.getPageNo(), cmd.getPageSize());
IPage<ActivityRechargeRankDTO> rankPage = userActivityRechargeDAO.pageRechargeRank(page, cmd.getActivityId());
@ -68,7 +74,7 @@ public class ActivityRechargeRankExe {
.setSpecialAccount(Optional.ofNullable(userProfile.getOwnSpecialId())
.map(OwnSpecialIdDTO::getAccount)
.orElse(null))
.setAmount("***"));
.setAmount(FIXED_ACTIVITY_ID.equals(cmd.getActivityId()) ? NumUtils.formatBigDecimal(dto.getTotalAmount()) : "***"));
}
result.setTopList(topList);

View File

@ -9,7 +9,6 @@ import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.google.common.collect.Lists;
import com.red.circle.common.business.core.enums.SysOriginPlatformEnum;
import com.red.circle.component.mq.MessageEvent;
import com.red.circle.component.mq.service.FixedTopic;
@ -31,6 +30,7 @@ import com.red.circle.other.app.convertor.user.UserProfileAppConvertor;
import com.red.circle.other.app.dto.clientobject.game.GameLuckyGiftMsgCO;
import com.red.circle.other.app.dto.cmd.activity.RankingDataUpdateCmd;
import com.red.circle.other.app.dto.cmd.gift.GiveAwayGiftBatchCmd;
import com.red.circle.other.app.service.activity.ActivityRechargeTicketService;
import com.red.circle.other.app.service.activity.RankingActivityService;
import com.red.circle.other.domain.gateway.user.UserProfileGateway;
import com.red.circle.other.domain.ranking.RankingActivityType;
@ -112,6 +112,7 @@ public class GameLuckyGiftCommon {
private final RankingActivityService rankingActivityService;
private final GiftMqMessage giftMqMessage;
private final GiftAppConvertor giftAppConvertor;
private final ActivityRechargeTicketService activityRechargeTicketService;
/**
* 发送幸运礼物抽奖mq.
@ -257,6 +258,8 @@ public class GameLuckyGiftCommon {
giftMqMessage.sendGift(timeId, giftBatchEvent);
}
// 累加用户获得的金币并发送抽奖券
activityRechargeTicketService.accumulatedRechargeAndAddTicket(param.getUserId(), rewardAmount);
}
@NotNull

View File

@ -0,0 +1,108 @@
package com.red.circle.other.app.service.activity;
import com.red.circle.component.redis.service.RedisService;
import com.red.circle.order.inner.model.enums.MonthlyRechargeType;
import com.red.circle.other.app.util.DistributedLockUtil;
import com.red.circle.other.infra.database.rds.dao.activity.UserActivityRechargeDAO;
import com.red.circle.other.inner.endpoint.activity.LotteryTicketClient;
import com.red.circle.tool.core.date.ZonedDateTimeAsiaRiyadhUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.concurrent.TimeUnit;
@Service
@RequiredArgsConstructor
@Slf4j
public class ActivityRechargeTicketService {
private final UserActivityRechargeDAO userActivityRechargeDAO;
private final RedisService redisService;
private final LotteryTicketClient lotteryTicketClient;
private final DistributedLockUtil distributedLockUtil;
/**
* 2026春节游戏礼物活动
*/
private static final Long FIXED_ACTIVITY_ID = 2007771533988204877L;
/**
* 每100000金币发放1张抽奖券
*/
private static final long TICKET_THRESHOLD = 100000L;
public void accumulatedRechargeAndAddTicket(Long userId, Long rewardAmount) {
// 1. 先累加金币到数据库
LocalDate today = ZonedDateTimeAsiaRiyadhUtils.now().toLocalDate();
String rechargeDate = today.toString();
userActivityRechargeDAO.incrAmount(
userId,
FIXED_ACTIVITY_ID,
rechargeDate,
MonthlyRechargeType.UNDEFINED.name(),
BigDecimal.valueOf(rewardAmount)
);
String lockKey = String.format("lucky:draw:lock:%s:%s", userId, FIXED_ACTIVITY_ID);
distributedLockUtil.executeWithLock(lockKey, () -> {
// 在锁内执行抽奖券发放逻辑
processTicketDistribution(userId);
});
}
/**
* 处理抽奖券发放在分布式锁保护下执行
*/
private void processTicketDistribution(Long userId) {
String thresholdKey = String.format("lucky:draw:threshold:%s:%s", userId, FIXED_ACTIVITY_ID);
BigDecimal totalWinCoins = userActivityRechargeDAO.getUserTotalAmount(userId, FIXED_ACTIVITY_ID);
if (totalWinCoins == null || totalWinCoins.longValue() == 0) {
return;
}
// 获取上次发放时的总金额
String lastTotalStr = redisService.getString(thresholdKey);
long lastTotal = lastTotalStr != null ? Long.parseLong(lastTotalStr) : 0L;
// 计算应发放的抽奖券数量
long currentTotal = totalWinCoins.longValue();
int currentTickets = (int) (currentTotal / TICKET_THRESHOLD); // 当前应有的券数
int lastTickets = (int) (lastTotal / TICKET_THRESHOLD); // 上次已发的券数
int ticketsToGive = currentTickets - lastTickets; // 本次应发券数
if (ticketsToGive > 0) {
log.info("准备发放抽奖券, userId={}, ticketsToGive={}, currentTotal={}, lastTotal={}",
userId, ticketsToGive, currentTotal, lastTotal);
// 逐张发放抽奖券
int successCount = 0;
for (int i = 0; i < ticketsToGive; i++) {
try {
lotteryTicketClient.addTicket(
userId,
FIXED_ACTIVITY_ID,
1,
"LUCK_GIFT",
"LUCK_GIFT_" + currentTotal + "_" + i
);
successCount++;
} catch (Exception e) {
log.error("发放第{}张抽奖券失败, userId={}, currentTotal={}",
i + 1, userId, currentTotal, e);
}
}
// 更新Redis记录只有成功发放了至少1张才更新
if (successCount > 0) {
long newThreshold = lastTotal + (successCount * TICKET_THRESHOLD);
redisService.setString(thresholdKey, String.valueOf(newThreshold));
log.info("抽奖券发放完成, userId={}, 成功发放={}/{}, 更新threshold={}",
userId, successCount, ticketsToGive, newThreshold);
}
}
}
}

View File

@ -29,6 +29,8 @@ import com.red.circle.other.app.dto.cmd.SpinsTaskProgressUpdateCmd;
import com.red.circle.other.app.dto.cmd.activity.RankingDataUpdateCmd;
import com.red.circle.other.app.enums.violation.GameOriginEnum;
import com.red.circle.other.app.service.SpinsUserTaskProgressService;
import com.red.circle.other.app.service.activity.ActivityRechargeService;
import com.red.circle.other.app.service.activity.ActivityRechargeTicketService;
import com.red.circle.other.app.service.activity.RankingActivityService;
import com.red.circle.other.app.service.task.TaskService;
import com.red.circle.other.app.util.DateTimeAsiaRiyadhUtils;
@ -89,6 +91,7 @@ public class GameBaishunServiceImpl implements GameBaishunService {
private final GameListCacheService gameListCacheService;
private final TaskService taskService;
private final GameActivityService gameActivityService;
private final ActivityRechargeTicketService activityRechargeTicketService;
@Value("${red-circle.game-rank.gameid}")
private String gameId;
@ -221,6 +224,9 @@ public class GameBaishunServiceImpl implements GameBaishunService {
//处理游戏获得任务
if (request.getCurrencyDiff() > 0) {
gameActivityService.handleGameSpendTask(userId, Math.abs(request.getCurrencyDiff()));
// 累加用户获得的金币并发送抽奖券
activityRechargeTicketService.accumulatedRechargeAndAddTicket(userId, request.getCurrencyDiff());
}
}

View File

@ -24,6 +24,7 @@ import com.red.circle.other.app.dto.clientobject.game.HotGameUpdateRequest;
import com.red.circle.other.app.dto.cmd.activity.RankingDataUpdateCmd;
import com.red.circle.other.app.dto.cmd.game.GameLxwlUpdateBalanceCmd;
import com.red.circle.other.app.enums.violation.GameOriginEnum;
import com.red.circle.other.app.service.activity.ActivityRechargeTicketService;
import com.red.circle.other.app.service.activity.RankingActivityService;
import com.red.circle.other.app.service.game.GameActivityService;
import com.red.circle.other.app.service.game.override.domain.HotGameUserProfile;
@ -96,6 +97,7 @@ public class HotGameServiceImpl implements HotGameService {
private final GameActivityService gameActivityService;
private final UserActivityRechargeService userActivityRechargeService;
private final GameVipLevelWeeklyService gameVipLevelWeeklyService;
private final ActivityRechargeTicketService activityRechargeTicketService;
@Value("${red-circle.game-rank.gameid}")
private String gameId;
@ -321,6 +323,9 @@ public class HotGameServiceImpl implements HotGameService {
//处理游戏获得任务
if (param.getType() == 2) {
gameActivityService.handleGameSpendTask(userId, param.getCoin());
// 累加用户获得的金币并发送抽奖券
activityRechargeTicketService.accumulatedRechargeAndAddTicket(userId, Math.abs(param.getCoin()));
}
return new HotGameResponse<HotGameCoin>()

View File

@ -12,6 +12,7 @@ import com.red.circle.other.app.convertor.user.UserProfileAppConvertor;
import com.red.circle.other.app.dto.cmd.activity.RankingDataUpdateCmd;
import com.red.circle.other.app.dto.cmd.party3rd.*;
import com.red.circle.other.app.enums.violation.GameOriginEnum;
import com.red.circle.other.app.service.activity.ActivityRechargeTicketService;
import com.red.circle.other.app.service.activity.RankingActivityService;
import com.red.circle.other.app.service.game.override.service.YomiGameService;
import com.red.circle.other.app.util.OfficialNoticeUtils;
@ -67,6 +68,7 @@ public class YomiGameServiceImpl implements YomiGameService {
private final RankingActivityService rankingActivityService;
private final GameActivityService gameActivityService;
private final GameRankingGateway gameRankingGateway;
private final ActivityRechargeTicketService activityRechargeTicketService;
@Override
public YomiTokenCO getToken(YomiGetTokenCmd cmd) {
@ -174,6 +176,9 @@ public class YomiGameServiceImpl implements YomiGameService {
//处理游戏获得任务
gameActivityService.handleGameSpendTask(userId, changeValue.longValue());
// 累加用户获得的金币并发送抽奖券
activityRechargeTicketService.accumulatedRechargeAndAddTicket(userId, Math.abs(changeValue.longValue()));
}
return new YomiBalanceCO(currentBalance);

View File

@ -25,7 +25,7 @@ public class UserActivityRechargeServiceImpl implements UserActivityRechargeServ
/**
* 2026春节活动
*/
private static final Long FIXED_ACTIVITY_ID = 2007771533988204877L;
private static final Long FIXED_ACTIVITY_ID = 2007771533988204888L;
/**
* 热游 用户VIP等级 固定id

View File

@ -1,5 +1,6 @@
import com.red.circle.OtherServiceApplication;
import com.red.circle.component.redis.service.RedisService;
import com.red.circle.other.app.service.activity.ActivityRechargeTicketService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
@ -18,6 +19,8 @@ public class RedisTest {
@Autowired
private RedisTemplate redisTemplate;
@Autowired
private ActivityRechargeTicketService activityRechargeTicketService;
@Test
public void testRedis(){
@ -46,4 +49,10 @@ public class RedisTest {
});
}
@Test
public void testRedis2(){
activityRechargeTicketService.accumulatedRechargeAndAddTicket(1957345312961527809L, 80000L);
}
}