|
@@ -113,32 +113,61 @@ public class GameEventGroupServiceImpl implements IGameEventGroupService {
|
|
|
if (bo.getEventId() == null) {
|
|
if (bo.getEventId() == null) {
|
|
|
Object cacheObject = RedisUtils.getCacheObject(GameEventConstant.DEFAULT_EVENT_ID);
|
|
Object cacheObject = RedisUtils.getCacheObject(GameEventConstant.DEFAULT_EVENT_ID);
|
|
|
if (cacheObject instanceof Integer) {
|
|
if (cacheObject instanceof Integer) {
|
|
|
- bo.setEventId(((Integer) cacheObject).longValue()); // 显式转换为 Long 类型
|
|
|
|
|
|
|
+ bo.setEventId(((Integer) cacheObject).longValue());
|
|
|
} else if (cacheObject instanceof Long) {
|
|
} else if (cacheObject instanceof Long) {
|
|
|
bo.setEventId((Long) cacheObject);
|
|
bo.setEventId((Long) cacheObject);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ // 1. 预获取混合性别字典值,用于 SQL 统计逻辑
|
|
|
|
|
+ List<SysDictDataVo> genderDict = dictTypeService.selectDictDataByType("sys_group_sex");
|
|
|
|
|
+ String mixGenderValue = genderDict.stream()
|
|
|
|
|
+ .filter(g -> "混合".equals(g.getDictLabel()))
|
|
|
|
|
+ .map(SysDictDataVo::getDictValue)
|
|
|
|
|
+ .findFirst().orElse("");
|
|
|
|
|
+
|
|
|
LambdaQueryWrapper<GameEventGroup> lqw = buildQueryWrapper(bo);
|
|
LambdaQueryWrapper<GameEventGroup> lqw = buildQueryWrapper(bo);
|
|
|
-// Page<GameEventGroupVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
|
|
|
|
|
- Page<GameEventGroupVo> result = baseMapper.selectPageEventGroupList(pageQuery.build(), lqw);
|
|
|
|
|
- result.getRecords().stream()
|
|
|
|
|
- .map(vo -> {
|
|
|
|
|
- Optional.ofNullable(vo.getProjectList())
|
|
|
|
|
- .filter(StringUtils::isNotBlank)
|
|
|
|
|
- .ifPresent(projectValue -> {
|
|
|
|
|
- List<Long> projectIds = JSONUtil.toList(projectValue, Long.class);
|
|
|
|
|
- List<GameEventProjectVo> projects =
|
|
|
|
|
- gameEventProjectService.listProjectsByEventIdAndProjectIndex(
|
|
|
|
|
- vo.getEventId(),
|
|
|
|
|
- projectIds);
|
|
|
|
|
- vo.setProjectList(projects.stream()
|
|
|
|
|
- .map(GameEventProjectVo::getProjectName)
|
|
|
|
|
- .filter(StringUtils::isNotBlank)
|
|
|
|
|
- .collect(Collectors.joining(",")));
|
|
|
|
|
- });
|
|
|
|
|
- return vo;
|
|
|
|
|
- })
|
|
|
|
|
- .toList(); // 收集结果
|
|
|
|
|
|
|
+ // 2. 使用单条 SQL 完成分页查询与符合条件的人数统计(标量子查询),实现最佳性能
|
|
|
|
|
+ Page<GameEventGroupVo> result = baseMapper.selectPageWithAthleteCount(pageQuery.build(), lqw, mixGenderValue);
|
|
|
|
|
+
|
|
|
|
|
+ List<GameEventGroupVo> records = result.getRecords();
|
|
|
|
|
+ if (records.isEmpty()) {
|
|
|
|
|
+ return TableDataInfo.build(result);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 3. 收集所有涉及的项目ID,用于批量查询项目名称(保留此性能优化)
|
|
|
|
|
+ Set<Long> allProjectIds = new HashSet<>();
|
|
|
|
|
+ records.forEach(vo -> {
|
|
|
|
|
+ if (vo.getProjectId() != null) allProjectIds.add(vo.getProjectId());
|
|
|
|
|
+ if (StringUtils.isNotBlank(vo.getProjectList())) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ allProjectIds.addAll(JSONUtil.toList(vo.getProjectList(), Long.class));
|
|
|
|
|
+ } catch (Exception ignored) {}
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // 批量查询项目信息并建立缓存 Map
|
|
|
|
|
+ Map<Long, String> projectNameMap = new HashMap<>();
|
|
|
|
|
+ if (!allProjectIds.isEmpty()) {
|
|
|
|
|
+ List<GameEventProjectVo> projects = gameEventProjectService.listProjectsByEventIdAndProjectIndex(bo.getEventId(), new ArrayList<>(allProjectIds));
|
|
|
|
|
+ projectNameMap = projects.stream().collect(Collectors.toMap(GameEventProjectVo::getProjectId, GameEventProjectVo::getProjectName, (k1, k2) -> k1));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 4. 遍历处理结果:此时 eligibleAthleteCount 已经由 SQL 自动填充
|
|
|
|
|
+ for (GameEventGroupVo vo : records) {
|
|
|
|
|
+ // 处理项目列表展示名称:从内存 Map 中获取
|
|
|
|
|
+ if (StringUtils.isNotBlank(vo.getProjectList())) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ List<Long> pIds = JSONUtil.toList(vo.getProjectList(), Long.class);
|
|
|
|
|
+ Map<Long, String> finalProjectNameMap = projectNameMap;
|
|
|
|
|
+ vo.setProjectList(pIds.stream()
|
|
|
|
|
+ .map(finalProjectNameMap::get)
|
|
|
|
|
+ .filter(StringUtils::isNotBlank)
|
|
|
|
|
+ .collect(Collectors.joining(",")));
|
|
|
|
|
+ } catch (Exception ignored) {}
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
return TableDataInfo.build(result);
|
|
return TableDataInfo.build(result);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -153,13 +182,13 @@ public class GameEventGroupServiceImpl implements IGameEventGroupService {
|
|
|
if (bo.getEventId() == null) {
|
|
if (bo.getEventId() == null) {
|
|
|
Object cacheObject = RedisUtils.getCacheObject(GameEventConstant.DEFAULT_EVENT_ID);
|
|
Object cacheObject = RedisUtils.getCacheObject(GameEventConstant.DEFAULT_EVENT_ID);
|
|
|
if (cacheObject instanceof Integer) {
|
|
if (cacheObject instanceof Integer) {
|
|
|
- bo.setEventId(((Integer) cacheObject).longValue()); // 显式转换为 Long 类型
|
|
|
|
|
|
|
+ bo.setEventId(((Integer) cacheObject).longValue()); // 显式转换为 Long 类型
|
|
|
} else if (cacheObject instanceof Long) {
|
|
} else if (cacheObject instanceof Long) {
|
|
|
bo.setEventId((Long) cacheObject);
|
|
bo.setEventId((Long) cacheObject);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
LambdaQueryWrapper<GameEventGroup> lqw = buildQueryWrapper(bo);
|
|
LambdaQueryWrapper<GameEventGroup> lqw = buildQueryWrapper(bo);
|
|
|
-// return baseMapper.selectVoList(lqw);
|
|
|
|
|
|
|
+ // return baseMapper.selectVoList(lqw);
|
|
|
return baseMapper.selectEventGroupList(lqw);
|
|
return baseMapper.selectEventGroupList(lqw);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -182,6 +211,7 @@ public class GameEventGroupServiceImpl implements IGameEventGroupService {
|
|
|
lqw.eq(bo.getTrackNum() != null, GameEventGroup::getTrackNum, bo.getTrackNum());
|
|
lqw.eq(bo.getTrackNum() != null, GameEventGroup::getTrackNum, bo.getTrackNum());
|
|
|
lqw.eq(bo.getFieldNum() != null, GameEventGroup::getFieldNum, bo.getFieldNum());
|
|
lqw.eq(bo.getFieldNum() != null, GameEventGroup::getFieldNum, bo.getFieldNum());
|
|
|
lqw.eq(bo.getDuration() != null, GameEventGroup::getDuration, bo.getDuration());
|
|
lqw.eq(bo.getDuration() != null, GameEventGroup::getDuration, bo.getDuration());
|
|
|
|
|
+ lqw.eq(GameEventGroup::getDelFlag, "0");
|
|
|
return lqw;
|
|
return lqw;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -196,7 +226,7 @@ public class GameEventGroupServiceImpl implements IGameEventGroupService {
|
|
|
if (bo.getEventId() == null) {
|
|
if (bo.getEventId() == null) {
|
|
|
Object cacheObject = RedisUtils.getCacheObject(GameEventConstant.DEFAULT_EVENT_ID);
|
|
Object cacheObject = RedisUtils.getCacheObject(GameEventConstant.DEFAULT_EVENT_ID);
|
|
|
if (cacheObject instanceof Integer) {
|
|
if (cacheObject instanceof Integer) {
|
|
|
- bo.setEventId(((Integer) cacheObject).longValue()); // 显式转换为 Long 类型
|
|
|
|
|
|
|
+ bo.setEventId(((Integer) cacheObject).longValue()); // 显式转换为 Long 类型
|
|
|
} else if (cacheObject instanceof Long) {
|
|
} else if (cacheObject instanceof Long) {
|
|
|
bo.setEventId((Long) cacheObject);
|
|
bo.setEventId((Long) cacheObject);
|
|
|
}
|
|
}
|
|
@@ -221,7 +251,7 @@ public class GameEventGroupServiceImpl implements IGameEventGroupService {
|
|
|
if (bo.getEventId() == null) {
|
|
if (bo.getEventId() == null) {
|
|
|
Object cacheObject = RedisUtils.getCacheObject(GameEventConstant.DEFAULT_EVENT_ID);
|
|
Object cacheObject = RedisUtils.getCacheObject(GameEventConstant.DEFAULT_EVENT_ID);
|
|
|
if (cacheObject instanceof Integer) {
|
|
if (cacheObject instanceof Integer) {
|
|
|
- bo.setEventId(((Integer) cacheObject).longValue()); // 显式转换为 Long 类型
|
|
|
|
|
|
|
+ bo.setEventId(((Integer) cacheObject).longValue()); // 显式转换为 Long 类型
|
|
|
} else if (cacheObject instanceof Long) {
|
|
} else if (cacheObject instanceof Long) {
|
|
|
bo.setEventId((Long) cacheObject);
|
|
bo.setEventId((Long) cacheObject);
|
|
|
}
|
|
}
|
|
@@ -235,7 +265,7 @@ public class GameEventGroupServiceImpl implements IGameEventGroupService {
|
|
|
* 保存前的数据校验
|
|
* 保存前的数据校验
|
|
|
*/
|
|
*/
|
|
|
private void validEntityBeforeSave(GameEventGroup entity) {
|
|
private void validEntityBeforeSave(GameEventGroup entity) {
|
|
|
- //TODO 做一些数据校验,如唯一约束
|
|
|
|
|
|
|
+ // TODO 做一些数据校验,如唯一约束
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -248,7 +278,7 @@ public class GameEventGroupServiceImpl implements IGameEventGroupService {
|
|
|
@Override
|
|
@Override
|
|
|
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
|
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
|
|
if (isValid) {
|
|
if (isValid) {
|
|
|
- //TODO 做一些业务上的校验,判断是否需要校验
|
|
|
|
|
|
|
+ // TODO 做一些业务上的校验,判断是否需要校验
|
|
|
}
|
|
}
|
|
|
ids.forEach(id -> getGameAthleteCompetitionGroupService().deleteGroupResultByGroupId(id));
|
|
ids.forEach(id -> getGameAthleteCompetitionGroupService().deleteGroupResultByGroupId(id));
|
|
|
return baseMapper.deleteByIds(ids) > 0;
|
|
return baseMapper.deleteByIds(ids) > 0;
|
|
@@ -263,9 +293,9 @@ public class GameEventGroupServiceImpl implements IGameEventGroupService {
|
|
|
@Override
|
|
@Override
|
|
|
public GameEventGroup queryByEventId(Long defaultEventId) {
|
|
public GameEventGroup queryByEventId(Long defaultEventId) {
|
|
|
return baseMapper.selectList(
|
|
return baseMapper.selectList(
|
|
|
- Wrappers.lambdaQuery(GameEventGroup.class)
|
|
|
|
|
- .eq(GameEventGroup::getEventId, defaultEventId)
|
|
|
|
|
- ).get(0);
|
|
|
|
|
|
|
+ Wrappers.lambdaQuery(GameEventGroup.class)
|
|
|
|
|
+ .eq(GameEventGroup::getEventId, defaultEventId))
|
|
|
|
|
+ .get(0);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -290,7 +320,7 @@ public class GameEventGroupServiceImpl implements IGameEventGroupService {
|
|
|
Map<String, Object> result = new HashMap<>();
|
|
Map<String, Object> result = new HashMap<>();
|
|
|
|
|
|
|
|
try {
|
|
try {
|
|
|
- //获取性别字典数据
|
|
|
|
|
|
|
+ // 获取性别字典数据
|
|
|
List<SysDictDataVo> genderDict = dictTypeService.selectDictDataByType("sys_group_sex");
|
|
List<SysDictDataVo> genderDict = dictTypeService.selectDictDataByType("sys_group_sex");
|
|
|
// 获取分组信息
|
|
// 获取分组信息
|
|
|
GameEventGroupVo groupInfo = queryById(groupId);
|
|
GameEventGroupVo groupInfo = queryById(groupId);
|
|
@@ -318,50 +348,50 @@ public class GameEventGroupServiceImpl implements IGameEventGroupService {
|
|
|
|
|
|
|
|
// 筛选符合条件的运动员
|
|
// 筛选符合条件的运动员
|
|
|
List<GameAthleteVo> eligibleAthletes = athletes.stream()
|
|
List<GameAthleteVo> eligibleAthletes = athletes.stream()
|
|
|
- .filter(athlete -> {
|
|
|
|
|
- // 检查是否参与该项目
|
|
|
|
|
- if (athlete.getProjectList() == null) {
|
|
|
|
|
- return false;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ .filter(athlete -> {
|
|
|
|
|
+ // 检查是否参与该项目
|
|
|
|
|
+ if (athlete.getProjectList() == null) {
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- // 处理项目列表
|
|
|
|
|
- List<String> projectIds = new ArrayList<>();
|
|
|
|
|
- if (athlete.getProjectList() != null) {
|
|
|
|
|
- projectIds = ((List<?>) athlete.getProjectList()).stream()
|
|
|
|
|
- .map(Object::toString)
|
|
|
|
|
- .toList();
|
|
|
|
|
- }
|
|
|
|
|
-// else if (athlete.getProjectList() instanceof String) {
|
|
|
|
|
-// String projectListStr = (String) athlete.getProjectList();
|
|
|
|
|
-// try {
|
|
|
|
|
-// projectIds = JSONUtil.toList(projectListStr, String.class);
|
|
|
|
|
-// } catch (Exception e) {
|
|
|
|
|
-// // 如果不是JSON格式,可能是逗号分隔的字符串
|
|
|
|
|
-// projectIds = List.of(projectListStr.split(","));
|
|
|
|
|
-// }
|
|
|
|
|
-// }
|
|
|
|
|
-
|
|
|
|
|
- String targetProjectId = groupInfo.getProjectId() != null ?
|
|
|
|
|
- groupInfo.getProjectId().toString() : null;
|
|
|
|
|
- if (targetProjectId == null || !projectIds.contains(targetProjectId)) {
|
|
|
|
|
- return false;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ // 处理项目列表
|
|
|
|
|
+ List<String> projectIds = new ArrayList<>();
|
|
|
|
|
+ if (athlete.getProjectList() != null) {
|
|
|
|
|
+ projectIds = ((List<?>) athlete.getProjectList()).stream()
|
|
|
|
|
+ .map(Object::toString)
|
|
|
|
|
+ .toList();
|
|
|
|
|
+ }
|
|
|
|
|
+ // else if (athlete.getProjectList() instanceof String) {
|
|
|
|
|
+ // String projectListStr = (String) athlete.getProjectList();
|
|
|
|
|
+ // try {
|
|
|
|
|
+ // projectIds = JSONUtil.toList(projectListStr, String.class);
|
|
|
|
|
+ // } catch (Exception e) {
|
|
|
|
|
+ // // 如果不是JSON格式,可能是逗号分隔的字符串
|
|
|
|
|
+ // projectIds = List.of(projectListStr.split(","));
|
|
|
|
|
+ // }
|
|
|
|
|
+ // }
|
|
|
|
|
+
|
|
|
|
|
+ String targetProjectId = groupInfo.getProjectId() != null ? groupInfo.getProjectId().toString()
|
|
|
|
|
+ : null;
|
|
|
|
|
+ if (targetProjectId == null || !projectIds.contains(targetProjectId)) {
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- // 检查性别是否匹配
|
|
|
|
|
- Optional<String> mixGender = genderDict.stream()
|
|
|
|
|
- .filter(g -> g.getDictLabel().equals("混合"))
|
|
|
|
|
- .map(SysDictDataVo::getDictValue)
|
|
|
|
|
- .findFirst();
|
|
|
|
|
- if (StringUtils.isNotBlank(groupInfo.getMemberGender())) {
|
|
|
|
|
- if (!groupInfo.getMemberGender().equals(
|
|
|
|
|
- athlete.getGender() != null ? athlete.getGender() : null)) {
|
|
|
|
|
- return groupInfo.getMemberGender().equals(mixGender.orElse(null));
|
|
|
|
|
|
|
+ // 检查性别是否匹配
|
|
|
|
|
+ Optional<String> mixGender = genderDict.stream()
|
|
|
|
|
+ .filter(g -> g.getDictLabel().equals("混合"))
|
|
|
|
|
+ .map(SysDictDataVo::getDictValue)
|
|
|
|
|
+ .findFirst();
|
|
|
|
|
+ if (StringUtils.isNotBlank(groupInfo.getMemberGender())) {
|
|
|
|
|
+ if (!groupInfo.getMemberGender().equals(
|
|
|
|
|
+ athlete.getGender() != null ? athlete.getGender() : null)) {
|
|
|
|
|
+ return groupInfo.getMemberGender().equals(mixGender.orElse(null));
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
- }
|
|
|
|
|
|
|
|
|
|
- return true;
|
|
|
|
|
- })
|
|
|
|
|
- .toList();
|
|
|
|
|
|
|
+ return true;
|
|
|
|
|
+ })
|
|
|
|
|
+ .toList();
|
|
|
|
|
|
|
|
if (eligibleAthletes.isEmpty()) {
|
|
if (eligibleAthletes.isEmpty()) {
|
|
|
result.put("success", false);
|
|
result.put("success", false);
|
|
@@ -386,7 +416,8 @@ public class GameEventGroupServiceImpl implements IGameEventGroupService {
|
|
|
int totalGroups = groupInfo.getIncludeGroupNum().intValue();
|
|
int totalGroups = groupInfo.getIncludeGroupNum().intValue();
|
|
|
|
|
|
|
|
// 每组分配人数
|
|
// 每组分配人数
|
|
|
- Long personsPerGroup = groupInfo.getPersonNum() != null ? groupInfo.getPersonNum() : groupInfo.getTrackNum();
|
|
|
|
|
|
|
+ Long personsPerGroup = groupInfo.getPersonNum() != null ? groupInfo.getPersonNum()
|
|
|
|
|
+ : groupInfo.getTrackNum();
|
|
|
if (personsPerGroup > groupInfo.getTrackNum()) {
|
|
if (personsPerGroup > groupInfo.getTrackNum()) {
|
|
|
log.warn("每组人数({})超过道数({}),将限制为道数", personsPerGroup, groupInfo.getTrackNum());
|
|
log.warn("每组人数({})超过道数({}),将限制为道数", personsPerGroup, groupInfo.getTrackNum());
|
|
|
personsPerGroup = groupInfo.getTrackNum();
|
|
personsPerGroup = groupInfo.getTrackNum();
|
|
@@ -432,23 +463,25 @@ public class GameEventGroupServiceImpl implements IGameEventGroupService {
|
|
|
|
|
|
|
|
// 只有项目属于团体项目才检查同一组中是否已有同一队伍的运动员
|
|
// 只有项目属于团体项目才检查同一组中是否已有同一队伍的运动员
|
|
|
boolean isValidCandidate = true;
|
|
boolean isValidCandidate = true;
|
|
|
- if (project != null && ProjectClassification.TEAM.getValue().equals(project.getClassification())) {
|
|
|
|
|
|
|
+ if (project != null
|
|
|
|
|
+ && ProjectClassification.TEAM.getValue().equals(project.getClassification())) {
|
|
|
// 团体项目:检查同一组中是否已有同一队伍的运动员
|
|
// 团体项目:检查同一组中是否已有同一队伍的运动员
|
|
|
boolean hasSameTeamInGroup = groupResult.entrySet().stream()
|
|
boolean hasSameTeamInGroup = groupResult.entrySet().stream()
|
|
|
- .anyMatch(entry -> {
|
|
|
|
|
- String[] keyParts = entry.getKey().split("-");
|
|
|
|
|
- if (keyParts.length >= 1) {
|
|
|
|
|
- String existingGroup = keyParts[0];
|
|
|
|
|
- return existingGroup.equals(String.valueOf(finalGroupIndex)) &&
|
|
|
|
|
- entry.getValue().getTeamId() != null &&
|
|
|
|
|
- entry.getValue().getTeamId().equals(candidateAthlete.getTeamId());
|
|
|
|
|
- }
|
|
|
|
|
- return false;
|
|
|
|
|
- });
|
|
|
|
|
|
|
+ .anyMatch(entry -> {
|
|
|
|
|
+ String[] keyParts = entry.getKey().split("-");
|
|
|
|
|
+ if (keyParts.length >= 1) {
|
|
|
|
|
+ String existingGroup = keyParts[0];
|
|
|
|
|
+ return existingGroup.equals(String.valueOf(finalGroupIndex)) &&
|
|
|
|
|
+ entry.getValue().getTeamId() != null &&
|
|
|
|
|
+ entry.getValue().getTeamId().equals(candidateAthlete.getTeamId());
|
|
|
|
|
+ }
|
|
|
|
|
+ return false;
|
|
|
|
|
+ });
|
|
|
if (hasSameTeamInGroup) {
|
|
if (hasSameTeamInGroup) {
|
|
|
isValidCandidate = false;
|
|
isValidCandidate = false;
|
|
|
log.debug("第{}组拒绝运动员{}:团体项目中同一组不能有同一队伍({})的运动员",
|
|
log.debug("第{}组拒绝运动员{}:团体项目中同一组不能有同一队伍({})的运动员",
|
|
|
- finalGroupIndex, candidateAthlete.getAthleteCode(), candidateAthlete.getTeamName());
|
|
|
|
|
|
|
+ finalGroupIndex, candidateAthlete.getAthleteCode(),
|
|
|
|
|
+ candidateAthlete.getTeamName());
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -466,19 +499,19 @@ public class GameEventGroupServiceImpl implements IGameEventGroupService {
|
|
|
String key = finalGroupIndex + "-" + track;
|
|
String key = finalGroupIndex + "-" + track;
|
|
|
groupResult.put(key, selectedAthlete);
|
|
groupResult.put(key, selectedAthlete);
|
|
|
log.debug("分配成功 - 第{}组第{}道: 运动员编号={}, 姓名={}, 队伍={}",
|
|
log.debug("分配成功 - 第{}组第{}道: 运动员编号={}, 姓名={}, 队伍={}",
|
|
|
- finalGroupIndex, track, selectedAthlete.getAthleteCode(),
|
|
|
|
|
- selectedAthlete.getName(), selectedAthlete.getTeamName());
|
|
|
|
|
|
|
+ finalGroupIndex, track, selectedAthlete.getAthleteCode(),
|
|
|
|
|
+ selectedAthlete.getName(), selectedAthlete.getTeamName());
|
|
|
} else {
|
|
} else {
|
|
|
// 检查是否有可用但未分配的运动员
|
|
// 检查是否有可用但未分配的运动员
|
|
|
long availableCount = eligibleAthletes.stream()
|
|
long availableCount = eligibleAthletes.stream()
|
|
|
- .filter(a -> !assignedAthleteIds.contains(a.getAthleteId()))
|
|
|
|
|
- .count();
|
|
|
|
|
|
|
+ .filter(a -> !assignedAthleteIds.contains(a.getAthleteId()))
|
|
|
|
|
+ .count();
|
|
|
if (availableCount > 0) {
|
|
if (availableCount > 0) {
|
|
|
log.warn("第{}组第{}道未找到合适的运动员,但仍有{}个符合条件的运动员未分配",
|
|
log.warn("第{}组第{}道未找到合适的运动员,但仍有{}个符合条件的运动员未分配",
|
|
|
- finalGroupIndex, track, availableCount);
|
|
|
|
|
|
|
+ finalGroupIndex, track, availableCount);
|
|
|
} else {
|
|
} else {
|
|
|
log.warn("第{}组第{}道未找到合适的运动员,所有符合条件的运动员都已被分配",
|
|
log.warn("第{}组第{}道未找到合适的运动员,所有符合条件的运动员都已被分配",
|
|
|
- finalGroupIndex, track);
|
|
|
|
|
|
|
+ finalGroupIndex, track);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -492,16 +525,16 @@ public class GameEventGroupServiceImpl implements IGameEventGroupService {
|
|
|
log.info("【已分配的运动员】");
|
|
log.info("【已分配的运动员】");
|
|
|
groupResult.forEach((key, athlete) -> {
|
|
groupResult.forEach((key, athlete) -> {
|
|
|
log.info(" 已分配 - 位置: {}, 运动员编号: {}, 姓名: {}, 队伍ID: {}, 队伍名称: {}",
|
|
log.info(" 已分配 - 位置: {}, 运动员编号: {}, 姓名: {}, 队伍ID: {}, 队伍名称: {}",
|
|
|
- key, athlete.getAthleteCode(), athlete.getName(),
|
|
|
|
|
- athlete.getTeamId(), athlete.getTeamName());
|
|
|
|
|
|
|
+ key, athlete.getAthleteCode(), athlete.getName(),
|
|
|
|
|
+ athlete.getTeamId(), athlete.getTeamName());
|
|
|
});
|
|
});
|
|
|
log.info("已分配运动员数量: {}", groupResult.size());
|
|
log.info("已分配运动员数量: {}", groupResult.size());
|
|
|
|
|
|
|
|
// 找出并记录未分配的运动员及原因
|
|
// 找出并记录未分配的运动员及原因
|
|
|
log.info("【未分配的运动员】");
|
|
log.info("【未分配的运动员】");
|
|
|
List<GameAthleteVo> unassignedAthletes = eligibleAthletes.stream()
|
|
List<GameAthleteVo> unassignedAthletes = eligibleAthletes.stream()
|
|
|
- .filter(athlete -> !assignedAthleteIds.contains(athlete.getAthleteId()))
|
|
|
|
|
- .toList();
|
|
|
|
|
|
|
+ .filter(athlete -> !assignedAthleteIds.contains(athlete.getAthleteId()))
|
|
|
|
|
+ .toList();
|
|
|
|
|
|
|
|
if (unassignedAthletes.isEmpty()) {
|
|
if (unassignedAthletes.isEmpty()) {
|
|
|
log.info(" 所有符合条件的运动员都已成功分配");
|
|
log.info(" 所有符合条件的运动员都已成功分配");
|
|
@@ -515,14 +548,16 @@ public class GameEventGroupServiceImpl implements IGameEventGroupService {
|
|
|
// 分析未分配原因
|
|
// 分析未分配原因
|
|
|
if (groupResult.size() >= totalTracksNeeded) {
|
|
if (groupResult.size() >= totalTracksNeeded) {
|
|
|
reason = String.format("道次已满(需要%d个道次,已分配%d个运动员)", totalTracksNeeded, groupResult.size());
|
|
reason = String.format("道次已满(需要%d个道次,已分配%d个运动员)", totalTracksNeeded, groupResult.size());
|
|
|
- } else if (project != null && ProjectClassification.TEAM.getValue().equals(project.getClassification())) {
|
|
|
|
|
|
|
+ } else if (project != null
|
|
|
|
|
+ && ProjectClassification.TEAM.getValue().equals(project.getClassification())) {
|
|
|
// 团体项目:分析每个组中是否有该队伍
|
|
// 团体项目:分析每个组中是否有该队伍
|
|
|
Map<Integer, Set<Long>> groupTeamMap = new HashMap<>();
|
|
Map<Integer, Set<Long>> groupTeamMap = new HashMap<>();
|
|
|
groupResult.forEach((key, assignedAthlete) -> {
|
|
groupResult.forEach((key, assignedAthlete) -> {
|
|
|
String[] keyParts = key.split("-");
|
|
String[] keyParts = key.split("-");
|
|
|
if (keyParts.length >= 1) {
|
|
if (keyParts.length >= 1) {
|
|
|
int group = Integer.parseInt(keyParts[0]);
|
|
int group = Integer.parseInt(keyParts[0]);
|
|
|
- groupTeamMap.computeIfAbsent(group, k -> new HashSet<>()).add(assignedAthlete.getTeamId());
|
|
|
|
|
|
|
+ groupTeamMap.computeIfAbsent(group, k -> new HashSet<>())
|
|
|
|
|
+ .add(assignedAthlete.getTeamId());
|
|
|
}
|
|
}
|
|
|
});
|
|
});
|
|
|
|
|
|
|
@@ -533,26 +568,27 @@ public class GameEventGroupServiceImpl implements IGameEventGroupService {
|
|
|
Set<Long> teamsInGroup = groupTeamMap.getOrDefault(g, new HashSet<>());
|
|
Set<Long> teamsInGroup = groupTeamMap.getOrDefault(g, new HashSet<>());
|
|
|
if (teamsInGroup.contains(athlete.getTeamId())) {
|
|
if (teamsInGroup.contains(athlete.getTeamId())) {
|
|
|
blockedByTeamRule = true;
|
|
blockedByTeamRule = true;
|
|
|
- if (!groupDetails.isEmpty()) groupDetails.append("、");
|
|
|
|
|
|
|
+ if (!groupDetails.isEmpty())
|
|
|
|
|
+ groupDetails.append("、");
|
|
|
groupDetails.append("第").append(g).append("组");
|
|
groupDetails.append("第").append(g).append("组");
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (blockedByTeamRule) {
|
|
if (blockedByTeamRule) {
|
|
|
reason = String.format("团体项目限制:队伍(%s)在第%s组已有运动员,同组不能重复分配",
|
|
reason = String.format("团体项目限制:队伍(%s)在第%s组已有运动员,同组不能重复分配",
|
|
|
- athlete.getTeamName(), groupDetails.toString());
|
|
|
|
|
|
|
+ athlete.getTeamName(), groupDetails.toString());
|
|
|
} else {
|
|
} else {
|
|
|
reason = "未知原因:可能是分配算法逻辑问题";
|
|
reason = "未知原因:可能是分配算法逻辑问题";
|
|
|
}
|
|
}
|
|
|
} else {
|
|
} else {
|
|
|
// 个人项目:道次未满但没有分配,可能是算法问题
|
|
// 个人项目:道次未满但没有分配,可能是算法问题
|
|
|
reason = String.format("道次未满(已分配%d/%d个道次),可能是分配算法限制",
|
|
reason = String.format("道次未满(已分配%d/%d个道次),可能是分配算法限制",
|
|
|
- groupResult.size(), totalTracksNeeded);
|
|
|
|
|
|
|
+ groupResult.size(), totalTracksNeeded);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
log.warn(" 未分配 - 运动员编号: {}, 姓名: {}, 队伍ID: {}, 队伍名称: {}, 原因: {}",
|
|
log.warn(" 未分配 - 运动员编号: {}, 姓名: {}, 队伍ID: {}, 队伍名称: {}, 原因: {}",
|
|
|
- athlete.getAthleteCode(), athlete.getName(),
|
|
|
|
|
- athlete.getTeamId(), athlete.getTeamName(), reason);
|
|
|
|
|
|
|
+ athlete.getAthleteCode(), athlete.getName(),
|
|
|
|
|
+ athlete.getTeamId(), athlete.getTeamName(), reason);
|
|
|
}
|
|
}
|
|
|
log.info("未分配运动员数量: {}", unassignedAthletes.size());
|
|
log.info("未分配运动员数量: {}", unassignedAthletes.size());
|
|
|
}
|
|
}
|
|
@@ -560,7 +596,8 @@ public class GameEventGroupServiceImpl implements IGameEventGroupService {
|
|
|
|
|
|
|
|
// 保存分组结果到数据库
|
|
// 保存分组结果到数据库
|
|
|
try {
|
|
try {
|
|
|
- boolean saveSuccess = getGameAthleteCompetitionGroupService().saveGroupResult(groupId, groupResult, groupInfo);
|
|
|
|
|
|
|
+ boolean saveSuccess = getGameAthleteCompetitionGroupService().saveGroupResult(groupId, groupResult,
|
|
|
|
|
+ groupInfo);
|
|
|
if (saveSuccess) {
|
|
if (saveSuccess) {
|
|
|
log.info("分组结果已保存到数据库,分组ID: {}", groupId);
|
|
log.info("分组结果已保存到数据库,分组ID: {}", groupId);
|
|
|
} else {
|
|
} else {
|
|
@@ -590,6 +627,7 @@ public class GameEventGroupServiceImpl implements IGameEventGroupService {
|
|
|
/**
|
|
/**
|
|
|
* 动态生成最优跑道分配顺序
|
|
* 动态生成最优跑道分配顺序
|
|
|
* 根据任意道数,先填所有组的中间道,然后填比中间道小1的道,再填比中间道大1的道,以此类推
|
|
* 根据任意道数,先填所有组的中间道,然后填比中间道小1的道,再填比中间道大1的道,以此类推
|
|
|
|
|
+ *
|
|
|
* @param totalTracks 总道数
|
|
* @param totalTracks 总道数
|
|
|
* @return 最优分配顺序的道次列表
|
|
* @return 最优分配顺序的道次列表
|
|
|
*/
|
|
*/
|
|
@@ -607,7 +645,7 @@ public class GameEventGroupServiceImpl implements IGameEventGroupService {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 计算中间位置
|
|
// 计算中间位置
|
|
|
- int middle = totalTracks%2==0 ? totalTracks / 2 : (totalTracks + 1) / 2;
|
|
|
|
|
|
|
+ int middle = totalTracks % 2 == 0 ? totalTracks / 2 : (totalTracks + 1) / 2;
|
|
|
log.info("为{}道生成中间位置: {}", totalTracks, middle);
|
|
log.info("为{}道生成中间位置: {}", totalTracks, middle);
|
|
|
|
|
|
|
|
// 从中间向两侧展开,先左后右(小的道次优先)
|
|
// 从中间向两侧展开,先左后右(小的道次优先)
|
|
@@ -683,7 +721,8 @@ public class GameEventGroupServiceImpl implements IGameEventGroupService {
|
|
|
Map<Integer, Map<Integer, String>> matrixData = new TreeMap<>();
|
|
Map<Integer, Map<Integer, String>> matrixData = new TreeMap<>();
|
|
|
for (Map.Entry<String, Object> entry : groupResult.entrySet()) {
|
|
for (Map.Entry<String, Object> entry : groupResult.entrySet()) {
|
|
|
String key = entry.getKey();
|
|
String key = entry.getKey();
|
|
|
- if (!key.contains("-")) continue;
|
|
|
|
|
|
|
+ if (!key.contains("-"))
|
|
|
|
|
+ continue;
|
|
|
|
|
|
|
|
String[] split = key.split("-");
|
|
String[] split = key.split("-");
|
|
|
try {
|
|
try {
|
|
@@ -692,9 +731,9 @@ public class GameEventGroupServiceImpl implements IGameEventGroupService {
|
|
|
|
|
|
|
|
GameAthleteVo athleteVo = JSONUtil.toBean(JSONUtil.toJsonStr(entry.getValue()), GameAthleteVo.class);
|
|
GameAthleteVo athleteVo = JSONUtil.toBean(JSONUtil.toJsonStr(entry.getValue()), GameAthleteVo.class);
|
|
|
String cellContent = String.format("%s\n%s\n%s",
|
|
String cellContent = String.format("%s\n%s\n%s",
|
|
|
- athleteVo.getAthleteCode(),
|
|
|
|
|
- athleteVo.getName(),
|
|
|
|
|
- athleteVo.getTeamName());
|
|
|
|
|
|
|
+ athleteVo.getAthleteCode(),
|
|
|
|
|
+ athleteVo.getName(),
|
|
|
|
|
+ athleteVo.getTeamName());
|
|
|
|
|
|
|
|
matrixData.computeIfAbsent(groupIndex, k -> new HashMap<>()).put(trackIndex, cellContent);
|
|
matrixData.computeIfAbsent(groupIndex, k -> new HashMap<>()).put(trackIndex, cellContent);
|
|
|
} catch (Exception ignored) {
|
|
} catch (Exception ignored) {
|
|
@@ -726,10 +765,10 @@ public class GameEventGroupServiceImpl implements IGameEventGroupService {
|
|
|
HorizontalCellStyleStrategy styleStrategy = new HorizontalCellStyleStrategy(null, contentStyle);
|
|
HorizontalCellStyleStrategy styleStrategy = new HorizontalCellStyleStrategy(null, contentStyle);
|
|
|
|
|
|
|
|
FastExcel.write(response.getOutputStream())
|
|
FastExcel.write(response.getOutputStream())
|
|
|
- .head(head)
|
|
|
|
|
- .registerWriteHandler(styleStrategy)
|
|
|
|
|
- .sheet("分组详情")
|
|
|
|
|
- .doWrite(dataList);
|
|
|
|
|
|
|
+ .head(head)
|
|
|
|
|
+ .registerWriteHandler(styleStrategy)
|
|
|
|
|
+ .sheet("分组详情")
|
|
|
|
|
+ .doWrite(dataList);
|
|
|
} catch (Exception e) {
|
|
} catch (Exception e) {
|
|
|
log.error("导出分组详情矩阵失败", e);
|
|
log.error("导出分组详情矩阵失败", e);
|
|
|
throw new RuntimeException("导出分组详情失败", e);
|
|
throw new RuntimeException("导出分组详情失败", e);
|