From 320c7afc6d8987084c032f177aa33d4fa6280a12 Mon Sep 17 00:00:00 2001 From: ltx <1006158920@qq.com> Date: Fri, 18 Sep 2026 17:39:01 +0800 Subject: [PATCH] =?UTF-8?q?update=EF=BC=9A=E8=B5=9B=E4=BA=8B=E6=A3=80?= =?UTF-8?q?=E5=BD=95=E9=A1=BA=E5=BA=8F&=E6=A3=80=E5=BD=95=E5=A4=A7?= =?UTF-8?q?=E5=B1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Client/CheckinController.Progress.cs | 83 +++++++++++-------- .../Client/CheckinController.cs | 17 +++- .../Workbench/WorkbenchController.cs | 26 +++++- YD_Event.Application/YD_Event.Application.xml | 8 +- 4 files changed, 93 insertions(+), 41 deletions(-) diff --git a/YD_Event.Application/Client/CheckinController.Progress.cs b/YD_Event.Application/Client/CheckinController.Progress.cs index 1fc93d0..8e3ec44 100644 --- a/YD_Event.Application/Client/CheckinController.Progress.cs +++ b/YD_Event.Application/Client/CheckinController.Progress.cs @@ -52,28 +52,30 @@ public partial class CheckinController // 未指定项目组别时投屏当前检录中的项目组别。 var targetProjectId = eventProjectId ?? context.CurrentCheckin?.EventProjectId; var targetGroupId = groupId ?? context.CurrentCheckin?.GroupId; - var units = options.Units - .Where(x => (!targetProjectId.HasValue || x.EventProjectId == targetProjectId.Value) && - (!targetGroupId.HasValue || x.GroupId == targetGroupId.Value)) - .OrderBy(x => x.Order) - .Select(unit => - { - var status = ResolveUnitStatus(unit, context, activeTasks); - return new CheckinScreenCastUnitDto + var units = !targetProjectId.HasValue || !targetGroupId.HasValue + ? new List() + : options.Units + .Where(x => x.EventProjectId == targetProjectId.Value && x.GroupId == targetGroupId.Value) + .OrderBy(x => x.Order) + .Select(unit => { - UnitKey = unit.UnitKey, - Order = unit.Order, - SessionIndex = unit.SessionIndex, - VenueName = unit.VenueName, - ProjectName = unit.ProjectName, - GroupName = unit.GroupName, - TeamName = ResolveTeamName(unit), - UnitName = unit.UnitName, - AthleteNames = unit.Athletes.Select(x => x.Name).ToList(), - CheckinStatus = status, - CheckinStatusText = ToCheckinStatusText(status) - }; - }).ToList(); + // 投屏的“当前检录项目”卡片只表达一检状态,避免二检/三检进度覆盖为“已上场”。 + var status = ResolveFirstCheckinUnitStatus(unit, context); + return new CheckinScreenCastUnitDto + { + UnitKey = unit.UnitKey, + Order = unit.Order, + SessionIndex = unit.SessionIndex, + VenueName = unit.VenueName, + ProjectName = unit.ProjectName, + GroupName = unit.GroupName, + TeamName = ResolveTeamName(unit), + UnitName = unit.UnitName, + AthleteNames = unit.Athletes.Select(x => x.Name).ToList(), + CheckinStatus = status, + CheckinStatusText = ToCheckinStatusText(status) + }; + }).ToList(); var now = DateTime.Now; return new CheckinScreenCastOutput @@ -136,17 +138,17 @@ public partial class CheckinController } var firstCheckinNo = activeTasks.Count == 0 ? 1 : activeTasks.Min(x => x.CheckinNo); - var lastCheckinNo = activeTasks.Count == 0 ? 1 : activeTasks.Max(x => x.CheckinNo); + var onStageCheckinNo = ResolveOnStageCheckinNo(activeTasks); var context = new CheckinProgressContext { PassedByKey = passedByKey, CheckerNameByKey = checkerNameByKey, FirstCheckinNo = firstCheckinNo, - LastCheckinNo = lastCheckinNo, + OnStageCheckinNo = onStageCheckinNo, ActiveCheckinNumbers = activeTasks.Select(x => x.CheckinNo).OrderBy(x => x).ToList() }; - // 按秩序册顺序汇总项目组别阶段;一检开始即为检录中,三检全部通过即为已完成。 + // 赛事检录顺序完全跟随一检进度:一检开始即为检录中,一检全部通过即切换下一项目。 var stages = options.Units .GroupBy(x => new { x.EventProjectId, x.GroupId, x.ProjectName, x.GroupName }) .Select(group => @@ -155,8 +157,6 @@ public partial class CheckinController var total = groupUnits.Count; var checkedCount = groupUnits.Count(x => context.IsPassed(x.UnitKey, firstCheckinNo)); - var finishedCount = groupUnits.Count(x => - context.IsPassed(x.UnitKey, lastCheckinNo)); return new CheckinProgressStageDto { EventProjectId = group.Key.EventProjectId, @@ -168,7 +168,7 @@ public partial class CheckinController TotalUnits = total, CheckedUnits = checkedCount, ProgressPercent = total == 0 ? 0 : (int)Math.Round(checkedCount * 100d / total), - StageStatus = ResolveStageStatus(total, checkedCount, finishedCount) + StageStatus = ResolveStageStatus(total, checkedCount) }; }) .OrderBy(x => x.Order) @@ -180,11 +180,12 @@ public partial class CheckinController foreach (var stage in stages) stage.StageStatusText = ToStageStatusText(stage.StageStatus); context.Stages = stages; - context.CurrentCheckin = stages.FirstOrDefault(x => x.StageStatus == 1); + // 当前检录项目同样只由一检推进;尚未扫入第一位选手时也展示下一待检项目。 + context.CurrentCheckin = stages.FirstOrDefault(x => x.StageStatus is 1 or 2); - // 当前正在比赛:末检次已通过且顺序最靠后的一列。 + // 当前正在比赛:三检通过视为上场;赛事仅配置两检时,二检通过即视为上场。 var competingUnit = options.Units - .Where(x => context.IsPassed(x.UnitKey, lastCheckinNo)) + .Where(x => context.IsPassed(x.UnitKey, onStageCheckinNo)) .OrderByDescending(x => x.Order) .FirstOrDefault(); if (competingUnit != null) @@ -213,7 +214,7 @@ public partial class CheckinController .Where(x => x.EventProjectId == context.CurrentCheckin.EventProjectId && x.GroupId == context.CurrentCheckin.GroupId) .OrderBy(x => x.Order) - .FirstOrDefault(x => !context.IsPassed(x.UnitKey, lastCheckinNo)); + .FirstOrDefault(x => !context.IsPassed(x.UnitKey, firstCheckinNo)); if (checkingUnit != null) { context.CurrentCheckin.TeamName = ResolveTeamName(checkingUnit); @@ -289,7 +290,7 @@ public partial class CheckinController private static int ResolveUnitStatus( CheckinOrderBookUnitDto unit, CheckinProgressContext context, List activeTasks) { - if (context.IsPassed(unit.UnitKey, context.LastCheckinNo)) return 3; + if (context.IsPassed(unit.UnitKey, context.OnStageCheckinNo)) return 3; if (context.IsPassed(unit.UnitKey, context.FirstCheckinNo)) return activeTasks.Count > 1 ? 2 : 3; @@ -299,9 +300,21 @@ public partial class CheckinController : 0; } - private static int ResolveStageStatus(int total, int checkedCount, int finishedCount) + /// 检录大屏当前项目中的队伍状态仅跟随一检。 + private static int ResolveFirstCheckinUnitStatus( + CheckinOrderBookUnitDto unit, CheckinProgressContext context) { - if (total > 0 && finishedCount == total) return 4; + if (context.IsPassed(unit.UnitKey, context.FirstCheckinNo)) return 2; + + var stage = context.CurrentCheckin; + return stage != null && stage.EventProjectId == unit.EventProjectId && stage.GroupId == unit.GroupId + ? 1 + : 0; + } + + private static int ResolveStageStatus(int total, int checkedCount) + { + if (total > 0 && checkedCount == total) return 4; if (checkedCount > 0) return 1; return 3; } @@ -340,7 +353,7 @@ public partial class CheckinController public Dictionary> PassedByKey { get; init; } = new(); public Dictionary> CheckerNameByKey { get; init; } = new(); public int FirstCheckinNo { get; init; } = 1; - public int LastCheckinNo { get; init; } = 1; + public int OnStageCheckinNo { get; init; } = 1; public List ActiveCheckinNumbers { get; init; } = new(); public List Stages { get; set; } = new(); public CheckinProgressStageDto? CurrentCheckin { get; set; } diff --git a/YD_Event.Application/Client/CheckinController.cs b/YD_Event.Application/Client/CheckinController.cs index abd10df..d8d3cad 100644 --- a/YD_Event.Application/Client/CheckinController.cs +++ b/YD_Event.Application/Client/CheckinController.cs @@ -388,7 +388,7 @@ public partial class CheckinController : IDynamicApiController .Select(x => x.SessionKey!).ToHashSet(); var activeTasks = await GetActiveEventTasksAsync(task.EventId); - // 末检次(默认三检)通过即视为已上场。 + // 三检通过视为已上场;仅配置两检时,二检通过即视为已上场。 var onStageKeys = await GetOnStageKeysAsync(activeTasks, allUnitKeys); HashSet previousPassedKeys; @@ -506,19 +506,28 @@ public partial class CheckinController : IDynamicApiController x.Status == AvailabilityStatus.Enable && !x.DeleteMark) .OrderBy(x => x.CheckinNo).ToListAsync(); - /// 末检次通过的秩序册列即为已上场,供检录端与运动员端统一判定。 + /// 三检通过即为已上场;仅配置两检时由二检标记上场。 private async Task> GetOnStageKeysAsync( List activeTasks, HashSet validUnitKeys) { if (activeTasks.Count == 0) return new HashSet(); - var lastTask = activeTasks.OrderByDescending(x => x.CheckinNo).First(); + var onStageCheckinNo = ResolveOnStageCheckinNo(activeTasks); + var onStageTask = activeTasks.First(x => x.CheckinNo == onStageCheckinNo); var records = await _recordRepository.AsQueryable() - .Where(x => x.TaskId == lastTask.Id && x.SessionKey != null && x.Checked && !x.DeleteMark) + .Where(x => x.TaskId == onStageTask.Id && x.SessionKey != null && x.Checked && !x.DeleteMark) .ToListAsync(); return records.Where(x => validUnitKeys.Contains(x.SessionKey!)) .Select(x => x.SessionKey!).ToHashSet(); } + /// 上场检次固定为三检;未配置三检但配置了二检时使用二检。 + private static int ResolveOnStageCheckinNo(List activeTasks) + { + if (activeTasks.Any(x => x.CheckinNo == 3)) return 3; + if (activeTasks.Any(x => x.CheckinNo == 2)) return 2; + return activeTasks.Count == 0 ? 1 : activeTasks.Min(x => x.CheckinNo); + } + private async Task EnsureCheckerAsync() { var userId = _authManager.UserId; diff --git a/YD_Event.Application/Workbench/WorkbenchController.cs b/YD_Event.Application/Workbench/WorkbenchController.cs index 268b53b..7e48bf7 100644 --- a/YD_Event.Application/Workbench/WorkbenchController.cs +++ b/YD_Event.Application/Workbench/WorkbenchController.cs @@ -603,11 +603,20 @@ public class WorkbenchController : IDynamicApiController if (expectedJudgeCount <= 0 || submittedJudgeCount < expectedJudgeCount) throw Oops.Bah("相关裁判评分单尚未全部提交,不能投屏"); + var unitName = string.Empty; + if (result.MerchantCertificationId.HasValue) + { + var merchant = await _merchantCertificationRepository.GetFirstAsync(m => + m.Id == result.MerchantCertificationId.Value && !m.DeleteMark); + unitName = merchant?.MerchantName ?? string.Empty; + } + var payload = new { EntryNo = entry.EntryNo, ParticipantName = entry.ParticipantName, TeamName = entry.TeamName, + UnitName = unitName, GroupName = entry.GroupName, DifficultyScore = result.DifficultyScore, PerformanceScore = result.PerformanceScore, @@ -722,13 +731,25 @@ public class WorkbenchController : IDynamicApiController r.DeductionScore, r.TotalScore, r.Score, - r.IsDisqualified + r.IsDisqualified, + r.MerchantCertificationId }) .ToListAsync(); if (!results.Any()) throw Oops.Bah("当前项目组别没有可投屏的已确认成绩"); + var rankingMerchantIds = results + .Where(r => r.MerchantCertificationId.HasValue) + .Select(r => r.MerchantCertificationId!.Value) + .Distinct() + .ToList(); + var rankingMerchantNames = (await _merchantCertificationRepository.AsQueryable() + .Where(m => rankingMerchantIds.Contains(m.Id) && !m.DeleteMark) + .Select(m => new { m.Id, m.MerchantName }) + .ToListAsync()) + .ToDictionary(m => m.Id, m => m.MerchantName); + // 落库名次可能是成绩刚生成时连同“待复核”成绩一起计算的。 // 投屏时必须以上面已经过状态筛选的有效成绩重新排名,避免待复核成绩隐形占位。 var scoreRuleId = results.Select(r => r.ScoreRuleId).First(); @@ -765,6 +786,9 @@ public class WorkbenchController : IDynamicApiController r.EntryNo, r.ParticipantName, r.TeamName, + UnitName = r.MerchantCertificationId.HasValue + ? rankingMerchantNames.GetValueOrDefault(r.MerchantCertificationId.Value) + : null, r.GroupName, r.TotalScore, r.Score, diff --git a/YD_Event.Application/YD_Event.Application.xml b/YD_Event.Application/YD_Event.Application.xml index b0bb70c..74bf558 100644 --- a/YD_Event.Application/YD_Event.Application.xml +++ b/YD_Event.Application/YD_Event.Application.xml @@ -1868,7 +1868,10 @@ 对报名了所选项目组别的人员发送检录通知;单人失败不影响整体流程。 - 末检次通过的秩序册列即为已上场,供检录端与运动员端统一判定。 + 三检通过即为已上场;仅配置两检时由二检标记上场。 + + + 上场检次固定为三检;未配置三检但配置了二检时使用二检。 汇总各检次的检录记录,生成项目组别三态与当前检录、当前比赛信息。 @@ -1879,6 +1882,9 @@ 秩序册列状态:0-等待中,1-检录中,2-已检录,3-已上场。 + + 检录大屏当前项目中的队伍状态仅跟随一检。 + 检录进度计算的中间上下文,避免重复查询检录记录。