Browse Source

feat(game-event): 实现运动员、裁判和队伍的批量关联清理功能

-解决裁判未负责项目时裁判码无法生成的bug
- 在 GameAthleteMapper 中新增 findByProjectIds 方法,支持根据项目 ID 列表批量查询运动员
- 在 GameRefereeMapper 中新增 findByProjectIds 方法,支持根据项目 ID 列表批量查询裁判
- 在 GameTeamMapper 中新增 findByAthleteIds 方法,支持根据运动员 ID 列表批量查询队伍
- 在 GameAthleteServiceImpl 中实现 removeAthleteFromTeams 方法,在删除运动员前清理其在队伍中的关联
- 在 GameEventProjectServiceImpl 中实现 removeProjectFromReferees 和 removeProjectFromAthletes 方法,在删除项目前清理相关裁判和运动员的关联
- 在 GameRefereeServiceImpl 中实现 cleanInvalidProjectAssociations 方法,用于清理无效的项目关联
- 在 GameTeamServiceImpl 中实现 removeTeamFromAthletes 方法,在删除队伍前清理运动员中的队伍关联
- 更新相关接口 IGameAthleteService、IGameRefereeService 和 IGameTeamService 添加对应的批量查询方法- 修改部分查询条件从 eq 改为 like,提升模糊搜索能力
- 优化 QRCodeUtils 中项目信息获取逻辑,增加异常处理和日志记录- 调整 pom.xml 中 profile 激活配置,确保默认环境正确加载
zhou 2 weeks ago
parent
commit
0395b6a156
19 changed files with 316 additions and 34 deletions
  1. 5 5
      pom.xml
  2. 1 1
      ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/controller/GameEventProjectController.java
  3. 4 1
      ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/controller/GameRefereeController.java
  4. 19 0
      ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/mapper/GameAthleteMapper.java
  5. 2 0
      ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/mapper/GameEventMapper.java
  6. 2 0
      ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/mapper/GameEventProjectMapper.java
  7. 20 1
      ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/mapper/GameRefereeMapper.java
  8. 16 0
      ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/mapper/GameTeamMapper.java
  9. 7 0
      ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/service/IGameAthleteService.java
  10. 7 0
      ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/service/IGameRefereeService.java
  11. 7 0
      ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/service/IGameTeamService.java
  12. 39 0
      ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/service/impl/GameAthleteServiceImpl.java
  13. 1 1
      ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/service/impl/GameEventConfigServiceImpl.java
  14. 2 2
      ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/service/impl/GameEventConfigTypeServiceImpl.java
  15. 95 8
      ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/service/impl/GameEventProjectServiceImpl.java
  16. 2 2
      ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/service/impl/GameEventServiceImpl.java
  17. 43 1
      ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/service/impl/GameRefereeServiceImpl.java
  18. 23 1
      ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/service/impl/GameTeamServiceImpl.java
  19. 21 11
      ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/utils/QRCodeUtils.java

+ 5 - 5
pom.xml

@@ -91,7 +91,10 @@
                 <monitor.username>ruoyi</monitor.username>
                 <monitor.password>123456</monitor.password>
             </properties>
-
+            <activation>
+                <!-- 默认环境 -->
+                <activeByDefault>true</activeByDefault>
+            </activation>
 
         </profile>
         <profile>
@@ -102,10 +105,7 @@
                 <monitor.username>ruoyi</monitor.username>
                 <monitor.password>123456</monitor.password>
             </properties>
-            <activation>
-                <!-- 默认环境 -->
-                <activeByDefault>true</activeByDefault>
-            </activation>
+
 
         </profile>
     </profiles>

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

@@ -113,7 +113,7 @@ public class GameEventProjectController extends BaseController {
     }
 
     /**
-     * 删除赛事项目
+     * 批量删除赛事项目
      *
      * @param projectIds 主键串
      */

+ 4 - 1
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/controller/GameRefereeController.java

@@ -25,6 +25,8 @@ import org.dromara.common.mybatis.core.page.TableDataInfo;
 import org.dromara.system.utils.QRCodeUtils;
 import com.fasterxml.jackson.databind.ObjectMapper;
 
+import static cn.dev33.satoken.SaManager.log;
+
 /**
  * 裁判
  *
@@ -130,7 +132,7 @@ public class GameRefereeController extends BaseController {
             // 获取裁判信息
             GameRefereeVo referee = gameRefereeService.queryById(refereeId);
             if (referee == null) {
-                return R.fail("裁判信息不存在");
+                return R.fail("裁判信息不存在,Id:" + refereeId);
             }
             // 调用工具类封装的裁判二维码生成逻辑
 //            String qrCodeBase64 = qrCodeUtils.generateRefereeQRCodeBase64(referee);
@@ -138,6 +140,7 @@ public class GameRefereeController extends BaseController {
 
             return R.ok("二维码生成成功", qrCodeBase64);
         } catch (Exception e) {
+            log.error("生成裁判二维码失败,裁判ID: {}", refereeId, e);
             return R.fail("生成二维码失败: " + e.getMessage());
         }
     }

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

@@ -1,10 +1,14 @@
 package org.dromara.system.mapper;
 
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Select;
 import org.dromara.system.domain.GameAthlete;
+import org.dromara.system.domain.bo.GameAthleteBo;
 import org.dromara.system.domain.vo.GameAthleteVo;
 import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
 
+import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 
@@ -14,6 +18,7 @@ import java.util.Map;
  * @author zlt
  * @date 2025-07-30
  */
+@Mapper
 public interface GameAthleteMapper extends BaseMapperPlus<GameAthlete, GameAthleteVo> {
 
     @Select("select * from game_athlete where user_id = #{userId} AND del_flag = '0'")
@@ -24,4 +29,18 @@ public interface GameAthleteMapper extends BaseMapperPlus<GameAthlete, GameAthle
 
     @Select("select athlete_id,name,team_id from game_athlete where event_id = #{eventId} and del_flag = '0'")
     List<GameAthleteVo> queryAthleteIdAndName(Long eventId);
+
+    /**
+     * 根据项目id列表查询运动员(批量查询)
+     * @param projectIds 项目id列表
+     * @return 运动员列表
+     */
+    @Select("<script>" +
+        "SELECT * FROM game_athlete " +
+        "WHERE del_flag = '0' and(" +
+        "<foreach collection='projectIds' item='projectId' separator=' OR '>" +
+        "JSON_CONTAINS(project_value, CAST(#{projectId} AS JSON))" +
+        "</foreach>" +")"+
+        "</script>")
+    List<GameAthleteBo> findByProjectIds(@Param("projectIds") Collection<Long> projectIds);
 }

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

@@ -1,5 +1,6 @@
 package org.dromara.system.mapper;
 
+import org.apache.ibatis.annotations.Mapper;
 import org.dromara.system.domain.GameEvent;
 import org.dromara.system.domain.vo.GameEventVo;
 import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
@@ -10,6 +11,7 @@ import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
  * @author zlt
  * @date 2025-07-30
  */
+@Mapper
 public interface GameEventMapper extends BaseMapperPlus<GameEvent, GameEventVo> {
 
 }

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

@@ -1,5 +1,6 @@
 package org.dromara.system.mapper;
 
+import org.apache.ibatis.annotations.Mapper;
 import org.dromara.system.domain.GameEventProject;
 import org.dromara.system.domain.vo.GameEventProjectVo;
 import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
@@ -10,6 +11,7 @@ import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
  * @author zlt
  * @date 2025-07-30
  */
+@Mapper
 public interface GameEventProjectMapper extends BaseMapperPlus<GameEventProject, GameEventProjectVo> {
 
 }

+ 20 - 1
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/mapper/GameRefereeMapper.java

@@ -1,10 +1,16 @@
 package org.dromara.system.mapper;
 
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
 import org.dromara.system.domain.GameReferee;
+import org.dromara.system.domain.bo.GameRefereeBo;
 import org.dromara.system.domain.vo.GameRefereeVo;
 import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
 import org.apache.ibatis.annotations.Mapper;
 
+import java.util.Collection;
+import java.util.List;
+
 /**
  * 裁判Mapper接口
  *
@@ -14,4 +20,17 @@ import org.apache.ibatis.annotations.Mapper;
 @Mapper
 public interface GameRefereeMapper extends BaseMapperPlus<GameReferee, GameRefereeVo> {
 
-}
+    /**
+     * 根据项目id列表查询裁判(批量查询)
+     * @param projectIds 项目id列表
+     * @return 裁判列表
+     */
+    @Select("<script>" +
+        "SELECT * FROM game_referee " +
+        "WHERE del_flag = '0' and (" +
+        "<foreach collection='projectIds' item='projectId' separator=' OR '>" +
+        "JSON_CONTAINS(project_list, CAST(#{projectId} AS JSON))" +
+        "</foreach>" + ")"+
+        "</script>")
+    List<GameRefereeBo> findByProjectIds(@Param("projectIds") Collection<Long> projectIds);
+}

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

@@ -2,9 +2,11 @@ package org.dromara.system.mapper;
 
 import org.apache.ibatis.annotations.Select;
 import org.dromara.system.domain.GameTeam;
+import org.dromara.system.domain.bo.GameTeamBo;
 import org.dromara.system.domain.vo.GameTeamVo;
 import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
 
+import java.util.Collection;
 import java.util.List;
 
 /**
@@ -30,4 +32,18 @@ public interface GameTeamMapper extends BaseMapperPlus<GameTeam, GameTeamVo> {
      * @return
      */
     boolean batchUpdateRg(Long rgId, List<Long> teamIds);
+
+    /**
+     * 根据运动员id列表查询队伍(批量查询)
+     * @param athleteIds 运动员id列表
+     * @return 队伍列表
+     */
+    @Select("<script>" +
+        "SELECT * FROM game_team " +
+        "WHERE del_flag = '0' and(" +
+        "<foreach collection='athleteIds' item='athleteId' separator=' OR '>" +
+        "JSON_CONTAINS(athlete_value, CAST(#{athleteId} AS JSON))" +
+        "</foreach>" +")"+
+        "</script>")
+    List<GameTeamBo> findByAthleteIds(Collection<Long> athleteIds);
 }

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

@@ -97,4 +97,11 @@ public interface IGameAthleteService {
     List<GameAthleteVo> queryListByEventIdAndProjectId(Long eventId, Long projectId, String searchValue);
 
     String queryMaxNumber(Long teamId);
+
+    /**
+     * 根据项目ID查询运动员列表
+     * @param projectIds 项目ID列表
+     * @return 运动员列表
+     */
+    List<GameAthleteBo> findByProjectIds(Collection<Long> projectIds);
 }

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

@@ -71,4 +71,11 @@ public interface IGameRefereeService {
      * @return
      */
     Long countReferee();
+
+    /**
+     * 根据项目id列表查询裁判(批量查询)
+     * @param projectIds 项目id列表
+     * @return 裁判列表
+     */
+    List<GameRefereeBo> findByProjectIds(Collection<Long> projectIds);
 }

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

@@ -137,4 +137,11 @@ public interface IGameTeamService {
     Boolean moveGroup(List<Long> teamIds, Long rgId);
 
     List<GameTeam> queryTeamByEventId(Long eventId);
+
+    /**
+     * 根据运动员id列表查询队伍信息
+     * @param athleteIds 运动员id列表
+     * @return 队伍信息
+     */
+    List<GameTeamBo> findByAthleteIds(Collection<Long> athleteIds);
 }

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

@@ -351,9 +351,43 @@ public class GameAthleteServiceImpl implements IGameAthleteService {
         if (isValid) {
             //TODO 做一些业务上的校验,判断是否需要校验
         }
+        //批量删除前,删除队伍中的关联数据
+        removeAthleteFromTeams(ids);
         return baseMapper.deleteByIds(ids) > 0;
     }
 
+    /**
+     * 从所有队伍的项目列表中移除指定运动员
+     *
+     * @param athleteIds 要移除的项目ID列表
+     */
+    private void removeAthleteFromTeams(Collection<Long> athleteIds) {
+        try {
+            if (CollectionUtils.isEmpty(athleteIds)) {
+                return;
+            }
+
+            // 查询所有包含这些项目的运动员
+            List<GameTeamBo> teams = gameTeamService.findByAthleteIds(athleteIds);
+
+            log.info("找到 {} 个队伍需要更新运动员关联,运动员ID列表: {}", teams.size(), athleteIds);
+
+            for (GameTeamBo team : teams) {
+                for (Long athleteId : athleteIds){
+                    if (team.getAthleteList() != null) {
+                        team.getAthleteList().remove(athleteId);
+                        log.info("已从队伍 {} 的运动员列表中移除项目 {}", team.getTeamName(), athleteId);
+                    }
+                }
+                gameTeamService.updateByBo(team);
+            }
+
+            log.info("队伍与运动员的关联清理完成,共处理 {} 个队伍", teams.size());
+        } catch (Exception e) {
+            log.error("清理队伍与运动员的关联失败,运动员ID列表: {}", athleteIds, e);
+            throw e;
+        }
+    }
 
     /**
      * 批量保存更新参赛队员信息
@@ -494,4 +528,9 @@ public class GameAthleteServiceImpl implements IGameAthleteService {
         );
         return gameAthlete != null ? gameAthlete.getAthleteCode() : "0";
     }
+
+    @Override
+    public List<GameAthleteBo> findByProjectIds(Collection<Long> projectIds) {
+        return baseMapper.findByProjectIds(projectIds);
+    }
 }

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

@@ -93,7 +93,7 @@ public class GameEventConfigServiceImpl implements IGameEventConfigService {
         LambdaQueryWrapper<GameEventConfig> lqw = Wrappers.lambdaQuery();
         lqw.orderByAsc(GameEventConfig::getConfigId);
         lqw.eq(bo.getEventId() != null, GameEventConfig::getEventId, bo.getEventId());
-        lqw.eq(StringUtils.isNotBlank(bo.getConfigType()), GameEventConfig::getConfigType, bo.getConfigType());
+        lqw.like(StringUtils.isNotBlank(bo.getConfigType()), GameEventConfig::getConfigType, bo.getConfigType());
         lqw.like(StringUtils.isNotBlank(bo.getConfigDesc()), GameEventConfig::getConfigDesc, bo.getConfigDesc());
         lqw.eq(StringUtils.isNotBlank(bo.getIsEnabled()), GameEventConfig::getIsEnabled, bo.getIsEnabled());
         lqw.eq(StringUtils.isNotBlank(bo.getStatus()), GameEventConfig::getStatus, bo.getStatus());

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

@@ -76,9 +76,9 @@ public class GameEventConfigTypeServiceImpl implements IGameEventConfigTypeServi
         Map<String, Object> params = bo.getParams();
         LambdaQueryWrapper<GameEventConfigType> lqw = Wrappers.lambdaQuery();
         lqw.orderByAsc(GameEventConfigType::getTypeId);
-        lqw.eq(StringUtils.isNotBlank(bo.getTypeCode()), GameEventConfigType::getTypeCode, bo.getTypeCode());
+        lqw.like(StringUtils.isNotBlank(bo.getTypeCode()), GameEventConfigType::getTypeCode, bo.getTypeCode());
         lqw.like(StringUtils.isNotBlank(bo.getTypeName()), GameEventConfigType::getTypeName, bo.getTypeName());
-        lqw.eq(StringUtils.isNotBlank(bo.getTypeDesc()), GameEventConfigType::getTypeDesc, bo.getTypeDesc());
+        lqw.like(StringUtils.isNotBlank(bo.getTypeDesc()), GameEventConfigType::getTypeDesc, bo.getTypeDesc());
         lqw.eq(StringUtils.isNotBlank(bo.getSortField()), GameEventConfigType::getSortField, bo.getSortField());
         lqw.eq(StringUtils.isNotBlank(bo.getIsEnabled()), GameEventConfigType::getIsEnabled, bo.getIsEnabled());
         lqw.eq(StringUtils.isNotBlank(bo.getStatus()), GameEventConfigType::getStatus, bo.getStatus());

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

@@ -1,7 +1,6 @@
 package org.dromara.system.service.impl;
 
 import cn.hutool.core.util.ObjectUtil;
-import cn.hutool.core.util.StrUtil;
 import cn.hutool.json.JSONUtil;
 import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
 import org.dromara.common.core.utils.MapstructUtils;
@@ -14,17 +13,21 @@ 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.GameAthlete;
 import org.dromara.system.domain.GameEvent;
-import org.dromara.system.domain.bo.GameEventBo;
+import org.dromara.system.domain.bo.GameAthleteBo;
 import org.dromara.system.domain.constant.GameEventConstant;
-import org.dromara.system.domain.vo.GameEventVo;
 import org.dromara.system.domain.vo.SysDictDataVo;
+import org.dromara.system.mapper.GameAthleteMapper;
 import org.dromara.system.mapper.GameEventMapper;
-import org.dromara.system.service.IGameEventService;
+import org.dromara.system.mapper.GameRefereeMapper;
+import org.dromara.system.service.IGameAthleteService;
+import org.dromara.system.service.IGameRefereeService;
 import org.dromara.system.service.ISysDictTypeService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Lazy;
 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;
@@ -33,7 +36,6 @@ import org.springframework.transaction.annotation.Transactional;
 
 import java.util.*;
 import java.util.stream.Collectors;
-import java.util.stream.Stream;
 
 /**
  * 赛事项目Service业务层处理
@@ -42,7 +44,7 @@ import java.util.stream.Stream;
  * @date 2025-07-30
  */
 @Slf4j
-@RequiredArgsConstructor
+//@RequiredArgsConstructor
 @Service
 public class GameEventProjectServiceImpl implements IGameEventProjectService {
 
@@ -50,6 +52,20 @@ public class GameEventProjectServiceImpl implements IGameEventProjectService {
     private final GameEventMapper gameEventMapper;
     private final ISysDictTypeService sysDictTypeService;
 
+    @Autowired
+    @Lazy
+    private IGameRefereeService gameRefereeService;
+
+    @Autowired
+    @Lazy
+    private IGameAthleteService gameAthleteService;
+
+    public GameEventProjectServiceImpl(GameEventProjectMapper baseMapper, GameEventMapper gameEventMapper, ISysDictTypeService sysDictTypeService) {
+        this.baseMapper = baseMapper;
+        this.gameEventMapper = gameEventMapper;
+        this.sysDictTypeService = sysDictTypeService;
+    }
+
     /**
      * 查询赛事项目
      *
@@ -59,7 +75,14 @@ public class GameEventProjectServiceImpl implements IGameEventProjectService {
     @Override
     public GameEventProjectVo queryById(Long projectId) {
         GameEventProjectVo vo = baseMapper.selectVoById(projectId);
-        vo.setRefereeGroups(JSONUtil.toList(vo.getRefereeGroup(), Long.class));
+        if (vo == null) {
+            return null;
+        }
+        if (vo.getRefereeGroup() != null && !"".equals(vo.getRefereeGroup())){
+            vo.setRefereeGroups(JSONUtil.toList(vo.getRefereeGroup(), Long.class));
+        }else{
+            vo.setRefereeGroups(new ArrayList<>());
+        }
         return vo;
     }
 
@@ -348,10 +371,74 @@ public class GameEventProjectServiceImpl implements IGameEventProjectService {
     public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
         if (isValid) {
             //TODO 做一些业务上的校验,判断是否需要校验
+
         }
+        //删除项目前批量删除裁判的关联信息
+        removeProjectFromReferees(ids);
+        //删除项目前批量删除运动员的关联信息
+        removeProjectFromAthletes(ids);
         return baseMapper.deleteByIds(ids) > 0;
     }
 
+    /**
+     * 从所有运动员的项目列表中移除指定项目
+     *
+     * @param projectIds 要移除的项目ID列表
+     */
+    private void removeProjectFromAthletes(Collection<Long> projectIds) {
+        try {
+            if (CollectionUtils.isEmpty(projectIds)) {
+                return;
+            }
+
+            // 查询所有包含这些项目的运动员
+            List<GameAthleteBo> athletes = gameAthleteService.findByProjectIds(projectIds);
+
+            log.info("找到 {} 名运动员需要更新项目关联,项目ID列表: {}", athletes.size(), projectIds);
+
+            for (GameAthleteBo athlete : athletes) {
+                for (Long projectId : projectIds){
+                    if (athlete.getProjectList() != null) {
+                        athlete.getProjectList().remove(projectId);
+                        log.info("已从运动员 {} 的项目列表中移除项目 {}", athlete.getName(), projectId);
+                    }
+                }
+                gameAthleteService.updateByBo(athlete);
+            }
+
+            log.info("运动员项目关联清理完成,共处理 {} 名运动员", athletes.size());
+        } catch (Exception e) {
+            log.error("清理运动员项目关联失败,项目ID列表: {}", projectIds, e);
+            throw e;
+        }
+    }
+
+    /**
+     * 从所有裁判的项目列表中移除指定项目
+     *
+     * @param ids 要移除的项目ID集合
+     */
+    private void removeProjectFromReferees(Collection<Long> ids) {
+        try {
+            // 查询所有包含该项目的裁判
+            List<GameRefereeBo> referees = gameRefereeService.findByProjectIds(ids);
+
+            for (GameRefereeBo referee : referees) {
+                for (Long projectId : ids) {
+                    if (referee.getProjectList2() != null) {
+                        // 从项目列表中移除该项目
+                        referee.getProjectList2().remove(projectId);
+                        log.info("已从裁判 {} 的项目列表中移除项目 {}", referee.getName(), projectId);
+                    }
+                }
+                gameRefereeService.updateByBo(referee);
+            }
+        } catch (Exception e) {
+            log.error("从裁判项目列表中移除项目失败,项目ID: {}", ids, e);
+            throw e;
+        }
+    }
+
     @Override
     public List<GameEventProjectVo> listProjectsByEventIdAndProjectIndex(Long eventId, List<Long> projectIds) {
         if (CollectionUtils.isEmpty(projectIds)) {

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

@@ -133,7 +133,7 @@ public class GameEventServiceImpl implements IGameEventService {
         Map<String, Object> params = bo.getParams();
         LambdaQueryWrapper<GameEvent> lqw = Wrappers.lambdaQuery();
         lqw.orderByAsc(GameEvent::getEventId);
-        lqw.eq(StringUtils.isNotBlank(bo.getEventCode()), GameEvent::getEventCode, bo.getEventCode());
+        lqw.like(StringUtils.isNotBlank(bo.getEventCode()), GameEvent::getEventCode, bo.getEventCode());
         lqw.like(StringUtils.isNotBlank(bo.getEventName()), GameEvent::getEventName, bo.getEventName());
         lqw.eq(StringUtils.isNotBlank(bo.getEventType()), GameEvent::getEventType, bo.getEventType());
         lqw.eq(StringUtils.isNotBlank(bo.getLocation()), GameEvent::getLocation, bo.getLocation());
@@ -779,7 +779,7 @@ public class GameEventServiceImpl implements IGameEventService {
                 .toList();
 
             // 4. 设置响应头,开始写 ZIP
-            response.setContentType("application/zip");
+//            response.setContentType("application/zip");
             response.setHeader("Content-Disposition", "attachment; filename=\"athlete_bibs.zip\"");
 
             // 5. 写入 ZIP 文件

+ 43 - 1
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/service/impl/GameRefereeServiceImpl.java

@@ -55,6 +55,9 @@ public class GameRefereeServiceImpl implements IGameRefereeService {
     @Override
     public GameRefereeVo queryById(Long refereeId){
         GameRefereeVo vo = gameRefereeMapper.selectVoById(refereeId);
+        if(vo == null){
+            return null;
+        }
         if (vo.getProjectList() != null) {
             vo.setProjectList2(JSONUtil.toList(vo.getProjectList(), Long.class));
         }
@@ -187,7 +190,7 @@ public class GameRefereeServiceImpl implements IGameRefereeService {
         }
 
         GameReferee update = MapstructUtils.convert(bo, GameReferee.class);
-        validEntityBeforeSave(update);
+        // validEntityBeforeSave(update);
         boolean flag = gameRefereeMapper.updateById(update) > 0;
 
         if (flag) {
@@ -295,6 +298,7 @@ public class GameRefereeServiceImpl implements IGameRefereeService {
      */
     private void validEntityBeforeSave(GameReferee entity){
         //TODO 做一些数据校验,如唯一约束
+        cleanInvalidProjectAssociations(entity.getRefereeId());
     }
 
     /**
@@ -348,4 +352,42 @@ public class GameRefereeServiceImpl implements IGameRefereeService {
             Wrappers.lambdaQuery(GameReferee.class)
         );
     }
+
+    @Override
+    public List<GameRefereeBo> findByProjectIds(Collection<Long> projectIds) {
+        return gameRefereeMapper.findByProjectIds(projectIds);
+    }
+
+    /**
+ * 清理无效的项目关联
+ *
+ * @param refereeId 裁判ID
+ */
+public void cleanInvalidProjectAssociations(Long refereeId) {
+    try {
+        GameRefereeVo referee = queryById(refereeId);
+        if (referee != null && referee.getProjectList2() != null) {
+            List<Long> validProjectIds = new ArrayList<>();
+
+            for (Long projectId : referee.getProjectList2()) {
+                GameEventProjectVo project = gameEventProjectService.queryById(projectId);
+                if (project != null) {
+                    validProjectIds.add(projectId);
+                } else {
+                    log.warn("发现无效的项目关联,裁判ID: {}, 项目ID: {}", refereeId, projectId);
+                }
+            }
+
+            // 如果发现无效关联,更新裁判记录
+            if (!validProjectIds.equals(referee.getProjectList2())) {
+                GameRefereeBo bo = MapstructUtils.convert(referee, GameRefereeBo.class);
+                bo.setProjectList2(validProjectIds);
+                updateByBo(bo);
+                log.info("已清理无效的项目关联,裁判ID: {}", refereeId);
+            }
+        }
+    } catch (Exception e) {
+        log.error("清理无效项目关联失败,裁判ID: {}", refereeId, e);
+    }
+}
 }

+ 23 - 1
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/service/impl/GameTeamServiceImpl.java

@@ -189,7 +189,7 @@ public class GameTeamServiceImpl implements IGameTeamService {
             });
 
         lqw.like(StringUtils.isNotBlank(bo.getTeamName()), GameTeam::getTeamName, bo.getTeamName());
-        lqw.eq(StringUtils.isNotBlank(bo.getTeamCode()), GameTeam::getTeamCode, bo.getTeamCode());
+        lqw.like(StringUtils.isNotBlank(bo.getTeamCode()), GameTeam::getTeamCode, bo.getTeamCode());
         lqw.eq(StringUtils.isNotBlank(bo.getLeader()), GameTeam::getLeader, bo.getLeader());
         lqw.eq(StringUtils.isNotBlank(bo.getAthleteValue()), GameTeam::getAthleteValue, bo.getAthleteValue());
         lqw.eq(StringUtils.isNotBlank(bo.getProjectValue()), GameTeam::getProjectValue, bo.getProjectValue());
@@ -280,9 +280,26 @@ public class GameTeamServiceImpl implements IGameTeamService {
         if (isValid) {
             //TODO 做一些业务上的校验,判断是否需要校验
         }
+        //批量删除前,删除运动员中的关联数据
+        removeTeamFromAthletes(ids);
         return baseMapper.deleteByIds(ids) > 0;
     }
 
+    private void removeTeamFromAthletes(Collection<Long> teamIds) {
+        if (CollectionUtils.isEmpty(teamIds)) {
+            return;
+        }
+        List<GameAthlete> athleteList = gameAthleteMapper.selectList(
+            Wrappers.<GameAthlete>lambdaQuery()
+                .in(GameAthlete::getTeamId, teamIds)
+        );
+        if (CollectionUtils.isEmpty(athleteList)) {
+            return;
+        }
+        List<GameAthlete> updateAthletes = athleteList.stream().peek(athlete -> athlete.setTeamId(null)).toList();
+        gameAthleteMapper.updateById(updateAthletes);
+    }
+
     /**
      * 批量保存参赛队伍信息
      *
@@ -464,4 +481,9 @@ public class GameTeamServiceImpl implements IGameTeamService {
                 .eq(GameTeam::getEventId, eventId)
         );
     }
+
+    @Override
+    public List<GameTeamBo> findByAthleteIds(Collection<Long> athleteIds) {
+        return baseMapper.findByAthleteIds(athleteIds);
+    }
 }

+ 21 - 11
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/utils/QRCodeUtils.java

@@ -22,6 +22,8 @@ import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.util.*;
 
+import static cn.dev33.satoken.SaManager.log;
+
 /**
  * 二维码生成工具类
  *
@@ -151,17 +153,25 @@ public class QRCodeUtils {
                 Map<String, Object> projectList = new HashMap<>();
                 for (Long pid : projectIds) {
                     if (pid == null) continue;
-                    GameEventProjectVo pvo = gameEventProjectService.queryById(pid);
-                    if (pvo != null) {
-                        Map<String, Object> project = new HashMap<>();
-                        project.put("projectType", pvo.getProjectType());
-                        project.put("projectName", pvo.getProjectName());
-                        project.put("classification", pvo.getClassification());
-                        project.put("orderType", pvo.getOrderType());
-                        project.put("gradeRule", pvo.getScoreRule());
-                        project.put("admissionRank",pvo.getRoundType());
-                        project.put("admissionPoint",pvo.getScoreValue());
-                        projectList.put(pvo.getProjectId().toString(), project);
+                    try {
+                        GameEventProjectVo pvo = gameEventProjectService.queryById(pid);
+                        if (pvo != null) {
+                            Map<String, Object> project = new HashMap<>();
+                            project.put("projectType", pvo.getProjectType());
+                            project.put("projectName", pvo.getProjectName());
+                            project.put("classification", pvo.getClassification());
+                            project.put("orderType", pvo.getOrderType());
+                            project.put("gradeRule", pvo.getScoreRule());
+                            project.put("admissionRank",pvo.getRoundType());
+                            project.put("admissionPoint",pvo.getScoreValue());
+                            projectList.put(pvo.getProjectId().toString(), project);
+                        }else{
+                            // 记录日志,项目不存在
+                            log.warn("项目ID {} 不存在,跳过处理", pid);
+                        }
+                    } catch (Exception e) {
+                        // 记录异常但不中断处理
+                        log.error("查询项目ID {} 失败: {}", pid, e.getMessage());
                     }
                 }
                 simpleData.put("projectList", projectList);