From fbde7b196dfc850aa9446c5e0e1632d81d3e6374 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=85=E6=88=BF?= Date: Sat, 17 Jan 2026 00:37:47 +0800 Subject: [PATCH] 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 --- .../buckets/.bloomcycle.bin/xl.meta | Bin 743 -> 743 bytes .../buckets/.usage-cache.bin.bkp/xl.meta | Bin 630 -> 637 bytes .../buckets/.usage-cache.bin/xl.meta | Bin 630 -> 637 bytes .../.minio.sys/buckets/.usage.json/xl.meta | Bin 2360 -> 2360 bytes .../.usage-cache.bin.bkp/xl.meta | Bin 636 -> 627 bytes .../000000-assets/.usage-cache.bin/xl.meta | Bin 636 -> 627 bytes .../assets/.usage-cache.bin.bkp/xl.meta | Bin 575 -> 575 bytes .../buckets/assets/.usage-cache.bin/xl.meta | Bin 575 -> 575 bytes .../MartialScheduleArrangeServiceImpl.java | 172 +----------- .../schedule/query/ScheduleQueryService.java | 253 ++++++++++++++++++ 10 files changed, 259 insertions(+), 166 deletions(-) create mode 100644 src/main/java/org/springblade/modules/martial/service/schedule/query/ScheduleQueryService.java diff --git a/minio_data/.minio.sys/buckets/.bloomcycle.bin/xl.meta b/minio_data/.minio.sys/buckets/.bloomcycle.bin/xl.meta index 4aaaa7adb06e4cea99accaf27f5407baf10e0b24..70509f49de4b523141d91aab87e28c98d56790dc 100644 GIT binary patch delta 444 zcmaFP`kZxw29I+k&!2!(M_Ar*e*QYq#8}|@q{S1LWOx*=3SPhS9peP^iRJZd5H%D3 z*vKcD8JZ*+85$%drx;ln88yY1V8%_>q)UW4$`fWaAXz)9ib~v*qMD=@Vjiv`}yZt^BKUPWqERGQBi7M3B!`S z)QXa``K-%}OA?DpQd5reu!2-%W@SbiK2*K1F1a!}C)GJWw;(4KD0_!N0IneQs?mvq z^*7-BG(lq_i7yDQud#;oP6W5pIGgz&f_v0h_ys4No6f}a_1hi<*Veef!2rRnG}hyL zh~REDcDJmBaFc;9P5)?YRGI;o&d@b(e;k3}W*Vy}_8_=Rjbj`)BDfEYH7p*$xtX%Y OQdu_<+(_fVd6NjdC_RMh*egE*mm+K4O^WH5lE=epZNliJiB_I}%Ug{f?nVWi9q8nn!#6PC$OHxY`({C!68JMM}r6naNCz>Q# zCYl+9C?-B%ynZ| z)k?dXqN@R^lZ-!c9e?#shNJVE@Qmquy3MpbI5f8E|8-#yWw^@9z``~8Afse`KFcbf z#Nv|Bf|SIP)Z;v?3_y^Xl^JQw-rc=AI6JezBQ-H6GcWznQs>0vjMV0}24J9@SX`W1 zQrxj9Ib*`2;;KuGt+5`9@{8pbl@&8APRRul#Z|?#8JL*3IT+YMW-cnrm@WrmFfc4k yKD1CDq;t};MJmNr3_yJh44e#=rWXwOHx)5_Y2dA4_AA+!lpyB8m%*}ZJr@AP0ght; delta 358 zcmey%@{MJJ29J~Z-VIy+A7NP?lwvp0#8}|_8vYAk?|M(%xNT0Tq8HPfiRE$XhgSt8 z7L_;#XI7;aPrS%*cnOFFq?h`JWag$`mgt5UGVzb;iRm{LQqmHW4ULl1 z3{4FT&5eyr5-rUw49$!zjgu`*EzQzQ7M7h$Pdd$TPPy`77-Qp-ywaSUBad}vbY)4W zZIrCYSu5YFxZ^~}?+e)~f$0oe(k{JQbMp8%4vnq)e_a?v8RoJwq;O6?$S7H#_jZ*} zVsS}mK}upt>Tw=c1|Z1HO8#o(boAEh;Oxu-kJQAR%)InNOPv#wGg6zEB^DQ_mK1j^ zO3s+DsJMz@QGPMQqOxL!#VNT!qPVJfHpqlUWf{{M7A7BBs1H&&X{`Ym=w4!Mjr9QP ukYi%v=3ro#<6@9qz@fl(^p|4~gF?!IPL5>~dpK@x=czhBM>5Oo*a84TDw2Ev diff --git a/minio_data/.minio.sys/buckets/.usage-cache.bin/xl.meta b/minio_data/.minio.sys/buckets/.usage-cache.bin/xl.meta index b1fa1dbbd0cb70409bed3321a793cced44ba8349..c8e19a8828384d130e36e802056580b69dc092ce 100644 GIT binary patch delta 351 zcmeyy@|R_T29I+k&sP27BP?w^v%)8u7z-2z@x-~c__OpcU3b$ubIHz$<#Fn#Rs|#$ zl{f}xR;3nCyvT5B35W%xm->ce=B8ej=!O_F@sEvynSohqT3S+aa-vC+WumD;ia~0k zsb!LpWtv&4Nm_F9+9C?-B%ynZ|)k?dXqN@R^lZ-!c9e?#s zhNJVE@Qmquy3MpbI5f8E|8-#yWw^@9z``~8Afse`KFcbf#Nv|Bf|SIP)Z;v?3_y^X zl^JQw-rc=AI6JezBQ-H6GcWznQs>0vjMV0}24J9@SX`W1Qrxj9Ib*`2;;KuGt+5`9 z@{8pbl@&8APRRul#Z|?#8JL*3IT+YMW-cnrm@WrmFfc4kKD1CDq;t};MJmNr3_yJh i44e#=rWXwOHx)5_Y2dA4_AA+!lpyB8m%*}ZJr@9R5`%vL delta 344 zcmey%@{MJJ29J~Z-gd>-BP^D7to;*Bj0HrOF>VNNbNM;ZVz*=TL!Rvu%j47!uL?*k zDsc?XtV%7Oc#+}o5)cbWFZB({%uT&4(G4+V;vXA@l(fWTL!;z0LsJ7ob7LcuL`!oE zLo*{w<75j{OS3eS$q|ft*6QV}Rx&m&$t%stIr3O%Mpu?}+D6HWoVD_;iaSnp{JxN_ z5}3}gCGFC?H7AdM#17NjJWq#oyCWdMTA ztmLmoPDgL84$jUj@JLO}$;?YXwA48WwRF*NFVPW#2h58_clhzu5f$k;7)>sdq4mlNk^M*c*^YIAhMBne+5H% z4FEBb`#m5qVK!klI5;^lFk><@F)(B}WMMdAF*P|eVK_EqF*!ApSOF$3^yXIg0fD4$ zb!=?K2dv7W&RGDYBD)(Y{{{3dQyNV>ZL$~`wKCK#)6I>Cd;OEF0UZxBH##&mE;uzd OF*7nWIWe=?0bmDdwmMS) delta 160 zcmV;R0AK&O61WnOC=5b3z1YNM!~`Me3!OM&Boz7z;f9xW2#Tyu-=K`9I3y{nuQcSRSW-U{ye3 zQHf)4W>sqO#ET3EmVj75dZ}+nW^U?biEfA?6aSb_j$l;FSdv{qW%5~8`6L#X zgchVEmZTo%VPyb<%&g2vBQXZ{NlYT~9gC7PCT`I$Ey&4FOj%T1#jq&9m|;;_F~j1N zTp&?gRXiKW&6v)xF!>Nj?F68jON_0t9zb<+OibJy4D51;IT#u^6udNcmA2R)xbVm< Py*T9Pi5onDfuXVh_HcxB delta 336 zcmey&@`q)D29J~Z-e||zBPy&REsm1>I-_`QlEsH#<_E7e#t1Q}O?WgrjzeRs{$Cb`yQ~Z@T$A@Rs>@oQIVG2r{#hzZ$;yw0RPfNX8cZ(t@1)#FUOj$r%$C6<1wiY>o9;lwT~j zsH~V_aY`L+lI<90CzZ X3{fRDJ^uB_QZ~#`p2IlnSx6oLoiK=y diff --git a/minio_data/.minio.sys/buckets/000000-assets/.usage-cache.bin/xl.meta b/minio_data/.minio.sys/buckets/000000-assets/.usage-cache.bin/xl.meta index ad35cde7818bb9a8eb23d8c0a55a9c068cc7f5cf..2e13a90d7f4f66ca55d1cdff3c8d3c62c9762f7b 100644 GIT binary patch delta 327 zcmeyv@|k6V29I+k_u(HOj zcbJ*nUf)_A>@B@V`u?nyc}q(S9FH}BUZxY3$f2=S|1S%}R91#1oRjx6s>elf$MvSNnC zDY-zRxT<(Ikee}`VPWziklG1AHJ2D$V?BWC?&=sKXBoZ QS$c8E(Gxd#0s}*30du5-uK)l5 delta 335 zcmey&@`q)D29J~ZUft#YjC!J2e?j1H;1P!ytVVf%+JLdKefEu`@Jq2t*_? WM3vO^_}3px*)T(S4&$t6A$b7ToQW6! diff --git a/minio_data/.minio.sys/buckets/assets/.usage-cache.bin.bkp/xl.meta b/minio_data/.minio.sys/buckets/assets/.usage-cache.bin.bkp/xl.meta index 94dce6763bdb8254238682b696495d06e89d312d..21ece1f432c23bbcc70784e2a270c89429170c67 100644 GIT binary patch delta 192 zcmdnbvY%yw29I+kPn++zBP>&9C&W)QF&0oWRC?<+!|6|hOnP&?b=K2~<@Ib3H531s zsxL_`Nld?~kYr(!YHVy_X=rF>k!YEmVv=N$Vvv+-U}j;Om}H!0JlT*@&2(Yex%8yd z4Cj)*6}@C^T#{FslXGOvkH?lfIQ91&?{T(wKlkP0y)WP5FYHg!aC^?SeZ#Gdin^0G sGiu4?v#jz-EG`KxNJ%V7J_vVzU_Vx04W(yNB{r; delta 191 zcmdnbvY%yw29J~Zo^#>cM_5w7&w4h|#8|+?<6Oq~txj84xqWk=u6bE+VtG9qM9suM zrjsKW)nb;UmL#U%R7f*4HcvG%G)+lKG)=WkG&43#F}E-_Gqp6bFgHp|GFe!5ER rs3nv4c9lG0WbYM=n diff --git a/minio_data/.minio.sys/buckets/assets/.usage-cache.bin/xl.meta b/minio_data/.minio.sys/buckets/assets/.usage-cache.bin/xl.meta index 0a0e25ea472cfca0307ef0c661dc54922a569996..c1a0deec3402965e42ff90578d12a422524ae832 100644 GIT binary patch delta 177 zcmdnbvY%yw29I+kPsrOJM_7bCBmE|t7z;d(b}&Di=4i2H&W3RIqWZ9j<@Ib3H532X zC?r{!q#7GrSQ;9dStME}rGgC_=3v;8iB$LSzjC#6>ci!_dHZI94&B-~k zCQW$h%tSfH8mZ=vq!05;kM5gj`s38Ti%WjC#qd3mTh={!GozMF-rH3^iNz(M1u2Oo dsmFO(8Gs-&EBUKoT*BeWKN+1^*l*V40|49DNGbpT diff --git a/src/main/java/org/springblade/modules/martial/service/impl/MartialScheduleArrangeServiceImpl.java b/src/main/java/org/springblade/modules/martial/service/impl/MartialScheduleArrangeServiceImpl.java index 52a983b..debbfa5 100644 --- a/src/main/java/org/springblade/modules/martial/service/impl/MartialScheduleArrangeServiceImpl.java +++ b/src/main/java/org/springblade/modules/martial/service/impl/MartialScheduleArrangeServiceImpl.java @@ -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 getUnlockedCompetitions() { - // 查询所有未锁定的赛事(schedule_status != 2) - LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); - wrapper.ne(MartialScheduleStatus::getScheduleStatus, 2) - .eq(MartialScheduleStatus::getIsDeleted, 0); - - List 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,165 +160,10 @@ public class MartialScheduleArrangeServiceImpl implements IMartialScheduleArrang @Override public Map getScheduleResult(Long competitionId) { - // 获取编排状态 - MartialScheduleStatus status = getOrCreateScheduleStatus(competitionId); - - // 获取分组列表 - LambdaQueryWrapper groupWrapper = new LambdaQueryWrapper<>(); - groupWrapper.eq(MartialScheduleGroup::getCompetitionId, competitionId) - .eq(MartialScheduleGroup::getIsDeleted, 0) - .orderByAsc(MartialScheduleGroup::getDisplayOrder); - - List groups = scheduleGroupMapper.selectList(groupWrapper); - - // 构建前端需要的数据结构 - List> scheduleGroups = new ArrayList<>(); - - for (MartialScheduleGroup group : groups) { - Map 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 detailWrapper = new LambdaQueryWrapper<>(); - detailWrapper.eq(MartialScheduleDetail::getScheduleGroupId, group.getId()) - .eq(MartialScheduleDetail::getIsDeleted, 0); - List details = scheduleDetailMapper.selectList(detailWrapper); - - List> scheduleDetails = new ArrayList<>(); - for (MartialScheduleDetail detail : details) { - Map 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()); - } - - // 获取该分组的参赛者 - LambdaQueryWrapper participantWrapper = new LambdaQueryWrapper<>(); - participantWrapper.eq(MartialScheduleParticipant::getScheduleGroupId, group.getId()) - .eq(MartialScheduleParticipant::getIsDeleted, 0); - List participants = scheduleParticipantMapper.selectList(participantWrapper); - - if (group.getProjectType() == 2) { - // 集体项目:按单位分组,并获取队员列表 - Map> orgGroupMap = participants.stream() - .collect(Collectors.groupingBy(MartialScheduleParticipant::getOrganization)); - - List> organizationGroups = new ArrayList<>(); - for (Map.Entry> entry : orgGroupMap.entrySet()) { - Map orgGroup = new HashMap<>(); - orgGroup.put("organization", entry.getKey()); - - List> orgParticipants = new ArrayList<>(); - for (MartialScheduleParticipant p : entry.getValue()) { - Map pData = new HashMap<>(); - pData.put("id", p.getParticipantId()); - pData.put("playerName", p.getPlayerName()); - pData.put("schoolUnit", p.getOrganization()); - - // 查询队伍信息和队员列表 - String teamName = p.getPlayerName(); - LambdaQueryWrapper teamWrapper = new LambdaQueryWrapper<>(); - teamWrapper.eq(MartialTeam::getTeamName, teamName) - .eq(MartialTeam::getIsDeleted, 0) - .last("LIMIT 1"); - MartialTeam team = teamMapper.selectOne(teamWrapper); - - List> memberList = new ArrayList<>(); - if (team != null) { - // 获取队员列表 - LambdaQueryWrapper memberWrapper = new LambdaQueryWrapper<>(); - memberWrapper.eq(MartialTeamMember::getTeamId, team.getId()) - .eq(MartialTeamMember::getIsDeleted, 0); - List members = teamMemberMapper.selectList(memberWrapper); - - for (MartialTeamMember member : members) { - // 获取队员详情 - MartialAthlete athlete = athleteMapper.selectById(member.getAthleteId()); - if (athlete != null) { - Map 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> individualParticipants = new ArrayList<>(); - for (MartialScheduleParticipant p : participants) { - Map pData = new HashMap<>(); - pData.put("id", p.getParticipantId()); - pData.put("organization", p.getOrganization()); - pData.put("playerName", p.getPlayerName()); - - // 获取该参赛者的场地时间段 - LambdaQueryWrapper 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 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 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; + return scheduleQueryService.getScheduleResult(competitionId); } + // ==================== 私有辅助方法 ==================== private MartialScheduleStatus getOrCreateScheduleStatus(Long competitionId) { diff --git a/src/main/java/org/springblade/modules/martial/service/schedule/query/ScheduleQueryService.java b/src/main/java/org/springblade/modules/martial/service/schedule/query/ScheduleQueryService.java new file mode 100644 index 0000000..fb1375a --- /dev/null +++ b/src/main/java/org/springblade/modules/martial/service/schedule/query/ScheduleQueryService.java @@ -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 getUnlockedCompetitions() { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.ne(MartialScheduleStatus::getScheduleStatus, 2) + .eq(MartialScheduleStatus::getIsDeleted, 0); + + List statusList = scheduleStatusMapper.selectList(wrapper); + return statusList.stream() + .map(MartialScheduleStatus::getCompetitionId) + .collect(Collectors.toList()); + } + + /** + * Get schedule result for a competition + */ + public Map getScheduleResult(Long competitionId) { + MartialScheduleStatus status = getOrCreateScheduleStatus(competitionId); + List groups = loadScheduleGroups(competitionId); + List> scheduleGroups = buildScheduleGroupsData(groups); + + Map 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 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 loadScheduleGroups(Long competitionId) { + LambdaQueryWrapper groupWrapper = new LambdaQueryWrapper<>(); + groupWrapper.eq(MartialScheduleGroup::getCompetitionId, competitionId) + .eq(MartialScheduleGroup::getIsDeleted, 0) + .orderByAsc(MartialScheduleGroup::getDisplayOrder); + return scheduleGroupMapper.selectList(groupWrapper); + } + + private List> buildScheduleGroupsData(List groups) { + List> scheduleGroups = new ArrayList<>(); + + for (MartialScheduleGroup group : groups) { + Map groupData = buildGroupData(group); + List details = loadScheduleDetails(group.getId()); + List> 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 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 buildGroupData(MartialScheduleGroup group) { + Map 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 loadScheduleDetails(Long groupId) { + LambdaQueryWrapper detailWrapper = new LambdaQueryWrapper<>(); + detailWrapper.eq(MartialScheduleDetail::getScheduleGroupId, groupId) + .eq(MartialScheduleDetail::getIsDeleted, 0); + return scheduleDetailMapper.selectList(detailWrapper); + } + + private List> buildScheduleDetails(List details) { + List> scheduleDetails = new ArrayList<>(); + for (MartialScheduleDetail detail : details) { + Map 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 loadParticipants(Long groupId) { + LambdaQueryWrapper participantWrapper = new LambdaQueryWrapper<>(); + participantWrapper.eq(MartialScheduleParticipant::getScheduleGroupId, groupId) + .eq(MartialScheduleParticipant::getIsDeleted, 0); + return scheduleParticipantMapper.selectList(participantWrapper); + } + + private List> buildOrganizationGroups(List participants, + List> scheduleDetails) { + Map> orgGroupMap = participants.stream() + .collect(Collectors.groupingBy(MartialScheduleParticipant::getOrganization)); + + List> organizationGroups = new ArrayList<>(); + for (Map.Entry> entry : orgGroupMap.entrySet()) { + Map 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> buildTeamParticipants(List participants) { + List> result = new ArrayList<>(); + for (MartialScheduleParticipant p : participants) { + Map 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> loadTeamMembers(String teamName) { + List> memberList = new ArrayList<>(); + LambdaQueryWrapper teamWrapper = new LambdaQueryWrapper<>(); + teamWrapper.eq(MartialTeam::getTeamName, teamName) + .eq(MartialTeam::getIsDeleted, 0) + .last("LIMIT 1"); + MartialTeam team = teamMapper.selectOne(teamWrapper); + + if (team != null) { + LambdaQueryWrapper memberWrapper = new LambdaQueryWrapper<>(); + memberWrapper.eq(MartialTeamMember::getTeamId, team.getId()) + .eq(MartialTeamMember::getIsDeleted, 0); + List members = teamMemberMapper.selectList(memberWrapper); + + for (MartialTeamMember member : members) { + MartialAthlete athlete = athleteMapper.selectById(member.getAthleteId()); + if (athlete != null) { + Map 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> buildIndividualParticipants(List participants) { + List> result = new ArrayList<>(); + for (MartialScheduleParticipant p : participants) { + Map 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 loadParticipantScheduleDetail(Long detailId) { + LambdaQueryWrapper pDetailWrapper = new LambdaQueryWrapper<>(); + pDetailWrapper.eq(MartialScheduleDetail::getId, detailId) + .eq(MartialScheduleDetail::getIsDeleted, 0) + .last("LIMIT 1"); + MartialScheduleDetail pDetail = scheduleDetailMapper.selectOne(pDetailWrapper); + + if (pDetail != null) { + Map 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; + } +}