Browse Source

feat(game-event): 新增成绩预览功能并优化项目查询

- 新增成绩预览列表查询、修改、删除接口实现
- 添加ScorePreviewVo和ScorePreviewUpdateBo数据对象
- 实现成绩预览相关的控制器和业务逻辑
- 优化项目选项精简列表查询功能
- 完善成绩删除时关联明细的处理逻辑
- 重构部分代码结构提升可维护性
zhou 2 tuần trước cách đây
mục cha
commit
6a275aa55f
13 tập tin đã thay đổi với 402 bổ sung5 xóa
  1. 10 0
      ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/controller/GameEventProjectController.java
  2. 31 0
      ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/controller/app_client/ToClientController.java
  3. 34 0
      ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/domain/bo/ScorePreviewUpdateBo.java
  4. 46 0
      ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/domain/vo/GameProjectOptionVo.java
  5. 39 0
      ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/domain/vo/ScorePreviewVo.java
  6. 6 0
      ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/mapper/app/ToClientMapper.java
  7. 6 0
      ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/service/IGameEventProjectService.java
  8. 8 0
      ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/service/IGameScoreService.java
  9. 17 0
      ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/service/app/IToClientService.java
  10. 27 4
      ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/service/impl/GameEventProjectServiceImpl.java
  11. 29 0
      ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/service/impl/GameScoreServiceImpl.java
  12. 127 1
      ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/service/impl/app/ToClientServiceImpl.java
  13. 22 0
      ruoyi-modules/ruoyi-game-event/src/main/resources/mapper/system/app/ToClientMapper.xml

+ 10 - 0
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/controller/GameEventProjectController.java

@@ -20,6 +20,7 @@ import org.dromara.common.core.validate.EditGroup;
 import org.dromara.common.log.enums.BusinessType;
 import org.dromara.common.excel.utils.ExcelUtil;
 import org.dromara.system.domain.vo.GameEventProjectVo;
+import org.dromara.system.domain.vo.GameProjectOptionVo;
 import org.dromara.system.domain.bo.GameEventProjectBo;
 import org.dromara.system.service.IGameEventProjectService;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
@@ -65,6 +66,15 @@ public class GameEventProjectController extends BaseController {
         return gameEventProjectService.queryAllProjectList(bo, pageQuery);
     }
 
+    /**
+     * 查询项目选项精简列表
+     */
+    @SaCheckPermission("system:gameEventProject:list")
+    @GetMapping("/optionList")
+    public R<List<GameProjectOptionVo>> optionList(GameEventProjectBo bo) {
+        return R.ok(gameEventProjectService.selectOptionList(bo));
+    }
+
     /**
      * 导出赛事项目列表
      */

+ 31 - 0
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/controller/app_client/ToClientController.java

@@ -8,7 +8,9 @@ import org.dromara.common.log.enums.BusinessType;
 import org.dromara.system.domain.GameEvent;
 import org.dromara.system.domain.GameEventProject;
 import org.dromara.system.domain.bo.ClientProjectSaveBo;
+import org.dromara.system.domain.bo.ScorePreviewUpdateBo;
 import org.dromara.system.domain.bo.ScoreSubmitBo;
+import org.dromara.system.domain.vo.ScorePreviewVo;
 import org.dromara.system.domain.vo.ScoreSheetVo;
 import org.dromara.system.service.app.IToClientService;
 import org.springframework.validation.annotation.Validated;
@@ -82,4 +84,33 @@ public class ToClientController {
         toClientService.submitScoreSheet(bo);
         return R.ok();
     }
+
+    /**
+     * 成绩预览列表查询 (接口8)
+     */
+    @GetMapping("/scorePreviewList")
+    public R<List<ScorePreviewVo>> scorePreviewList(@RequestParam Long projectId) {
+        return R.ok(toClientService.getScorePreviewList(projectId));
+    }
+
+    /**
+     * 成绩预览列表修改成绩 (接口9)
+     */
+    @Log(title = "app客户端修改预览成绩", businessType = BusinessType.UPDATE)
+    @RepeatSubmit()
+    @PostMapping("/scorePreviewUpdate")
+    public R<Void> scorePreviewUpdate(@Validated @RequestBody ScorePreviewUpdateBo bo) {
+        toClientService.updateScorePreview(bo);
+        return R.ok();
+    }
+
+    /**
+     * 成绩预览列表删除成绩 (接口10)
+     */
+    @Log(title = "app客户端删除预览成绩", businessType = BusinessType.DELETE)
+    @DeleteMapping("/scorePreviewRemove/{scoreId}")
+    public R<Void> scorePreviewRemove(@PathVariable Long scoreId) {
+        toClientService.removeScorePreview(scoreId);
+        return R.ok();
+    }
 }

+ 34 - 0
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/domain/bo/ScorePreviewUpdateBo.java

@@ -0,0 +1,34 @@
+package org.dromara.system.domain.bo;
+
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 成绩预览列表修改业务对象
+ */
+@Data
+public class ScorePreviewUpdateBo {
+
+    /** 成绩ID */
+    @NotNull(message = "成绩ID不能为空")
+    private Long scoreId;
+
+    /** 队员号码 */
+    private String athleteCode;
+
+    /** 队员姓名 */
+    private String name;
+
+    /** 队伍名称 */
+    private String teamName;
+
+    /** 成绩 */
+    @NotBlank(message = "成绩不能为空")
+    private String score;
+
+    /** 成绩明细列表 */
+    private List<GameScoreDetailBo> details;
+}

+ 46 - 0
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/domain/vo/GameProjectOptionVo.java

@@ -0,0 +1,46 @@
+package org.dromara.system.domain.vo;
+
+import io.github.linpeilie.annotations.AutoMapper;
+import org.dromara.system.domain.GameEventProject;
+import lombok.Data;
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * 项目下拉选项精简视图对象
+ *
+ * @author zlt
+ */
+@Data
+@AutoMapper(target = GameEventProject.class)
+public class GameProjectOptionVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 项目ID
+     */
+    private Long projectId;
+
+    /**
+     * 项目名称
+     */
+    private String projectName;
+
+    /**
+     * 项目分类(0个人 1团体)
+     */
+    private String classification;
+
+    /**
+     * 成绩规则
+     */
+    private String scoreRule;
+
+    /**
+     * 计量单位
+     */
+    private String countUnit;
+
+}

+ 39 - 0
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/domain/vo/ScorePreviewVo.java

@@ -0,0 +1,39 @@
+package org.dromara.system.domain.vo;
+
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 成绩预览列表视图对象
+ */
+@Data
+public class ScorePreviewVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /** 成绩ID */
+    private Long scoreId;
+    /** 运动员ID */
+    private Long athleteId;
+    /** 队伍ID */
+    private Long teamId;
+    /** 队员号码 */
+    private String athleteCode;
+    /** 队员姓名 */
+    private String name;
+    /** 队伍名称 */
+    private String teamName;
+    /** 成绩 */
+    private String score;
+    /** 积分 */
+    private Integer scorePoint;
+    /** 名次 */
+    private Integer scoreRank;
+
+    /** 成绩明细列表 */
+    private List<ScoreSheetDetailVo> details;
+}

+ 6 - 0
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/mapper/app/ToClientMapper.java

@@ -2,6 +2,7 @@ package org.dromara.system.mapper.app;
 
 import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Param;
+import org.dromara.system.domain.vo.ScorePreviewVo;
 import org.dromara.system.domain.vo.ScoreSheetItemVo;
 import org.dromara.system.domain.vo.ScoreSheetVo;
 
@@ -20,4 +21,9 @@ public interface ToClientMapper {
      * 获取成绩记录单项列表
      */
     List<ScoreSheetItemVo> selectScoreSheetItems(@Param("eventId") Long eventId, @Param("projectId") Long projectId);
+
+    /**
+     * 获取成绩预览列表 (接口8)
+     */
+    List<ScorePreviewVo> selectScorePreviewList(@Param("projectId") Long projectId);
 }

+ 6 - 0
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/service/IGameEventProjectService.java

@@ -3,6 +3,7 @@ package org.dromara.system.service;
 import org.dromara.system.domain.GameEventProject;
 import org.dromara.system.domain.vo.GameEventProjectVo;
 import org.dromara.system.domain.bo.GameEventProjectBo;
+import org.dromara.system.domain.vo.GameProjectOptionVo;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
 import org.dromara.common.mybatis.core.page.PageQuery;
 
@@ -128,4 +129,9 @@ public interface IGameEventProjectService {
      * 项目ID列表为空的话就查询所有
      */
     List<GameEventProjectVo> queryListByEventIdAndProjectIds(Long eventId, List<Long> projectIds);
+
+    /**
+     * 查询项目选项精简列表
+     */
+    List<GameProjectOptionVo> selectOptionList(GameEventProjectBo bo);
 }

+ 8 - 0
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/service/IGameScoreService.java

@@ -76,6 +76,14 @@ public interface IGameScoreService {
      */
     Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
 
+    /**
+     * 删除成绩及其关联的明细
+     *
+     * @param scoreId 成绩ID
+     * @return 是否成功
+     */
+    Boolean deleteWithDetails(Long scoreId);
+
     /**
      * 获取用户端获奖名单
      * @param eventId

+ 17 - 0
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/service/app/IToClientService.java

@@ -3,7 +3,9 @@ package org.dromara.system.service.app;
 import org.dromara.system.domain.GameEvent;
 import org.dromara.system.domain.GameEventProject;
 import org.dromara.system.domain.bo.ClientProjectSaveBo;
+import org.dromara.system.domain.bo.ScorePreviewUpdateBo;
 import org.dromara.system.domain.bo.ScoreSubmitBo;
+import org.dromara.system.domain.vo.ScorePreviewVo;
 import org.dromara.system.domain.vo.ScoreSheetVo;
 
 import java.util.List;
@@ -41,4 +43,19 @@ public interface IToClientService {
      * 提交成绩记录单 (接口6 提交)
      */
     void submitScoreSheet(ScoreSubmitBo bo);
+
+    /**
+     * 成绩预览列表查询 (接口8)
+     */
+    List<ScorePreviewVo> getScorePreviewList(Long projectId);
+
+    /**
+     * 成绩预览列表修改 (接口9)
+     */
+    void updateScorePreview(ScorePreviewUpdateBo bo);
+
+    /**
+     * 成绩预览列表删除 (接口10)
+     */
+    void removeScorePreview(Long scoreId);
 }

+ 27 - 4
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/service/impl/GameEventProjectServiceImpl.java

@@ -26,6 +26,7 @@ import org.springframework.stereotype.Service;
 import org.dromara.system.domain.bo.GameEventProjectBo;
 import org.dromara.system.domain.bo.GameRefereeBo;
 import org.dromara.system.domain.vo.GameEventProjectVo;
+import org.dromara.system.domain.vo.GameProjectOptionVo;
 import org.dromara.system.domain.vo.GameProjectStatsVo;
 import org.dromara.system.service.IGameEventProjectService;
 import org.springframework.transaction.annotation.Transactional;
@@ -741,9 +742,31 @@ public class GameEventProjectServiceImpl implements IGameEventProjectService {
      */
     @Override
     public List<GameEventProjectVo> queryListByEventIdAndProjectIds(Long eventId, List<Long> projectIds) {
-        return baseMapper.selectVoList(
-                Wrappers.lambdaQuery(GameEventProject.class)
-                        .eq(GameEventProject::getEventId, eventId)
-                        .in(projectIds != null && !projectIds.isEmpty(),GameEventProject::getProjectId, projectIds));
+        return baseMapper.selectVoList(Wrappers.lambdaQuery(GameEventProject.class)
+            .eq(GameEventProject::getEventId, eventId)
+            .in(CollectionUtils.isNotEmpty(projectIds), GameEventProject::getProjectId, projectIds));
+    }
+
+    /**
+     * 查询项目选项精简列表
+     */
+    @Override
+    public List<GameProjectOptionVo> selectOptionList(GameEventProjectBo bo) {
+        if (bo.getEventId() == null) {
+            Object cacheObject = RedisUtils.getCacheObject(GameEventConstant.DEFAULT_EVENT_ID);
+            if (cacheObject instanceof Integer) {
+                bo.setEventId(((Integer) cacheObject).longValue());
+            } else if (cacheObject instanceof Long) {
+                bo.setEventId((Long) cacheObject);
+            }
+        }
+        return baseMapper.selectVoList(Wrappers.lambdaQuery(GameEventProject.class)
+            .eq(bo.getEventId() != null, GameEventProject::getEventId, bo.getEventId())
+            .select(GameEventProject::getProjectId,
+                GameEventProject::getProjectName,
+                GameEventProject::getClassification,
+                GameEventProject::getCountUnit,
+                GameEventProject::getScoreRule)
+            .orderByAsc(GameEventProject::getProjectId), GameProjectOptionVo.class);
     }
 }

+ 29 - 0
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/service/impl/GameScoreServiceImpl.java

@@ -245,6 +245,35 @@ public class GameScoreServiceImpl implements IGameScoreService {
         return baseMapper.deleteByIds(ids) > 0;
     }
 
+    /**
+     * 删除成绩及其关联的明细
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean deleteWithDetails(Long scoreId) {
+        GameScore score = baseMapper.selectById(scoreId);
+        if (score == null) {
+            return false;
+        }
+        // 1. 删除成绩明细
+        // 优先根据 scoreId 删除,如果是团体项目则尝试根据 teamId + projectId 删除
+        LambdaQueryWrapper<GameScoreDetail> detailLqw = Wrappers.lambdaQuery(GameScoreDetail.class)
+            .eq(GameScoreDetail::getProjectId, score.getProjectId());
+
+        if (score.getAthleteId() != null) {
+            detailLqw.and(w -> w.eq(GameScoreDetail::getScoreId, scoreId)
+                .eq(GameScoreDetail::getAthleteId, score.getAthleteId()));
+        } else if (score.getTeamId() != null) {
+            detailLqw.or().eq(GameScoreDetail::getTeamId, score.getTeamId());
+        } else {
+            detailLqw.eq(GameScoreDetail::getScoreId, scoreId);
+        }
+        scoreDetailMapper.delete(detailLqw);
+
+        // 2. 删除主成绩记录
+        return baseMapper.deleteById(scoreId) > 0;
+    }
+
     /**
      * 获取用户端获奖名单
      */

+ 127 - 1
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/service/impl/app/ToClientServiceImpl.java

@@ -9,12 +9,14 @@ import org.dromara.common.core.utils.StringUtils;
 import org.dromara.system.domain.*;
 import org.dromara.system.domain.bo.*;
 import org.dromara.system.domain.constant.ProjectClassification;
+import org.dromara.system.domain.vo.ScorePreviewVo;
 import org.dromara.system.domain.vo.ScoreSheetDetailVo;
 import org.dromara.system.domain.vo.ScoreSheetItemVo;
 import org.dromara.system.domain.vo.ScoreSheetVo;
 import org.dromara.system.mapper.GameAthleteMapper;
 import org.dromara.system.mapper.GameEventMapper;
 import org.dromara.system.mapper.GameEventProjectMapper;
+import org.dromara.system.mapper.GameScoreMapper;
 import org.dromara.system.mapper.app.ToClientMapper;
 import org.dromara.system.service.IGameScoreService;
 import org.dromara.system.service.IGameRankGroupService;
@@ -38,6 +40,7 @@ public class ToClientServiceImpl implements IToClientService {
     private final IGameRankGroupService gameRankGroupService;
     private final ToClientMapper baseMapper;
     private final IGameScoreService gameScoreService;
+    private final GameScoreMapper gameScoreMapper;
     private final GameAthleteMapper gameAthleteMapper;
 
     /**
@@ -444,6 +447,130 @@ public class ToClientServiceImpl implements IToClientService {
         }
     }
 
+    @Override
+    public List<ScorePreviewVo> getScorePreviewList(Long projectId) {
+        List<ScorePreviewVo> list = baseMapper.selectScorePreviewList(projectId);
+        if (CollectionUtils.isEmpty(list)) {
+            return list;
+        }
+
+        GameEventProject project = projectMapper.selectById(projectId);
+        if (project == null) {
+            return list;
+        }
+
+        // 1. 批量查询明细数据
+        List<GameScoreDetail> allDetails = Db.list(Wrappers.lambdaQuery(GameScoreDetail.class)
+                .eq(GameScoreDetail::getProjectId, projectId)
+                .eq(GameScoreDetail::getDelFlag, "0"));
+
+        if (!allDetails.isEmpty()) {
+            Map<Long, List<ScoreSheetDetailVo>> detailMap;
+            if (ProjectClassification.TEAM.getValue().equals(project.getClassification())) {
+                // 团体项目:按 teamId 分组
+                detailMap = allDetails.stream()
+                        .filter(d -> d.getTeamId() != null)
+                        .map(this::convertToDetailVo)
+                        .collect(Collectors.groupingBy(ScoreSheetDetailVo::getTeamId));
+
+                list.forEach(item -> item.setDetails(detailMap.get(item.getTeamId())));
+            } else {
+                // 个人项目:按 athleteId 分组
+                detailMap = allDetails.stream()
+                        .filter(d -> d.getAthleteId() != null)
+                        .map(this::convertToDetailVo)
+                        .collect(Collectors.groupingBy(ScoreSheetDetailVo::getAthleteId));
+
+                list.forEach(item -> {
+                    List<ScoreSheetDetailVo> details = detailMap.get(item.getAthleteId());
+                    if (details == null && item.getScoreId() != null) {
+                        // 兜底:按 scoreId 匹配
+                        details = allDetails.stream()
+                                .filter(d -> Objects.equals(d.getScoreId(), item.getScoreId()))
+                                .map(this::convertToDetailVo)
+                                .toList();
+                    }
+                    item.setDetails(details);
+                });
+            }
+        }
+
+        // 2. 处理时间格式转换
+        if (StringUtils.isNotBlank(project.getTimingFormat())) {
+            list.forEach(item -> {
+                if (StringUtils.isNotBlank(item.getScore())) {
+                    item.setScore(convertDecimalToTimeScore(new BigDecimal(item.getScore()), project.getTimingFormat()));
+                }
+                if (item.getDetails() != null) {
+                    item.getDetails().forEach(detail -> {
+                        if (StringUtils.isNotBlank(detail.getPerformanceValue())) {
+                            detail.setPerformanceValue(convertDecimalToTimeScore(
+                                    new BigDecimal(detail.getPerformanceValue()),
+                                    project.getTimingFormat()));
+                        }
+                    });
+                }
+            });
+        }
+        return list;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void updateScorePreview(ScorePreviewUpdateBo bo) {
+        GameScore score = gameScoreMapper.selectById(bo.getScoreId());
+        if (score == null) {
+            throw new RuntimeException("成绩记录不存在");
+        }
+
+        GameEventProject project = projectMapper.selectById(score.getProjectId());
+
+        GameScoreBo scoreBo = new GameScoreBo();
+        scoreBo.setScoreId(score.getScoreId());
+        scoreBo.setEventId(score.getEventId());
+        scoreBo.setProjectId(score.getProjectId());
+        scoreBo.setAthleteId(score.getAthleteId());
+        scoreBo.setTeamId(score.getTeamId());
+
+        if (CollectionUtils.isNotEmpty(bo.getDetails())) {
+            // 如果提交了明细列表,则优先更新明细
+            List<GameScoreDetailBo> details = bo.getDetails().stream().map(d -> {
+                GameScoreDetailBo dbo = new GameScoreDetailBo();
+                dbo.setDetailId(d.getDetailId());
+                dbo.setAttemptIndex(d.getAttemptIndex());
+                dbo.setPerformanceValue(d.getPerformanceValue());
+                dbo.setFaultA(d.getFaultA());
+                dbo.setFaultB(d.getFaultB());
+                return dbo;
+            }).toList();
+            scoreBo.setDetails(details);
+        } else {
+            // 如果没有明细,则更新单次成绩
+            BigDecimal performance = parsePerformanceValue(bo.getScore());
+            if (project != null && ProjectClassification.TEAM.getValue().equals(project.getClassification())) {
+                scoreBo.setTeamPerformance(performance);
+            } else {
+                scoreBo.setIndividualPerformance(performance);
+            }
+        }
+
+        gameScoreService.updateScoreAndRecalculate(scoreBo);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void removeScorePreview(Long scoreId) {
+        GameScore score = gameScoreMapper.selectById(scoreId);
+        if (score == null) {
+            return;
+        }
+        // 删除成绩及明细
+        gameScoreService.deleteWithDetails(scoreId);
+
+        // 重新计算排名
+        gameScoreService.recalculateRankingsAndPoints(score.getEventId(), score.getProjectId());
+    }
+
     /**
      * 批量保存配置信息
      */
@@ -528,4 +655,3 @@ public class ToClientServiceImpl implements IToClientService {
         }
     }
 }
-

+ 22 - 0
ruoyi-modules/ruoyi-game-event/src/main/resources/mapper/system/app/ToClientMapper.xml

@@ -64,4 +64,26 @@
                OR JSON_CONTAINS(a.project_value, JSON_ARRAY(CAST(#{projectId} AS CHAR))))
         ORDER BY a.track_index ASC, a.athlete_code ASC
     </select>
+
+    <select id="selectScorePreviewList" resultType="org.dromara.system.domain.vo.ScorePreviewVo">
+        SELECT
+            s.score_id as scoreId,
+            s.athlete_id as athleteId,
+            s.team_id as teamId,
+            a.athlete_code as athleteCode,
+            a.name as name,
+            t.team_name as teamName,
+            CASE
+                WHEN p.classification = '0' THEN CAST(s.individual_performance AS CHAR)
+                ELSE CAST(s.team_performance AS CHAR)
+            END as score,
+            s.score_point as scorePoint,
+            s.score_rank as scoreRank
+        FROM game_score s
+        LEFT JOIN game_athlete a ON s.athlete_id = a.athlete_id AND a.del_flag = '0'
+        LEFT JOIN game_team t ON s.team_id = t.team_id AND t.del_flag = '0'
+        JOIN game_event_project p ON s.project_id = p.project_id
+        WHERE s.project_id = #{projectId} AND s.del_flag = '0'
+        ORDER BY s.score_rank ASC, s.score_id DESC
+    </select>
 </mapper>