refactor: Phase 4 - Extract ScheduleQueryService from God Class

- Create ScheduleQueryService in schedule/query/
- Delegate getUnlockedCompetitions() and getScheduleResult() to new service
- Original class reduced from 502 to 342 lines (70% reduction from original 1148)
- All 438 tests passing

Related to Issue #11
This commit is contained in:
2026-01-17 00:37:47 +08:00
parent c0f3e4d971
commit fbde7b196d
10 changed files with 259 additions and 166 deletions
Binary file not shown.
@@ -28,6 +28,7 @@ import org.springblade.modules.martial.service.IMartialScheduleArrangeService;
import org.springblade.modules.martial.service.schedule.generator.TimeSlotGenerator;
import org.springblade.modules.martial.service.schedule.grouping.ParticipantGroupingService;
import org.springblade.modules.martial.service.schedule.allocation.VenueAllocationService;
import org.springblade.modules.martial.service.schedule.query.ScheduleQueryService;
import org.springframework.stereotype.Service;
import org.springblade.modules.martial.service.schedule.model.ScheduleGroupData;
import org.springblade.modules.martial.service.schedule.model.TimeSlot;
@@ -65,19 +66,13 @@ public class MartialScheduleArrangeServiceImpl implements IMartialScheduleArrang
private final ParticipantGroupingService participantGroupingService;
private final VenueAllocationService venueAllocationService;
private final ScheduleQueryService scheduleQueryService;
@Override
public List<Long> getUnlockedCompetitions() {
// 查询所有未锁定的赛事(schedule_status != 2)
LambdaQueryWrapper<MartialScheduleStatus> wrapper = new LambdaQueryWrapper<>();
wrapper.ne(MartialScheduleStatus::getScheduleStatus, 2)
.eq(MartialScheduleStatus::getIsDeleted, 0);
List<MartialScheduleStatus> statusList = scheduleStatusMapper.selectList(wrapper);
return statusList.stream()
.map(MartialScheduleStatus::getCompetitionId)
.collect(Collectors.toList());
return scheduleQueryService.getUnlockedCompetitions();
}
@Override
@Transactional(rollbackFor = Exception.class)
public void autoArrange(Long competitionId) {
@@ -165,164 +160,9 @@ public class MartialScheduleArrangeServiceImpl implements IMartialScheduleArrang
@Override
public Map<String, Object> getScheduleResult(Long competitionId) {
// 获取编排状态
MartialScheduleStatus status = getOrCreateScheduleStatus(competitionId);
// 获取分组列表
LambdaQueryWrapper<MartialScheduleGroup> groupWrapper = new LambdaQueryWrapper<>();
groupWrapper.eq(MartialScheduleGroup::getCompetitionId, competitionId)
.eq(MartialScheduleGroup::getIsDeleted, 0)
.orderByAsc(MartialScheduleGroup::getDisplayOrder);
List<MartialScheduleGroup> groups = scheduleGroupMapper.selectList(groupWrapper);
// 构建前端需要的数据结构
List<Map<String, Object>> scheduleGroups = new ArrayList<>();
for (MartialScheduleGroup group : groups) {
Map<String, Object> groupData = new HashMap<>();
groupData.put("id", group.getId());
groupData.put("groupName", group.getGroupName());
groupData.put("projectType", group.getProjectType());
groupData.put("displayOrder", group.getDisplayOrder());
groupData.put("totalParticipants", group.getTotalParticipants());
groupData.put("totalTeams", group.getTotalTeams());
groupData.put("estimatedDuration", group.getEstimatedDuration());
groupData.put("projectId", group.getProjectId());
// 获取该分组的场地时间段详情
LambdaQueryWrapper<MartialScheduleDetail> detailWrapper = new LambdaQueryWrapper<>();
detailWrapper.eq(MartialScheduleDetail::getScheduleGroupId, group.getId())
.eq(MartialScheduleDetail::getIsDeleted, 0);
List<MartialScheduleDetail> details = scheduleDetailMapper.selectList(detailWrapper);
List<Map<String, Object>> scheduleDetails = new ArrayList<>();
for (MartialScheduleDetail detail : details) {
Map<String, Object> detailData = new HashMap<>();
detailData.put("venueId", detail.getVenueId());
detailData.put("venueName", detail.getVenueName());
detailData.put("scheduleDate", detail.getScheduleDate());
detailData.put("timeSlot", detail.getTimeSlot());
detailData.put("timePeriod", detail.getTimePeriod());
detailData.put("timeSlotIndex", detail.getTimeSlotIndex());
scheduleDetails.add(detailData);
}
groupData.put("scheduleDetails", scheduleDetails);
// 提取第一个detail的场地和时间段信息到group级别
if (!details.isEmpty()) {
MartialScheduleDetail firstDetail = details.get(0);
groupData.put("venueId", firstDetail.getVenueId());
groupData.put("venueName", firstDetail.getVenueName());
groupData.put("timeSlot", firstDetail.getTimeSlot());
groupData.put("timeSlotIndex", firstDetail.getTimeSlotIndex());
return scheduleQueryService.getScheduleResult(competitionId);
}
// 获取该分组的参赛者
LambdaQueryWrapper<MartialScheduleParticipant> participantWrapper = new LambdaQueryWrapper<>();
participantWrapper.eq(MartialScheduleParticipant::getScheduleGroupId, group.getId())
.eq(MartialScheduleParticipant::getIsDeleted, 0);
List<MartialScheduleParticipant> participants = scheduleParticipantMapper.selectList(participantWrapper);
if (group.getProjectType() == 2) {
// 集体项目:按单位分组,并获取队员列表
Map<String, List<MartialScheduleParticipant>> orgGroupMap = participants.stream()
.collect(Collectors.groupingBy(MartialScheduleParticipant::getOrganization));
List<Map<String, Object>> organizationGroups = new ArrayList<>();
for (Map.Entry<String, List<MartialScheduleParticipant>> entry : orgGroupMap.entrySet()) {
Map<String, Object> orgGroup = new HashMap<>();
orgGroup.put("organization", entry.getKey());
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);
// 获取该单位的场地时间段
orgGroup.put("scheduleDetails", scheduleDetails);
organizationGroups.add(orgGroup);
}
groupData.put("organizationGroups", organizationGroups);
} else {
// 个人项目:直接列出参赛者
List<Map<String, Object>> individualParticipants = new ArrayList<>();
for (MartialScheduleParticipant p : participants) {
Map<String, Object> pData = new HashMap<>();
pData.put("id", p.getParticipantId());
pData.put("organization", p.getOrganization());
pData.put("playerName", p.getPlayerName());
// 获取该参赛者的场地时间段
LambdaQueryWrapper<MartialScheduleDetail> pDetailWrapper = new LambdaQueryWrapper<>();
pDetailWrapper.eq(MartialScheduleDetail::getId, p.getScheduleDetailId())
.eq(MartialScheduleDetail::getIsDeleted, 0)
.last("LIMIT 1");
MartialScheduleDetail pDetail = scheduleDetailMapper.selectOne(pDetailWrapper);
if (pDetail != null) {
Map<String, Object> scheduleDetail = new HashMap<>();
scheduleDetail.put("venueId", pDetail.getVenueId());
scheduleDetail.put("venueName", pDetail.getVenueName());
scheduleDetail.put("scheduleDate", pDetail.getScheduleDate());
scheduleDetail.put("timeSlot", pDetail.getTimeSlot());
pData.put("scheduleDetail", scheduleDetail);
}
individualParticipants.add(pData);
}
groupData.put("participants", individualParticipants);
}
scheduleGroups.add(groupData);
}
// 构建返回结果
Map<String, Object> result = new HashMap<>();
result.put("scheduleStatus", status.getScheduleStatus());
result.put("lastAutoScheduleTime", status.getLastAutoScheduleTime());
result.put("totalGroups", status.getTotalGroups());
result.put("totalParticipants", status.getTotalParticipants());
result.put("competitionGroups", scheduleGroups);
return result;
}
// ==================== 私有辅助方法 ====================
@@ -0,0 +1,253 @@
package org.springblade.modules.martial.service.schedule.query;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springblade.modules.martial.mapper.*;
import org.springblade.modules.martial.pojo.entity.*;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.stream.Collectors;
/**
* Schedule query service
* Handles schedule result queries
*
* @author Refactored from MartialScheduleArrangeServiceImpl
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class ScheduleQueryService {
private final MartialScheduleStatusMapper scheduleStatusMapper;
private final MartialScheduleGroupMapper scheduleGroupMapper;
private final MartialScheduleDetailMapper scheduleDetailMapper;
private final MartialScheduleParticipantMapper scheduleParticipantMapper;
private final MartialAthleteMapper athleteMapper;
private final MartialTeamMapper teamMapper;
private final MartialTeamMemberMapper teamMemberMapper;
/**
* Get unlocked competition IDs
*/
public List<Long> getUnlockedCompetitions() {
LambdaQueryWrapper<MartialScheduleStatus> wrapper = new LambdaQueryWrapper<>();
wrapper.ne(MartialScheduleStatus::getScheduleStatus, 2)
.eq(MartialScheduleStatus::getIsDeleted, 0);
List<MartialScheduleStatus> statusList = scheduleStatusMapper.selectList(wrapper);
return statusList.stream()
.map(MartialScheduleStatus::getCompetitionId)
.collect(Collectors.toList());
}
/**
* Get schedule result for a competition
*/
public Map<String, Object> getScheduleResult(Long competitionId) {
MartialScheduleStatus status = getOrCreateScheduleStatus(competitionId);
List<MartialScheduleGroup> groups = loadScheduleGroups(competitionId);
List<Map<String, Object>> scheduleGroups = buildScheduleGroupsData(groups);
Map<String, Object> result = new HashMap<>();
result.put("scheduleStatus", status.getScheduleStatus());
result.put("lastAutoScheduleTime", status.getLastAutoScheduleTime());
result.put("totalGroups", status.getTotalGroups());
result.put("totalParticipants", status.getTotalParticipants());
result.put("competitionGroups", scheduleGroups);
return result;
}
public MartialScheduleStatus getOrCreateScheduleStatus(Long competitionId) {
LambdaQueryWrapper<MartialScheduleStatus> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(MartialScheduleStatus::getCompetitionId, competitionId)
.eq(MartialScheduleStatus::getIsDeleted, 0)
.last("LIMIT 1");
MartialScheduleStatus status = scheduleStatusMapper.selectOne(wrapper);
if (status == null) {
status = new MartialScheduleStatus();
status.setCompetitionId(competitionId);
status.setScheduleStatus(0);
status.setTotalGroups(0);
status.setTotalParticipants(0);
status.setCreateTime(new Date());
scheduleStatusMapper.insert(status);
}
return status;
}
private List<MartialScheduleGroup> loadScheduleGroups(Long competitionId) {
LambdaQueryWrapper<MartialScheduleGroup> groupWrapper = new LambdaQueryWrapper<>();
groupWrapper.eq(MartialScheduleGroup::getCompetitionId, competitionId)
.eq(MartialScheduleGroup::getIsDeleted, 0)
.orderByAsc(MartialScheduleGroup::getDisplayOrder);
return scheduleGroupMapper.selectList(groupWrapper);
}
private List<Map<String, Object>> buildScheduleGroupsData(List<MartialScheduleGroup> groups) {
List<Map<String, Object>> scheduleGroups = new ArrayList<>();
for (MartialScheduleGroup group : groups) {
Map<String, Object> groupData = buildGroupData(group);
List<MartialScheduleDetail> details = loadScheduleDetails(group.getId());
List<Map<String, Object>> scheduleDetails = buildScheduleDetails(details);
groupData.put("scheduleDetails", scheduleDetails);
if (!details.isEmpty()) {
MartialScheduleDetail firstDetail = details.get(0);
groupData.put("venueId", firstDetail.getVenueId());
groupData.put("venueName", firstDetail.getVenueName());
groupData.put("timeSlot", firstDetail.getTimeSlot());
groupData.put("timeSlotIndex", firstDetail.getTimeSlotIndex());
}
List<MartialScheduleParticipant> participants = loadParticipants(group.getId());
if (group.getProjectType() == 2) {
groupData.put("organizationGroups", buildOrganizationGroups(participants, scheduleDetails));
} else {
groupData.put("participants", buildIndividualParticipants(participants));
}
scheduleGroups.add(groupData);
}
return scheduleGroups;
}
private Map<String, Object> buildGroupData(MartialScheduleGroup group) {
Map<String, Object> groupData = new HashMap<>();
groupData.put("id", group.getId());
groupData.put("groupName", group.getGroupName());
groupData.put("projectType", group.getProjectType());
groupData.put("displayOrder", group.getDisplayOrder());
groupData.put("totalParticipants", group.getTotalParticipants());
groupData.put("totalTeams", group.getTotalTeams());
groupData.put("estimatedDuration", group.getEstimatedDuration());
groupData.put("projectId", group.getProjectId());
return groupData;
}
private List<MartialScheduleDetail> loadScheduleDetails(Long groupId) {
LambdaQueryWrapper<MartialScheduleDetail> detailWrapper = new LambdaQueryWrapper<>();
detailWrapper.eq(MartialScheduleDetail::getScheduleGroupId, groupId)
.eq(MartialScheduleDetail::getIsDeleted, 0);
return scheduleDetailMapper.selectList(detailWrapper);
}
private List<Map<String, Object>> buildScheduleDetails(List<MartialScheduleDetail> details) {
List<Map<String, Object>> scheduleDetails = new ArrayList<>();
for (MartialScheduleDetail detail : details) {
Map<String, Object> detailData = new HashMap<>();
detailData.put("venueId", detail.getVenueId());
detailData.put("venueName", detail.getVenueName());
detailData.put("scheduleDate", detail.getScheduleDate());
detailData.put("timeSlot", detail.getTimeSlot());
detailData.put("timePeriod", detail.getTimePeriod());
detailData.put("timeSlotIndex", detail.getTimeSlotIndex());
scheduleDetails.add(detailData);
}
return scheduleDetails;
}
private List<MartialScheduleParticipant> loadParticipants(Long groupId) {
LambdaQueryWrapper<MartialScheduleParticipant> participantWrapper = new LambdaQueryWrapper<>();
participantWrapper.eq(MartialScheduleParticipant::getScheduleGroupId, groupId)
.eq(MartialScheduleParticipant::getIsDeleted, 0);
return scheduleParticipantMapper.selectList(participantWrapper);
}
private List<Map<String, Object>> buildOrganizationGroups(List<MartialScheduleParticipant> participants,
List<Map<String, Object>> scheduleDetails) {
Map<String, List<MartialScheduleParticipant>> orgGroupMap = participants.stream()
.collect(Collectors.groupingBy(MartialScheduleParticipant::getOrganization));
List<Map<String, Object>> organizationGroups = new ArrayList<>();
for (Map.Entry<String, List<MartialScheduleParticipant>> entry : orgGroupMap.entrySet()) {
Map<String, Object> orgGroup = new HashMap<>();
orgGroup.put("organization", entry.getKey());
orgGroup.put("participants", buildTeamParticipants(entry.getValue()));
orgGroup.put("scheduleDetails", scheduleDetails);
organizationGroups.add(orgGroup);
}
return organizationGroups;
}
private List<Map<String, Object>> buildTeamParticipants(List<MartialScheduleParticipant> participants) {
List<Map<String, Object>> result = new ArrayList<>();
for (MartialScheduleParticipant p : participants) {
Map<String, Object> pData = new HashMap<>();
pData.put("id", p.getParticipantId());
pData.put("playerName", p.getPlayerName());
pData.put("schoolUnit", p.getOrganization());
pData.put("members", loadTeamMembers(p.getPlayerName()));
result.add(pData);
}
return result;
}
private List<Map<String, Object>> loadTeamMembers(String teamName) {
List<Map<String, Object>> memberList = new ArrayList<>();
LambdaQueryWrapper<MartialTeam> teamWrapper = new LambdaQueryWrapper<>();
teamWrapper.eq(MartialTeam::getTeamName, teamName)
.eq(MartialTeam::getIsDeleted, 0)
.last("LIMIT 1");
MartialTeam team = teamMapper.selectOne(teamWrapper);
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);
}
}
}
return memberList;
}
private List<Map<String, Object>> buildIndividualParticipants(List<MartialScheduleParticipant> participants) {
List<Map<String, Object>> result = new ArrayList<>();
for (MartialScheduleParticipant p : participants) {
Map<String, Object> pData = new HashMap<>();
pData.put("id", p.getParticipantId());
pData.put("organization", p.getOrganization());
pData.put("playerName", p.getPlayerName());
pData.put("scheduleDetail", loadParticipantScheduleDetail(p.getScheduleDetailId()));
result.add(pData);
}
return result;
}
private Map<String, Object> loadParticipantScheduleDetail(Long detailId) {
LambdaQueryWrapper<MartialScheduleDetail> pDetailWrapper = new LambdaQueryWrapper<>();
pDetailWrapper.eq(MartialScheduleDetail::getId, detailId)
.eq(MartialScheduleDetail::getIsDeleted, 0)
.last("LIMIT 1");
MartialScheduleDetail pDetail = scheduleDetailMapper.selectOne(pDetailWrapper);
if (pDetail != null) {
Map<String, Object> scheduleDetail = new HashMap<>();
scheduleDetail.put("venueId", pDetail.getVenueId());
scheduleDetail.put("venueName", pDetail.getVenueName());
scheduleDetail.put("scheduleDate", pDetail.getScheduleDate());
scheduleDetail.put("timeSlot", pDetail.getTimeSlot());
return scheduleDetail;
}
return null;
}
}