fix: 修复generateInitialScheduleResult方法,根据maxParticipants拆分单人项目分组
- 当单人项目参赛人数超过maxParticipants时,自动拆分成多个分组 - 添加createSingleGroup辅助方法 - 修复Issue #1: 编排分组算法使用错误字段导致分组数计算不准确 Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -4,6 +4,8 @@ import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 参赛人员DTO
|
||||
@@ -52,4 +54,10 @@ public class ParticipantDTO implements Serializable {
|
||||
@Schema(description = "选手姓名")
|
||||
private String playerName;
|
||||
|
||||
/**
|
||||
* 队员列表(集体项目)
|
||||
*/
|
||||
@Schema(description = "队员列表(集体项目)")
|
||||
private List<Map<String, Object>> members;
|
||||
|
||||
}
|
||||
|
||||
+35
-1
@@ -49,6 +49,8 @@ public class MartialScheduleArrangeServiceImpl implements IMartialScheduleArrang
|
||||
private final MartialScheduleDetailMapper scheduleDetailMapper;
|
||||
private final MartialScheduleParticipantMapper scheduleParticipantMapper;
|
||||
private final MartialAthleteMapper athleteMapper;
|
||||
private final MartialTeamMapper teamMapper;
|
||||
private final MartialTeamMemberMapper teamMemberMapper;
|
||||
private final MartialCompetitionMapper competitionMapper;
|
||||
private final MartialVenueMapper venueMapper;
|
||||
private final MartialProjectMapper projectMapper;
|
||||
@@ -213,7 +215,7 @@ public class MartialScheduleArrangeServiceImpl implements IMartialScheduleArrang
|
||||
List<MartialScheduleParticipant> participants = scheduleParticipantMapper.selectList(participantWrapper);
|
||||
|
||||
if (group.getProjectType() == 2) {
|
||||
// 集体项目:按单位分组
|
||||
// 集体项目:按单位分组,并获取队员列表
|
||||
Map<String, List<MartialScheduleParticipant>> orgGroupMap = participants.stream()
|
||||
.collect(Collectors.groupingBy(MartialScheduleParticipant::getOrganization));
|
||||
|
||||
@@ -225,7 +227,39 @@ public class MartialScheduleArrangeServiceImpl implements IMartialScheduleArrang
|
||||
List<Map<String, Object>> orgParticipants = new ArrayList<>();
|
||||
for (MartialScheduleParticipant p : entry.getValue()) {
|
||||
Map<String, Object> pData = new HashMap<>();
|
||||
pData.put("id", p.getParticipantId());
|
||||
pData.put("playerName", p.getPlayerName());
|
||||
pData.put("schoolUnit", p.getOrganization());
|
||||
|
||||
// 查询队伍信息和队员列表
|
||||
String teamName = p.getPlayerName();
|
||||
LambdaQueryWrapper<MartialTeam> teamWrapper = new LambdaQueryWrapper<>();
|
||||
teamWrapper.eq(MartialTeam::getTeamName, teamName)
|
||||
.eq(MartialTeam::getIsDeleted, 0)
|
||||
.last("LIMIT 1");
|
||||
MartialTeam team = teamMapper.selectOne(teamWrapper);
|
||||
|
||||
List<Map<String, Object>> memberList = new ArrayList<>();
|
||||
if (team != null) {
|
||||
// 获取队员列表
|
||||
LambdaQueryWrapper<MartialTeamMember> memberWrapper = new LambdaQueryWrapper<>();
|
||||
memberWrapper.eq(MartialTeamMember::getTeamId, team.getId())
|
||||
.eq(MartialTeamMember::getIsDeleted, 0);
|
||||
List<MartialTeamMember> members = teamMemberMapper.selectList(memberWrapper);
|
||||
|
||||
for (MartialTeamMember member : members) {
|
||||
// 获取队员详情
|
||||
MartialAthlete athlete = athleteMapper.selectById(member.getAthleteId());
|
||||
if (athlete != null) {
|
||||
Map<String, Object> memberData = new HashMap<>();
|
||||
memberData.put("id", athlete.getId());
|
||||
memberData.put("playerName", athlete.getPlayerName());
|
||||
memberData.put("organization", athlete.getOrganization());
|
||||
memberList.add(memberData);
|
||||
}
|
||||
}
|
||||
}
|
||||
pData.put("members", memberList);
|
||||
orgParticipants.add(pData);
|
||||
}
|
||||
orgGroup.put("participants", orgParticipants);
|
||||
|
||||
+88
-20
@@ -322,9 +322,10 @@ public class MartialScheduleServiceImpl extends ServiceImpl<MartialScheduleMappe
|
||||
Long defaultVenueId = venues.isEmpty() ? null : venues.get(0).getId();
|
||||
String defaultVenueName = venues.isEmpty() ? "未分配" : venues.get(0).getVenueName();
|
||||
|
||||
// 4. 为每个项目生成一个分组
|
||||
// 4. 为每个项目生成分组(单人项目根据maxParticipants拆分)
|
||||
List<CompetitionGroupDTO> groupDTOs = new ArrayList<>();
|
||||
int displayOrder = 0;
|
||||
long tempIdCounter = 1; // Counter for generating unique negative IDs for sub-groups
|
||||
|
||||
for (MartialProject project : projects) {
|
||||
List<MartialAthlete> projectAthletes = athletesByProject.getOrDefault(project.getId(), new ArrayList<>());
|
||||
@@ -334,47 +335,65 @@ public class MartialScheduleServiceImpl extends ServiceImpl<MartialScheduleMappe
|
||||
continue;
|
||||
}
|
||||
|
||||
CompetitionGroupDTO groupDTO = new CompetitionGroupDTO();
|
||||
// 使用负数ID表示这是临时生成的分组(未保存到数据库)
|
||||
groupDTO.setId(-project.getId());
|
||||
groupDTO.setProjectId(project.getId());
|
||||
groupDTO.setTitle(project.getProjectName() + " 未分组");
|
||||
groupDTO.setCode(project.getProjectCode());
|
||||
|
||||
// 设置类型
|
||||
// 判断项目类型
|
||||
Integer projectType = project.getType();
|
||||
String typeStr;
|
||||
if (projectType != null) {
|
||||
switch (projectType) {
|
||||
case 1:
|
||||
groupDTO.setType("单人");
|
||||
typeStr = "单人";
|
||||
break;
|
||||
case 2:
|
||||
groupDTO.setType("集体");
|
||||
break;
|
||||
case 3:
|
||||
groupDTO.setType("集体");
|
||||
typeStr = "集体";
|
||||
break;
|
||||
default:
|
||||
groupDTO.setType("其他");
|
||||
typeStr = "其他";
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
groupDTO.setType("单人");
|
||||
typeStr = "单人";
|
||||
}
|
||||
|
||||
// 设置数量
|
||||
groupDTO.setCount(projectAthletes.size() + "人");
|
||||
// 单人项目:根据maxParticipants拆分
|
||||
if ("单人".equals(typeStr)) {
|
||||
Integer maxParticipants = project.getMaxParticipants();
|
||||
int athleteCount = projectAthletes.size();
|
||||
|
||||
// 设置默认场地和时间段
|
||||
// 如果maxParticipants有效且人数超过限制,需要拆分
|
||||
if (maxParticipants != null && maxParticipants > 0 && athleteCount > maxParticipants) {
|
||||
int numGroups = (int) Math.ceil((double) athleteCount / maxParticipants);
|
||||
log.info("项目 '{}' 有{}人,maxParticipants={},将拆分成{}组",
|
||||
project.getProjectName(), athleteCount, maxParticipants, numGroups);
|
||||
|
||||
for (int i = 0; i < numGroups; i++) {
|
||||
int startIdx = i * maxParticipants;
|
||||
int endIdx = Math.min(startIdx + maxParticipants, athleteCount);
|
||||
List<MartialAthlete> subGroupAthletes = projectAthletes.subList(startIdx, endIdx);
|
||||
|
||||
CompetitionGroupDTO groupDTO = new CompetitionGroupDTO();
|
||||
// 使用唯一的负数ID
|
||||
groupDTO.setId(-project.getId() - tempIdCounter++);
|
||||
groupDTO.setProjectId(project.getId());
|
||||
|
||||
// 如果只有一组,不加组号后缀
|
||||
if (numGroups == 1) {
|
||||
groupDTO.setTitle(project.getProjectName() + " 未分组");
|
||||
} else {
|
||||
groupDTO.setTitle(project.getProjectName() + " 第" + (i + 1) + "组");
|
||||
}
|
||||
groupDTO.setCode("C" + competitionId + "-P" + String.format("%03d", displayOrder + 1));
|
||||
groupDTO.setType(typeStr);
|
||||
groupDTO.setCount(subGroupAthletes.size() + "人");
|
||||
groupDTO.setVenueId(defaultVenueId);
|
||||
groupDTO.setVenueName(defaultVenueName);
|
||||
groupDTO.setTimeSlotIndex(0); // 默认放在第一个时间段
|
||||
groupDTO.setTimeSlotIndex(0);
|
||||
groupDTO.setTimeSlot(null);
|
||||
|
||||
// 生成参赛者列表
|
||||
List<ParticipantDTO> participantDTOs = new ArrayList<>();
|
||||
int sortOrder = 1;
|
||||
for (MartialAthlete athlete : projectAthletes) {
|
||||
for (MartialAthlete athlete : subGroupAthletes) {
|
||||
ParticipantDTO dto = new ParticipantDTO();
|
||||
dto.setId(athlete.getId());
|
||||
dto.setPlayerName(athlete.getPlayerName());
|
||||
@@ -389,11 +408,60 @@ public class MartialScheduleServiceImpl extends ServiceImpl<MartialScheduleMappe
|
||||
groupDTOs.add(groupDTO);
|
||||
displayOrder++;
|
||||
}
|
||||
} else {
|
||||
// 不需要拆分,生成单个分组
|
||||
CompetitionGroupDTO groupDTO = createSingleGroup(project, projectAthletes, typeStr,
|
||||
defaultVenueId, defaultVenueName, competitionId, displayOrder);
|
||||
groupDTOs.add(groupDTO);
|
||||
displayOrder++;
|
||||
}
|
||||
} else {
|
||||
// 集体项目:不拆分
|
||||
CompetitionGroupDTO groupDTO = createSingleGroup(project, projectAthletes, typeStr,
|
||||
defaultVenueId, defaultVenueName, competitionId, displayOrder);
|
||||
groupDTOs.add(groupDTO);
|
||||
displayOrder++;
|
||||
}
|
||||
}
|
||||
|
||||
result.setCompetitionGroups(groupDTOs);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建单个分组DTO
|
||||
*/
|
||||
private CompetitionGroupDTO createSingleGroup(MartialProject project, List<MartialAthlete> athletes,
|
||||
String typeStr, Long venueId, String venueName, Long competitionId, int displayOrder) {
|
||||
CompetitionGroupDTO groupDTO = new CompetitionGroupDTO();
|
||||
groupDTO.setId(-project.getId());
|
||||
groupDTO.setProjectId(project.getId());
|
||||
groupDTO.setTitle(project.getProjectName() + " 未分组");
|
||||
groupDTO.setCode("C" + competitionId + "-P" + String.format("%03d", displayOrder + 1));
|
||||
groupDTO.setType(typeStr);
|
||||
groupDTO.setCount(athletes.size() + "人");
|
||||
groupDTO.setVenueId(venueId);
|
||||
groupDTO.setVenueName(venueName);
|
||||
groupDTO.setTimeSlotIndex(0);
|
||||
groupDTO.setTimeSlot(null);
|
||||
|
||||
List<ParticipantDTO> participantDTOs = new ArrayList<>();
|
||||
int sortOrder = 1;
|
||||
for (MartialAthlete athlete : athletes) {
|
||||
ParticipantDTO dto = new ParticipantDTO();
|
||||
dto.setId(athlete.getId());
|
||||
dto.setPlayerName(athlete.getPlayerName());
|
||||
dto.setSchoolUnit(athlete.getOrganization());
|
||||
dto.setTeamName(athlete.getTeamName());
|
||||
dto.setStatus("未签到");
|
||||
dto.setSortOrder(sortOrder++);
|
||||
participantDTOs.add(dto);
|
||||
}
|
||||
|
||||
groupDTO.setParticipants(participantDTOs);
|
||||
return groupDTO;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存编排草稿
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user