feat(schedule): 无编排数据时自动从项目和选手表生成初始分组

- 修改 getScheduleResult 方法,当没有编排数据时调用 generateInitialScheduleResult
- 新增 generateInitialScheduleResult 方法,从项目和选手表生成初始分组
- CompetitionGroupDTO 添加 projectId 字段
- ParticipantDTO 添加 teamName 字段
- 用户进入编排页面可直接看到选手数据,无需先执行自动编排
This commit is contained in:
2025-12-30 11:10:01 +08:00
parent 16b55adf81
commit c7058b8b07
3 changed files with 133 additions and 7 deletions

View File

@@ -23,6 +23,12 @@ public class CompetitionGroupDTO implements Serializable {
@Schema(description = "分组ID")
private Long id;
/**
* 项目ID
*/
@Schema(description = "项目ID")
private Long projectId;
/**
* 分组标题
*/

View File

@@ -28,6 +28,12 @@ public class ParticipantDTO implements Serializable {
@Schema(description = "学校/单位")
private String schoolUnit;
/**
* 队伍名称
*/
@Schema(description = "队伍名称")
private String teamName;
/**
* 状态:未签到/已签到/异常
*/

View File

@@ -147,10 +147,8 @@ public class MartialScheduleServiceImpl extends ServiceImpl<MartialScheduleMappe
List<ScheduleGroupDetailVO> details = scheduleGroupMapper.selectScheduleGroupDetails(competitionId);
if (details.isEmpty()) {
result.setIsDraft(true);
result.setIsCompleted(false);
result.setCompetitionGroups(new ArrayList<>());
return result;
// 没有编排数据时,从项目和选手表生成初始分组
return generateInitialScheduleResult(competitionId);
}
// 按分组ID分组数据
@@ -173,7 +171,7 @@ public class MartialScheduleServiceImpl extends ServiceImpl<MartialScheduleMappe
continue;
}
// 获取第一条记录作为分组信息(同一分组的记录,分组信息是相同的)
// 获取第一条记录作为分组信息
ScheduleGroupDetailVO firstDetail = groupDetails.get(0);
CompetitionGroupDTO groupDTO = new CompetitionGroupDTO();
@@ -207,11 +205,11 @@ public class MartialScheduleServiceImpl extends ServiceImpl<MartialScheduleMappe
groupDTO.setVenueId(firstDetail.getVenueId());
groupDTO.setVenueName(firstDetail.getVenueName());
groupDTO.setTimeSlot(firstDetail.getTimeSlot());
groupDTO.setTimeSlotIndex(firstDetail.getTimeSlotIndex() != null ? firstDetail.getTimeSlotIndex() : 0); // 直接从数据库读取
groupDTO.setTimeSlotIndex(firstDetail.getTimeSlotIndex() != null ? firstDetail.getTimeSlotIndex() : 0);
// 获取参赛者列表
List<ParticipantDTO> participantDTOs = groupDetails.stream()
.filter(d -> d.getParticipantId() != null) // 过滤掉没有参赛者的记录
.filter(d -> d.getParticipantId() != null)
.map(d -> {
ParticipantDTO dto = new ParticipantDTO();
dto.setId(d.getParticipantId());
@@ -240,6 +238,122 @@ public class MartialScheduleServiceImpl extends ServiceImpl<MartialScheduleMappe
return result;
}
/**
* 没有编排数据时,从项目和选手表生成初始分组
*/
private ScheduleResultDTO generateInitialScheduleResult(Long competitionId) {
ScheduleResultDTO result = new ScheduleResultDTO();
result.setIsDraft(true);
result.setIsCompleted(false);
// 1. 获取该赛事的所有项目
List<MartialProject> projects = projectService.list(
new QueryWrapper<MartialProject>()
.eq("competition_id", competitionId)
.eq("is_deleted", 0)
.orderByAsc("id")
);
if (projects.isEmpty()) {
result.setCompetitionGroups(new ArrayList<>());
return result;
}
// 2. 获取该赛事的所有选手
List<MartialAthlete> athletes = athleteService.list(
new QueryWrapper<MartialAthlete>()
.eq("competition_id", competitionId)
.eq("is_deleted", 0)
);
// 按项目ID分组选手
Map<Long, List<MartialAthlete>> athletesByProject = athletes.stream()
.collect(Collectors.groupingBy(MartialAthlete::getProjectId));
// 3. 获取该赛事的第一个场地作为默认场地
List<MartialVenue> venues = venueService.list(
new QueryWrapper<MartialVenue>()
.eq("competition_id", competitionId)
.eq("is_deleted", 0)
.orderByAsc("id")
.last("LIMIT 1")
);
Long defaultVenueId = venues.isEmpty() ? null : venues.get(0).getId();
String defaultVenueName = venues.isEmpty() ? "未分配" : venues.get(0).getVenueName();
// 4. 为每个项目生成一个分组
List<CompetitionGroupDTO> groupDTOs = new ArrayList<>();
int displayOrder = 0;
for (MartialProject project : projects) {
List<MartialAthlete> projectAthletes = athletesByProject.getOrDefault(project.getId(), new ArrayList<>());
// 跳过没有选手的项目
if (projectAthletes.isEmpty()) {
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();
if (projectType != null) {
switch (projectType) {
case 1:
groupDTO.setType("单人");
break;
case 2:
groupDTO.setType("双人");
break;
case 3:
groupDTO.setType("集体");
break;
default:
groupDTO.setType("其他");
break;
}
} else {
groupDTO.setType("单人");
}
// 设置数量
groupDTO.setCount(projectAthletes.size() + "");
// 设置默认场地和时间段
groupDTO.setVenueId(defaultVenueId);
groupDTO.setVenueName(defaultVenueName);
groupDTO.setTimeSlotIndex(0); // 默认放在第一个时间段
groupDTO.setTimeSlot(null);
// 生成参赛者列表
List<ParticipantDTO> participantDTOs = new ArrayList<>();
int sortOrder = 1;
for (MartialAthlete athlete : projectAthletes) {
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);
groupDTOs.add(groupDTO);
displayOrder++;
}
result.setCompetitionGroups(groupDTOs);
return result;
}
/**
* 保存编排草稿
*