Эх сурвалжийг харах

feat(game-event): 完善赛事项目管理功能

- 增加计算项目参赛人数和参赛队伍数的逻辑- 实现删除项目时同步清理关联的分组信息
- 优化导出数据功能,复用查询列表逻辑
- 调整Excel导出字段顺序和注释,提升可读性
- 为GameTeamMapper添加@Mapper注解以支持MyBatis扫描- 移除部分VO类中冗余的ExcelProperty注解
zhou 2 долоо хоног өмнө
parent
commit
788e1f0590

+ 26 - 26
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/domain/vo/GameEventProjectVo.java

@@ -48,7 +48,7 @@ public class GameEventProjectVo implements Serializable {
     /**
      * 赛事ID
      */
-    @ExcelProperty(value = "赛事名称")
+//    @ExcelProperty(value = "赛事名称")
     private String eventName;
 
     /**
@@ -101,31 +101,45 @@ public class GameEventProjectVo implements Serializable {
     @DateTimeFormat("yyyy-MM-dd HH:mm:ss")
     private Date endTime;
 
+    /**
+     * 比赛轮次
+     */
+    @ExcelProperty(value = "比赛轮次", converter = ExcelDictConvert.class)
+    @ExcelDictFormat(dictType = "game_round")
+    private String gameRound;
+
+    /**
+     * 比赛阶段
+     */
+    @ExcelProperty(value = "比赛阶段", converter = ExcelDictConvert.class)
+    @ExcelDictFormat(dictType = "game_stage")
+    private String gameStage;
+
     /**
      * 更新时间
      */
-    @ExcelProperty(value = "更新时间")
+//    @ExcelProperty(value = "更新时间")
     @DateTimeFormat("yyyy-MM-dd HH:mm:ss")
     private Date updateTime;
 
+    /**
+     * 项目限报人数
+     */
+    @ExcelProperty(value = "项目限报人数")
+    private Integer limitPerson;
+
     /**
      * 参赛组数
      */
-    @ExcelProperty(value = "参赛组数")
+//    @ExcelProperty(value = "参赛组数")
     private Long groupNum;
 
     /**
      * 参赛人数
      */
-    @ExcelProperty(value = "参赛人数")
+//    @ExcelProperty(value = "参赛人数")
     private Long participateNum;
 
-    /**
-     * 项目限报人数
-     */
-    @ExcelProperty(value = "项目限报人数")
-    private Integer limitPerson;
-
     /**
      * 录取名次
      */
@@ -135,7 +149,7 @@ public class GameEventProjectVo implements Serializable {
     /**
      * 排序方式
      */
-    @ExcelProperty(value = "排序方式")
+    @ExcelProperty(value = "排序方式", converter = ExcelDictConvert.class)
     @ExcelDictFormat(readConverterExp = "0=升序,1=降序")
     private String orderType;
 
@@ -155,23 +169,9 @@ public class GameEventProjectVo implements Serializable {
     /**
      * 奖项
      */
-    @ExcelProperty(value = "奖项")
+//    @ExcelProperty(value = "奖项")
     private String award;
 
-    /**
-     * 比赛轮次
-     */
-    @ExcelProperty(value = "比赛轮次", converter = ExcelDictConvert.class)
-    @ExcelDictFormat(dictType = "game_round")
-    private String gameRound;
-
-    /**
-     * 比赛阶段
-     */
-    @ExcelProperty(value = "比赛阶段", converter = ExcelDictConvert.class)
-    @ExcelDictFormat(dictType = "game_stage")
-    private String gameStage;
-
     /**
      * 状态(0正常 1停用)
      */

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

@@ -91,7 +91,7 @@ public class GameEventVo implements Serializable {
     /**
      * 赛事链接Url
      */
-    @ExcelProperty(value = "赛事链接")
+//    @ExcelProperty(value = "赛事链接")
     @Translation(type = TransConstant.OSS_ID_TO_URL, mapper = "eventUrl")
     private String eventUrlUrl;
     /**
@@ -103,7 +103,7 @@ public class GameEventVo implements Serializable {
     /**
      * 裁判码Url
      */
-    @ExcelProperty(value = "裁判码")
+//    @ExcelProperty(value = "裁判码")
     @Translation(type = TransConstant.OSS_ID_TO_URL, mapper = "refereeUrl")
     private String refereeUrlUrl;
     /**

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

@@ -45,13 +45,13 @@ public class GameTeamVo implements Serializable {
     /**
      * 排名分组名
      */
-    @ExcelProperty(value = "分组名", converter = ExcelDictConvert.class)
+    @ExcelProperty(value = "分组名")
     private String rgName;
 
     /**
      * 赛事名称
      */
-    @ExcelProperty(value = "赛事名称")
+//    @ExcelProperty(value = "赛事名称")
     private String eventName;
 
     /**

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

@@ -1,5 +1,6 @@
 package org.dromara.system.mapper;
 
+import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Select;
 import org.dromara.system.domain.GameTeam;
 import org.dromara.system.domain.bo.GameTeamBo;
@@ -15,6 +16,7 @@ import java.util.List;
  * @author zlt
  * @date 2025-07-30
  */
+@Mapper
 public interface GameTeamMapper extends BaseMapperPlus<GameTeam, GameTeamVo> {
 
     @Select("""

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

@@ -53,6 +53,8 @@ public interface IGameAthleteService {
      */
     List<GameAthleteVo> queryList(GameAthleteBo bo);
 
+    List<GameAthleteVo> exportData(GameAthleteBo bo);
+
     /**
      * 新增参赛队员
      *

+ 8 - 6
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/service/impl/GameAthleteServiceImpl.java

@@ -38,6 +38,7 @@ import org.springframework.stereotype.Service;
 
 import java.util.*;
 import java.util.stream.Collectors;
+import java.util.stream.IntStream;
 
 /**
  * 参赛队员Service业务层处理
@@ -232,20 +233,21 @@ public class GameAthleteServiceImpl implements IGameAthleteService {
                     vo.setProjectList(projects);
                 });
         });
-        
+
         return athleteList;
     }
 
     /**
      * 导出数据
      */
+    @Override
     public List<GameAthleteVo> exportData(GameAthleteBo bo) {
         List<GameAthleteVo> athleteList = queryList(bo);
         // 设置序号
         setRowNumbers(athleteList);
         // 转换队伍ID为队伍名称
         convertTeamIdToName(athleteList);
-        
+
         // 转换项目ID列表为项目名称列表
         convertProjectIdsToNames(athleteList);
 
@@ -269,7 +271,7 @@ public class GameAthleteServiceImpl implements IGameAthleteService {
             .map(GameAthleteVo::getTeamId)
             .filter(Objects::nonNull)
             .collect(Collectors.toSet());
-        
+
         // 2. 批量查询队伍信息
         Map<Long, String> teamIdToNameMap = new HashMap<>();
         if (CollUtil.isNotEmpty(teamIds)) {
@@ -279,7 +281,7 @@ public class GameAthleteServiceImpl implements IGameAthleteService {
             teamIdToNameMap = teams.stream()
                 .collect(Collectors.toMap(GameTeam::getTeamId, GameTeam::getTeamName));
         }
-        
+
         // 3. 设置队伍名称
         final Map<Long, String> finalTeamMap = teamIdToNameMap;
         athleteList.forEach(athlete -> {
@@ -298,7 +300,7 @@ public class GameAthleteServiceImpl implements IGameAthleteService {
                 allProjectIds.addAll(athlete.getProjectList());
             }
         });
-        
+
         // 2. 批量查询项目信息
         Map<Long, String> projectIdToNameMap = new HashMap<>();
         if (CollUtil.isNotEmpty(allProjectIds)) {
@@ -308,7 +310,7 @@ public class GameAthleteServiceImpl implements IGameAthleteService {
             projectIdToNameMap = projects.stream()
                 .collect(Collectors.toMap(GameEventProject::getProjectId, GameEventProject::getProjectName));
         }
-        
+
         // 3. 设置项目名称列表
         final Map<Long, String> finalProjectMap = projectIdToNameMap;
         athleteList.forEach(athlete -> {

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

@@ -13,13 +13,11 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.dromara.common.redis.utils.RedisUtils;
-import org.dromara.system.domain.GameEvent;
+import org.dromara.system.domain.*;
 import org.dromara.system.domain.bo.GameAthleteBo;
 import org.dromara.system.domain.constant.GameEventConstant;
 import org.dromara.system.domain.vo.SysDictDataVo;
-import org.dromara.system.mapper.GameAthleteMapper;
-import org.dromara.system.mapper.GameEventMapper;
-import org.dromara.system.mapper.GameRefereeMapper;
+import org.dromara.system.mapper.*;
 import org.dromara.system.service.IGameAthleteService;
 import org.dromara.system.service.IGameRefereeService;
 import org.dromara.system.service.ISysDictTypeService;
@@ -29,8 +27,6 @@ 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.GameEventProject;
-import org.dromara.system.mapper.GameEventProjectMapper;
 import org.dromara.system.service.IGameEventProjectService;
 import org.springframework.transaction.annotation.Transactional;
 
@@ -51,6 +47,9 @@ public class GameEventProjectServiceImpl implements IGameEventProjectService {
     private final GameEventProjectMapper baseMapper;
     private final GameEventMapper gameEventMapper;
     private final ISysDictTypeService sysDictTypeService;
+    private final GameTeamMapper gameTeamMapper;
+    private final GameAthleteMapper gameAthleteMapper;
+    private final GameEventGroupMapper gameEventGroupMapper;
 
     @Autowired
     @Lazy
@@ -60,10 +59,15 @@ public class GameEventProjectServiceImpl implements IGameEventProjectService {
     @Lazy
     private IGameAthleteService gameAthleteService;
 
-    public GameEventProjectServiceImpl(GameEventProjectMapper baseMapper, GameEventMapper gameEventMapper, ISysDictTypeService sysDictTypeService) {
+    public GameEventProjectServiceImpl(GameEventProjectMapper baseMapper, GameEventMapper gameEventMapper,
+        ISysDictTypeService sysDictTypeService, GameTeamMapper gameTeamMapper, GameAthleteMapper gameAthleteMapper,
+        GameEventGroupMapper gameEventGroupMapper) {
         this.baseMapper = baseMapper;
         this.gameEventMapper = gameEventMapper;
         this.sysDictTypeService = sysDictTypeService;
+        this.gameTeamMapper = gameTeamMapper;
+        this.gameAthleteMapper = gameAthleteMapper;
+        this.gameEventGroupMapper = gameEventGroupMapper;
     }
 
     /**
@@ -209,6 +213,74 @@ public class GameEventProjectServiceImpl implements IGameEventProjectService {
         return list;
     }
 
+    /**
+     * 计算项目的参赛人数
+     * @param projectId 项目ID
+     * @return 参赛人数
+     */
+    private Long calculateParticipateNum(Long projectId) {
+        if (projectId == null) {
+            return 0L;
+        }
+
+        // 查询所有运动员,筛选出参与该项目的运动员
+        List<GameAthlete> allAthletes = gameAthleteMapper.selectList(
+            Wrappers.lambdaQuery(GameAthlete.class)
+                .select(GameAthlete::getProjectValue)
+        );
+
+        long count = allAthletes.stream()
+            .filter(athlete -> {
+                if (StringUtils.isNotBlank(athlete.getProjectValue())) {
+                    try {
+                        List<Long> projectList = JSONUtil.toList(athlete.getProjectValue(), Long.class);
+                        return projectList.contains(projectId);
+                    } catch (Exception e) {
+                        log.warn("解析运动员项目列表失败: {}", athlete.getProjectValue(), e);
+                        return false;
+                    }
+                }
+                return false;
+            })
+            .count();
+
+        return count;
+    }
+
+    /**
+     * 计算项目的参赛队伍数
+     * @param projectId 项目ID
+     * @return 参赛队伍数
+     */
+    private Long calculateGroupNum(Long projectId) {
+        if (projectId == null) {
+            return 0L;
+        }
+
+        // 查询所有队伍,筛选出参与该项目的队伍
+        List<GameTeam> allTeams = gameTeamMapper.selectList(
+            Wrappers.lambdaQuery(GameTeam.class)
+                .select(GameTeam::getProjectValue)
+        );
+
+        long count = allTeams.stream()
+            .filter(team -> {
+                if (StringUtils.isNotBlank(team.getProjectValue())) {
+                    try {
+                        List<Long> projectList = JSONUtil.toList(team.getProjectValue(), Long.class);
+                        return projectList.contains(projectId);
+                    } catch (Exception e) {
+                        log.warn("解析队伍项目列表失败: {}", team.getProjectValue(), e);
+                        return false;
+                    }
+                }
+                return false;
+            })
+            .count();
+
+        return count;
+    }
+
     private LambdaQueryWrapper<GameEventProject> buildQueryWrapper(GameEventProjectBo bo) {
         Map<String, Object> params = bo.getParams();
         LambdaQueryWrapper<GameEventProject> lqw = Wrappers.lambdaQuery();
@@ -377,6 +449,8 @@ public class GameEventProjectServiceImpl implements IGameEventProjectService {
         removeProjectFromReferees(ids);
         //删除项目前批量删除运动员的关联信息
         removeProjectFromAthletes(ids);
+        //删除项目前批量删除分组表game_event_group中的关联信息
+        removeProjectFromGroups(ids);
         return baseMapper.deleteByIds(ids) > 0;
     }
 
@@ -439,6 +513,43 @@ public class GameEventProjectServiceImpl implements IGameEventProjectService {
         }
     }
 
+    /**
+     * 从所有分组中移除指定项目的关联信息
+     *
+     * @param projectIds 要移除的项目ID集合
+     */
+    private void removeProjectFromGroups(Collection<Long> projectIds) {
+        try {
+            if (CollectionUtils.isEmpty(projectIds)) {
+                return;
+            }
+
+            // 查询所有包含这些项目的分组
+            List<GameEventGroup> groups = gameEventGroupMapper.selectList(
+                Wrappers.lambdaQuery(GameEventGroup.class)
+                    .in(GameEventGroup::getProjectId, projectIds)
+            );
+
+            log.info("找到 {} 个分组需要删除,项目ID列表: {}", groups.size(), projectIds);
+
+            if (CollectionUtils.isNotEmpty(groups)) {
+                // 提取分组ID列表
+                List<Long> groupIds = groups.stream()
+                    .map(GameEventGroup::getGroupId)
+                    .collect(Collectors.toList());
+
+                // 批量删除分组
+                int deletedCount = gameEventGroupMapper.deleteBatchIds(groupIds);
+                log.info("成功删除 {} 个分组,分组ID列表: {}", deletedCount, groupIds);
+            }
+
+            log.info("分组关联清理完成,共处理 {} 个分组", groups.size());
+        } catch (Exception e) {
+            log.error("清理分组关联失败,项目ID列表: {}", projectIds, e);
+            throw e;
+        }
+    }
+
     @Override
     public List<GameEventProjectVo> listProjectsByEventIdAndProjectIndex(Long eventId, List<Long> projectIds) {
         if (CollectionUtils.isEmpty(projectIds)) {