From 78c9b31280ea2c0b65b38c785ee4ad72d41000d9 Mon Sep 17 00:00:00 2001 From: tianfeng <769204422@qq.com> Date: Tue, 10 Feb 2026 15:10:15 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=20=E5=B9=B8=E8=BF=90&?= =?UTF-8?q?=E9=AD=94=E6=B3=95=E7=A4=BC=E7=89=A9&=E6=B8=B8=E6=88=8F=20?= =?UTF-8?q?=E8=B5=A2=E5=BE=97=E9=87=91=E5=B8=81=E5=8F=91=E9=80=81=E6=8A=BD?= =?UTF-8?q?=E5=A5=96=E5=88=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../game/party3rd/GameHkysRestController.java | 5 + .../activity/ActivityRechargeRankExe.java | 8 +- .../app/common/gift/GameLuckyGiftCommon.java | 5 +- .../ActivityRechargeTicketService.java | 108 ++++++++++++++++++ .../service/game/GameBaishunServiceImpl.java | 6 + .../app/service/game/HotGameServiceImpl.java | 5 + .../app/service/game/YomiGameServiceImpl.java | 5 + .../impl/UserActivityRechargeServiceImpl.java | 2 +- .../other-start/src/test/java/RedisTest.java | 9 ++ 9 files changed, 150 insertions(+), 3 deletions(-) create mode 100644 rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/service/activity/ActivityRechargeTicketService.java diff --git a/rc-service/rc-service-other/other-adapter/src/main/java/com/red/circle/other/adapter/app/game/party3rd/GameHkysRestController.java b/rc-service/rc-service-other/other-adapter/src/main/java/com/red/circle/other/adapter/app/game/party3rd/GameHkysRestController.java index 4ebdcf4a..d066bfe5 100644 --- a/rc-service/rc-service-other/other-adapter/src/main/java/com/red/circle/other/adapter/app/game/party3rd/GameHkysRestController.java +++ b/rc-service/rc-service-other/other-adapter/src/main/java/com/red/circle/other/adapter/app/game/party3rd/GameHkysRestController.java @@ -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())); } diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/ActivityRechargeRankExe.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/ActivityRechargeRankExe.java index 17000a2f..2570a2c7 100644 --- a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/ActivityRechargeRankExe.java +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/ActivityRechargeRankExe.java @@ -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 page = new Page<>(cmd.getPageNo(), cmd.getPageSize()); IPage 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); diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/common/gift/GameLuckyGiftCommon.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/common/gift/GameLuckyGiftCommon.java index 393d57f4..cd4099b1 100644 --- a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/common/gift/GameLuckyGiftCommon.java +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/common/gift/GameLuckyGiftCommon.java @@ -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 diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/service/activity/ActivityRechargeTicketService.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/service/activity/ActivityRechargeTicketService.java new file mode 100644 index 00000000..e158a49f --- /dev/null +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/service/activity/ActivityRechargeTicketService.java @@ -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); + } + } + } +} \ No newline at end of file diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/service/game/GameBaishunServiceImpl.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/service/game/GameBaishunServiceImpl.java index 7680c9e0..79d16724 100644 --- a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/service/game/GameBaishunServiceImpl.java +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/service/game/GameBaishunServiceImpl.java @@ -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()); } } diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/service/game/HotGameServiceImpl.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/service/game/HotGameServiceImpl.java index cfacbd60..9b40d299 100644 --- a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/service/game/HotGameServiceImpl.java +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/service/game/HotGameServiceImpl.java @@ -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() diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/service/game/YomiGameServiceImpl.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/service/game/YomiGameServiceImpl.java index 266c248a..14adffc5 100644 --- a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/service/game/YomiGameServiceImpl.java +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/service/game/YomiGameServiceImpl.java @@ -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); diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/activity/impl/UserActivityRechargeServiceImpl.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/activity/impl/UserActivityRechargeServiceImpl.java index 04c81471..0042d274 100644 --- a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/activity/impl/UserActivityRechargeServiceImpl.java +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/activity/impl/UserActivityRechargeServiceImpl.java @@ -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 diff --git a/rc-service/rc-service-other/other-start/src/test/java/RedisTest.java b/rc-service/rc-service-other/other-start/src/test/java/RedisTest.java index 046bcde7..8f754f9c 100644 --- a/rc-service/rc-service-other/other-start/src/test/java/RedisTest.java +++ b/rc-service/rc-service-other/other-start/src/test/java/RedisTest.java @@ -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); + + } + }