From 57806172d44d9799d70a0e56109c50d22832e265 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=85=E6=88=BF?= Date: Fri, 23 Jan 2026 16:38:49 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E9=9B=86=E4=BD=93=E9=A1=B9=E7=9B=AE?= =?UTF-8?q?=E6=8C=89=E6=80=BB=E6=88=90=E5=91=98=E6=95=B0=E6=8B=86=E5=88=86?= =?UTF-8?q?=E8=80=8C=E9=9D=9E=E9=98=9F=E4=BC=8D=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 修改 ParticipantGroupingService 按场地容量(maxParticipants)判断拆分 - 当所有队伍的总成员数超过场地容量时自动拆分成多组 - 新增 getTeamMemberCount 和 calculateTotalMembers 方法 Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> --- .../grouping/ParticipantGroupingService.java | 127 +++++++++++++----- 1 file changed, 91 insertions(+), 36 deletions(-) diff --git a/src/main/java/org/springblade/modules/martial/service/schedule/grouping/ParticipantGroupingService.java b/src/main/java/org/springblade/modules/martial/service/schedule/grouping/ParticipantGroupingService.java index a277f4b..532333f 100644 --- a/src/main/java/org/springblade/modules/martial/service/schedule/grouping/ParticipantGroupingService.java +++ b/src/main/java/org/springblade/modules/martial/service/schedule/grouping/ParticipantGroupingService.java @@ -4,10 +4,15 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springblade.modules.martial.config.ScheduleConfig; import org.springblade.modules.martial.mapper.MartialProjectMapper; +import org.springblade.modules.martial.mapper.MartialTeamMapper; +import org.springblade.modules.martial.mapper.MartialTeamMemberMapper; import org.springblade.modules.martial.pojo.entity.MartialAthlete; import org.springblade.modules.martial.pojo.entity.MartialProject; +import org.springblade.modules.martial.pojo.entity.MartialTeam; +import org.springblade.modules.martial.pojo.entity.MartialTeamMember; import org.springblade.modules.martial.service.schedule.model.ScheduleGroupData; import org.springframework.stereotype.Service; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import java.util.*; import java.util.stream.Collectors; @@ -15,8 +20,6 @@ import java.util.stream.Collectors; /** * Participant grouping service * Groups athletes by project and category for schedule arrangement - * - * @author Refactored from MartialScheduleArrangeServiceImpl */ @Slf4j @Service @@ -24,11 +27,10 @@ import java.util.stream.Collectors; public class ParticipantGroupingService { private final MartialProjectMapper projectMapper; + private final MartialTeamMapper teamMapper; + private final MartialTeamMemberMapper teamMemberMapper; private final ScheduleConfig scheduleConfig; - /** - * Auto group participants by project and category - */ public List autoGroup(List athletes) { List groups = new ArrayList<>(); int displayOrder = 1; @@ -108,16 +110,51 @@ public class ParticipantGroupingService { .collect(Collectors.toList()); } + /** + * Get member count for a team by team name + */ + private int getTeamMemberCount(String teamName) { + if (teamName == null || teamName.isEmpty()) { + return 1; + } + MartialTeam team = teamMapper.selectOne( + new LambdaQueryWrapper() + .eq(MartialTeam::getTeamName, teamName) + .eq(MartialTeam::getIsDeleted, 0) + .last("LIMIT 1") + ); + if (team == null) { + return 1; + } + Long count = teamMemberMapper.selectCount( + new LambdaQueryWrapper() + .eq(MartialTeamMember::getTeamId, team.getId()) + .eq(MartialTeamMember::getIsDeleted, 0) + ); + return count != null && count > 0 ? count.intValue() : 1; + } + + /** + * Calculate total members across all teams + */ + private int calculateTotalMembers(List teams) { + int total = 0; + for (MartialAthlete team : teams) { + total += getTeamMemberCount(team.getPlayerName()); + } + return total; + } + private int groupTeamAthletes(List teamAthletes, Map projectMap, List groups, int displayOrder) { Map> teamGroupMap = teamAthletes.stream() .collect(Collectors.groupingBy(a -> String.valueOf(a.getProjectId()))); for (Map.Entry> entry : teamGroupMap.entrySet()) { - List members = entry.getValue(); - if (members.isEmpty()) continue; + List teams = entry.getValue(); + if (teams.isEmpty()) continue; - MartialAthlete first = members.get(0); + MartialAthlete first = teams.get(0); MartialProject project = projectMap.get(first.getProjectId()); if (project == null) { log.warn("Project not found, projectId: {}, skipping", first.getProjectId()); @@ -126,66 +163,84 @@ public class ParticipantGroupingService { String projectName = project.getProjectName(); String categoryName = getProjectCategoryName(project); - int maxTeamsPerGroup = (project.getMaxParticipants() != null && project.getMaxParticipants() > 0) - ? project.getMaxParticipants() : members.size(); + int maxParticipants = (project.getMaxParticipants() != null && project.getMaxParticipants() > 0) + ? project.getMaxParticipants() : Integer.MAX_VALUE; int durationPerTeam = (project.getEstimatedDuration() != null && project.getEstimatedDuration() > 0) ? project.getEstimatedDuration() : 5; - // Team projects: each record in members represents one team - int teamCount = members.size(); + int totalMembers = calculateTotalMembers(teams); + int teamCount = teams.size(); - if (teamCount <= maxTeamsPerGroup) { - // No need to split, create single group + log.info("Team project '{}': {} teams, {} total members, venue capacity: {}", + projectName + " " + categoryName, teamCount, totalMembers, maxParticipants); + + if (totalMembers <= maxParticipants) { ScheduleGroupData group = ScheduleGroupData.builder() .groupName(projectName + (categoryName.isEmpty() ? "" : " " + categoryName)) .projectId(first.getProjectId()) .projectType(2) - .maxParticipants(maxTeamsPerGroup) + .maxParticipants(maxParticipants) .category(categoryName) .displayOrder(displayOrder++) - .totalParticipants(members.size()) + .totalParticipants(totalMembers) .totalTeams(teamCount) - .athletes(members) + .athletes(teams) .estimatedDuration(teamCount * durationPerTeam) .build(); groups.add(group); } else { - // Split into sub-groups like individual projects - displayOrder = splitTeamIntoSubGroups(members, project, projectName, categoryName, - maxTeamsPerGroup, durationPerTeam, groups, displayOrder); + displayOrder = splitTeamsByMemberCount(teams, project, projectName, categoryName, + maxParticipants, durationPerTeam, groups, displayOrder); } } return displayOrder; } /** - * Split team project into sub-groups when team count exceeds maxParticipants + * Split teams into sub-groups based on total member count and venue capacity */ - private int splitTeamIntoSubGroups(List members, MartialProject project, - String projectName, String categoryName, int maxTeamsPerGroup, - int durationPerTeam, List groups, int displayOrder) { - int totalTeams = members.size(); - int numSubGroups = (int) Math.ceil((double) totalTeams / maxTeamsPerGroup); + private int splitTeamsByMemberCount(List teams, MartialProject project, + String projectName, String categoryName, int maxParticipants, + int durationPerTeam, List groups, int displayOrder) { + List> subGroups = new ArrayList<>(); + List currentGroup = new ArrayList<>(); + int currentMemberCount = 0; - log.info("Team project '{}' has {} teams, splitting into {} groups (max {} per group)", - projectName + " " + categoryName, totalTeams, numSubGroups, maxTeamsPerGroup); + for (MartialAthlete team : teams) { + int teamMemberCount = getTeamMemberCount(team.getPlayerName()); + + if (currentMemberCount + teamMemberCount > maxParticipants && !currentGroup.isEmpty()) { + subGroups.add(new ArrayList<>(currentGroup)); + currentGroup.clear(); + currentMemberCount = 0; + } + + currentGroup.add(team); + currentMemberCount += teamMemberCount; + } + + if (!currentGroup.isEmpty()) { + subGroups.add(currentGroup); + } - for (int i = 0; i < numSubGroups; i++) { - int startIdx = i * maxTeamsPerGroup; - int endIdx = Math.min(startIdx + maxTeamsPerGroup, totalTeams); - List subGroupMembers = new ArrayList<>(members.subList(startIdx, endIdx)); - int subGroupTeamCount = subGroupMembers.size(); + log.info("Team project '{}' split into {} groups based on venue capacity {}", + projectName + " " + categoryName, subGroups.size(), maxParticipants); + + for (int i = 0; i < subGroups.size(); i++) { + List subGroupTeams = subGroups.get(i); + int subGroupMemberCount = calculateTotalMembers(subGroupTeams); + int subGroupTeamCount = subGroupTeams.size(); ScheduleGroupData group = ScheduleGroupData.builder() .groupName(projectName + " " + categoryName + " 第" + (i + 1) + "组") .projectId(project.getId()) .projectType(2) - .maxParticipants(maxTeamsPerGroup) + .maxParticipants(maxParticipants) .displayOrder(displayOrder++) .category(categoryName) - .totalParticipants(subGroupMembers.size()) + .totalParticipants(subGroupMemberCount) .totalTeams(subGroupTeamCount) - .athletes(subGroupMembers) + .athletes(subGroupTeams) .estimatedDuration(subGroupTeamCount * durationPerTeam) .build(); groups.add(group);