diff --git a/rc-service/rc-service-other/other-adapter/src/main/java/com/red/circle/other/adapter/app/activity/RankingActivityRestController.java b/rc-service/rc-service-other/other-adapter/src/main/java/com/red/circle/other/adapter/app/activity/RankingActivityRestController.java index 474a393f..bfdec906 100644 --- a/rc-service/rc-service-other/other-adapter/src/main/java/com/red/circle/other/adapter/app/activity/RankingActivityRestController.java +++ b/rc-service/rc-service-other/other-adapter/src/main/java/com/red/circle/other/adapter/app/activity/RankingActivityRestController.java @@ -59,6 +59,9 @@ public class RankingActivityRestController extends BaseController { return rankingActivityService.getRankingList(cmd); } + + + /** * 查询历史Top1列表(周榜) * @@ -89,4 +92,17 @@ public class RankingActivityRestController extends BaseController { cmd.setTemplateId("2001207026499137537"); return rankingActivityService.getTopFourRankingWithReward(cmd); } + + /** + * 查询总榜前三名 + * + * 用途:获取指定活动的总榜(跨所有周期,按用户ID分组汇总)前三名用户 + * + * @param cmd 查询命令 + * @return 总榜前三名 + */ + @PostMapping("/top-three-overall") + public List getTopThreeOverall(@RequestBody @Validated RankingListQueryCmd cmd) { + return rankingActivityService.getTopThreeOverall(cmd); + } } \ 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/activity/RankingActivityServiceImpl.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/service/activity/RankingActivityServiceImpl.java index 435bf55f..01d6bfa8 100644 --- a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/service/activity/RankingActivityServiceImpl.java +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/service/activity/RankingActivityServiceImpl.java @@ -20,12 +20,16 @@ import java.util.Objects; import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; +import java.util.stream.IntStream; import com.red.circle.other.domain.gateway.user.UserProfileGateway; import com.red.circle.other.domain.model.user.UserProfile; 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.gateway.RankingActivityGateway; import com.red.circle.tool.core.collection.CollectionUtils; +import com.red.circle.tool.core.num.NumUtils; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -45,6 +49,7 @@ public class RankingActivityServiceImpl implements RankingActivityService { private final RedisService redisService; private final UserMqMessageService userMqMessageService; private final UserProfileGateway userProfileGateway; + private final RankingActivityGateway rankingActivityGateway; private static final String RANKING_LIST_CACHE_KEY_PREFIX = "ranking_list:"; private static final int CACHE_EXPIRE_MINUTES = 10; @@ -224,4 +229,46 @@ public class RankingActivityServiceImpl implements RankingActivityService { private String buildRankingListCacheKey(RankingListQueryCmd cmd) { return RANKING_LIST_CACHE_KEY_PREFIX + RankingActivityType.getByCode(cmd.getActivityType()).name() + ":" + cmd.getCycleKey(); } + + @Override + public List getTopThreeOverall(RankingListQueryCmd cmd) { + // 查询总榜排行(按用户ID分组汇总) + List records = rankingActivityGateway.getOverallRankingList( + cmd.getReqSysOrigin().getOrigin(), + RankingActivityType.getByCode(cmd.getActivityType()), + 3 // 只获取前三名 + ); + + if (CollectionUtils.isEmpty(records)) { + return List.of(); + } + + // 获取用户信息 + Set userIds = records.stream() + .map(RankingActivityRecord::getUserId) + .collect(Collectors.toSet()); + + Map userProfileMap = userProfileGateway.mapByUserIds(userIds); + + // 转换为VO并设置排名 + return IntStream.range(0, records.size()) + .mapToObj(i -> { + RankingActivityRecord record = records.get(i); + UserProfile profile = userProfileMap.get(record.getUserId()); + + RankingUserVO vo = new RankingUserVO(); + vo.setUserId(record.getUserId()); + vo.setRank(i + 1); // 排名从1开始 + vo.setQuantity(NumUtils.formatLong(record.getQuantity())); + + if (profile != null) { + vo.setAccount(profile.getAccount()); + vo.setNickname(profile.getUserNickname()); + vo.setAvatar(profile.getUserAvatar()); + } + + return vo; + }) + .collect(Collectors.toList()); + } } diff --git a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/service/activity/RankingActivityService.java b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/service/activity/RankingActivityService.java index 6c21b553..e028afb8 100644 --- a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/service/activity/RankingActivityService.java +++ b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/service/activity/RankingActivityService.java @@ -55,4 +55,12 @@ public interface RankingActivityService { * @return 排行榜前四名 */ List getTopFourRankingWithReward(RankingListQueryCmd cmd); + + /** + * 获取总榜前三名 + * + * @param cmd 查询命令 + * @return 总榜前三名用户列表 + */ + List getTopThreeOverall(RankingListQueryCmd cmd); } diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/gateway/RankingActivityGateway.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/gateway/RankingActivityGateway.java index 67dd9356..7ab0dfcd 100644 --- a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/gateway/RankingActivityGateway.java +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/gateway/RankingActivityGateway.java @@ -108,4 +108,18 @@ public interface RankingActivityGateway { RankingActivityType activityType, String cycleKey ); -} \ No newline at end of file + + /** + * 查询总榜排行(按用户ID分组汇总所有周期数据) + * + * @param sysOrigin 平台 + * @param activityType 活动类型 + * @param topN 查询数量 + * @return 总榜排行列表 + */ + List getOverallRankingList( + String sysOrigin, + RankingActivityType activityType, + Integer topN + ); +} diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/gateway/RankingActivityGatewayImpl.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/gateway/RankingActivityGatewayImpl.java index f5576c19..466fcbfa 100644 --- a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/gateway/RankingActivityGatewayImpl.java +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/gateway/RankingActivityGatewayImpl.java @@ -9,6 +9,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.data.domain.PageRequest; import org.springframework.data.mongodb.core.FindAndModifyOptions; import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.aggregation.Aggregation; import org.springframework.data.mongodb.core.query.Criteria; import org.springframework.stereotype.Component; import org.springframework.data.mongodb.core.query.Query; @@ -164,4 +165,44 @@ public class RankingActivityGatewayImpl implements RankingActivityGateway { userIds, activityType, cycleKey, NOT_DELETED ); } -} \ No newline at end of file + + @Override + public List getOverallRankingList( + String sysOrigin, + RankingActivityType activityType, + Integer topN) { + + // 使用 MongoDB 聚合查询,按 userId 分组汇总所有周期的数据 + Aggregation aggregation = + Aggregation.newAggregation( + // 1. 匹配条件:平台、活动类型、未删除 + Aggregation.match( + Criteria.where("sysOrigin").is(sysOrigin) + .and("activityType").is(activityType) + .and("deleted").is(NOT_DELETED) + ), + // 2. 按 userId 分组,汇总 quantity + Aggregation.group("userId") + .sum("quantity").as("quantity") + .first("userId").as("userId") + .first("userSex").as("userSex") + .first("activityType").as("activityType") + .first("dimension").as("dimension"), + // 3. 按总数量降序排序 + Aggregation.sort( + org.springframework.data.domain.Sort.Direction.DESC, "quantity" + ), + // 4. 限制返回数量 + Aggregation.limit(topN) + ); + + // 执行聚合查询 + List results = mongoTemplate.aggregate( + aggregation, + "ranking_activity_record", // collection name + RankingActivityRecord.class + ).getMappedResults(); + + return results; + } +}