|
@@ -15,15 +15,18 @@ import org.dromara.common.mybatis.core.page.TableDataInfo;
|
|
|
import org.dromara.common.redis.utils.RedisUtils;
|
|
import org.dromara.common.redis.utils.RedisUtils;
|
|
|
import org.dromara.system.domain.GameAthlete;
|
|
import org.dromara.system.domain.GameAthlete;
|
|
|
import org.dromara.system.domain.GameEvent;
|
|
import org.dromara.system.domain.GameEvent;
|
|
|
|
|
+import org.dromara.system.domain.GameRankGroup;
|
|
|
import org.dromara.system.domain.GameTeam;
|
|
import org.dromara.system.domain.GameTeam;
|
|
|
|
|
+import org.dromara.system.domain.bo.GameRankGroupBo;
|
|
|
import org.dromara.system.domain.bo.GameTeamBo;
|
|
import org.dromara.system.domain.bo.GameTeamBo;
|
|
|
import org.dromara.system.domain.constant.GameEventConstant;
|
|
import org.dromara.system.domain.constant.GameEventConstant;
|
|
|
import org.dromara.system.domain.vo.GameRankGroupVo;
|
|
import org.dromara.system.domain.vo.GameRankGroupVo;
|
|
|
|
|
+import org.dromara.system.domain.vo.GameTeamImportVo;
|
|
|
import org.dromara.system.domain.vo.GameTeamVo;
|
|
import org.dromara.system.domain.vo.GameTeamVo;
|
|
|
import org.dromara.system.mapper.GameAthleteMapper;
|
|
import org.dromara.system.mapper.GameAthleteMapper;
|
|
|
import org.dromara.system.mapper.GameEventMapper;
|
|
import org.dromara.system.mapper.GameEventMapper;
|
|
|
|
|
+import org.dromara.system.mapper.GameRankGroupMapper;
|
|
|
import org.dromara.system.mapper.GameTeamMapper;
|
|
import org.dromara.system.mapper.GameTeamMapper;
|
|
|
-import org.dromara.system.service.IGameEventProjectService;
|
|
|
|
|
import org.dromara.system.service.IGameRankGroupService;
|
|
import org.dromara.system.service.IGameRankGroupService;
|
|
|
import org.dromara.system.service.IGameTeamService;
|
|
import org.dromara.system.service.IGameTeamService;
|
|
|
import org.springframework.stereotype.Service;
|
|
import org.springframework.stereotype.Service;
|
|
@@ -50,6 +53,7 @@ public class GameTeamServiceImpl implements IGameTeamService {
|
|
|
private final GameEventMapper gameEventMapper;
|
|
private final GameEventMapper gameEventMapper;
|
|
|
|
|
|
|
|
private final IGameRankGroupService gameRankGroupService;
|
|
private final IGameRankGroupService gameRankGroupService;
|
|
|
|
|
+ private final GameRankGroupMapper gameRankGroupMapper;
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* 查询参赛队伍
|
|
* 查询参赛队伍
|
|
@@ -497,4 +501,149 @@ public class GameTeamServiceImpl implements IGameTeamService {
|
|
|
public List<GameTeamBo> findByAthleteIds(Collection<Long> athleteIds) {
|
|
public List<GameTeamBo> findByAthleteIds(Collection<Long> athleteIds) {
|
|
|
return baseMapper.findByAthleteIds(athleteIds);
|
|
return baseMapper.findByAthleteIds(athleteIds);
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
|
|
+ public String importTeam(List<GameTeamImportVo> teamList, Boolean isUpdateSupport) {
|
|
|
|
|
+ if (CollUtil.isEmpty(teamList)) {
|
|
|
|
|
+ throw new ServiceException("导入队伍数据不能为空!");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 1. 获取当前默认赛事ID
|
|
|
|
|
+ Long eventId = null;
|
|
|
|
|
+ Object cacheObject = RedisUtils.getCacheObject(GameEventConstant.DEFAULT_EVENT_ID);
|
|
|
|
|
+ if (cacheObject instanceof Integer) {
|
|
|
|
|
+ eventId = ((Integer) cacheObject).longValue();
|
|
|
|
|
+ } else if (cacheObject instanceof Long) {
|
|
|
|
|
+ eventId = (Long) cacheObject;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (eventId == null) {
|
|
|
|
|
+ throw new ServiceException("未设置当前默认赛事,请先选择赛事!");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 2. 加载所有排名分组,建立 名称 -> ID 映射 (仅查询必要字段节省内存)
|
|
|
|
|
+ List<GameRankGroupVo> rankGroups = gameRankGroupMapper.selectVoList(Wrappers.<GameRankGroup>lambdaQuery()
|
|
|
|
|
+ .eq(GameRankGroup::getEventId, eventId)
|
|
|
|
|
+ .eq(GameRankGroup::getDelFlag, "0")
|
|
|
|
|
+ .select(GameRankGroup::getRgId, GameRankGroup::getRgName)
|
|
|
|
|
+ );
|
|
|
|
|
+ Map<String, Long> rgNameMap = rankGroups.stream()
|
|
|
|
|
+ .filter(g -> StringUtils.isNotBlank(g.getRgName()))
|
|
|
|
|
+ .collect(Collectors.toMap(GameRankGroupVo::getRgName, GameRankGroupVo::getRgId, (v1, v2) -> v1));
|
|
|
|
|
+
|
|
|
|
|
+ // 3. 性能优化:批量预查现有队伍 (Name -> Team) 避免循环查询
|
|
|
|
|
+ Set<String> importNames = teamList.stream()
|
|
|
|
|
+ .map(GameTeamImportVo::getTeamName)
|
|
|
|
|
+ .filter(StringUtils::isNotBlank)
|
|
|
|
|
+ .collect(Collectors.toSet());
|
|
|
|
|
+
|
|
|
|
|
+ Map<String, GameTeam> existingTeamMap = new HashMap<>();
|
|
|
|
|
+ if (CollUtil.isNotEmpty(importNames)) {
|
|
|
|
|
+ List<GameTeam> existingTeams = baseMapper.selectList(Wrappers.<GameTeam>lambdaQuery()
|
|
|
|
|
+ .eq(GameTeam::getEventId, eventId)
|
|
|
|
|
+ .in(GameTeam::getTeamName, importNames)
|
|
|
|
|
+ .eq(GameTeam::getDelFlag, "0"));
|
|
|
|
|
+ existingTeamMap = existingTeams.stream()
|
|
|
|
|
+ .collect(Collectors.toMap(GameTeam::getTeamName, t -> t, (v1, v2) -> v1));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 4. 性能优化:批量预查现有队伍编号 (Code -> TeamId) 用于快速唯一性校验
|
|
|
|
|
+ Set<String> importCodes = teamList.stream()
|
|
|
|
|
+ .map(GameTeamImportVo::getTeamCode)
|
|
|
|
|
+ .filter(StringUtils::isNotBlank)
|
|
|
|
|
+ .collect(Collectors.toSet());
|
|
|
|
|
+
|
|
|
|
|
+ Map<String, Long> existingCodeMap = new HashMap<>();
|
|
|
|
|
+ if (CollUtil.isNotEmpty(importCodes)) {
|
|
|
|
|
+ List<GameTeam> codes = baseMapper.selectList(Wrappers.<GameTeam>lambdaQuery()
|
|
|
|
|
+ .eq(GameTeam::getEventId, eventId)
|
|
|
|
|
+ .in(GameTeam::getTeamCode, importCodes)
|
|
|
|
|
+ .eq(GameTeam::getDelFlag, "0")
|
|
|
|
|
+ .select(GameTeam::getTeamCode, GameTeam::getTeamId));
|
|
|
|
|
+ existingCodeMap = codes.stream()
|
|
|
|
|
+ .collect(Collectors.toMap(GameTeam::getTeamCode, GameTeam::getTeamId, (v1, v2) -> v1));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ int successNum = 0;
|
|
|
|
|
+ int failureNum = 0;
|
|
|
|
|
+ StringBuilder successMsg = new StringBuilder();
|
|
|
|
|
+ StringBuilder failureMsg = new StringBuilder();
|
|
|
|
|
+
|
|
|
|
|
+ List<GameTeam> insertList = new ArrayList<>();
|
|
|
|
|
+ List<GameTeam> updateList = new ArrayList<>();
|
|
|
|
|
+
|
|
|
|
|
+ for (GameTeamImportVo teamVo : teamList) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ String teamName = teamVo.getTeamName();
|
|
|
|
|
+ if (StringUtils.isBlank(teamName)) {
|
|
|
|
|
+ failureNum++;
|
|
|
|
|
+ failureMsg.append("<br/>").append(failureNum).append("、队伍名称不能为空");
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 关联排名分组 (内存查找)
|
|
|
|
|
+ if (StringUtils.isNotBlank(teamVo.getRgName())) {
|
|
|
|
|
+ Long rgId = rgNameMap.get(teamVo.getRgName());
|
|
|
|
|
+ if (rgId == null) {
|
|
|
|
|
+ failureNum++;
|
|
|
|
|
+ failureMsg.append("<br/>").append(failureNum).append("、队伍 [").append(teamName)
|
|
|
|
|
+ .append("] 关联的分组 [").append(teamVo.getRgName()).append("] 不存在,导入失败");
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ teamVo.setRgId(rgId);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 编号唯一性校验 (内存查找)
|
|
|
|
|
+ if (StringUtils.isNotBlank(teamVo.getTeamCode())) {
|
|
|
|
|
+ Long existIdWithCode = existingCodeMap.get(teamVo.getTeamCode());
|
|
|
|
|
+ GameTeam existTeamWithName = existingTeamMap.get(teamName);
|
|
|
|
|
+ // 逻辑:如果编号已存在,但对应的 ID 不是当前名称匹配到的队伍 ID,说明该编号被别的队伍占用了
|
|
|
|
|
+ if (existIdWithCode != null && (existTeamWithName == null || !existIdWithCode.equals(existTeamWithName.getTeamId()))) {
|
|
|
|
|
+ failureNum++;
|
|
|
|
|
+ failureMsg.append("<br/>").append(failureNum).append("、队伍 [").append(teamName).append("] 的编号 [")
|
|
|
|
|
+ .append(teamVo.getTeamCode()).append("] 已被其他队伍使用");
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ GameTeam existingTeam = existingTeamMap.get(teamName);
|
|
|
|
|
+ if (existingTeam == null) {
|
|
|
|
|
+ GameTeam team = MapstructUtils.convert(teamVo, GameTeam.class);
|
|
|
|
|
+ team.setEventId(eventId);
|
|
|
|
|
+ insertList.add(team);
|
|
|
|
|
+ successNum++;
|
|
|
|
|
+ } else if (isUpdateSupport) {
|
|
|
|
|
+ GameTeam team = MapstructUtils.convert(teamVo, GameTeam.class);
|
|
|
|
|
+ team.setTeamId(existingTeam.getTeamId());
|
|
|
|
|
+ team.setEventId(eventId);
|
|
|
|
|
+ updateList.add(team);
|
|
|
|
|
+ successNum++;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ failureNum++;
|
|
|
|
|
+ failureMsg.append("<br/>").append(failureNum).append("、队伍 [").append(teamName).append("] 已存在");
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ failureNum++;
|
|
|
|
|
+ String msg = "<br/>" + failureNum + "、队伍 [" + teamVo.getTeamName() + "] 导入异常:";
|
|
|
|
|
+ failureMsg.append(msg).append(e.getMessage());
|
|
|
|
|
+ log.error(msg, e);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 5. 批量执行数据库写入,大幅提升性能
|
|
|
|
|
+ if (CollUtil.isNotEmpty(insertList)) {
|
|
|
|
|
+ baseMapper.insertBatch(insertList);
|
|
|
|
|
+ }
|
|
|
|
|
+ if (CollUtil.isNotEmpty(updateList)) {
|
|
|
|
|
+ baseMapper.updateBatchById(updateList);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (failureNum > 0) {
|
|
|
|
|
+ failureMsg.insert(0, "很抱歉,导入过程中出现错误!共 " + failureNum + " 条失败,错误如下:");
|
|
|
|
|
+ throw new ServiceException(failureMsg.toString());
|
|
|
|
|
+ } else {
|
|
|
|
|
+ successMsg.insert(0, "恭喜您,数据已全部导入成功!共 " + successNum + " 条。");
|
|
|
|
|
+ }
|
|
|
|
|
+ return successMsg.toString();
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|