Explorar o código

feat(game): 扩展成绩管理功能支持失误统计和明细管理

- 在GameScore实体中添加faultA和faultB字段用于记录失误次数
- 在GameScoreBo业务对象中增加失误字段和details成绩明细列表
- 扩展GameScoreDetail实体添加projectId、teamId、athleteId关联字段
- 实现成绩明细的批量保存和更新功能
- 重构成绩更新逻辑支持根据明细自动汇总主成绩和失误统计
- 优化团体项目成绩处理逻辑改为批量操作提升性能
- 完善排名计算算法支持多维度排序规则包括失误次数权重
- 为GameScoreDetailMapper添加@Mapper注解确保正确注入
- 优化Excel导出功能修复单元格类型转换问题
zhou hai 1 semana
pai
achega
a1daa5b6d2

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

@@ -88,6 +88,16 @@ public class GameScore extends TenantEntity {
      */
     private Integer extraPoint;
 
+    /**
+     * 失误次数A
+     */
+    private Integer faultA;
+
+    /**
+     * 失误次数B
+     */
+    private Integer faultB;
+
     /**
      * 成绩状态(0等待处理1处理完毕)
      */

+ 15 - 0
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/domain/GameScoreDetail.java

@@ -63,6 +63,21 @@ public class GameScoreDetail extends TenantEntity {
      */
     private String remark;
 
+    /**
+     * 项目ID
+     */
+    private Long projectId;
+
+    /**
+     * 队伍ID
+     */
+    private Long teamId;
+
+    /**
+     * 运动员ID
+     */
+    private Long athleteId;
+
     /**
      * 删除标志(0代表存在 1代表删除)
      */

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

@@ -11,6 +11,7 @@ import jakarta.validation.constraints.*;
 
 import java.math.BigDecimal;
 import java.util.Date;
+import java.util.List;
 
 /**
  * 成绩业务对象 game_score
@@ -93,6 +94,21 @@ public class GameScoreBo extends BaseEntity {
      */
     private Integer extraPoint;
 
+    /**
+     * 失误次数A
+     */
+    private Integer faultA;
+
+    /**
+     * 失误次数B
+     */
+    private Integer faultB;
+
+    /**
+     * 成绩明细列表
+     */
+    private List<GameScoreDetailBo> details;
+
     /**
      * 更新时间
      */

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

@@ -66,5 +66,20 @@ public class GameScoreDetailBo extends BaseEntity {
     @NotBlank(message = "单次备注(如:踩线)不能为空", groups = { AddGroup.class, EditGroup.class })
     private String remark;
 
+    /**
+     * 项目ID
+     */
+    private Long projectId;
+
+    /**
+     * 队伍ID
+     */
+    private Long teamId;
+
+    /**
+     * 运动员ID
+     */
+    private Long athleteId;
+
 
 }

+ 17 - 2
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/domain/vo/GameScoreDetailVo.java

@@ -13,8 +13,6 @@ import java.io.Serial;
 import java.io.Serializable;
 import java.util.Date;
 
-
-
 /**
  * 成绩明细视图对象 game_score_detail
  *
@@ -77,5 +75,22 @@ public class GameScoreDetailVo implements Serializable {
     @ExcelProperty(value = "单次备注(如:踩线)")
     private String remark;
 
+    /**
+     * 项目ID
+     */
+    // @ExcelProperty(value = "项目ID")
+    private Long projectId;
+
+    /**
+     * 队伍ID
+     */
+    // @ExcelProperty(value = "队伍ID")
+    private Long teamId;
+
+    /**
+     * 运动员ID
+     */
+    // @ExcelProperty(value = "运动员ID")
+    private Long athleteId;
 
 }

+ 12 - 3
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/domain/vo/GameScoreVo.java

@@ -13,8 +13,6 @@ import java.io.Serializable;
 import java.math.BigDecimal;
 import java.util.Date;
 
-
-
 /**
  * 成绩视图对象 game_score
  *
@@ -105,6 +103,18 @@ public class GameScoreVo implements Serializable {
     @ExcelProperty(value = "额外加分")
     private Integer extraPoint;
 
+    /**
+     * 失误次数A
+     */
+    // @ExcelProperty(value = "失误次数A")
+    private Integer faultA;
+
+    /**
+     * 失误次数B
+     */
+    // @ExcelProperty(value = "失误次数B")
+    private Integer faultB;
+
     /**
      * 更新时间
      */
@@ -131,5 +141,4 @@ public class GameScoreVo implements Serializable {
     @ExcelProperty(value = "备注")
     private String remark;
 
-
 }

+ 2 - 0
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/mapper/GameScoreDetailMapper.java

@@ -1,5 +1,6 @@
 package org.dromara.system.mapper;
 
+import org.apache.ibatis.annotations.Mapper;
 import org.dromara.system.domain.GameScoreDetail;
 import org.dromara.system.domain.vo.GameScoreDetailVo;
 import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
@@ -10,6 +11,7 @@ import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
  * @author z
  * @date 2026-05-08
  */
+@Mapper
 public interface GameScoreDetailMapper extends BaseMapperPlus<GameScoreDetail, GameScoreDetailVo> {
 
 }

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

@@ -75,6 +75,9 @@ public class GameScoreDetailServiceImpl implements IGameScoreDetailService {
         LambdaQueryWrapper<GameScoreDetail> lqw = Wrappers.lambdaQuery();
         lqw.orderByAsc(GameScoreDetail::getDetailId);
         lqw.eq(bo.getScoreId() != null, GameScoreDetail::getScoreId, bo.getScoreId());
+        lqw.eq(bo.getProjectId() != null, GameScoreDetail::getProjectId, bo.getProjectId());
+        lqw.eq(bo.getAthleteId() != null, GameScoreDetail::getAthleteId, bo.getAthleteId());
+        lqw.eq(bo.getTeamId() != null, GameScoreDetail::getTeamId, bo.getTeamId());
         lqw.eq(bo.getAttemptIndex() != null, GameScoreDetail::getAttemptIndex, bo.getAttemptIndex());
         lqw.eq(bo.getPerformanceValue() != null, GameScoreDetail::getPerformanceValue, bo.getPerformanceValue());
         lqw.eq(bo.getFaultA() != null, GameScoreDetail::getFaultA, bo.getFaultA());

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

@@ -19,16 +19,14 @@ import org.dromara.system.domain.constant.GameEventConstant;
 import org.dromara.system.domain.constant.ProjectClassification;
 import org.dromara.system.domain.constant.SortType;
 import org.dromara.system.domain.vo.*;
-import org.dromara.system.mapper.GameAthleteMapper;
-import org.dromara.system.mapper.GameEventProjectMapper;
-import org.dromara.system.mapper.GameTeamMapper;
-import org.dromara.system.mapper.GameRankGroupMapper;
+import org.dromara.system.mapper.*;
 import org.dromara.system.service.*;
 import org.springframework.stereotype.Service;
 import org.dromara.system.domain.bo.GameScoreBo;
-import org.dromara.system.mapper.GameScoreMapper;
+import org.dromara.system.domain.bo.GameScoreDetailBo;
 
 import java.math.BigDecimal;
+import java.math.RoundingMode;
 import java.time.LocalDateTime;
 import java.time.ZoneId;
 import java.time.format.DateTimeFormatter;
@@ -45,6 +43,7 @@ import java.net.URLEncoder;
 // Apache POI imports for dynamic Excel export
 import org.apache.poi.ss.usermodel.*;
 import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.springframework.transaction.annotation.Transactional;
 
 /**
  * 成绩Service业务层处理
@@ -67,8 +66,10 @@ public class GameScoreServiceImpl implements IGameScoreService {
     private final GameTeamMapper gameTeamMapper;
     private final GameRankGroupMapper gameRankGroupMapper;
     private final ISysDictTypeService dictTypeService;
+    private final GameScoreDetailMapper scoreDetailMapper;
 
     private static final Long HEALTH_CHECK = 1950743780869537804L;
+    private final GameScoreMapper gameScoreMapper;
 
     /**
      * 查询成绩
@@ -321,7 +322,8 @@ public class GameScoreServiceImpl implements IGameScoreService {
             teamCountWrapper.select("DISTINCT team_id")
                     .eq("event_id", eventId)
                     .isNotNull("team_id")
-                .apply("(JSON_CONTAINS(project_value, CAST({0} AS JSON)) OR JSON_CONTAINS(project_value, JSON_ARRAY(CAST({0} AS CHAR))))", projectId);
+                    .apply("(JSON_CONTAINS(project_value, CAST({0} AS JSON)) OR JSON_CONTAINS(project_value, JSON_ARRAY(CAST({0} AS CHAR))))",
+                            projectId);
             long totalTeamCount = gameAthleteMapper.selectCount(teamCountWrapper);
 
             stats.put("participantCount", totalTeamCount);
@@ -523,39 +525,23 @@ public class GameScoreServiceImpl implements IGameScoreService {
      * 更新成绩并重新计算排名积分
      */
     @Override
+    @Transactional(rollbackFor = Exception.class)
     public Boolean updateScoreAndRecalculate(GameScoreBo bo) {
-        log.info("开始处理成绩更新,scoreId: {}, eventId: {}, projectId: {}, teamId: {}",
-                bo.getScoreId(), bo.getEventId(), bo.getProjectId(), bo.getTeamId());
-
-        // 判断是否是手动排名计算(没有具体成绩数据,只有基本信息)
-        boolean isManualRankingCalculation = (bo.getScoreId() == null &&
-                bo.getAthleteId() == null &&
-                bo.getTeamId() == null &&
-                bo.getIndividualPerformance() == null &&
-                bo.getTeamPerformance() == null);
-
-        // log.info("手动排名计算判断: scoreId={}, athleteId={}, teamId={},
-        // individualPerformance={}, teamPerformance={}, isManualRanking={}",
-        // bo.getScoreId(), bo.getAthleteId(), bo.getTeamId(),
-        // bo.getIndividualPerformance(), bo.getTeamPerformance(),
-        // isManualRankingCalculation);
-
-        if (isManualRankingCalculation) {
-            // 手动排名计算:直接重新计算排名和积分
-            // log.info("检测到手动排名计算请求,跳过成绩更新,直接计算排名");
-            Boolean result = recalculateRankingsAndPoints(bo.getEventId(), bo.getProjectId());
-            // log.info("手动排名计算完成,结果: {}", result);
-            return result;
-        }
+        log.info("开始处理成绩更新,scoreId: {}, eventId: {}, projectId: {}",
+                bo.getScoreId(), bo.getEventId(), bo.getProjectId());
 
-        // 获取项目信息,判断是个人项目还是团体项目
+        // 1. 获取项目配置信息
         GameEventProjectVo project = gameEventProjectService.queryById(bo.getProjectId());
-        // log.info("项目信息: projectId: {}, classification: {}", bo.getProjectId(),
-        // project != null ? project.getClassification() : "null");
+        if (project == null) return false;
+
+        // 自动分析汇总成绩和失误
+        if (bo.getDetails() != null && !bo.getDetails().isEmpty()) {
+            calculateAndSetAggregatePerformance(bo, project);
+        }
 
         Boolean result = false;
 
-        if (project != null && ProjectClassification.TEAM.getValue().equals(project.getClassification())) {
+        if (ProjectClassification.TEAM.getValue().equals(project.getClassification())) {
             // 团体项目:为队伍中的所有运动员创建或更新成绩记录
             // log.info("处理团体项目成绩更新");
             result = handleTeamScoreUpdate(bo);
@@ -572,8 +558,12 @@ public class GameScoreServiceImpl implements IGameScoreService {
         }
 
         if (result) {
+            // 个人项目:如果传了明细,则保存 (团体项目已在 handleTeamScoreUpdate 中处理过)
+            if ("0".equals(project.getClassification()) && bo.getDetails() != null && !bo.getDetails().isEmpty()) {
+                saveScoreDetails(bo.getScoreId(), bo.getProjectId(), bo.getAthleteId(), null, bo.getDetails());
+            }
+
             // 重新计算排名和积分
-            // log.info("开始重新计算排名和积分");
             recalculateRankingsAndPoints(bo.getEventId(), bo.getProjectId());
         }
 
@@ -582,65 +572,124 @@ public class GameScoreServiceImpl implements IGameScoreService {
     }
 
     /**
-     * 处理团体项目成绩更新
+     * 根据明细和项目规则计算并设置汇总成绩和失误次数
      */
-    private Boolean handleTeamScoreUpdate(GameScoreBo bo) {
-        try {
-            log.info("开始处理团体项目成绩更新,teamId: {}", bo.getTeamId());
+    private void calculateAndSetAggregatePerformance(GameScoreBo bo, GameEventProjectVo project) {
+        List<GameScoreDetailBo> details = bo.getDetails();
+        String rule = project.getScoreRule();
+
+        // 1. 汇总失误次数 (通常是所有轮次的累加)
+        int totalFaultA = details.stream().mapToInt(d -> d.getFaultA() != null ? d.getFaultA() : 0).sum();
+        int totalFaultB = details.stream().mapToInt(d -> d.getFaultB() != null ? d.getFaultB() : 0).sum();
+        bo.setFaultA(totalFaultA);
+        bo.setFaultB(totalFaultB);
+
+        // 2. 汇总主成绩
+        List<BigDecimal> values = details.stream()
+                .map(GameScoreDetailBo::getPerformanceValue)
+                .filter(Objects::nonNull)
+                .toList();
+
+        if (values.isEmpty()) return;
 
-            // 获取队伍中的所有运动员
-            List<GameAthleteVo> teamAthletes = gameAthleteService.queryListByEventIdAndProjectId(
-                    bo.getEventId(), bo.getProjectId(), null);
+        BigDecimal aggregate = BigDecimal.ZERO;
 
-            // log.info("找到参与项目的运动员数量: {}", teamAthletes.size());
+        // 优先从 orderType 中解析统计逻辑 (4-求和, 5-最大值, 6-最小值, 7-平均值)
+        String orderType = project.getOrderType();
+        String statsLogic = null;
+        if (StringUtils.isNotBlank(orderType)) {
+            String[] types = orderType.split(",");
+            for (String t : types) {
+                if (Arrays.asList("4", "5", "6", "7").contains(t)) {
+                    statsLogic = t;
+                    break;
+                }
+            }
+        }
 
-            // 过滤出属于指定队伍的运动员
-            List<GameAthleteVo> relevantAthletes = teamAthletes.stream()
-                    .filter(athlete -> athlete.getTeamId() != null && athlete.getTeamId().equals(bo.getTeamId()))
-                    .toList();
+        if (statsLogic != null) {
+            // 如果 orderType 中指定了统计逻辑,则按指定逻辑计算
+            aggregate = switch (statsLogic) {
+                case "4" -> // 求和
+                    values.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
+                case "5" -> // 最大值
+                    values.stream().max(BigDecimal::compareTo).get();
+                case "6" -> // 最小值
+                    values.stream().min(BigDecimal::compareTo).get();
+                case "7" -> {
+                    BigDecimal sum = values.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
+                    yield sum.divide(new BigDecimal(values.size()), 3, RoundingMode.HALF_UP);
+                }
+                default -> aggregate;
+            };
+        } else {
+            // 如果没有指定统计逻辑,走原有的 scoreRule 逻辑(兜底方案)
+            aggregate = switch (rule) {
+                case "1" -> // 计时类 -> 取最小值(最快)
+                    values.stream().min(BigDecimal::compareTo).get(); // 距离/远度类 -> 取最大值
+                case "2", "6" -> // 多次计数最大值 -> 取最大值
+                    values.stream().max(BigDecimal::compareTo).get();
+                case "4" -> // 多次计数求和 -> 取总和
+                    values.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
+                case "7" -> {
+                    BigDecimal sum = values.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
+                    yield sum.divide(new BigDecimal(values.size()), 3, RoundingMode.HALF_UP);
+                }
+                default ->
+                    // 其他情况如果只有一条明细,直接取第一条
+                    values.get(0);
+            };
+        }
 
-            // log.info("队伍 {} 的运动员数量: {}", bo.getTeamId(), relevantAthletes.size());
+        // 设置到对应的成绩字段
+        if (ProjectClassification.TEAM.getValue().equals(project.getClassification())) {
+            bo.setTeamPerformance(aggregate);
+        } else {
+            bo.setIndividualPerformance(aggregate);
+        }
+    }
 
-            if (relevantAthletes.isEmpty()) {
+    /**
+     * 处理团体项目成绩更新
+     */
+    private Boolean handleTeamScoreUpdate(GameScoreBo bo) {
+        try {
+            List<Long> atheleteIds = gameAthleteMapper.selectObjs(new QueryWrapper<GameAthlete>()
+                    .select("athlete_id")
+                    .eq("event_id", bo.getEventId())
+                    .eq("team_id", bo.getTeamId())
+                    .apply("(JSON_CONTAINS(project_value, CAST({0} AS JSON)) OR JSON_CONTAINS(project_value, JSON_ARRAY(CAST({0} AS CHAR))))",
+                            bo.getProjectId())
+                    .eq("del_flag", "0"));
+            if (atheleteIds.isEmpty()) {
                 log.warn("未找到队伍 {} 的运动员", bo.getTeamId());
                 return false;
             }
 
+            List<GameScore> scoreList = new ArrayList<>();
             // 为每个运动员创建或更新成绩记录
-            for (GameAthleteVo athlete : relevantAthletes) {
-                // log.info("处理运动员 {} 的成绩记录", athlete.getAthleteId());
-
-                GameScoreBo athleteScoreBo = new GameScoreBo();
-                athleteScoreBo.setEventId(bo.getEventId());
-                athleteScoreBo.setProjectId(bo.getProjectId());
-                athleteScoreBo.setAthleteId(athlete.getAthleteId());
-                athleteScoreBo.setTeamId(bo.getTeamId());
-                athleteScoreBo.setIndividualPerformance(BigDecimal.ZERO); // 团体项目个人成绩为0
-                athleteScoreBo.setTeamPerformance(bo.getTeamPerformance());
-                // athleteScoreBo.setLeaderPoint(bo.getLeaderPoint());
-                // athleteScoreBo.setExtraPoint(bo.getExtraPoint());
-                athleteScoreBo.setScoreType("team");
-                athleteScoreBo.setStatusFlag("0");
-                athleteScoreBo.setStatus("0");
-                athleteScoreBo.setRemark("团体项目成绩");
-
-                // 查找是否已有该运动员的成绩记录
-                GameScoreVo existingScore = getScoreByAthleteIdAndProjectId(athlete.getAthleteId(), bo.getProjectId());
-                if (existingScore != null) {
-                    // 更新现有记录
-                    // log.info("更新运动员 {} 的现有成绩记录", athlete.getAthleteId());
-                    athleteScoreBo.setScoreId(existingScore.getScoreId());
-                    Boolean updateResult = updateByBo(athleteScoreBo);
-                    // log.info("更新结果: {}", updateResult);
-                } else {
-                    // 插入新记录
-                    // log.info("为运动员 {} 插入新成绩记录", athlete.getAthleteId());
-                    Boolean insertResult = insertByBo(athleteScoreBo);
-                    // log.info("插入结果: {}", insertResult);
-                }
+            for (Long athleteId : atheleteIds) {
+                GameScore athleteScore = new GameScore();
+                athleteScore.setEventId(bo.getEventId());
+                athleteScore.setProjectId(bo.getProjectId());
+                athleteScore.setAthleteId(athleteId);
+                athleteScore.setTeamId(bo.getTeamId());
+                athleteScore.setIndividualPerformance(BigDecimal.ZERO);
+                athleteScore.setTeamPerformance(bo.getTeamPerformance());
+                athleteScore.setFaultA(bo.getFaultA());
+                athleteScore.setFaultB(bo.getFaultB());
+                athleteScore.setScoreType("team");
+                athleteScore.setStatusFlag("0");
+                athleteScore.setStatus("0");
+                scoreList.add(athleteScore);
+            }
+            gameScoreMapper.insertOrUpdateBatch(scoreList);
+
+            // 团体项目明细:按项目ID + 队伍ID 存储,全队共享一份数据
+            if (bo.getDetails() != null && !bo.getDetails().isEmpty()) {
+                saveScoreDetails(null, bo.getProjectId(), null, bo.getTeamId(), bo.getDetails());
             }
 
-            // log.info("团体项目成绩更新处理完成");
             return true;
         } catch (Exception e) {
             log.error("处理团体项目成绩更新失败", e);
@@ -649,166 +698,159 @@ public class GameScoreServiceImpl implements IGameScoreService {
     }
 
     /**
-     * 重新计算项目排名和积分
+     * 批量保存明细(支持按项目+人/队 唯一关联)
      */
-    @Override
-    public Boolean recalculateRankingsAndPoints(Long eventId, Long projectId) {
-        try {
-            // 获取项目配置信息
-            GameEventProjectVo project = gameEventProjectService.queryById(projectId);
-            if (project == null) {
-                log.error("项目不存在,projectId: {}", projectId);
-                return false;
-            }
-
-            String classification = project.getClassification();
-            String scoreValue = project.getScoreValue();
-
-            // 获取所有相关成绩记录
-            GameScoreBo queryBo = new GameScoreBo();
-            queryBo.setEventId(eventId);
-            queryBo.setProjectId(projectId);
-            List<GameScoreVo> allScores = queryList(queryBo);
+    private void saveScoreDetails(Long scoreId, Long projectId, Long athleteId, Long teamId,
+            List<GameScoreDetailBo> details) {
+        // 更新或新增明细
+        if (details != null && !details.isEmpty()) {
+            List<GameScoreDetail> entityList = details.stream().map(d -> {
+                GameScoreDetail entity = BeanUtil.copyProperties(d, GameScoreDetail.class);
+                entity.setScoreId(scoreId);
+                entity.setProjectId(projectId);
+                entity.setAthleteId(athleteId);
+                entity.setTeamId(teamId);
+                return entity;
+            }).collect(Collectors.toList());
 
-            if (ProjectClassification.SINGLE.getValue().equals(classification)) {
-                // 个人项目:按个人成绩排序
-                return handleIndividualProjectRanking(allScores, scoreValue, eventId, projectId);
-            } else {
-                // 团体项目:按队伍汇总积分后排序
-                return handleTeamProjectRanking(allScores, scoreValue, eventId, projectId);
-            }
-        } catch (Exception e) {
-            log.error("重新计算排名和积分失败", e);
-            return false;
+            scoreDetailMapper.insertOrUpdateBatch(entityList);
         }
     }
 
     /**
-     * 处理个人项目排名和积分计算
+     * 重新计算项目排名和积分
      */
-    private Boolean handleIndividualProjectRanking(List<GameScoreVo> allScores, String scoreValue, Long eventId,
-            Long projectId) {
-        // 获取项目信息,确定排序方式
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean recalculateRankingsAndPoints(Long eventId, Long projectId) {
+        // 1. 获取项目规则
         GameEventProjectVo project = gameEventProjectService.queryById(projectId);
-        if (project == null) {
-            log.error("项目不存在,projectId: {}", projectId);
+        if (project == null)
             return false;
-        }
 
-        String orderType = project.getOrderType();
-        // log.info("个人项目排名计算,projectId: {}, orderType: {}", projectId, orderType);
-
-        // 根据orderType决定排序方式
-        // orderType: 0-升序(成绩越小越好),1-降序(成绩越大越好)
-        List<GameScoreVo> sortedScores = allScores.stream()
-                .sorted((a, b) -> {
-                    BigDecimal aIndividualPerformance = a.getIndividualPerformance() != null
-                            ? a.getIndividualPerformance()
-                            : BigDecimal.ZERO;
-                    BigDecimal bIndividualPerformance = b.getIndividualPerformance() != null
-                            ? b.getIndividualPerformance()
-                            : BigDecimal.ZERO;
-
-                    if (orderType.equals(SortType.ASC.getValue())) {
-                        // 升序:成绩越小越好
-                        return aIndividualPerformance.compareTo(bIndividualPerformance);
-                    } else {
-                        // 降序:成绩越大越好(默认)
-                        return bIndividualPerformance.compareTo(aIndividualPerformance);
-                    }
-                })
-                .toList();
+        String orderType = project.getOrderType() != null ? project.getOrderType() : "1";
+        String scoreValueStr = project.getScoreValue();
+        List<Integer> pointConfig = StringUtils.isEmpty(scoreValueStr) ? new ArrayList<>()
+                : Arrays.stream(scoreValueStr.split(",")).map(String::trim).map(Integer::parseInt).toList();
 
-        // 解析积分分值
-        List<Integer> pointValues = Arrays.stream(scoreValue.split(","))
-                .map(String::trim)
-                .map(Integer::parseInt)
-                .toList();
+        // 2. 获取所有有效成绩
+        List<GameScoreVo> allScores = queryList(new GameScoreBo() {
+            {
+                setEventId(eventId);
+                setProjectId(projectId);
+            }
+        });
+        if (allScores.isEmpty())
+            return true;
 
-        // 根据orderType决定积分分配方式
-        if (orderType.equals(SortType.ASC.getValue())) {
-            // 升序项目:成绩越小,积分分配越多
-            for (int i = 0; i < sortedScores.size(); i++) {
-                GameScoreVo score = sortedScores.get(i);
-                int basePoints = i < pointValues.size() ? pointValues.get(i) : 0;
-                // int leaderPoint = score.getLeaderPoint() != null ? score.getLeaderPoint() :
-                // 0;
-                // int extraPoint = score.getExtraPoint() != null ? score.getExtraPoint() : 0;
-                // int totalPoints = basePoints + leaderPoint + extraPoint;
-
-                // 更新成绩记录
-                GameScoreBo updateBo = new GameScoreBo();
-                updateBo.setScoreId(score.getScoreId());
-                updateBo.setScorePoint(basePoints);
-                updateBo.setEventId(eventId);
-                updateBo.setProjectId(projectId);
+        List<GameScore> updateList = new ArrayList<>();
 
-                updateByBo(updateBo);
+        // 3. 根据项目类型执行不同的排名逻辑
+        if ("0".equals(project.getClassification())) {
+            // --- 个人项目排名 ---
+            allScores.sort((a, b) -> compareScores(a, b, orderType, "0"));
+
+            int currentRank = 1;
+            for (int i = 0; i < allScores.size(); i++) {
+                GameScoreVo current = allScores.get(i);
+                if (i > 0 && compareScores(current, allScores.get(i - 1), orderType, "0") != 0) {
+                    currentRank = i + 1;
+                }
+                int points = (currentRank <= pointConfig.size()) ? pointConfig.get(currentRank - 1) : 0;
+
+                updateList.add(buildUpdateScore(current.getScoreId(), currentRank, points));
             }
         } else {
-            // 降序项目:成绩越大,积分分配越多
-            for (int i = 0; i < sortedScores.size(); i++) {
-                GameScoreVo score = sortedScores.get(i);
-                int basePoints = i < pointValues.size() ? pointValues.get(i) : 0;
-                // int leaderPoint = score.getLeaderPoint() != null ? score.getLeaderPoint() :
-                // 0;
-                // int extraPoint = score.getExtraPoint() != null ? score.getExtraPoint() : 0;
-                // int totalPoints = basePoints + leaderPoint + extraPoint;
-
-                // 更新成绩记录
-                GameScoreBo updateBo = new GameScoreBo();
-                updateBo.setScoreId(score.getScoreId());
-                updateBo.setScorePoint(basePoints);
-                updateBo.setEventId(eventId);
-                updateBo.setProjectId(projectId);
+            // --- 团体项目排名 ---
+            // 3.1 按队伍分组汇总
+            Map<Long, List<GameScoreVo>> teamGroups = allScores.stream()
+                    .filter(s -> s.getTeamId() != null)
+                    .collect(Collectors.groupingBy(GameScoreVo::getTeamId));
+
+            // 3.2 提取每个队的代表成绩进行排序
+            List<Long> sortedTeamIds = new ArrayList<>(teamGroups.keySet());
+            sortedTeamIds.sort((id1, id2) -> {
+                GameScoreVo score1 = teamGroups.get(id1).get(0);
+                GameScoreVo score2 = teamGroups.get(id2).get(0);
+                return compareScores(score1, score2, orderType, "1");
+            });
+
+            // 3.3 分配名次并分发给队员
+            int currentRank = 1;
+            for (int i = 0; i < sortedTeamIds.size(); i++) {
+                Long teamId = sortedTeamIds.get(i);
+                if (i > 0) {
+                    GameScoreVo currentTeamScore = teamGroups.get(teamId).get(0);
+                    GameScoreVo prevTeamScore = teamGroups.get(sortedTeamIds.get(i - 1)).get(0);
+                    if (compareScores(currentTeamScore, prevTeamScore, orderType, "1") != 0) {
+                        currentRank = i + 1;
+                    }
+                }
 
-                updateByBo(updateBo);
+                // 团体积分通常有加成(此处可根据需求调整,默认取配置)
+                int points = (currentRank <= pointConfig.size()) ? pointConfig.get(currentRank - 1) : 0;
+
+                // 将该队的名次和积分应用给该项目下该队的所有人
+                for (GameScoreVo memberScore : teamGroups.get(teamId)) {
+                    updateList.add(buildUpdateScore(memberScore.getScoreId(), currentRank, points));
+                }
             }
         }
 
-        // 然后按积分重新排序确定排名
-        // List<GameScoreVo> scoresWithPoints = queryList(new GameScoreBo() {{
-        // setEventId(eventId);
-        // setProjectId(projectId);
-        // }});
-
-        // 按积分排序(降序,积分越高排名越靠前)
-        // List<GameScoreVo> sortedByPoints = scoresWithPoints.stream()
-        // .sorted((a, b) -> {
-        // Integer aPoints = a.getScorePoint() != null ? a.getScorePoint() : 0;
-        // Integer bPoints = b.getScorePoint() != null ? b.getScorePoint() : 0;
-        // return Integer.compare(bPoints, aPoints);
-        // })
-        // .toList();
-
-        // 更新排名(支持并列排名)
-        int currentRank = 1;
-        for (int i = 0; i < sortedScores.size(); i++) {
-            GameScoreVo score = sortedScores.get(i);
-            BigDecimal currentPoints = score.getIndividualPerformance() != null ? score.getIndividualPerformance()
-                    : BigDecimal.ZERO;
+        // 4. 批量执行更新
+        if (!updateList.isEmpty()) {
+            baseMapper.updateBatchById(updateList);
+        }
 
-            // 如果不是第一个,检查是否与前一个成绩相同
-            if (i > 0) {
-                BigDecimal previousPoints = sortedScores.get(i - 1).getIndividualPerformance() != null
-                        ? sortedScores.get(i - 1).getIndividualPerformance()
-                        : BigDecimal.ZERO;
-                if (!currentPoints.equals(previousPoints)) {
-                    currentRank = i + 1;
-                }
-            }
+        return true;
+    }
 
-            // 更新排名
-            GameScoreBo updateBo = new GameScoreBo();
-            updateBo.setScoreId(score.getScoreId());
-            updateBo.setScoreRank(currentRank);
-            updateBo.setEventId(eventId);
-            updateBo.setProjectId(projectId);
+    private GameScore buildUpdateScore(Long scoreId, int rank, int points) {
+        GameScore update = new GameScore();
+        update.setScoreId(scoreId);
+        update.setScoreRank(rank);
+        update.setScorePoint(points);
+        return update;
+    }
+
+    /**
+     * 统一的分数比较器
+     */
+    private int compareScores(GameScoreVo a, GameScoreVo b, String orderType, String classification) {
+        // 第一级:主成绩 (0-个人, 1-团队)
+        BigDecimal perfA = "0".equals(classification) ? a.getIndividualPerformance() : a.getTeamPerformance();
+        BigDecimal perfB = "0".equals(classification) ? b.getIndividualPerformance() : b.getTeamPerformance();
+        if (perfA == null)
+            perfA = BigDecimal.ZERO;
+        if (perfB == null)
+            perfB = BigDecimal.ZERO;
+
+        int res = 0;
+        if (orderType.contains("0"))
+            res = perfA.compareTo(perfB); // 升序
+        else
+            res = perfB.compareTo(perfA); // 降序
+
+        if (res != 0)
+            return res;
+
+        // 第二级:失误次数A (越少越好)
+        if (orderType.contains("2")) {
+            res = Integer.compare(a.getFaultA() != null ? a.getFaultA() : 0,
+                    b.getFaultA() != null ? b.getFaultA() : 0);
+            if (res != 0)
+                return res;
+        }
 
-            updateByBo(updateBo);
+        // 第三级:失误次数B (越多越好)
+        if (orderType.contains("3")) {
+            res = Integer.compare(b.getFaultB() != null ? b.getFaultB() : 0,
+                    a.getFaultB() != null ? a.getFaultB() : 0);
+            if (res != 0)
+                return res;
         }
 
-        return true;
+        return res;
     }
 
     /**
@@ -1095,8 +1137,8 @@ public class GameScoreServiceImpl implements IGameScoreService {
             // 6. 按排名排序(排名为0或null的排在最后)
             return result.stream()
                     .sorted((a, b) -> {
-                        Integer rankA = a.getScoreRank() != null ? a.getScoreRank() : Integer.MAX_VALUE;
-                        Integer rankB = b.getScoreRank() != null ? b.getScoreRank() : Integer.MAX_VALUE;
+                        int rankA = a.getScoreRank() != null ? a.getScoreRank() : Integer.MAX_VALUE;
+                        int rankB = b.getScoreRank() != null ? b.getScoreRank() : Integer.MAX_VALUE;
                         return Integer.compare(rankA, rankB);
                     })
                     .collect(Collectors.toList());
@@ -1231,10 +1273,10 @@ public class GameScoreServiceImpl implements IGameScoreService {
                 CellStyle currentRowStyle = (rowIndex % 2 == 0) ? dataStyleEven : dataStyleOdd;
 
                 // 基础列数据
-                createCellWithStyle(dataRow, colIndex++, (Integer) rowData.get("序号"), currentRowStyle);
-                createCellWithStyle(dataRow, colIndex++, (String) rowData.get("代表队名称"), currentRowStyle);
-                createCellWithStyle(dataRow, colIndex++, (Integer) rowData.get("排名"), currentRowStyle);
-                createCellWithStyle(dataRow, colIndex++, (Integer) rowData.get("总分"), currentRowStyle);
+                createCellWithStyle(dataRow, colIndex++, rowData.get("序号"), currentRowStyle);
+                createCellWithStyle(dataRow, colIndex++, rowData.get("代表队名称"), currentRowStyle);
+                createCellWithStyle(dataRow, colIndex++, rowData.get("排名"), currentRowStyle);
+                createCellWithStyle(dataRow, colIndex++, rowData.get("总分"), currentRowStyle);
 
                 // 动态项目列数据
                 for (GameEventProjectVo project : projects) {
@@ -1245,8 +1287,8 @@ public class GameScoreServiceImpl implements IGameScoreService {
                 }
 
                 // 加分列数据
-                createCellWithStyle(dataRow, colIndex++, (Integer) rowData.get("领导加分"), currentRowStyle);
-                createCellWithStyle(dataRow, colIndex++, (Integer) rowData.get("额外加分"), currentRowStyle);
+                createCellWithStyle(dataRow, colIndex++, rowData.get("领导加分"), currentRowStyle);
+                createCellWithStyle(dataRow, colIndex++, rowData.get("额外加分"), currentRowStyle);
             }
 
             // 自动调整列宽