|
@@ -15,9 +15,7 @@ import org.dromara.system.domain.bo.GameTeamBo;
|
|
|
import org.dromara.system.domain.vo.*;
|
|
import org.dromara.system.domain.vo.*;
|
|
|
import org.dromara.system.service.*;
|
|
import org.dromara.system.service.*;
|
|
|
import org.springframework.stereotype.Service;
|
|
import org.springframework.stereotype.Service;
|
|
|
-import org.springframework.context.annotation.Lazy;
|
|
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
-import org.springframework.beans.factory.InitializingBean;
|
|
|
|
|
import org.dromara.system.domain.bo.GameEventGroupBo;
|
|
import org.dromara.system.domain.bo.GameEventGroupBo;
|
|
|
import org.dromara.system.domain.constant.GameEventConstant;
|
|
import org.dromara.system.domain.constant.GameEventConstant;
|
|
|
import org.dromara.system.domain.constant.ProjectClassification;
|
|
import org.dromara.system.domain.constant.ProjectClassification;
|
|
@@ -348,8 +346,8 @@ public class GameEventGroupServiceImpl implements IGameEventGroupService {
|
|
|
.findFirst();
|
|
.findFirst();
|
|
|
if (StringUtils.isNotBlank(groupInfo.getMemberGender())) {
|
|
if (StringUtils.isNotBlank(groupInfo.getMemberGender())) {
|
|
|
if (!groupInfo.getMemberGender().equals(
|
|
if (!groupInfo.getMemberGender().equals(
|
|
|
- athlete.getGender() != null ? athlete.getGender().toString() : null)) {
|
|
|
|
|
- return false;
|
|
|
|
|
|
|
+ athlete.getGender() != null ? athlete.getGender() : null)) {
|
|
|
|
|
+ return groupInfo.getMemberGender().equals(mixGender.orElse(null));
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -373,44 +371,48 @@ public class GameEventGroupServiceImpl implements IGameEventGroupService {
|
|
|
// 分组结果
|
|
// 分组结果
|
|
|
Map<String, GameAthleteVo> groupResult = new HashMap<>();
|
|
Map<String, GameAthleteVo> groupResult = new HashMap<>();
|
|
|
|
|
|
|
|
- // 按组别和道次分配运动员
|
|
|
|
|
- for (int groupIndex = 1; groupIndex <= groupInfo.getIncludeGroupNum(); groupIndex++) {
|
|
|
|
|
- final int currentGroupIndex = groupIndex; // 创建final变量用于lambda表达式
|
|
|
|
|
- // 每组分配 personNum 个运动员,但不超过 trackNum
|
|
|
|
|
- Long personsPerGroup = groupInfo.getPersonNum() != null ? groupInfo.getPersonNum() : groupInfo.getTrackNum();
|
|
|
|
|
- // 如果每组人数超过道数,限制为道数(否则无法显示)
|
|
|
|
|
- if (personsPerGroup > groupInfo.getTrackNum()) {
|
|
|
|
|
- log.warn("每组人数({})超过道数({}),将限制为道数", personsPerGroup, groupInfo.getTrackNum());
|
|
|
|
|
- personsPerGroup = groupInfo.getTrackNum();
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ // 实际可用的道次数量
|
|
|
|
|
+ int actualTrackNum = groupInfo.getTrackNum().intValue();
|
|
|
|
|
|
|
|
- int personsPerGroupInt = personsPerGroup.intValue();
|
|
|
|
|
|
|
+ // 总组数
|
|
|
|
|
+ int totalGroups = groupInfo.getIncludeGroupNum().intValue();
|
|
|
|
|
|
|
|
- // 实际可用的道次数量
|
|
|
|
|
- int actualTrackNum = groupInfo.getTrackNum().intValue();
|
|
|
|
|
|
|
+ // 每组分配人数
|
|
|
|
|
+ Long personsPerGroup = groupInfo.getPersonNum() != null ? groupInfo.getPersonNum() : groupInfo.getTrackNum();
|
|
|
|
|
+ if (personsPerGroup > groupInfo.getTrackNum()) {
|
|
|
|
|
+ log.warn("每组人数({})超过道数({}),将限制为道数", personsPerGroup, groupInfo.getTrackNum());
|
|
|
|
|
+ personsPerGroup = groupInfo.getTrackNum();
|
|
|
|
|
+ }
|
|
|
|
|
+ int personsPerGroupInt = personsPerGroup.intValue();
|
|
|
|
|
|
|
|
- // 动态生成最优分配顺序:从中间开始,按照空位规则(空8道>空1道>空7道>空2道)
|
|
|
|
|
- List<Integer> optimalTrackOrder = generateOptimalTrackOrder(actualTrackNum);
|
|
|
|
|
|
|
+ // 动态生成最优分配顺序:从中间开始,按照空位规则(空最大道>空最小道>空次大道>空次小道)
|
|
|
|
|
+ List<Integer> optimalTrackOrder = generateOptimalTrackOrder(actualTrackNum);
|
|
|
|
|
|
|
|
- // 根据实际道数和需要人数调整分配顺序
|
|
|
|
|
- List<Integer> tracksToAssign = new ArrayList<>();
|
|
|
|
|
- for (Integer track : optimalTrackOrder) {
|
|
|
|
|
- if (track <= actualTrackNum && tracksToAssign.size() < personsPerGroupInt) {
|
|
|
|
|
- tracksToAssign.add(track);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ // 根据需要分配的人数过滤道次
|
|
|
|
|
+ List<Integer> tracksToAssign = new ArrayList<>();
|
|
|
|
|
+ for (Integer track : optimalTrackOrder) {
|
|
|
|
|
+ if (track <= actualTrackNum && tracksToAssign.size() < personsPerGroupInt) {
|
|
|
|
|
+ tracksToAssign.add(track);
|
|
|
}
|
|
}
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- // 确保我们只分配需要的人数,多余的道次留空
|
|
|
|
|
- if (tracksToAssign.size() > personsPerGroupInt) {
|
|
|
|
|
- tracksToAssign = tracksToAssign.subList(0, personsPerGroupInt);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ // 确保我们只分配需要的人数,多余的道次留空
|
|
|
|
|
+ if (tracksToAssign.size() > personsPerGroupInt) {
|
|
|
|
|
+ tracksToAssign = tracksToAssign.subList(0, personsPerGroupInt);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- // 按优化的道次顺序分配运动员
|
|
|
|
|
- for (Integer track : tracksToAssign) {
|
|
|
|
|
|
|
+ // 空位规则应用于列(道次)而非行(组别)
|
|
|
|
|
+ // 对每个道次,按组别顺序分配运动员
|
|
|
|
|
+ for (Integer track : tracksToAssign) {
|
|
|
|
|
+ // 对当前道次,按组别顺序分配
|
|
|
|
|
+ for (int groupIndex = 1; groupIndex <= totalGroups; groupIndex++) {
|
|
|
// 寻找可用的运动员
|
|
// 寻找可用的运动员
|
|
|
GameAthleteVo selectedAthlete = null;
|
|
GameAthleteVo selectedAthlete = null;
|
|
|
int athleteIndex = 0;
|
|
int athleteIndex = 0;
|
|
|
|
|
|
|
|
|
|
+ // 创建final局部变量,用于lambda表达式中引用
|
|
|
|
|
+ final int finalGroupIndex = groupIndex;
|
|
|
|
|
+
|
|
|
while (athleteIndex < shuffledAthletes.size() && selectedAthlete == null) {
|
|
while (athleteIndex < shuffledAthletes.size() && selectedAthlete == null) {
|
|
|
GameAthleteVo candidateAthlete = shuffledAthletes.get(athleteIndex);
|
|
GameAthleteVo candidateAthlete = shuffledAthletes.get(athleteIndex);
|
|
|
|
|
|
|
@@ -421,16 +423,15 @@ public class GameEventGroupServiceImpl implements IGameEventGroupService {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 只有项目属于团体项目才检查同一组中是否已有同一队伍的运动员
|
|
// 只有项目属于团体项目才检查同一组中是否已有同一队伍的运动员
|
|
|
- // 个人项目(classification="0")不限制同一队伍,团体项目(classification="1")才限制
|
|
|
|
|
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 -> {
|
|
.anyMatch(entry -> {
|
|
|
String[] keyParts = entry.getKey().split("-");
|
|
String[] keyParts = entry.getKey().split("-");
|
|
|
if (keyParts.length >= 1) {
|
|
if (keyParts.length >= 1) {
|
|
|
String existingGroup = keyParts[0];
|
|
String existingGroup = keyParts[0];
|
|
|
- return existingGroup.equals(String.valueOf(currentGroupIndex)) &&
|
|
|
|
|
|
|
+ return existingGroup.equals(String.valueOf(finalGroupIndex)) &&
|
|
|
entry.getValue().getTeamId() != null &&
|
|
entry.getValue().getTeamId() != null &&
|
|
|
entry.getValue().getTeamId().equals(candidateAthlete.getTeamId());
|
|
entry.getValue().getTeamId().equals(candidateAthlete.getTeamId());
|
|
|
}
|
|
}
|
|
@@ -439,10 +440,9 @@ public class GameEventGroupServiceImpl implements IGameEventGroupService {
|
|
|
if (hasSameTeamInGroup) {
|
|
if (hasSameTeamInGroup) {
|
|
|
isValidCandidate = false;
|
|
isValidCandidate = false;
|
|
|
log.debug("第{}组拒绝运动员{}:团体项目中同一组不能有同一队伍({})的运动员",
|
|
log.debug("第{}组拒绝运动员{}:团体项目中同一组不能有同一队伍({})的运动员",
|
|
|
- currentGroupIndex, candidateAthlete.getAthleteCode(), candidateAthlete.getTeamId());
|
|
|
|
|
|
|
+ finalGroupIndex, candidateAthlete.getAthleteCode(), candidateAthlete.getTeamName());
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
- // 个人项目(classification="0"或null):允许同一组中有同一队伍的运动员,不进行队伍限制检查
|
|
|
|
|
|
|
|
|
|
if (isValidCandidate) {
|
|
if (isValidCandidate) {
|
|
|
selectedAthlete = candidateAthlete;
|
|
selectedAthlete = candidateAthlete;
|
|
@@ -455,10 +455,10 @@ public class GameEventGroupServiceImpl implements IGameEventGroupService {
|
|
|
|
|
|
|
|
// 如果找到了合适的运动员,分配到当前组和道次
|
|
// 如果找到了合适的运动员,分配到当前组和道次
|
|
|
if (selectedAthlete != null) {
|
|
if (selectedAthlete != null) {
|
|
|
- String key = currentGroupIndex + "-" + track;
|
|
|
|
|
|
|
+ String key = finalGroupIndex + "-" + track;
|
|
|
groupResult.put(key, selectedAthlete);
|
|
groupResult.put(key, selectedAthlete);
|
|
|
log.debug("分配成功 - 第{}组第{}道: 运动员编号={}, 姓名={}, 队伍={}",
|
|
log.debug("分配成功 - 第{}组第{}道: 运动员编号={}, 姓名={}, 队伍={}",
|
|
|
- currentGroupIndex, track, selectedAthlete.getAthleteCode(),
|
|
|
|
|
|
|
+ finalGroupIndex, track, selectedAthlete.getAthleteCode(),
|
|
|
selectedAthlete.getName(), selectedAthlete.getTeamName());
|
|
selectedAthlete.getName(), selectedAthlete.getTeamName());
|
|
|
} else {
|
|
} else {
|
|
|
// 检查是否有可用但未分配的运动员
|
|
// 检查是否有可用但未分配的运动员
|
|
@@ -467,10 +467,10 @@ public class GameEventGroupServiceImpl implements IGameEventGroupService {
|
|
|
.count();
|
|
.count();
|
|
|
if (availableCount > 0) {
|
|
if (availableCount > 0) {
|
|
|
log.warn("第{}组第{}道未找到合适的运动员,但仍有{}个符合条件的运动员未分配",
|
|
log.warn("第{}组第{}道未找到合适的运动员,但仍有{}个符合条件的运动员未分配",
|
|
|
- currentGroupIndex, track, availableCount);
|
|
|
|
|
|
|
+ finalGroupIndex, track, availableCount);
|
|
|
} else {
|
|
} else {
|
|
|
log.warn("第{}组第{}道未找到合适的运动员,所有符合条件的运动员都已被分配",
|
|
log.warn("第{}组第{}道未找到合适的运动员,所有符合条件的运动员都已被分配",
|
|
|
- currentGroupIndex, track);
|
|
|
|
|
|
|
+ finalGroupIndex, track);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -499,10 +499,6 @@ public class GameEventGroupServiceImpl implements IGameEventGroupService {
|
|
|
log.info(" 所有符合条件的运动员都已成功分配");
|
|
log.info(" 所有符合条件的运动员都已成功分配");
|
|
|
} else {
|
|
} else {
|
|
|
// 计算需要的道次总数(每组人数 × 组数,但不超过道数)
|
|
// 计算需要的道次总数(每组人数 × 组数,但不超过道数)
|
|
|
- int personsPerGroup = groupInfo.getPersonNum() != null &&
|
|
|
|
|
- groupInfo.getPersonNum() <= groupInfo.getTrackNum()
|
|
|
|
|
- ? groupInfo.getPersonNum().intValue()
|
|
|
|
|
- : groupInfo.getTrackNum().intValue();
|
|
|
|
|
Long totalTracksNeeded = groupInfo.getIncludeGroupNum() * personsPerGroup;
|
|
Long totalTracksNeeded = groupInfo.getIncludeGroupNum() * personsPerGroup;
|
|
|
|
|
|
|
|
for (GameAthleteVo athlete : unassignedAthletes) {
|
|
for (GameAthleteVo athlete : unassignedAthletes) {
|
|
@@ -603,7 +599,8 @@ public class GameEventGroupServiceImpl implements IGameEventGroupService {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 计算中间位置
|
|
// 计算中间位置
|
|
|
- int middle = totalTracks / 2 + 1;
|
|
|
|
|
|
|
+ int middle = totalTracks%2==0 ? totalTracks / 2 : (totalTracks + 1) / 2;
|
|
|
|
|
+ log.info("为{}道生成中间位置: {}", totalTracks, middle);
|
|
|
|
|
|
|
|
// 从中间向两侧展开,先左后右(小的道次优先)
|
|
// 从中间向两侧展开,先左后右(小的道次优先)
|
|
|
// 使用队列来按层序存储道次
|
|
// 使用队列来按层序存储道次
|