马梓彭 b7a4adfdcc Merge branch 'dev_2.0'
# Conflicts:
#	YD_Event.Application/Judge/JudgeScoringController.cs
2026-09-08 16:29:04 +08:00

535 lines
26 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using YD_Event.Application.Auth;
using YD_Event.Application.Scoring.Dtos;
namespace YD_Event.Application.Scoring;
/// <summary>
/// 裁判评分与成绩计算(后台记分台)
/// </summary>
[ApiDescriptionSettings("打分系统")]
[Route("api/judgescore")]
public class JudgeScoreService : IDynamicApiController, ITransient
{
/// <summary>
/// 修正状态:0-已申请
/// </summary>
private const int CorrectionStatusApplied = 0;
/// <summary>
/// 修正状态:10-已批准
/// </summary>
private const int CorrectionStatusApproved = 10;
/// <summary>
/// 修正状态:20-已拒绝
/// </summary>
private const int CorrectionStatusRejected = 20;
/// <summary>
/// 修正状态:30-裁判修改中
/// </summary>
private const int CorrectionStatusEditing = 30;
/// <summary>
/// 修正状态:40-已完成
/// </summary>
private const int CorrectionStatusCompleted = 40;
/// <summary>
/// 修正状态:90-已取消
/// </summary>
private const int CorrectionStatusCancelled = 90;
/// <summary>
/// 评分单状态:20-已确认
/// </summary>
private const int SheetStatusConfirmed = 20;
/// <summary>
/// 场次状态:60-已结束
/// </summary>
private const int SessionStatusFinished = 60;
/// <summary>
/// 消息类型:1-成绩修正提醒
/// </summary>
private const int MessageTypeCorrection = 1;
private readonly ISqlSugarRepository<EventSession> _sessionRepository;
private readonly ISqlSugarRepository<EventSessionEntry> _entryRepository;
private readonly ISqlSugarRepository<EventVenue> _venueRepository;
private readonly ISqlSugarRepository<YD_Event.Core.Entities.ScoreRule> _ruleRepository;
private readonly ISqlSugarRepository<EventJudgeAssignment> _assignmentRepository;
private readonly ISqlSugarRepository<EventJudgeScoreSheet> _sheetRepository;
private readonly ISqlSugarRepository<EventScoreCorrection> _correctionRepository;
private readonly ISqlSugarRepository<EventJudgeMessage> _messageRepository;
private readonly ISqlSugarRepository<EventJudgeScoreAttachment> _attachmentRepository;
private readonly ISqlSugarRepository<YD_Event.Core.Entities.Referee> _refereeRepository;
private readonly ISqlSugarRepository<EventResult> _resultRepository;
private readonly EventScoreCalculationService _calculationService;
private readonly IIdGenerator _idGenerator;
private readonly AuthManager _authManager;
public JudgeScoreService(ISqlSugarRepository<EventSession> sessionRepository,
ISqlSugarRepository<EventSessionEntry> entryRepository, ISqlSugarRepository<EventVenue> venueRepository,
ISqlSugarRepository<YD_Event.Core.Entities.ScoreRule> ruleRepository,
ISqlSugarRepository<EventJudgeAssignment> assignmentRepository,
ISqlSugarRepository<EventJudgeScoreSheet> sheetRepository,
ISqlSugarRepository<EventScoreCorrection> correctionRepository,
ISqlSugarRepository<EventJudgeMessage> messageRepository,
ISqlSugarRepository<EventJudgeScoreAttachment> attachmentRepository,
ISqlSugarRepository<YD_Event.Core.Entities.Referee> refereeRepository,
ISqlSugarRepository<EventResult> resultRepository,
EventScoreCalculationService calculationService, IIdGenerator idGenerator, AuthManager authManager)
{
_sessionRepository = sessionRepository; _entryRepository = entryRepository; _venueRepository = venueRepository;
_ruleRepository = ruleRepository; _assignmentRepository = assignmentRepository; _sheetRepository = sheetRepository;
_correctionRepository = correctionRepository; _messageRepository = messageRepository;
_attachmentRepository = attachmentRepository;
_refereeRepository = refereeRepository; _resultRepository = resultRepository;
_calculationService = calculationService; _idGenerator = idGenerator; _authManager = authManager;
}
/// <summary>
/// 获取场次记分台。按当前已提交的评分单实时算分,不写库,可随时刷新查看进度。
/// </summary>
[HttpGet("board/{sessionId}")]
[DisplayName("获取场次记分台")]
public async Task<JudgeScoreBoardOutput> GetBoard(long sessionId)
{
var ctx = await _calculationService.LoadContextAsync(sessionId);
var outcomes = await _calculationService.EvaluateSessionAsync(sessionId, ctx);
return await BuildBoardAsync(ctx, outcomes);
}
/// <summary>
/// 重算整场成绩。所有应到裁判都已提交的出场写入成绩并按规则重排名次,未评满的出场只返回进度。
/// </summary>
[HttpPost("recalculate/{sessionId}")]
[DisplayName("重算场次成绩")]
[UnitOfWork]
public async Task<JudgeScoreBoardOutput> Recalculate(long sessionId)
{
var ctx = await _calculationService.LoadContextAsync(sessionId);
var outcomes = await _calculationService.RecalculateSessionAsync(sessionId,
EventScoreCalculationService.SourceTypeNormal, _authManager.UserId, ctx);
return await BuildBoardAsync(ctx, outcomes);
}
/// <summary>
/// 成绩排名查询。按项目、组别筛选,名次为 0 的(未评满、退赛、取消资格)排在最后。
/// </summary>
[HttpGet("ranking")]
[DisplayName("成绩排名查询")]
public async Task<List<JudgeRankingRowOutput>> GetRanking([FromQuery] JudgeRankingQueryInput input)
{
if (input.EventId <= 0) throw Oops.Bah("请指定赛事");
var results = await _resultRepository.AsQueryable()
.Where(x => x.EventId == input.EventId && x.Status == AvailabilityStatus.Enable)
.WhereIF(input.ProjectId.HasValue, x => x.ProjectId == input.ProjectId!.Value)
.WhereIF(!string.IsNullOrWhiteSpace(input.GroupName), x => x.GroupName == input.GroupName)
.WhereIF(input.ResultStatus.HasValue, x => x.ResultStatus == input.ResultStatus!.Value)
.ToListAsync();
return results
.OrderBy(x => x.ProjectId).ThenBy(x => x.GroupName)
// 名次 0 表示尚未参与排名,统一沉到组内末尾,避免占据第一名的位置。
.ThenBy(x => x.Rank == 0 ? int.MaxValue : x.Rank)
.ThenByDescending(x => x.TotalScore ?? 0m).ThenBy(x => x.ParticipantName)
.Select(x => new JudgeRankingRowOutput
{
ResultId = x.Id,
SessionEntryId = x.SessionEntryId,
ProjectId = x.ProjectId,
ProjectTypeName = x.ProjectTypeName ?? string.Empty,
GroupName = x.GroupName ?? string.Empty,
ParticipantName = x.ParticipantName ?? string.Empty,
Rank = x.Rank,
TotalScore = x.Score ?? string.Empty,
DifficultyScore = x.DifficultyScore,
PerformanceScore = x.PerformanceScore,
RequiredScore = x.RequiredScore,
DeductionScore = x.DeductionScore,
IsDisqualified = x.IsDisqualified,
ResultStatus = x.ResultStatus,
ResultStatusName = ResultStatusName(x.ResultStatus),
ResultVersion = x.ResultVersion,
ReviewUserId = x.ReviewUserId,
ReviewTime = x.ReviewTime
}).ToList();
}
/// <summary>
/// 确认场次成绩。仅在全场都已评满时确认,确认后裁判端不能再自行申请修正。
/// </summary>
[HttpPost("confirm/{sessionId}")]
[DisplayName("确认场次成绩")]
[UnitOfWork]
public async Task<ConfirmSessionScoreOutput> ConfirmSession(long sessionId)
{
var session = await _sessionRepository.GetFirstAsync(x => x.Id == sessionId);
if (session == null) throw Oops.Bah("比赛场次不存在");
var ctx = await _calculationService.LoadContextAsync(session);
// 先只算不写:确认被拒时不留下任何写库痕迹,也不会把已确认的成绩打回待复核。
var preview = await _calculationService.EvaluateSessionAsync(sessionId, ctx);
var output = new ConfirmSessionScoreOutput
{
PendingEntries = preview.Where(x => !x.IsSkipped && !x.IsCompleted).Select(x => x.EntryNo).ToList()
};
// 有出场没评满就不确认,否则先确认的成绩会挡住后到的评分。
if (output.PendingEntries.Count > 0) return output;
var outcomes = await _calculationService.RecalculateSessionAsync(sessionId,
EventScoreCalculationService.SourceTypeNormal, _authManager.UserId, ctx);
var entryIds = outcomes.Select(x => (long?)x.SessionEntryId).ToList();
var results = await _resultRepository.GetListAsync(x => entryIds.Contains(x.SessionEntryId)
&& x.ResultStatus == EventScoreCalculationService.ResultStatusPendingReview);
var now = DateTime.Now;
foreach (var result in results)
{
result.ResultStatus = EventScoreCalculationService.ResultStatusConfirmed;
result.ReviewUserId = _authManager.UserId;
result.ReviewTime = now;
result.UpdatedUserId = _authManager.UserId;
result.UpdatedTime = now;
}
if (results.Count > 0) await _resultRepository.UpdateRangeAsync(results);
output.ConfirmedCount = results.Count;
// 评分单一并置为已确认,裁判端据此禁用修正入口。
var plainIds = outcomes.Select(x => x.SessionEntryId).ToList();
var sheets = await _sheetRepository.GetListAsync(x => plainIds.Contains(x.SessionEntryId)
&& x.IsCurrent && x.SheetStatus == EventScoreCalculationService.SheetStatusSubmitted);
foreach (var sheet in sheets)
{
sheet.SheetStatus = SheetStatusConfirmed;
sheet.UpdatedUserId = _authManager.UserId;
sheet.UpdatedTime = now;
}
if (sheets.Count > 0) await _sheetRepository.UpdateRangeAsync(sheets);
if (session.SessionStatus != SessionStatusFinished)
{
session.SessionStatus = SessionStatusFinished;
session.Version++;
session.EndTime ??= now;
session.UpdatedUserId = _authManager.UserId;
session.UpdatedTime = now;
await _sessionRepository.UpdateAsync(session);
}
output.SessionFinished = true;
return output;
}
/// <summary>
/// 获取成绩修正申请列表
/// </summary>
[HttpGet("corrections/{eventId}")]
[DisplayName("获取成绩修正申请列表")]
public async Task<List<JudgeCorrectionOutput>> GetCorrections(long eventId, [FromQuery] int? correctionStatus = null)
{
var corrections = (await _correctionRepository.AsQueryable()
.Where(x => x.EventId == eventId)
.WhereIF(correctionStatus.HasValue, x => x.CorrectionStatus == correctionStatus!.Value)
.ToListAsync())
.OrderByDescending(x => x.CreatedTime).ToList();
if (corrections.Count == 0) return new List<JudgeCorrectionOutput>();
var sessionIds = corrections.Select(x => x.SessionId).Distinct().ToList();
var sessions = await _sessionRepository.GetListAsync(x => sessionIds.Contains(x.Id));
var ruleIds = sessions.Select(x => x.ScoreRuleId).Distinct().ToList();
var rules = await _ruleRepository.GetListAsync(x => ruleIds.Contains(x.Id));
// 每个场次的小数位取自各自的计分规则,避免跨规则显示口径不一致。
var configs = sessions.GroupBy(x => x.Id).ToDictionary(x => x.Key,
x => ScoreRuleConfigService.Parse(rules.FirstOrDefault(r => r.Id == x.First().ScoreRuleId)?.RuleConfigJson));
var entryIds = corrections.Select(x => x.SessionEntryId).Distinct().ToList();
var entries = await _entryRepository.GetListAsync(x => entryIds.Contains(x.Id));
var sheetIds = corrections.Select(x => x.OriginalScoreSheetId)
.Concat(corrections.Where(x => x.NewScoreSheetId.HasValue).Select(x => x.NewScoreSheetId!.Value))
.Distinct().ToList();
var sheets = await _sheetRepository.GetListAsync(x => sheetIds.Contains(x.Id));
var assignmentIds = corrections.Select(x => x.JudgeAssignmentId).Distinct().ToList();
var assignments = await _assignmentRepository.GetListAsync(x => assignmentIds.Contains(x.Id));
var refereeIds = assignments.Select(x => x.RefereeId).Distinct().ToList();
var referees = await _refereeRepository.GetListAsync(x => refereeIds.Contains(x.Id));
return corrections.Select(correction =>
{
var session = sessions.FirstOrDefault(x => x.Id == correction.SessionId);
var entry = entries.FirstOrDefault(x => x.Id == correction.SessionEntryId);
var original = sheets.FirstOrDefault(x => x.Id == correction.OriginalScoreSheetId);
var updated = correction.NewScoreSheetId.HasValue
? sheets.FirstOrDefault(x => x.Id == correction.NewScoreSheetId!.Value)
: null;
var assignment = assignments.FirstOrDefault(x => x.Id == correction.JudgeAssignmentId);
var referee = assignment == null ? null : referees.FirstOrDefault(x => x.Id == assignment.RefereeId);
var config = configs.TryGetValue(correction.SessionId, out var found) ? found : ScoreRuleConfigService.Parse(null);
return new JudgeCorrectionOutput
{
Id = correction.Id,
SessionId = correction.SessionId,
SessionName = session == null ? string.Empty : session.SessionName ?? session.SessionNo,
SessionEntryId = correction.SessionEntryId,
EntryNo = entry?.EntryNo ?? string.Empty,
ParticipantName = entry == null
? string.Empty
: string.IsNullOrWhiteSpace(entry.TeamName) ? entry.ParticipantName : entry.TeamName!,
OriginalScoreSheetId = correction.OriginalScoreSheetId,
NewScoreSheetId = correction.NewScoreSheetId,
JudgeRole = correction.JudgeRole,
RefereeName = referee?.Name ?? string.Empty,
OriginalScore = original == null ? string.Empty : config.Format(original.TotalScore),
NewScore = updated == null ? null : config.Format(updated.TotalScore),
ApplyReason = correction.ApplyReason,
ApproveRemark = correction.ApproveRemark,
CorrectionStatus = correction.CorrectionStatus,
CorrectionStatusName = CorrectionStatusName(correction.CorrectionStatus),
CreatedTime = correction.CreatedTime,
ApproveTime = correction.ApproveTime,
CompletedTime = correction.CompletedTime
};
}).ToList();
}
/// <summary>
/// 后台发起成绩修正。发起后该裁判可重新提交这张评分单,原评分在新评分提交时才失效。
/// </summary>
[HttpPost("corrections/initiate")]
[DisplayName("发起成绩修正")]
[UnitOfWork]
public async Task<long> InitiateCorrection([FromBody] InitiateJudgeCorrectionInput input)
{
if (string.IsNullOrWhiteSpace(input.Reason)) throw Oops.Bah("请填写修正原因");
var sheet = await _sheetRepository.GetFirstAsync(x => x.Id == input.ScoreSheetId);
if (sheet == null) throw Oops.Bah("评分单不存在");
if (!sheet.IsCurrent || sheet.SheetStatus < EventScoreCalculationService.SheetStatusSubmitted)
throw Oops.Bah("该评分单不是当前生效的已提交评分,无需修正");
if (await HasOpenCorrectionAsync(sheet.Id)) throw Oops.Bah("该评分单已有修正流程在处理中");
var now = DateTime.Now;
var correction = new EventScoreCorrection
{
Id = _idGenerator.NextId(),
EventId = sheet.EventId,
SessionId = sheet.SessionId,
SessionEntryId = sheet.SessionEntryId,
OriginalScoreSheetId = sheet.Id,
JudgeAssignmentId = sheet.JudgeAssignmentId,
JudgeRole = sheet.JudgeRole,
ApplyUserId = _authManager.UserId,
ApplyReason = input.Reason.Trim(),
// 后台发起本身即代表已批准,裁判端可直接重新评分。
CorrectionStatus = CorrectionStatusApproved,
ApproveUserId = _authManager.UserId,
ApproveRemark = "赛事管理员发起",
ApproveTime = now,
CreatedUserId = _authManager.UserId,
CreatedTime = now
};
await _correctionRepository.InsertAsync(correction);
await NotifyRefereeAsync(correction, sheet, "成绩修正通知",
$"请对{sheet.JudgeRole}号位的评分重新提交,原因:{correction.ApplyReason}");
return correction.Id;
}
/// <summary>
/// 审批裁判提交的成绩修正申请
/// </summary>
[HttpPost("corrections/approve")]
[DisplayName("审批成绩修正申请")]
[UnitOfWork]
public async Task ApproveCorrection([FromBody] ApproveJudgeCorrectionInput input)
{
var correction = await _correctionRepository.GetFirstAsync(x => x.Id == input.CorrectionId);
if (correction == null) throw Oops.Bah("修正申请不存在");
if (correction.CorrectionStatus != CorrectionStatusApplied)
throw Oops.Bah($"该申请当前为“{CorrectionStatusName(correction.CorrectionStatus)}”,不能重复审批");
var sheet = await _sheetRepository.GetFirstAsync(x => x.Id == correction.OriginalScoreSheetId);
if (sheet == null) throw Oops.Bah("被修正的评分单不存在");
var now = DateTime.Now;
correction.CorrectionStatus = input.Approved ? CorrectionStatusApproved : CorrectionStatusRejected;
correction.ApproveUserId = _authManager.UserId;
correction.ApproveRemark = input.ApproveRemark;
correction.ApproveTime = now;
if (!input.Approved) correction.CompletedTime = now;
correction.UpdatedUserId = _authManager.UserId;
correction.UpdatedTime = now;
await _correctionRepository.UpdateAsync(correction);
await NotifyRefereeAsync(correction, sheet,
input.Approved ? "成绩修正申请已通过" : "成绩修正申请被驳回",
input.Approved
? $"{sheet.JudgeRole}号位的修正申请已通过,请重新提交评分。"
: $"{sheet.JudgeRole}号位的修正申请未通过。{input.ApproveRemark}");
}
/// <summary>
/// 组装记分台数据,名次与成绩状态取已落库的成绩
/// </summary>
private async Task<JudgeScoreBoardOutput> BuildBoardAsync(ScoringContext ctx, List<EntryCalculationOutcome> outcomes)
{
var venue = await _venueRepository.GetFirstAsync(x => x.Id == ctx.Session.VenueId);
var output = new JudgeScoreBoardOutput
{
SessionId = ctx.Session.Id,
EventId = ctx.Session.EventId,
SessionName = ctx.Session.SessionName ?? ctx.Session.SessionNo,
VenueName = venue?.VenueName ?? string.Empty,
ProjectName = ctx.Project.Name,
RuleName = ctx.Rule.RuleName,
Formula = EntryResultCalculationService.BuildFormula(ctx.Config),
SessionStatus = ctx.Session.SessionStatus,
EntryCount = outcomes.Count,
CompletedCount = outcomes.Count(x => x.IsCompleted)
};
if (outcomes.Count == 0) return output;
var entryIds = outcomes.Select(x => (long?)x.SessionEntryId).ToList();
var results = await _resultRepository.GetListAsync(x => entryIds.Contains(x.SessionEntryId)
&& x.ResultStatus != EventScoreCalculationService.ResultStatusVoided);
var sheetIds = outcomes.SelectMany(x => x.Aggregate?.Symbols ?? new List<EntrySymbolScore>())
.SelectMany(x => x.Judges).Select(x => x.ScoreSheetId).Distinct().ToList();
var annotationUrls = sheetIds.Count == 0
? new Dictionary<long, string>()
: (await _attachmentRepository.GetListAsync(x => sheetIds.Contains(x.ScoreSheetId)
&& x.IsCurrent && x.AttachmentType == "score_annotation_png"))
.GroupBy(x => x.ScoreSheetId).ToDictionary(x => x.Key, x => x.OrderByDescending(y => y.CreatedTime).First().FileUrl);
// 一个出场(队伍)的多名运动员共享同一名次,取任意一条即可。
var resultByEntry = results.Where(x => x.SessionEntryId.HasValue)
.GroupBy(x => x.SessionEntryId!.Value).ToDictionary(x => x.Key, x => x.First());
foreach (var outcome in outcomes)
{
resultByEntry.TryGetValue(outcome.SessionEntryId, out var result);
var entry = new JudgeScoreBoardEntryOutput
{
SessionEntryId = outcome.SessionEntryId,
EntryNo = outcome.EntryNo,
ParticipantName = outcome.ParticipantName,
GroupName = outcome.GroupName,
IsCompleted = outcome.IsCompleted,
IsSkipped = outcome.IsSkipped,
SkipReason = outcome.SkipReason,
IsDisqualified = outcome.IsDisqualified,
TotalScore = outcome.IsDisqualified
? "取消资格"
: outcome.IsCompleted ? ctx.Config.Format(outcome.TotalScore) : string.Empty,
Rank = result?.Rank ?? 0,
ResultStatus = result?.ResultStatus ?? 0,
ResultStatusName = ResultStatusName(result?.ResultStatus ?? 0),
Progress = outcome.Roles.Select(role => new JudgeBoardRoleProgressOutput
{
RoleType = role.RoleType, RoleName = role.RoleName, Symbol = role.Symbol,
ExpectedCount = role.ExpectedCount, SubmittedCount = role.SubmittedCount,
PendingJudges = role.PendingJudges
}).ToList()
};
if (outcome.Aggregate != null)
{
entry.Symbols = outcome.Aggregate.Symbols.Select(symbol => new JudgeSymbolScoreOutput
{
Symbol = symbol.Symbol, Label = symbol.Label, RoleType = symbol.RoleType,
Aggregate = symbol.Aggregate, Sign = symbol.Sign, Value = ctx.Config.Format(symbol.Value),
Judges = symbol.Judges.Select(judge => new JudgeBoardSheetScoreOutput
{
ScoreSheetId = judge.ScoreSheetId, RefereeId = judge.RefereeId,
RefereeName = judge.JudgeName ?? string.Empty, JudgeRole = judge.JudgeRole,
JudgeRoleType = judge.JudgeRoleType, Value = ctx.Config.Format(judge.Value),
IsDisqualified = judge.IsDisqualified,
AnnotationUrl = annotationUrls.GetValueOrDefault(judge.ScoreSheetId)
}).ToList()
}).ToList();
}
output.Entries.Add(entry);
}
// 出场状态不在计算结果里,单独回填,前端据此区分退赛与未上场。
var plainIds = outcomes.Select(x => x.SessionEntryId).ToList();
var entries = await _entryRepository.GetListAsync(x => plainIds.Contains(x.Id));
foreach (var row in output.Entries)
{
var source = entries.FirstOrDefault(x => x.Id == row.SessionEntryId);
if (source == null) continue;
row.EntryStatus = source.EntryStatus;
row.PlayOrder = source.PlayOrder;
}
return output;
}
/// <summary>
/// 该评分单是否已有未结束的修正流程
/// </summary>
private async Task<bool> HasOpenCorrectionAsync(long scoreSheetId) =>
await _correctionRepository.IsAnyAsync(x => x.OriginalScoreSheetId == scoreSheetId
&& (x.CorrectionStatus == CorrectionStatusApplied
|| x.CorrectionStatus == CorrectionStatusApproved
|| x.CorrectionStatus == CorrectionStatusEditing));
/// <summary>
/// 给被修正的裁判发一条站内消息,裁判端在消息列表里看到修正提醒
/// </summary>
private async Task NotifyRefereeAsync(EventScoreCorrection correction, EventJudgeScoreSheet sheet,
string title, string content)
{
var receiverUserId = sheet.JudgeUserId;
if (!receiverUserId.HasValue)
{
var assignment = await _assignmentRepository.GetFirstAsync(x => x.Id == correction.JudgeAssignmentId);
receiverUserId = assignment?.JudgeUserId;
}
if (!receiverUserId.HasValue)
{
var referee = await _refereeRepository.GetFirstAsync(x => x.Id == sheet.RefereeId);
receiverUserId = referee?.AppUserId;
}
// 裁判还没绑定小程序账号时消息无处投递,此时只留修正记录,不阻断主流程。
if (!receiverUserId.HasValue) return;
await _messageRepository.InsertAsync(new EventJudgeMessage
{
Id = _idGenerator.NextId(),
EventId = correction.EventId,
ReceiverUserId = receiverUserId.Value,
RefereeId = sheet.RefereeId,
MessageType = MessageTypeCorrection,
Title = title,
Content = content.Length > 512 ? content[..512] : content,
RelationType = nameof(EventScoreCorrection),
RelationId = correction.Id,
IsRead = false,
CreatedUserId = _authManager.UserId,
CreatedTime = DateTime.Now
});
}
/// <summary>
/// 成绩状态名称
/// </summary>
private static string ResultStatusName(int status) => status switch
{
0 => "未生成",
EventScoreCalculationService.ResultStatusPendingReview => "待复核",
EventScoreCalculationService.ResultStatusConfirmed => "已确认",
EventScoreCalculationService.ResultStatusVoided => "已作废",
_ => status.ToString()
};
/// <summary>
/// 修正状态名称
/// </summary>
private static string CorrectionStatusName(int status) => status switch
{
CorrectionStatusApplied => "已申请",
CorrectionStatusApproved => "已批准",
CorrectionStatusRejected => "已拒绝",
CorrectionStatusEditing => "裁判修改中",
CorrectionStatusCompleted => "已完成",
CorrectionStatusCancelled => "已取消",
_ => status.ToString()
};
}