update:赛事检录顺序&检录大屏
This commit is contained in:
parent
93567c00b8
commit
320c7afc6d
@ -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<CheckinScreenCastUnitDto>()
|
||||
: 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<CheckinTask> 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)
|
||||
/// <summary>检录大屏当前项目中的队伍状态仅跟随一检。</summary>
|
||||
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<string, Dictionary<int, DateTime?>> PassedByKey { get; init; } = new();
|
||||
public Dictionary<string, Dictionary<int, string>> CheckerNameByKey { get; init; } = new();
|
||||
public int FirstCheckinNo { get; init; } = 1;
|
||||
public int LastCheckinNo { get; init; } = 1;
|
||||
public int OnStageCheckinNo { get; init; } = 1;
|
||||
public List<int> ActiveCheckinNumbers { get; init; } = new();
|
||||
public List<CheckinProgressStageDto> Stages { get; set; } = new();
|
||||
public CheckinProgressStageDto? CurrentCheckin { get; set; }
|
||||
|
||||
@ -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<string> previousPassedKeys;
|
||||
@ -506,19 +506,28 @@ public partial class CheckinController : IDynamicApiController
|
||||
x.Status == AvailabilityStatus.Enable && !x.DeleteMark)
|
||||
.OrderBy(x => x.CheckinNo).ToListAsync();
|
||||
|
||||
/// <summary>末检次通过的秩序册列即为已上场,供检录端与运动员端统一判定。</summary>
|
||||
/// <summary>三检通过即为已上场;仅配置两检时由二检标记上场。</summary>
|
||||
private async Task<HashSet<string>> GetOnStageKeysAsync(
|
||||
List<CheckinTask> activeTasks, HashSet<string> validUnitKeys)
|
||||
{
|
||||
if (activeTasks.Count == 0) return new HashSet<string>();
|
||||
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();
|
||||
}
|
||||
|
||||
/// <summary>上场检次固定为三检;未配置三检但配置了二检时使用二检。</summary>
|
||||
private static int ResolveOnStageCheckinNo(List<CheckinTask> 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<long> EnsureCheckerAsync()
|
||||
{
|
||||
var userId = _authManager.UserId;
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -1868,7 +1868,10 @@
|
||||
<summary>对报名了所选项目组别的人员发送检录通知;单人失败不影响整体流程。</summary>
|
||||
</member>
|
||||
<member name="M:YD_Event.Application.Client.CheckinController.GetOnStageKeysAsync(System.Collections.Generic.List{YD_Event.Core.Entities.CheckinTask},System.Collections.Generic.HashSet{System.String})">
|
||||
<summary>末检次通过的秩序册列即为已上场,供检录端与运动员端统一判定。</summary>
|
||||
<summary>三检通过即为已上场;仅配置两检时由二检标记上场。</summary>
|
||||
</member>
|
||||
<member name="M:YD_Event.Application.Client.CheckinController.ResolveOnStageCheckinNo(System.Collections.Generic.List{YD_Event.Core.Entities.CheckinTask})">
|
||||
<summary>上场检次固定为三检;未配置三检但配置了二检时使用二检。</summary>
|
||||
</member>
|
||||
<member name="M:YD_Event.Application.Client.CheckinController.BuildProgressContextAsync(YD_Event.Application.Client.Dtos.CheckinEventOptionsDto,System.Collections.Generic.List{YD_Event.Core.Entities.CheckinTask})">
|
||||
<summary>汇总各检次的检录记录,生成项目组别三态与当前检录、当前比赛信息。</summary>
|
||||
@ -1879,6 +1882,9 @@
|
||||
<member name="M:YD_Event.Application.Client.CheckinController.ResolveUnitStatus(YD_Event.Application.Client.Dtos.CheckinOrderBookUnitDto,YD_Event.Application.Client.CheckinController.CheckinProgressContext,System.Collections.Generic.List{YD_Event.Core.Entities.CheckinTask})">
|
||||
<summary>秩序册列状态:0-等待中,1-检录中,2-已检录,3-已上场。</summary>
|
||||
</member>
|
||||
<member name="M:YD_Event.Application.Client.CheckinController.ResolveFirstCheckinUnitStatus(YD_Event.Application.Client.Dtos.CheckinOrderBookUnitDto,YD_Event.Application.Client.CheckinController.CheckinProgressContext)">
|
||||
<summary>检录大屏当前项目中的队伍状态仅跟随一检。</summary>
|
||||
</member>
|
||||
<member name="T:YD_Event.Application.Client.CheckinController.CheckinProgressContext">
|
||||
<summary>检录进度计算的中间上下文,避免重复查询检录记录。</summary>
|
||||
</member>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user