update:编排顺序
This commit is contained in:
parent
57df359e53
commit
6e19fce024
@ -135,6 +135,11 @@ public class JudgeSessionDto
|
|||||||
/// 我已提交评分的出场数
|
/// 我已提交评分的出场数
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int ScoredCount { get; set; }
|
public int ScoredCount { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 场次在赛事编排中的顺序
|
||||||
|
/// </summary>
|
||||||
|
public int ArrangementOrder { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -157,6 +162,11 @@ public class JudgeEntryDto
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public int PlayOrder { get; set; }
|
public int PlayOrder { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 秩序册中的全局出场顺序;非秩序册数据为0
|
||||||
|
/// </summary>
|
||||||
|
public long ScheduleOrder { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 参赛者/参赛队名称
|
/// 参赛者/参赛队名称
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -643,6 +653,11 @@ public class SaveJudgeScoreInput
|
|||||||
/// 各项评分录入值
|
/// 各项评分录入值
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public List<JudgeScoreItemInput> Items { get; set; } = new();
|
public List<JudgeScoreItemInput> Items { get; set; } = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 主裁花样赛扣分系数(各扣分项合计值,不是最终得分系数 M)
|
||||||
|
/// </summary>
|
||||||
|
public decimal? DeductionCoefficient { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -660,6 +675,11 @@ public class SubmitJudgeScoreInput
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public List<JudgeScoreItemInput> Items { get; set; } = new();
|
public List<JudgeScoreItemInput> Items { get; set; } = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 主裁花样赛扣分系数(各扣分项合计值,不是最终得分系数 M)
|
||||||
|
/// </summary>
|
||||||
|
public decimal? DeductionCoefficient { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 幂等键,取评分表接口返回值。弱网重试时同一幂等键只会提交一次。
|
/// 幂等键,取评分表接口返回值。弱网重试时同一幂等键只会提交一次。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@ -162,14 +162,14 @@ public class JudgeScoringController : IDynamicApiController
|
|||||||
.ToListAsync()).ToDictionary(x => x.Id);
|
.ToListAsync()).ToDictionary(x => x.Id);
|
||||||
|
|
||||||
sessions = sessions
|
sessions = sessions
|
||||||
.OrderBy(x => eventProjects.TryGetValue(x.EventProjectId, out var eventProject)
|
.OrderBy(x => GetArrangementSequence(x.SessionNo))
|
||||||
|
.ThenBy(x => eventProjects.TryGetValue(x.EventProjectId, out var eventProject)
|
||||||
&& projects.TryGetValue(eventProject.ProjectId, out var project)
|
&& projects.TryGetValue(eventProject.ProjectId, out var project)
|
||||||
? project.SortIndex
|
? project.SortIndex
|
||||||
: int.MaxValue)
|
: int.MaxValue)
|
||||||
.ThenBy(x => eventProjects.TryGetValue(x.EventProjectId, out var eventProject)
|
.ThenBy(x => eventProjects.TryGetValue(x.EventProjectId, out var eventProject)
|
||||||
? eventProject.ProjectId
|
? eventProject.ProjectId
|
||||||
: long.MaxValue)
|
: long.MaxValue)
|
||||||
.ThenBy(x => GetArrangementSequence(x.SessionNo))
|
|
||||||
.ThenBy(x => venues.TryGetValue(x.VenueId, out var venue) ? venue.Sort : int.MaxValue)
|
.ThenBy(x => venues.TryGetValue(x.VenueId, out var venue) ? venue.Sort : int.MaxValue)
|
||||||
.ThenBy(x => x.SessionNo)
|
.ThenBy(x => x.SessionNo)
|
||||||
.ThenBy(x => x.Id)
|
.ThenBy(x => x.Id)
|
||||||
@ -216,7 +216,11 @@ public class JudgeScoringController : IDynamicApiController
|
|||||||
JudgeRoleType = roleType,
|
JudgeRoleType = roleType,
|
||||||
JudgeRoleName = slot?.Name ?? JudgeRoleSchemaService.RoleName(roleType),
|
JudgeRoleName = slot?.Name ?? JudgeRoleSchemaService.RoleName(roleType),
|
||||||
EntryCount = entries.Count(x => x.SessionId == session.Id),
|
EntryCount = entries.Count(x => x.SessionId == session.Id),
|
||||||
ScoredCount = mySheets.Count(x => x.SessionId == session.Id)
|
ScoredCount = mySheets.Count(x => x.SessionId == session.Id),
|
||||||
|
ArrangementOrder = GetArrangementSequence(session.SessionNo) is var order
|
||||||
|
&& order < int.MaxValue
|
||||||
|
? order
|
||||||
|
: 0
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return rows;
|
return rows;
|
||||||
@ -266,7 +270,10 @@ public class JudgeScoringController : IDynamicApiController
|
|||||||
var config = ScoreRuleConfigService.Parse(
|
var config = ScoreRuleConfigService.Parse(
|
||||||
(await _ruleRepository.GetFirstAsync(x => x.Id == session.ScoreRuleId))?.RuleConfigJson);
|
(await _ruleRepository.GetFirstAsync(x => x.Id == session.ScoreRuleId))?.RuleConfigJson);
|
||||||
|
|
||||||
var entries = (await _entryRepository.AsQueryable().Where(x => x.SessionId == sessionId).ToListAsync())
|
var entries = (await _entryRepository.AsQueryable()
|
||||||
|
.Where(x => x.SessionId == sessionId && !x.IsVoided &&
|
||||||
|
x.Status == AvailabilityStatus.Enable && !x.DeleteMark)
|
||||||
|
.ToListAsync())
|
||||||
.OrderBy(x => x.PlayOrder).ThenBy(x => x.Id).ToList();
|
.OrderBy(x => x.PlayOrder).ThenBy(x => x.Id).ToList();
|
||||||
if (entries.Count == 0) return new List<JudgeEntryDto>();
|
if (entries.Count == 0) return new List<JudgeEntryDto>();
|
||||||
var entryIds = entries.Select(x => x.Id).ToList();
|
var entryIds = entries.Select(x => x.Id).ToList();
|
||||||
@ -289,6 +296,7 @@ public class JudgeScoringController : IDynamicApiController
|
|||||||
SessionEntryId = entry.Id,
|
SessionEntryId = entry.Id,
|
||||||
EntryNo = entry.EntryNo,
|
EntryNo = entry.EntryNo,
|
||||||
PlayOrder = entry.PlayOrder,
|
PlayOrder = entry.PlayOrder,
|
||||||
|
ScheduleOrder = entry.SourceType == 1 ? entry.Id : 0,
|
||||||
ParticipantName = string.IsNullOrWhiteSpace(entry.TeamName) ? entry.ParticipantName : entry.TeamName!,
|
ParticipantName = string.IsNullOrWhiteSpace(entry.TeamName) ? entry.ParticipantName : entry.TeamName!,
|
||||||
GroupName = entry.GroupName,
|
GroupName = entry.GroupName,
|
||||||
EntryStatus = entry.EntryStatus,
|
EntryStatus = entry.EntryStatus,
|
||||||
@ -364,7 +372,11 @@ public class JudgeScoringController : IDynamicApiController
|
|||||||
ProjectName = ctx.Project.Name,
|
ProjectName = ctx.Project.Name,
|
||||||
RuleName = ctx.Rule.RuleName,
|
RuleName = ctx.Rule.RuleName,
|
||||||
GroupName = entry.GroupName,
|
GroupName = entry.GroupName,
|
||||||
SessionVenue = $"{ctx.Session.SessionName ?? ctx.Session.SessionNo}-{venue?.VenueName ?? "-"}",
|
SessionVenue = BuildSessionVenue(
|
||||||
|
ctx.Session,
|
||||||
|
ctx.Project.Name,
|
||||||
|
entry.GroupName,
|
||||||
|
venue?.VenueName ?? "-"),
|
||||||
EntryNo = entry.EntryNo,
|
EntryNo = entry.EntryNo,
|
||||||
ParticipantName = string.IsNullOrWhiteSpace(entry.TeamName) ? entry.ParticipantName : entry.TeamName!,
|
ParticipantName = string.IsNullOrWhiteSpace(entry.TeamName) ? entry.ParticipantName : entry.TeamName!,
|
||||||
MemberNames = members,
|
MemberNames = members,
|
||||||
@ -440,6 +452,7 @@ public class JudgeScoringController : IDynamicApiController
|
|||||||
throw Oops.Bah("已提交评分,如需修改请先申请成绩修正");
|
throw Oops.Bah("已提交评分,如需修改请先申请成绩修正");
|
||||||
|
|
||||||
var calculation = ScoreSheetCalculationService.Calculate(definitions, ToInputValues(input.Items), ctx.Config, false);
|
var calculation = ScoreSheetCalculationService.Calculate(definitions, ToInputValues(input.Items), ctx.Config, false);
|
||||||
|
ValidateDeductionCoefficient(input.DeductionCoefficient, calculation, ctx.Config, roleType);
|
||||||
var task = await EnsureTaskAsync(entry, ctx, assignment, roleType, submitted == null ? 0 : TaskTypeCorrection);
|
var task = await EnsureTaskAsync(entry, ctx, assignment, roleType, submitted == null ? 0 : TaskTypeCorrection);
|
||||||
var draft = await _sheetRepository.GetFirstAsync(x => x.SessionEntryId == entry.Id
|
var draft = await _sheetRepository.GetFirstAsync(x => x.SessionEntryId == entry.Id
|
||||||
&& x.JudgeAssignmentId == assignment.Id && x.SheetStatus == SheetStatusDraft);
|
&& x.JudgeAssignmentId == assignment.Id && x.SheetStatus == SheetStatusDraft);
|
||||||
@ -497,6 +510,7 @@ public class JudgeScoringController : IDynamicApiController
|
|||||||
|
|
||||||
// 正式提交才校验必填项与取值范围。
|
// 正式提交才校验必填项与取值范围。
|
||||||
var calculation = ScoreSheetCalculationService.Calculate(definitions, ToInputValues(input.Items), ctx.Config, true);
|
var calculation = ScoreSheetCalculationService.Calculate(definitions, ToInputValues(input.Items), ctx.Config, true);
|
||||||
|
ValidateDeductionCoefficient(input.DeductionCoefficient, calculation, ctx.Config, roleType);
|
||||||
var task = await EnsureTaskAsync(entry, ctx, assignment, roleType, correction == null ? 0 : TaskTypeCorrection);
|
var task = await EnsureTaskAsync(entry, ctx, assignment, roleType, correction == null ? 0 : TaskTypeCorrection);
|
||||||
var draft = await _sheetRepository.GetFirstAsync(x => x.SessionEntryId == entry.Id
|
var draft = await _sheetRepository.GetFirstAsync(x => x.SessionEntryId == entry.Id
|
||||||
&& x.JudgeAssignmentId == assignment.Id && x.SheetStatus == SheetStatusDraft);
|
&& x.JudgeAssignmentId == assignment.Id && x.SheetStatus == SheetStatusDraft);
|
||||||
@ -1145,6 +1159,31 @@ public class JudgeScoringController : IDynamicApiController
|
|||||||
CountValue = x.CountValue
|
CountValue = x.CountValue
|
||||||
}).ToList();
|
}).ToList();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 校验主裁端上传的扣分系数。最终得分系数 M 仍由平台按 1-扣分系数计算,
|
||||||
|
/// 这里不信任客户端结果,只用于确认页面明细与上传系数属于同一评分快照。
|
||||||
|
/// </summary>
|
||||||
|
private static void ValidateDeductionCoefficient(decimal? uploaded,
|
||||||
|
ScoreSheetCalculationResult calculation, ScoreRuleConfig config, string roleType)
|
||||||
|
{
|
||||||
|
if (uploaded == null) return; // 兼容尚未升级的裁判端。
|
||||||
|
if (!config.IsFactorTotal || !string.Equals(
|
||||||
|
JudgeRoleSchemaService.NormalizeRoleType(roleType),
|
||||||
|
JudgeRoleSchemaService.RoleChief,
|
||||||
|
StringComparison.OrdinalIgnoreCase))
|
||||||
|
throw Oops.Bah("当前评分表不支持上传扣分系数");
|
||||||
|
|
||||||
|
if (uploaded < 0m || uploaded > 1m)
|
||||||
|
throw Oops.Bah("扣分系数必须在0至1之间");
|
||||||
|
|
||||||
|
// 明细行保留了递进扣分的未舍入小计,用它校验 0.125 等三位小数系数。
|
||||||
|
var expected = calculation.Lines
|
||||||
|
.Where(x => x.ScoreDimension == ScoreDimensionCode.Deduction)
|
||||||
|
.Sum(x => x.Subtotal);
|
||||||
|
if (Math.Abs(uploaded.Value - expected) > 0.0005m)
|
||||||
|
throw Oops.Bah($"扣分系数与扣分明细不一致,应为{expected:0.###}");
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 组装合计预览
|
/// 组装合计预览
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -1275,6 +1314,43 @@ public class JudgeScoringController : IDynamicApiController
|
|||||||
: 0;
|
: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 构建裁判端展示用的“场次-场地”,去除秩序册导入时写入场次名的项目和组别信息。
|
||||||
|
/// </summary>
|
||||||
|
private static string BuildSessionVenue(
|
||||||
|
EventSession session,
|
||||||
|
string projectName,
|
||||||
|
string groupName,
|
||||||
|
string venueName)
|
||||||
|
{
|
||||||
|
var sessionName = session.SessionName ?? string.Empty;
|
||||||
|
foreach (var redundant in new[] { projectName, groupName, venueName })
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrWhiteSpace(redundant))
|
||||||
|
sessionName = sessionName.Replace(
|
||||||
|
redundant,
|
||||||
|
string.Empty,
|
||||||
|
StringComparison.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
sessionName = Regex.Replace(
|
||||||
|
sessionName,
|
||||||
|
@"^[\s·|/_—–-]+|[\s·|/_—–-]+$",
|
||||||
|
string.Empty).Trim();
|
||||||
|
if (string.IsNullOrWhiteSpace(sessionName))
|
||||||
|
{
|
||||||
|
var arrangementOrder = GetArrangementSequence(session.SessionNo);
|
||||||
|
sessionName = arrangementOrder > 0 && arrangementOrder < int.MaxValue
|
||||||
|
? $"第{arrangementOrder}场"
|
||||||
|
: session.SessionNo;
|
||||||
|
}
|
||||||
|
|
||||||
|
return string.IsNullOrWhiteSpace(venueName)
|
||||||
|
|| sessionName.Contains(venueName, StringComparison.OrdinalIgnoreCase)
|
||||||
|
? sessionName
|
||||||
|
: $"{sessionName}-{venueName}";
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取用于裁判场次选择的赛事实时状态,避免后台状态同步延迟导致比赛中场次不可见。
|
/// 获取用于裁判场次选择的赛事实时状态,避免后台状态同步延迟导致比赛中场次不可见。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user