斋月实时勋章处理

This commit is contained in:
tianfeng 2026-02-10 16:16:22 +08:00
parent dbd943e1f4
commit 38fde49712

View File

@ -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<RankingActivityRecord> top10 = rankingActivityGateway.getRankingList(
SysOriginPlatformEnum.LIKEI.name(),
RankingActivityType.RAMADAN,
RankingCycleType.MONTHLY,
"2026-02-17",
null,
10
);
// 2. 查询所有持有排名徽章的用户
List<BadgeBackpack> allBackpackList = badgeBackpackService.query()
.in(BadgeBackpack::getBadgeId, Arrays.asList(BADGE_IDS))
.list()
.stream()
.filter(RamadanRankingBadgeTask::filterAvailable)
.collect(Collectors.toList());
// 3. 构建"用户应得徽章集合"Map<userId, Set<badgeId>>
Map<Long, Set<Long>> 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<userId, Set<badgeId>>
Map<Long, Set<Long>> userCurrentBadgesMap = new HashMap<>();
for (BadgeBackpack backpack : allBackpackList) {
userCurrentBadgesMap.computeIfAbsent(backpack.getUserId(), k -> new HashSet<>())
.add(backpack.getBadgeId());
}
// 5. 发放缺失的徽章
for (Map.Entry<Long, Set<Long>> entry : userShouldHaveBadgesMap.entrySet()) {
Long userId = entry.getKey();
Set<Long> shouldHaveBadges = entry.getValue();
Set<Long> 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<Long, Set<Long>> entry : userCurrentBadgesMap.entrySet()) {
Long userId = entry.getKey();
Set<Long> currentBadges = entry.getValue();
Set<Long> 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<BadgeBackpack> 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);
}
}