This commit is contained in:
马梓彭 2026-09-23 11:06:58 +08:00
commit 48ae547de9
2 changed files with 116 additions and 36 deletions

View File

@ -766,12 +766,32 @@ public class JudgeScoringController : IDynamicApiController
var messages = await _messageRepository.AsQueryable() var messages = await _messageRepository.AsQueryable()
.Where(x => x.RefereeId == referee.Id || x.ReceiverUserId == userId) .Where(x => x.RefereeId == referee.Id || x.ReceiverUserId == userId)
.WhereIF(onlyUnread == true, x => !x.IsRead) .WhereIF(onlyUnread == true, x => !x.IsRead)
.ToListAsync(); .ToListAsync())
.OrderByDescending(x => x.CreatedTime).ToList();
// 成绩修正只服务于进行中的赛事。赛事状态同步可能有延迟,因此同时结合
// 赛事时间计算实时状态;赛事结束后不再向裁判端返回对应通知。
var correctionEventIds = messages
.Where(IsScoreCorrectionMessage)
.Select(x => x.EventId)
.Distinct()
.ToList();
if (correctionEventIds.Count > 0)
{
var now = DateTime.Now;
var endedEventIds = (await _eventRepository.AsQueryable()
.Where(x => correctionEventIds.Contains(x.Id))
.ToListAsync())
.Where(x => GetEffectiveEventStatus(x, now) == EventStatus.Ended)
.Select(x => x.Id)
.ToHashSet();
messages = messages
.Where(x => !IsScoreCorrectionMessage(x) || !endedEventIds.Contains(x.EventId))
.ToList();
}
messages = messages.OrderByDescending(x => x.CreatedTime).ToList();
var correctionIds = messages var correctionIds = messages
.Where(x => string.Equals(x.RelationType, nameof(EventScoreCorrection), StringComparison.OrdinalIgnoreCase) .Where(x => IsScoreCorrectionMessage(x) && x.RelationId.HasValue)
&& x.RelationId.HasValue)
.Select(x => x.RelationId!.Value).Distinct().ToList(); .Select(x => x.RelationId!.Value).Distinct().ToList();
var corrections = correctionIds.Count == 0 var corrections = correctionIds.Count == 0
? new Dictionary<long, EventScoreCorrection>() ? new Dictionary<long, EventScoreCorrection>()
@ -1453,6 +1473,13 @@ public class JudgeScoringController : IDynamicApiController
return calculatedStatus; return calculatedStatus;
} }
/// <summary>
/// 兼容历史实体名和当前业务关系名两种成绩修正消息标识。
/// </summary>
private static bool IsScoreCorrectionMessage(EventJudgeMessage message) =>
string.Equals(message.RelationType, "ScoreCorrection", StringComparison.OrdinalIgnoreCase) ||
string.Equals(message.RelationType, nameof(EventScoreCorrection), StringComparison.OrdinalIgnoreCase);
/// <summary> /// <summary>
/// 场次状态名称 /// 场次状态名称
/// </summary> /// </summary>

View File

@ -4,6 +4,7 @@ using YD_Event.Application.Scoring.Dtos;
using YD_Event.Application.Workbench.Dtos; using YD_Event.Application.Workbench.Dtos;
using YD_Event.Core.Entities; using YD_Event.Core.Entities;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using System.Text.RegularExpressions;
namespace YD_Event.Application.Workbench; namespace YD_Event.Application.Workbench;
@ -196,7 +197,10 @@ public class WorkbenchController : IDynamicApiController
var eventProjectDict = eventProjects.ToDictionary(ep => ep.Id); var eventProjectDict = eventProjects.ToDictionary(ep => ep.Id);
sessions = sessions sessions = sessions
.OrderBy(s => eventProjectDict.TryGetValue(s.EventProjectId, out var eventProject) // 场次号末段保存了秩序册预览中的全局编排序号。先按该序号排序,
// 前端再按项目合并时,项目顺序便与它在秩序册中首次出现的顺序一致。
.OrderBy(s => GetArrangementSequence(s.SessionNo))
.ThenBy(s => eventProjectDict.TryGetValue(s.EventProjectId, out var eventProject)
&& projectDict.TryGetValue(eventProject.ProjectId, out var project) && projectDict.TryGetValue(eventProject.ProjectId, out var project)
? project.SortIndex ? project.SortIndex
: int.MaxValue) : int.MaxValue)
@ -363,6 +367,13 @@ public class WorkbenchController : IDynamicApiController
.OrderBy(s => s.JudgeRole) .OrderBy(s => s.JudgeRole)
.ToListAsync(); .ToListAsync();
// 表头必须以场次裁判分配为准,不能等评分单生成后才出现裁判列。
var assignments = await _assignmentRepository.AsQueryable()
.Where(a => !a.DeleteMark && a.SessionId == sessionId && a.AssignmentStatus < 9 &&
a.Status == Core.Enum.AvailabilityStatus.Enable)
.OrderBy(a => a.JudgeRole)
.ToListAsync();
// 批量查询当前评分单的动态评分项明细,按评分单分组挂到各裁判评分下 // 批量查询当前评分单的动态评分项明细,按评分单分组挂到各裁判评分下
var sheetIds = sheets.Select(s => s.Id).ToList(); var sheetIds = sheets.Select(s => s.Id).ToList();
var scoreItems = await _scoreDetailRepository.AsQueryable() var scoreItems = await _scoreDetailRepository.AsQueryable()
@ -382,7 +393,8 @@ public class WorkbenchController : IDynamicApiController
d.Sort d.Sort
}).ToListAsync(); }).ToListAsync();
var refereeIds = sheets.Select(s => s.RefereeId).Distinct().ToList(); var refereeIds = assignments.Select(a => a.RefereeId)
.Concat(sheets.Select(s => s.RefereeId)).Distinct().ToList();
var refereeMap = (await _refereeRepository.AsQueryable() var refereeMap = (await _refereeRepository.AsQueryable()
.Where(r => refereeIds.Contains(r.Id)) .Where(r => refereeIds.Contains(r.Id))
.Select(r => new { r.Id, r.Name }) .Select(r => new { r.Id, r.Name })
@ -401,11 +413,62 @@ public class WorkbenchController : IDynamicApiController
.ToDictionary(g => g.Key, g => g.OrderByDescending(r => r.ResultVersion) .ToDictionary(g => g.Key, g => g.OrderByDescending(r => r.ResultVersion)
.ThenBy(r => r.Id).First()); .ThenBy(r => r.Id).First());
WorkbenchJudgeScoreDto MapSheet(EventJudgeScoreSheet sheet) => new()
{
ScoreSheetId = sheet.Id,
JudgeRole = sheet.JudgeRole,
JudgeRoleType = sheet.JudgeRoleType,
JudgeRoleName = JudgeRoleSchemaService.RoleNameOf(roleSlots, sheet.JudgeRoleType),
JudgeName = refereeMap.GetValueOrDefault(sheet.RefereeId, ""),
SheetStatus = sheet.SheetStatus,
SheetStatusName = GetSheetStatusName(sheet.SheetStatus),
DifficultyScore = sheet.DifficultyScore,
PerformanceScore = sheet.PerformanceScore,
RequiredScore = sheet.RequiredScore,
DeductionScore = sheet.DeductionScore,
TotalScore = sheet.TotalScore,
IsDisqualified = sheet.IsDisqualified,
SubmittedTime = sheet.SubmittedTime,
HasPendingCorrection = pendingCorrectionSet.Contains(sheet.Id),
ScoreItems = scoreItems.Where(d => d.ScoreSheetId == sheet.Id).Select(d => new WorkbenchScoreItemDto
{
ItemCode = d.ItemCode,
ItemName = d.ItemName,
SubjectCode = d.SubjectCode,
ItemType = d.ItemType,
ScoreDimension = d.ScoreDimension,
CountValue = d.CountValue,
InputValue = d.InputValue,
Subtotal = d.Subtotal,
Sort = d.Sort
}).ToList()
};
return entries.Select(e => return entries.Select(e =>
{ {
var result = resultDict.GetValueOrDefault(e.Id); var result = resultDict.GetValueOrDefault(e.Id);
var entrySheets = sheets.Where(s => s.SessionEntryId == e.Id).ToList(); var entrySheets = sheets.Where(s => s.SessionEntryId == e.Id).ToList();
var assignedScores = assignments.Select(assignment =>
{
var sheet = entrySheets.FirstOrDefault(s => s.RefereeId == assignment.RefereeId &&
s.JudgeRole == assignment.JudgeRole);
return sheet != null ? MapSheet(sheet) : new WorkbenchJudgeScoreDto
{
ScoreSheetId = 0,
JudgeRole = assignment.JudgeRole,
JudgeRoleType = assignment.JudgeRoleType ?? string.Empty,
JudgeRoleName = JudgeRoleSchemaService.RoleNameOf(roleSlots, assignment.JudgeRoleType ?? string.Empty),
JudgeName = refereeMap.GetValueOrDefault(assignment.RefereeId, ""),
SheetStatus = 0,
SheetStatusName = "待提交"
};
}).ToList();
var assignmentKeys = assignments.Select(a => $"{a.RefereeId}:{a.JudgeRole}").ToHashSet();
assignedScores.AddRange(entrySheets
.Where(sheet => !assignmentKeys.Contains($"{sheet.RefereeId}:{sheet.JudgeRole}"))
.Select(MapSheet));
return new WorkbenchEntryDetailDto return new WorkbenchEntryDetailDto
{ {
SessionEntryId = e.Id, SessionEntryId = e.Id,
@ -438,36 +501,7 @@ public class WorkbenchController : IDynamicApiController
ReviewTime = result.ReviewTime, ReviewTime = result.ReviewTime,
Rank = result.Rank Rank = result.Rank
} : null, } : null,
JudgeScores = entrySheets.Select(sheet => new WorkbenchJudgeScoreDto JudgeScores = assignedScores
{
ScoreSheetId = sheet.Id,
JudgeRole = sheet.JudgeRole,
JudgeRoleType = sheet.JudgeRoleType,
JudgeRoleName = JudgeRoleSchemaService.RoleNameOf(roleSlots, sheet.JudgeRoleType),
JudgeName = refereeMap.GetValueOrDefault(sheet.RefereeId, ""),
SheetStatus = sheet.SheetStatus,
SheetStatusName = GetSheetStatusName(sheet.SheetStatus),
DifficultyScore = sheet.DifficultyScore,
PerformanceScore = sheet.PerformanceScore,
RequiredScore = sheet.RequiredScore,
DeductionScore = sheet.DeductionScore,
TotalScore = sheet.TotalScore,
IsDisqualified = sheet.IsDisqualified,
SubmittedTime = sheet.SubmittedTime,
HasPendingCorrection = pendingCorrectionSet.Contains(sheet.Id),
ScoreItems = scoreItems.Where(d => d.ScoreSheetId == sheet.Id).Select(d => new WorkbenchScoreItemDto
{
ItemCode = d.ItemCode,
ItemName = d.ItemName,
SubjectCode = d.SubjectCode,
ItemType = d.ItemType,
ScoreDimension = d.ScoreDimension,
CountValue = d.CountValue,
InputValue = d.InputValue,
Subtotal = d.Subtotal,
Sort = d.Sort
}).ToList()
}).ToList()
}; };
}).ToList(); }).ToList();
} }
@ -1972,6 +2006,25 @@ public class WorkbenchController : IDynamicApiController
#region 辅助方法 #region 辅助方法
/// <summary>
/// 获取场次在秩序册/自动编排中的全局顺序。
/// 秩序册导入及花样赛自动编排生成的场次号末段均保存该顺序;
/// 无全局序号的速度项目回退到项目配置及场地顺序。
/// </summary>
private static int GetArrangementSequence(string? sessionNo)
{
if (string.IsNullOrWhiteSpace(sessionNo)) return int.MaxValue;
var match = Regex.Match(sessionNo, @"^EP\d+-(?:V)?\d+(?:-(?<sequence>\d+))?$",
RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
if (!match.Success) return int.MaxValue;
return match.Groups["sequence"].Success &&
int.TryParse(match.Groups["sequence"].Value, out var sequence)
? sequence
: int.MaxValue;
}
private static string GetSessionStatusName(int status) private static string GetSessionStatusName(int status)
{ {
return status switch return status switch