From 725d7b4a46586c0cdfcd33c27b67a9f8f8487683 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A9=AC=E6=A2=93=E5=BD=AD?= Date: Sun, 20 Sep 2026 14:43:01 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8C=89=E2=80=9C=E9=A1=B9=E7=9B=AE=20+=20?= =?UTF-8?q?=E5=9C=BA=E5=9C=B0=E2=80=9D=E6=98=BE=E7=A4=BA=E8=A3=81=E5=88=A4?= =?UTF-8?q?=E5=88=86=E9=85=8D=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Event/Dtos/JudgeAssignmentDtos.cs | 16 ++--- .../Event/JudgeAssignmentService.cs | 68 +++++++++++++------ 2 files changed, 56 insertions(+), 28 deletions(-) diff --git a/YD_Event.Application/Event/Dtos/JudgeAssignmentDtos.cs b/YD_Event.Application/Event/Dtos/JudgeAssignmentDtos.cs index 54d0027..d132244 100644 --- a/YD_Event.Application/Event/Dtos/JudgeAssignmentDtos.cs +++ b/YD_Event.Application/Event/Dtos/JudgeAssignmentDtos.cs @@ -160,7 +160,7 @@ public class JudgeAssignmentProjectOutput public List JudgeRoleSections { get; set; } = new(); /// - /// 项目下的场次分配列表 + /// 项目下按场地归并后的裁判分配列表 /// public List Sessions { get; set; } = new(); } @@ -213,17 +213,17 @@ public class JudgeRoleSlotOutput } /// -/// 场次裁判分配情况 +/// 项目场地裁判分配情况 /// public class JudgeAssignmentSessionOutput { /// - /// 比赛场次ID + /// 代表场次ID,用于定位同一项目、同一场地的裁判分配单元 /// public long SessionId { get; set; } /// - /// 场次名称 + /// 分配单元名称(项目名称-场地名称) /// public string SessionName { get; set; } = null!; @@ -238,7 +238,7 @@ public class JudgeAssignmentSessionOutput public bool Assigned { get; set; } /// - /// 场次内的裁判席位列表 + /// 该项目场地下共用的裁判席位列表 /// public List Assignments { get; set; } = new(); } @@ -285,7 +285,7 @@ public class JudgeAssignmentItemOutput } /// -/// 保存场次裁判分配输入 +/// 保存项目场地裁判分配输入 /// public class SaveJudgeAssignmentsInput { @@ -295,12 +295,12 @@ public class SaveJudgeAssignmentsInput public long EventId { get; set; } /// - /// 比赛场次ID + /// 代表场次ID,用于定位同一项目、同一场地的裁判分配单元 /// public long SessionId { get; set; } /// - /// 该场次的裁判分配列表 + /// 该项目场地下共用的裁判分配列表 /// public List Assignments { get; set; } = new(); } diff --git a/YD_Event.Application/Event/JudgeAssignmentService.cs b/YD_Event.Application/Event/JudgeAssignmentService.cs index dc4d5cc..11b7c15 100644 --- a/YD_Event.Application/Event/JudgeAssignmentService.cs +++ b/YD_Event.Application/Event/JudgeAssignmentService.cs @@ -95,19 +95,30 @@ public class JudgeAssignmentService : IDynamicApiController, ITransient EventProjectId = ep.Id, ProjectName = project.Name, RuleName = rule?.RuleName ?? "未配置计分规则", JudgeRoleSections = sections }; - foreach (var session in sessions.Where(x => x.EventProjectId == ep.Id) - .OrderBy(x => venueMap.GetValueOrDefault(x.VenueId)?.Sort) - .ThenBy(x => x.SessionNo)) + // 裁判按“项目 + 场地”分配;同一场地因不同组别拆出的多个实际场次共用一套裁判。 + var projectSessions = sessions.Where(x => x.EventProjectId == ep.Id) + .GroupBy(x => x.VenueId) + .OrderBy(x => venueMap.GetValueOrDefault(x.Key)?.Sort) + .ThenBy(x => x.Key); + foreach (var venueSessions in projectSessions) { - var items = assignments.Where(x => x.SessionId == session.Id) + var orderedSessions = venueSessions.OrderBy(x => x.SessionNo).ThenBy(x => x.Id).ToList(); + var sessionIds = orderedSessions.Select(x => x.Id).ToHashSet(); + var assignmentSessionId = assignments.Where(x => sessionIds.Contains(x.SessionId)) + .Select(x => x.SessionId) + .FirstOrDefault(); + var representativeSession = orderedSessions.FirstOrDefault(x => x.Id == assignmentSessionId) + ?? orderedSessions[0]; + var items = assignments.Where(x => x.SessionId == representativeSession.Id) .Select(x => ToAssignmentItemOutput(x, referees.FirstOrDefault(r => r.Id == x.RefereeId), slotMap)) // 先按规则中的裁判类型排序(规则里没有的历史类型排到最后),同类型内再按席位编码排列。 .OrderBy(x => slotOrder.GetValueOrDefault(x.JudgeRoleType, int.MaxValue)) .ThenBy(x => x.JudgeRole, StringComparer.OrdinalIgnoreCase).ToList(); group.Sessions.Add(new JudgeAssignmentSessionOutput { - SessionId = session.Id, SessionName = session.SessionName ?? session.SessionNo, - VenueName = venueMap.GetValueOrDefault(session.VenueId)?.VenueName ?? "-", + SessionId = representativeSession.Id, + SessionName = $"{project.Name}-{venueMap.GetValueOrDefault(representativeSession.VenueId)?.VenueName ?? "-"}", + VenueName = venueMap.GetValueOrDefault(representativeSession.VenueId)?.VenueName ?? "-", Assigned = items.Count > 0, Assignments = items }); } @@ -127,18 +138,27 @@ public class JudgeAssignmentService : IDynamicApiController, ITransient var allReferees = await GetEventReferees(eventId); - // 如果场次没有设置时间,则不进行冲突检测 - if (!session.StartTime.HasValue || !session.EndTime.HasValue) + var eventSessions = await _sessionRepository.AsQueryable() + .Where(x => x.EventId == eventId && x.SessionStatus != 90) + .ToListAsync(); + var assignmentUnitSessions = eventSessions + .Where(x => x.EventProjectId == session.EventProjectId && x.VenueId == session.VenueId) + .ToList(); + var timedAssignmentUnitSessions = assignmentUnitSessions + .Where(x => x.StartTime.HasValue && x.EndTime.HasValue) + .ToList(); + if (timedAssignmentUnitSessions.Count == 0) { return allReferees; } - - // 查找同时段已分配的裁判ID(场次时间重叠且已分配) - var conflictSessions = await _sessionRepository.AsQueryable() - .Where(x => x.EventId == eventId && x.Id != sessionId && x.SessionStatus != 90) - .Where(x => x.StartTime.HasValue && x.EndTime.HasValue) - .Where(x => (x.StartTime.Value <= session.EndTime.Value && x.EndTime.Value >= session.StartTime.Value)) - .ToListAsync(); + + // 查找与分配单元内任一实际场次时间重叠的裁判;兄弟场次共用裁判,不互相判定为冲突。 + var assignmentUnitSessionIds = assignmentUnitSessions.Select(x => x.Id).ToHashSet(); + var conflictSessions = eventSessions + .Where(x => !assignmentUnitSessionIds.Contains(x.Id) && x.StartTime.HasValue && x.EndTime.HasValue) + .Where(x => timedAssignmentUnitSessions.Any(unit => + x.StartTime!.Value <= unit.EndTime!.Value && x.EndTime!.Value >= unit.StartTime!.Value)) + .ToList(); if (conflictSessions.Count == 0) { @@ -157,7 +177,8 @@ public class JudgeAssignmentService : IDynamicApiController, ITransient } /// - /// 保存场次裁判分配。 + /// 保存场地裁判分配。 + /// 传入的场次仅用于定位“项目 + 场地”,分配结果会同步到该分配单元下的全部实际场次。 /// 同一裁判类型可分配多名裁判,人数上下限由计分规则的裁判席位配置决定。 /// /// 场次裁判分配信息。 @@ -200,21 +221,28 @@ public class JudgeAssignmentService : IDynamicApiController, ITransient var candidates = await GetEventReferees(input.EventId); var seats = BuildSeats(slots, grouped, candidates); + // 评分、任务和成绩仍按实际场次关联,因此为每个兄弟场次各保存一份相同的裁判席位。 + var assignmentUnitSessions = eventSessions + .Where(x => x.EventProjectId == session.EventProjectId && x.VenueId == session.VenueId) + .ToList(); + var assignmentUnitSessionIds = assignmentUnitSessions.Select(x => x.Id).ToList(); + // 赛前允许反复修改已提交的分配。保存新版本后先回到草稿态,重新提交后裁判端才可见。 - await _assignmentRepository.SoftDeleteAsync(x => x.SessionId == input.SessionId && x.AssignmentStatus < 9); + await _assignmentRepository.SoftDeleteAsync(x => assignmentUnitSessionIds.Contains(x.SessionId) && x.AssignmentStatus < 9); var now = DateTime.Now; var refereeIds = seats.Select(x => x.Candidate.RefereeId).Distinct().ToList(); var refereeUsers = (await _refereeRepository.AsQueryable() .Where(x => refereeIds.Contains(x.Id)).ToListAsync()) .ToDictionary(x => x.Id, x => x.AppUserId); - await _assignmentRepository.InsertRangeAsync(seats.Select(x => new EventJudgeAssignment + var newAssignments = assignmentUnitSessions.SelectMany(sessionItem => seats.Select(x => new EventJudgeAssignment { - Id = _idGenerator.NextId(), EventId = input.EventId, SessionId = input.SessionId, + Id = _idGenerator.NextId(), EventId = input.EventId, SessionId = sessionItem.Id, EventRefereeId = x.Candidate.EventRefereeId, RefereeId = x.Candidate.RefereeId, JudgeUserId = refereeUsers.GetValueOrDefault(x.Candidate.RefereeId), JudgeRole = x.SeatCode, JudgeRoleType = x.Slot.Code, AssignmentStatus = 0, Status = AvailabilityStatus.Enable, CreatedUserId = _authManager.UserId, CreatedTime = now - }).ToList()); + })).ToList(); + await _assignmentRepository.InsertRangeAsync(newAssignments); } ///