|
|
@@ -7,6 +7,8 @@ import com.xuekairui.quiz.service.RankService;
|
|
|
import com.xuekairui.quiz.util.QuizDedupUtils;
|
|
|
import com.xuekairui.quiz.vo.MyRankVO;
|
|
|
import com.xuekairui.quiz.vo.RankListVO;
|
|
|
+import com.xuekairui.user.entity.User;
|
|
|
+import com.xuekairui.user.mapper.UserMapper;
|
|
|
import lombok.RequiredArgsConstructor;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
|
|
|
@@ -28,14 +30,16 @@ import java.util.stream.Collectors;
|
|
|
public class RankServiceImpl implements RankService {
|
|
|
|
|
|
private final QuizUserRecordMapper userRecordMapper;
|
|
|
+ private final UserMapper userMapper;
|
|
|
|
|
|
@Override
|
|
|
- public RankListVO getRankList(Long userId, String period, String rankType, int pageNo, int pageSize) {
|
|
|
+ public RankListVO getRankList(Long userId, String period, String rankType) {
|
|
|
LocalDateTime[] timeRange = getTimeRange(period);
|
|
|
|
|
|
List<QuizUserRecord> records = userRecordMapper.selectList(
|
|
|
new LambdaQueryWrapper<QuizUserRecord>()
|
|
|
.eq(QuizUserRecord::getStatus, 1)
|
|
|
+ .ne(QuizUserRecord::getAnswerType, 99)
|
|
|
.ge(QuizUserRecord::getCreateTime, timeRange[0])
|
|
|
.le(QuizUserRecord::getCreateTime, timeRange[1])
|
|
|
);
|
|
|
@@ -47,23 +51,43 @@ public class RankServiceImpl implements RankService {
|
|
|
List<UserStats> sorted = new ArrayList<>(statsMap.values());
|
|
|
if ("correctRate".equals(rankType)) {
|
|
|
sorted.sort((a, b) -> b.correctRate.compareTo(a.correctRate));
|
|
|
- } else {
|
|
|
- // 默认按做题总数排序
|
|
|
+ } else if ("totalCount".equals(rankType)) {
|
|
|
sorted.sort((a, b) -> b.totalCount - a.totalCount);
|
|
|
+ } else {
|
|
|
+ // 默认按做对题数排序
|
|
|
+ sorted.sort((a, b) -> b.correctCount - a.correctCount);
|
|
|
}
|
|
|
|
|
|
- // 分页
|
|
|
+ // 固定取 TOP 10
|
|
|
int total = sorted.size();
|
|
|
- int fromIndex = Math.min((pageNo - 1) * pageSize, total);
|
|
|
- int toIndex = Math.min(fromIndex + pageSize, total);
|
|
|
- List<UserStats> pageList = sorted.subList(fromIndex, toIndex);
|
|
|
+ int topSize = Math.min(10, total);
|
|
|
+ List<UserStats> topList = sorted.subList(0, topSize);
|
|
|
|
|
|
List<RankListVO.RankItemVO> list = new ArrayList<>();
|
|
|
- int rank = fromIndex + 1;
|
|
|
- for (UserStats stats : pageList) {
|
|
|
+ // 批量查询用户昵称
|
|
|
+ List<Long> userIds = topList.stream().map(s -> s.userId).collect(Collectors.toList());
|
|
|
+ Map<Long, String> nicknameMap = new LinkedHashMap<>();
|
|
|
+ if (!userIds.isEmpty()) {
|
|
|
+ List<User> users = userMapper.selectList(
|
|
|
+ new LambdaQueryWrapper<User>()
|
|
|
+ .in(User::getId, userIds)
|
|
|
+ .select(User::getId, User::getNickname)
|
|
|
+ );
|
|
|
+ for (User u : users) {
|
|
|
+ nicknameMap.put(u.getId(), u.getNickname());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ int rank = 1;
|
|
|
+ for (UserStats stats : topList) {
|
|
|
+ String nick = nicknameMap.get(stats.userId);
|
|
|
+ // 本人返回完整昵称,其他用户脱敏
|
|
|
+ if (!stats.userId.equals(userId)) {
|
|
|
+ nick = maskNickname(nick);
|
|
|
+ }
|
|
|
list.add(RankListVO.RankItemVO.builder()
|
|
|
.rank(rank++)
|
|
|
.userId(stats.userId)
|
|
|
+ .nickname(nick)
|
|
|
.totalCount(stats.totalCount)
|
|
|
.correctCount(stats.correctCount)
|
|
|
.correctRate(stats.correctRate)
|
|
|
@@ -79,27 +103,11 @@ public class RankServiceImpl implements RankService {
|
|
|
.build();
|
|
|
}
|
|
|
|
|
|
- @Override
|
|
|
- public MyRankVO getMyRank(Long userId, String period, String rankType) {
|
|
|
- LocalDateTime[] timeRange = getTimeRange(period);
|
|
|
-
|
|
|
- List<QuizUserRecord> records = userRecordMapper.selectList(
|
|
|
- new LambdaQueryWrapper<QuizUserRecord>()
|
|
|
- .eq(QuizUserRecord::getStatus, 1)
|
|
|
- .ge(QuizUserRecord::getCreateTime, timeRange[0])
|
|
|
- .le(QuizUserRecord::getCreateTime, timeRange[1])
|
|
|
- );
|
|
|
-
|
|
|
- Map<Long, UserStats> statsMap = aggregateStats(records);
|
|
|
-
|
|
|
- // 排序并找到当前用户的排名
|
|
|
- List<UserStats> sorted = new ArrayList<>(statsMap.values());
|
|
|
- if ("correctRate".equals(rankType)) {
|
|
|
- sorted.sort((a, b) -> b.correctRate.compareTo(a.correctRate));
|
|
|
- } else {
|
|
|
- sorted.sort((a, b) -> b.totalCount - a.totalCount);
|
|
|
- }
|
|
|
-
|
|
|
+ /**
|
|
|
+ * 构建当前用户自身排名数据
|
|
|
+ */
|
|
|
+ private MyRankVO buildMyRank(Long userId, Map<Long, UserStats> statsMap,
|
|
|
+ List<UserStats> sorted, String period, String rankType) {
|
|
|
UserStats myStats = statsMap.get(userId);
|
|
|
int myRank = 0;
|
|
|
for (int i = 0; i < sorted.size(); i++) {
|
|
|
@@ -111,6 +119,7 @@ public class RankServiceImpl implements RankService {
|
|
|
|
|
|
MyRankVO.MyRankVOBuilder builder = MyRankVO.builder()
|
|
|
.userId(userId)
|
|
|
+ .nickname(getNickname(userId))
|
|
|
.rank(myRank)
|
|
|
.totalUsers(sorted.size())
|
|
|
.period(period)
|
|
|
@@ -130,6 +139,54 @@ public class RankServiceImpl implements RankService {
|
|
|
return builder.build();
|
|
|
}
|
|
|
|
|
|
+ @Override
|
|
|
+ public MyRankVO getMyRank(Long userId, String period, String rankType) {
|
|
|
+ LocalDateTime[] timeRange = getTimeRange(period);
|
|
|
+
|
|
|
+ List<QuizUserRecord> records = userRecordMapper.selectList(
|
|
|
+ new LambdaQueryWrapper<QuizUserRecord>()
|
|
|
+ .eq(QuizUserRecord::getStatus, 1)
|
|
|
+ .ne(QuizUserRecord::getAnswerType, 99)
|
|
|
+ .ge(QuizUserRecord::getCreateTime, timeRange[0])
|
|
|
+ .le(QuizUserRecord::getCreateTime, timeRange[1])
|
|
|
+ );
|
|
|
+
|
|
|
+ Map<Long, UserStats> statsMap = aggregateStats(records);
|
|
|
+
|
|
|
+ // 排序
|
|
|
+ List<UserStats> sorted = new ArrayList<>(statsMap.values());
|
|
|
+ if ("correctRate".equals(rankType)) {
|
|
|
+ sorted.sort((a, b) -> b.correctRate.compareTo(a.correctRate));
|
|
|
+ } else if ("totalCount".equals(rankType)) {
|
|
|
+ sorted.sort((a, b) -> b.totalCount - a.totalCount);
|
|
|
+ } else {
|
|
|
+ sorted.sort((a, b) -> b.correctCount - a.correctCount);
|
|
|
+ }
|
|
|
+
|
|
|
+ return buildMyRank(userId, statsMap, sorted, period, rankType);
|
|
|
+ }
|
|
|
+
|
|
|
+ private String getNickname(Long userId) {
|
|
|
+ if (userId == null) return null;
|
|
|
+ User user = userMapper.selectById(userId);
|
|
|
+ return user != null ? user.getNickname() : null;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 昵称脱敏:保留首字,其余用 * 替换
|
|
|
+ * 例:张三 → 张*,张三丰 → 张**,John → J***
|
|
|
+ */
|
|
|
+ private String maskNickname(String nickname) {
|
|
|
+ if (nickname == null || nickname.isEmpty()) return nickname;
|
|
|
+ if (nickname.length() == 1) return "*";
|
|
|
+ StringBuilder sb = new StringBuilder();
|
|
|
+ sb.append(nickname.charAt(0));
|
|
|
+ for (int i = 1; i < nickname.length(); i++) {
|
|
|
+ sb.append("*");
|
|
|
+ }
|
|
|
+ return sb.toString();
|
|
|
+ }
|
|
|
+
|
|
|
private Map<Long, UserStats> aggregateStats(List<QuizUserRecord> records) {
|
|
|
Map<Long, List<QuizUserRecord>> grouped = records.stream()
|
|
|
.collect(Collectors.groupingBy(QuizUserRecord::getUserId));
|
|
|
@@ -175,7 +232,7 @@ public class RankServiceImpl implements RankService {
|
|
|
|
|
|
private LocalDateTime[] getTimeRange(String period) {
|
|
|
LocalDate today = LocalDate.now();
|
|
|
- return switch (period != null ? period : "all") {
|
|
|
+ return switch (period != null ? period : "week") {
|
|
|
case "week" -> new LocalDateTime[]{
|
|
|
today.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY)).atStartOfDay(),
|
|
|
today.with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY)).atTime(LocalTime.MAX)
|