From 38fde497128e7457d3a38ea552467a87c6479446 Mon Sep 17 00:00:00 2001 From: tianfeng <769204422@qq.com> Date: Tue, 10 Feb 2026 16:16:22 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=8B=E6=9C=88=E5=AE=9E=E6=97=B6=E5=8B=8B?= =?UTF-8?q?=E7=AB=A0=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../activity/RamadanRankingBadgeTask.java | 160 ++++++++++++++++++ 1 file changed, 160 insertions(+) create mode 100644 rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/scheduler/activity/RamadanRankingBadgeTask.java diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/scheduler/activity/RamadanRankingBadgeTask.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/scheduler/activity/RamadanRankingBadgeTask.java new file mode 100644 index 00000000..ed5c2cb3 --- /dev/null +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/scheduler/activity/RamadanRankingBadgeTask.java @@ -0,0 +1,160 @@ +package com.red.circle.other.app.scheduler.activity; + +import com.red.circle.common.business.core.enums.SysOriginPlatformEnum; +import com.red.circle.component.redis.annotation.TaskCacheLock; +import com.red.circle.mq.business.model.event.BadgeOperateEvent; +import com.red.circle.mq.rocket.business.producer.UserMqMessageService; +import com.red.circle.other.domain.ranking.RankingActivityType; +import com.red.circle.other.domain.ranking.RankingCycleType; +import com.red.circle.other.infra.database.mongo.entity.activity.RankingActivityRecord; +import com.red.circle.other.infra.database.rds.entity.badge.BadgeBackpack; +import com.red.circle.other.infra.database.rds.service.badge.BadgeBackpackService; +import com.red.circle.other.infra.gateway.RankingActivityGateway; +import com.red.circle.other.inner.enums.material.BadgeBackpackExpireType; +import com.red.circle.tool.core.date.TimestampUtils; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.util.*; +import java.util.stream.Collectors; + + +@Slf4j +@Component +@RequiredArgsConstructor +public class RamadanRankingBadgeTask { + + private final BadgeBackpackService badgeBackpackService; + private final UserMqMessageService userMqMessageService; + private final RankingActivityGateway rankingActivityGateway; + + // 排名徽章ID数组:[第一名, 第二名, 第三名] + private final static Long[] BADGE_IDS = new Long[]{ + 2012070776778235906L, // 第一名 + 2012070846403682305L, // 第二名 + 2012070905480708098L // 第三名 + }; + + /** + * 每分钟发放和收回排名徽章 + */ +// @Scheduled(cron = "0 0/1 * * * *", zone = "Asia/Riyadh") + @TaskCacheLock(key = "RAMADAN_RANKING_BADGE_TASK", expireSecond = 20) + public void sendWeekRankingReward() { + try { + // 获取前十名 + List top10 = rankingActivityGateway.getRankingList( + SysOriginPlatformEnum.LIKEI.name(), + RankingActivityType.RAMADAN, + RankingCycleType.MONTHLY, + "2026-02-17", + null, + 10 + ); + + // 2. 查询所有持有排名徽章的用户 + List allBackpackList = badgeBackpackService.query() + .in(BadgeBackpack::getBadgeId, Arrays.asList(BADGE_IDS)) + .list() + .stream() + .filter(RamadanRankingBadgeTask::filterAvailable) + .collect(Collectors.toList()); + + // 3. 构建"用户应得徽章集合":Map> + Map> userShouldHaveBadgesMap = new HashMap<>(); + + for (int rank = 0; rank < top10.size() && rank < 10; rank++) { + RankingActivityRecord rankingData = top10.get(rank); + Long badgeId = BADGE_IDS[rank]; + userShouldHaveBadgesMap.computeIfAbsent(rankingData.getUserId(), k -> new HashSet<>()).add(badgeId); + } + + // 4. 构建"用户当前持有徽章集合":Map> + Map> userCurrentBadgesMap = new HashMap<>(); + for (BadgeBackpack backpack : allBackpackList) { + userCurrentBadgesMap.computeIfAbsent(backpack.getUserId(), k -> new HashSet<>()) + .add(backpack.getBadgeId()); + } + + // 5. 发放缺失的徽章 + for (Map.Entry> entry : userShouldHaveBadgesMap.entrySet()) { + Long userId = entry.getKey(); + Set shouldHaveBadges = entry.getValue(); + Set currentBadges = userCurrentBadgesMap.getOrDefault(userId, Collections.emptySet()); + + // 找出缺失的徽章(应得但当前没有的) + for (Long badgeId : shouldHaveBadges) { + if (!currentBadges.contains(badgeId)) { + grantBadge(userId, badgeId); + int rank = Arrays.asList(BADGE_IDS).indexOf(badgeId) + 1; + log.info("排名徽章发放:rank={}, userId={}, badgeId={}", rank, userId, badgeId); + } + } + } + + // 6. 收回多余的徽章 + for (Map.Entry> entry : userCurrentBadgesMap.entrySet()) { + Long userId = entry.getKey(); + Set currentBadges = entry.getValue(); + Set shouldHaveBadges = userShouldHaveBadgesMap.getOrDefault(userId, Collections.emptySet()); + + // 找出多余的徽章(当前有但不应得的) + for (Long badgeId : currentBadges) { + if (!shouldHaveBadges.contains(badgeId)) { + revokeBadge(userId, badgeId); + int rank = Arrays.asList(BADGE_IDS).indexOf(badgeId) + 1; + log.info("排名徽章收回:rank={}, userId={}, badgeId={} (用户不在该排名中)", + rank, userId, badgeId); + } + } + } + + } catch (Exception e) { + log.error("排名徽章任务执行异常", e); + } + } + + /** + * 检查用户是否已持有该徽章 + */ + private boolean hasUserBadge(List backpackList, Long userId, Long badgeId) { + return backpackList.stream() + .anyMatch(b -> Objects.equals(b.getUserId(), userId) + && Objects.equals(b.getBadgeId(), badgeId)); + } + + private static boolean filterAvailable(BadgeBackpack badgeBackpack) { + return Objects.equals(badgeBackpack.getExpireType(), + BadgeBackpackExpireType.PERMANENT.name()) + || badgeBackpack.getExpireTime().after(TimestampUtils.now()); + } + + /** + * 发放徽章 + */ + private void grantBadge(Long userId, Long badgeId) { + BadgeOperateEvent event = new BadgeOperateEvent() + .setUserId(userId) + .setBadgeId(badgeId) + .setDays(1L) + .setOperationType(BadgeOperateEvent.OperationType.WEAR.name()); + + userMqMessageService.sendBadgeOperateEvent(event); + } + + /** + * 收回徽章 + */ + private void revokeBadge(Long userId, Long badgeId) { + BadgeOperateEvent event = new BadgeOperateEvent() + .setUserId(userId) + .setBadgeId(badgeId) + .setDays(1L) + .setOperationType(BadgeOperateEvent.OperationType.REMOVE.name()); + + userMqMessageService.sendBadgeOperateEvent(event); + } + +}