From 4ba1cb265d0479cfa76a567d452dedde560c4e16 Mon Sep 17 00:00:00 2001 From: Hikaru Saito Date: Mon, 6 Apr 2026 18:30:53 +0900 Subject: [PATCH 1/5] =?UTF-8?q?=E7=A7=91=E7=9B=AEID=E3=81=AE=E3=81=BF?= =?UTF-8?q?=E3=81=A7=E6=95=99=E5=AE=A4=E6=A4=9C=E7=B4=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internal/service/personal_calendar_item.go | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/internal/service/personal_calendar_item.go b/internal/service/personal_calendar_item.go index 992c6b9..efbf639 100644 --- a/internal/service/personal_calendar_item.go +++ b/internal/service/personal_calendar_item.go @@ -93,6 +93,7 @@ func (s *PersonalCalendarItemService) List( dayToTimetableItems := make(map[domain.DayOfWeek][]domain.TimetableItem) subjectPeriodToRooms := make(map[string][]domain.Room) + subjectToRooms := make(map[string][]domain.Room) for _, item := range timetableItems { if item.Slot == nil { continue @@ -103,6 +104,10 @@ func (s *PersonalCalendarItemService) List( dayToTimetableItems[item.Slot.DayOfWeek] = append(dayToTimetableItems[item.Slot.DayOfWeek], item) key := item.Subject.ID + "/" + string(item.Slot.DayOfWeek) + "/" + string(item.Slot.Period) subjectPeriodToRooms[key] = item.Rooms + // 科目IDのみのマップも作成(補講用) + if _, exists := subjectToRooms[item.Subject.ID]; !exists { + subjectToRooms[item.Subject.ID] = item.Rooms + } } // datesからFrom/Untilを算出 @@ -207,7 +212,6 @@ func (s *PersonalCalendarItemService) List( // 補講アイテムの追加 // Cancelled が既にある同キーは上書きしない(Cancelled > Makeup の優先度) - mcDow := weekdayToDayOfWeek(date.Weekday()) for key, mc := range makeupMap { if key.date != dateStr { continue @@ -215,8 +219,10 @@ func (s *PersonalCalendarItemService) List( if existing, exists := resultMap[key]; exists && existing.Status == domain.PersonalCalendarItemStatusCancelled { continue } - // TODO: 補講の教室は時間割の教室で代替しているが、実際は異なる場合がある - rooms, ok := subjectPeriodToRooms[mc.Subject.ID+"/"+string(mcDow)+"/"+string(mc.Period)] + // 補講の教室情報はDBに保存されていないため、 + // 該当科目の通常時間割から最初に見つかった教室を代替として使用する。 + // 実際の補講教室とは異なる可能性がある。 + rooms, ok := subjectToRooms[mc.Subject.ID] if !ok { rooms = []domain.Room{} } From 924e2b5e3e58b56bf9d1026667b9a216136aa317 Mon Sep 17 00:00:00 2001 From: Hikaru Saito Date: Mon, 6 Apr 2026 18:48:40 +0900 Subject: [PATCH 2/5] =?UTF-8?q?=E5=90=8C=E3=81=98=E7=A7=91=E7=9B=AEID?= =?UTF-8?q?=E3=81=AE=E5=85=A8=E6=95=99=E5=AE=A4=E3=82=92=E9=87=8D=E8=A4=87?= =?UTF-8?q?=E7=84=A1=E3=81=97=E3=81=A7=E8=BF=94=E3=81=99=E3=82=88=E3=81=86?= =?UTF-8?q?=E3=81=AB=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internal/service/personal_calendar_item.go | 34 +++++++++++++--------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/internal/service/personal_calendar_item.go b/internal/service/personal_calendar_item.go index efbf639..37d5989 100644 --- a/internal/service/personal_calendar_item.go +++ b/internal/service/personal_calendar_item.go @@ -30,11 +30,11 @@ type personalCalendarItemRoomChangeRepository interface { type PersonalCalendarItemService struct { courseRegistrationRepo personalCalendarItemCourseRegistrationRepository - timetableItemRepo personalCalendarItemTimetableItemRepository - cancelledClassRepo personalCalendarItemCancelledClassRepository - makeupClassRepo personalCalendarItemMakeupClassRepository - roomChangeRepo personalCalendarItemRoomChangeRepository - substituteDayMap map[string]domain.DayOfWeek + timetableItemRepo personalCalendarItemTimetableItemRepository + cancelledClassRepo personalCalendarItemCancelledClassRepository + makeupClassRepo personalCalendarItemMakeupClassRepository + roomChangeRepo personalCalendarItemRoomChangeRepository + substituteDayMap map[string]domain.DayOfWeek } func NewPersonalCalendarItemService( @@ -47,11 +47,11 @@ func NewPersonalCalendarItemService( ) *PersonalCalendarItemService { return &PersonalCalendarItemService{ courseRegistrationRepo: courseRegistrationRepo, - timetableItemRepo: timetableItemRepo, - cancelledClassRepo: cancelledClassRepo, - makeupClassRepo: makeupClassRepo, - roomChangeRepo: roomChangeRepo, - substituteDayMap: substituteDayMap, + timetableItemRepo: timetableItemRepo, + cancelledClassRepo: cancelledClassRepo, + makeupClassRepo: makeupClassRepo, + roomChangeRepo: roomChangeRepo, + substituteDayMap: substituteDayMap, } } @@ -94,6 +94,7 @@ func (s *PersonalCalendarItemService) List( dayToTimetableItems := make(map[domain.DayOfWeek][]domain.TimetableItem) subjectPeriodToRooms := make(map[string][]domain.Room) subjectToRooms := make(map[string][]domain.Room) + subjectRoomIDs := make(map[string]map[string]struct{}) // 重複除去用 for _, item := range timetableItems { if item.Slot == nil { continue @@ -104,9 +105,16 @@ func (s *PersonalCalendarItemService) List( dayToTimetableItems[item.Slot.DayOfWeek] = append(dayToTimetableItems[item.Slot.DayOfWeek], item) key := item.Subject.ID + "/" + string(item.Slot.DayOfWeek) + "/" + string(item.Slot.Period) subjectPeriodToRooms[key] = item.Rooms - // 科目IDのみのマップも作成(補講用) - if _, exists := subjectToRooms[item.Subject.ID]; !exists { - subjectToRooms[item.Subject.ID] = item.Rooms + + // 科目IDのみのマップも作成(補講用・重複なし) + if subjectRoomIDs[item.Subject.ID] == nil { + subjectRoomIDs[item.Subject.ID] = make(map[string]struct{}) + } + for _, room := range item.Rooms { + if _, exists := subjectRoomIDs[item.Subject.ID][room.ID]; !exists { + subjectRoomIDs[item.Subject.ID][room.ID] = struct{}{} + subjectToRooms[item.Subject.ID] = append(subjectToRooms[item.Subject.ID], room) + } } } From 34aa4a0c08980e3c8fad3b021ee364a19fa04bc7 Mon Sep 17 00:00:00 2001 From: Hikaru Saito Date: Mon, 6 Apr 2026 19:42:03 +0900 Subject: [PATCH 3/5] =?UTF-8?q?subjectPeriodYoRooms=E5=89=8A=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internal/service/personal_calendar_item.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/internal/service/personal_calendar_item.go b/internal/service/personal_calendar_item.go index 37d5989..c92faaf 100644 --- a/internal/service/personal_calendar_item.go +++ b/internal/service/personal_calendar_item.go @@ -92,7 +92,6 @@ func (s *PersonalCalendarItemService) List( } dayToTimetableItems := make(map[domain.DayOfWeek][]domain.TimetableItem) - subjectPeriodToRooms := make(map[string][]domain.Room) subjectToRooms := make(map[string][]domain.Room) subjectRoomIDs := make(map[string]map[string]struct{}) // 重複除去用 for _, item := range timetableItems { @@ -103,8 +102,6 @@ func (s *PersonalCalendarItemService) List( continue } dayToTimetableItems[item.Slot.DayOfWeek] = append(dayToTimetableItems[item.Slot.DayOfWeek], item) - key := item.Subject.ID + "/" + string(item.Slot.DayOfWeek) + "/" + string(item.Slot.Period) - subjectPeriodToRooms[key] = item.Rooms // 科目IDのみのマップも作成(補講用・重複なし) if subjectRoomIDs[item.Subject.ID] == nil { From 5f6f90f4b442ce849f36e200034d0532093184f1 Mon Sep 17 00:00:00 2001 From: Hikaru Saito Date: Mon, 6 Apr 2026 19:49:10 +0900 Subject: [PATCH 4/5] =?UTF-8?q?=E6=95=99=E5=AE=A4=E3=81=AE=E9=A0=86?= =?UTF-8?q?=E5=BA=8F=E3=82=BD=E3=83=BC=E3=83=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internal/service/personal_calendar_item.go | 43 ++++++++++++++++++---- 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/internal/service/personal_calendar_item.go b/internal/service/personal_calendar_item.go index c92faaf..34c527a 100644 --- a/internal/service/personal_calendar_item.go +++ b/internal/service/personal_calendar_item.go @@ -93,7 +93,8 @@ func (s *PersonalCalendarItemService) List( dayToTimetableItems := make(map[domain.DayOfWeek][]domain.TimetableItem) subjectToRooms := make(map[string][]domain.Room) - subjectRoomIDs := make(map[string]map[string]struct{}) // 重複除去用 + subjectToBestItem := make(map[string]domain.TimetableItem) // 補講用に最適な時間割を保持 + for _, item := range timetableItems { if item.Slot == nil { continue @@ -103,16 +104,44 @@ func (s *PersonalCalendarItemService) List( } dayToTimetableItems[item.Slot.DayOfWeek] = append(dayToTimetableItems[item.Slot.DayOfWeek], item) - // 科目IDのみのマップも作成(補講用・重複なし) - if subjectRoomIDs[item.Subject.ID] == nil { - subjectRoomIDs[item.Subject.ID] = make(map[string]struct{}) + // 補講用に最適な時間割を選択(空でないRoomsを優先し、同点なら曜日/時限が最小のものを選ぶ) + bestItem, exists := subjectToBestItem[item.Subject.ID] + if !exists { + subjectToBestItem[item.Subject.ID] = item + } else { + // 空でないRoomsを優先 + currentHasRooms := len(item.Rooms) > 0 + bestHasRooms := len(bestItem.Rooms) > 0 + + shouldReplace := false + if currentHasRooms && !bestHasRooms { + shouldReplace = true + } else if currentHasRooms == bestHasRooms { + // 同条件なら曜日/時限が辞書順で小さい方を選ぶ + if item.Slot.DayOfWeek < bestItem.Slot.DayOfWeek { + shouldReplace = true + } else if item.Slot.DayOfWeek == bestItem.Slot.DayOfWeek && item.Slot.Period < bestItem.Slot.Period { + shouldReplace = true + } + } + + if shouldReplace { + subjectToBestItem[item.Subject.ID] = item + } } + } + + // 選択された最適な時間割から教室情報を抽出(重複削除) + for subjectID, item := range subjectToBestItem { + seenRoomIDs := make(map[string]struct{}) + uniqueRooms := make([]domain.Room, 0, len(item.Rooms)) for _, room := range item.Rooms { - if _, exists := subjectRoomIDs[item.Subject.ID][room.ID]; !exists { - subjectRoomIDs[item.Subject.ID][room.ID] = struct{}{} - subjectToRooms[item.Subject.ID] = append(subjectToRooms[item.Subject.ID], room) + if _, exists := seenRoomIDs[room.ID]; !exists { + seenRoomIDs[room.ID] = struct{}{} + uniqueRooms = append(uniqueRooms, room) } } + subjectToRooms[subjectID] = uniqueRooms } // datesからFrom/Untilを算出 From d97d127a99514e49881b9f2f440bb80bdb36a9ab Mon Sep 17 00:00:00 2001 From: Hikaru Saito Date: Mon, 6 Apr 2026 23:10:16 +0900 Subject: [PATCH 5/5] =?UTF-8?q?=E3=82=B3=E3=83=A1=E3=83=B3=E3=83=88?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internal/service/personal_calendar_item.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/internal/service/personal_calendar_item.go b/internal/service/personal_calendar_item.go index 34c527a..7b37c77 100644 --- a/internal/service/personal_calendar_item.go +++ b/internal/service/personal_calendar_item.go @@ -254,7 +254,8 @@ func (s *PersonalCalendarItemService) List( continue } // 補講の教室情報はDBに保存されていないため、 - // 該当科目の通常時間割から最初に見つかった教室を代替として使用する。 + // 該当科目の通常時間割から選択された最適な教室を代替として使用する。 + // (空でないRoomsを優先し、同点なら曜日/時限が辞書順で最小のものを選択) // 実際の補講教室とは異なる可能性がある。 rooms, ok := subjectToRooms[mc.Subject.ID] if !ok {