工作台裁判列按裁判类型展示对应分值,不再统一错误地读取评分单总分。

主裁列现在展示最终汇总扣分,已包含表现裁判和主裁的失误次数平均换算结果。
This commit is contained in:
ltx 2026-09-28 14:26:18 +08:00
parent 100764fde7
commit 44065282e3
5 changed files with 71 additions and 24 deletions

View File

@ -129,7 +129,7 @@ public class ScoreItemDefinition
public List<decimal>? StepDeductions { get; set; }
/// <summary>
/// 规定元素目标完成量(个人花样、车轮跳花样默认 4),只配在缺失数自动项上
/// 规定元素目标完成量(个人花样为 4,车轮跳花样为 4 类 × 每类 4 个),只配在缺失数自动项上
/// </summary>
public decimal? RequiredTarget { get; set; }

View File

@ -431,12 +431,12 @@ public class JudgeScoreItemDto
public List<decimal>? StepDeductions { get; set; }
/// <summary>
/// 规定元素目标完成量(个人花样、车轮跳花样为 4)
/// 规定元素目标完成量(个人花样为 4,车轮跳花样为 16)
/// </summary>
public decimal? RequiredTarget { get; set; }
/// <summary>
/// 规定元素是否按类别计完成量。true 时该类别录入数量大于 0 即计一类(车轮跳花样),
/// 规定元素是否按类别计完成量。true 时该类别录入数量大于 0 即计一类(如表演赛),
/// false 时按数量 × 单位分值折算(个人花样 3 级及以上按 1 计、2 级及以下按 0.5 计)。
/// </summary>
public bool RequiredAsCategory { get; set; }

View File

@ -104,9 +104,14 @@ public static class FreestyleRuleDefinition
public const decimal RequiredMissingUnit = 0.025m;
/// <summary>
/// 车轮跳花样的规定元素目标类别数(力量和体操、多摇、绳子运用、互动配合)
/// 车轮跳花样每类规定元素的要求完成数量。
/// </summary>
public const decimal WheelRequiredTarget = 4m;
public const decimal WheelRequiredCountPerElement = 4m;
/// <summary>
/// 车轮跳花样规定元素应完成总数:4 类 × 每类 4 个。
/// </summary>
public static decimal WheelRequiredTarget => WheelRequiredElements.Count * WheelRequiredCountPerElement;
/// <summary>
/// 摇绳运动员难度取用的动作数(少于 20 个动作时分母仍按 20)
@ -241,7 +246,7 @@ public static class FreestyleRuleDefinition
items.AddRange(BuildPerformanceItems(ref sort));
items.AddRange(BuildChiefDeductionItems("T_INTERVAL", "间歇", ref sort));
// 规定元素:每类只要有动作即计一类完成,缺失类别数由服务端算出后参与 Q。
// 规定元素:4 类元素每类均需完成 4 个,未完成数由服务端算出后参与 Q。
foreach (var element in WheelRequiredElements)
{
items.Add(new PrescribedRuleItemDefinition
@ -249,9 +254,9 @@ public static class FreestyleRuleDefinition
JudgeRoleType = RoleChief, ItemCode = element.ItemCode, ItemName = element.ItemName,
ItemType = ScoreItemType.RequiredElement, ScoreDimension = ScoreDimensionType.Required,
CalcMode = ScoreCalcMode.CountByUnit,
UnitValue = 1m, MinValue = 0m, MaxValue = 50m, StepValue = 1m, DefaultValue = 0m,
UnitValue = 1m, MinValue = 0m, MaxValue = WheelRequiredCountPerElement, StepValue = 1m, DefaultValue = 0m,
IsRequired = false, Sort = ++sort,
ExtensionJson = FreestyleItemExtension.RequiredElement()
ExtensionJson = FreestyleItemExtension.Count("个")
});
}
items.Add(new PrescribedRuleItemDefinition
@ -519,7 +524,7 @@ public static class FreestyleItemExtension
new JObject { ["inputMode"] = "count", ["unitLabel"] = unitLabel }.ToString(Formatting.None);
/// <summary>
/// 规定元素类别项:录入数量大于 0 即计一类完成
/// 规定元素类别项:录入数量大于 0 即计一类完成(表演赛使用)。
/// </summary>
public static string RequiredElement() =>
new JObject

View File

@ -7,6 +7,13 @@ namespace YD_Event.Application.Scoring;
/// </summary>
public static class ScoreSheetCalculationService
{
private const decimal WheelRequiredCountPerElement = 4m;
private const decimal WheelRequiredTotal = 16m;
private static readonly string[] WheelRequiredElementCodes =
{
"REQ_STRENGTH_GYMNASTICS", "REQ_MULTIPLE_ROPE", "REQ_ROPE_MANIPULATION", "REQ_INTERACTION"
};
/// <summary>
/// 按项目类型判断评分项适用范围
/// </summary>
@ -24,18 +31,23 @@ public static class ScoreSheetCalculationService
/// </summary>
public static List<ScoreItemDefinition> ResolveItems(IEnumerable<ScoreRuleItem> ruleItems, string judgeRoleType, string scope)
{
return ruleItems
var matchedItems = ruleItems
.Where(x => string.Equals(x.JudgeRoleType, judgeRoleType, StringComparison.OrdinalIgnoreCase))
.Where(x => MatchScope(x, scope))
.OrderBy(x => x.ItemType).ThenBy(x => x.Sort).ThenBy(x => x.Id)
.Select(x => CreateDefinition(x, scope))
.ToList();
var isWheelRequiredRule = WheelRequiredElementCodes.All(code => matchedItems.Any(item =>
string.Equals(item.ItemCode, code, StringComparison.OrdinalIgnoreCase)));
return matchedItems.Select(x => CreateDefinition(x, scope, isWheelRequiredRule)).ToList();
}
/// <summary>
/// 解析评分项定义。scope 为 personal 或 team,用于取对应的分值上限。
/// </summary>
public static ScoreItemDefinition CreateDefinition(ScoreRuleItem item, string scope)
public static ScoreItemDefinition CreateDefinition(ScoreRuleItem item, string scope) =>
CreateDefinition(item, scope, false);
private static ScoreItemDefinition CreateDefinition(ScoreRuleItem item, string scope, bool isWheelRequiredRule)
{
var definition = new ScoreItemDefinition
{
@ -51,7 +63,11 @@ public static class ScoreSheetCalculationService
// 扩展配置由人工维护,格式不合法时按无扩展配置处理,评分项本身仍然可用。
try { extension = JObject.Parse(item.ExtensionJson); } catch (JsonException) { extension = null; }
}
if (extension == null) return definition;
if (extension == null)
{
ApplyWheelRequiredElementCompatibility(item, definition, isWheelRequiredRule);
return definition;
}
definition.InputMode = extension["inputMode"]?.ToString() ?? definition.InputMode;
definition.UnitLabel = extension["unitLabel"]?.ToString();
@ -81,9 +97,31 @@ public static class ScoreSheetCalculationService
definition.StepDeductions = stepDeductions
.Select(x => ReadDecimal(x)).Where(x => x.HasValue).Select(x => x!.Value).ToList();
}
ApplyWheelRequiredElementCompatibility(item, definition, isWheelRequiredRule);
return definition;
}
/// <summary>
/// 兼容尚未执行规则数据更新的环境:车轮跳 4 类规定元素每类均需完成 4 个。
/// </summary>
private static void ApplyWheelRequiredElementCompatibility(ScoreRuleItem item, ScoreItemDefinition definition,
bool isWheelRequiredRule)
{
if (!isWheelRequiredRule) return;
if (WheelRequiredElementCodes.Contains(item.ItemCode, StringComparer.OrdinalIgnoreCase))
{
definition.MaxValue = WheelRequiredCountPerElement;
definition.StepValue = 1m;
definition.RequiredAsCategory = false;
return;
}
if (!string.Equals(item.ItemCode, "REQUIRED_MISSING", StringComparison.OrdinalIgnoreCase)) return;
definition.MaxValue = WheelRequiredTotal;
definition.RequiredTarget = WheelRequiredTotal;
}
/// <summary>
/// 读取扩展配置里的文本,空白按未配置处理
/// </summary>
@ -155,6 +193,9 @@ public static class ScoreSheetCalculationService
inputMap.TryGetValue(definition.ItemCode, out var input);
var line = BuildLine(definition, input, requireAll);
if (line == null) continue;
// 难度裁判端的单项小计与规则展示精度保持一致。
if (definition.Item.ScoreDimension == ScoreDimensionCode.Difficulty)
line.Subtotal = config.Round(line.Subtotal);
result.Lines.Add(line);
if (definition.IsDisqualifyReason)
@ -348,7 +389,8 @@ public static class ScoreSheetCalculationService
/// <summary>
/// 规定元素完成量与缺失量。
/// 按数量折算时(个人花样)3 级及以上按 1 计、2 级及以下按 0.5 计;
/// 按类别计数时(车轮跳花样)每个类别只要录入数量大于 0 就计一类。
/// 按类别计数时(如表演赛)每个类别只要录入数量大于 0 就计一类;
/// 车轮跳花样按实际完成数累加,4 类元素每类上限 4 个。
/// 缺失量 = max(0, 目标数 - 完成量),作为自动项落明细,供跨裁判聚合按 Q = 1 - 系数 × 缺失量 计算。
/// </summary>
private static void ApplyRequiredElements(List<ScoreItemDefinition> definitions,

View File

@ -1285,13 +1285,13 @@
"ParentItemCode": null,
"UnitValue": 1,
"MinValue": 0,
"MaxValue": 50,
"MaxValue": 4,
"StepValue": 1,
"DefaultValue": 0,
"CalcMode": 0,
"ScoreDimension": 3,
"IsRequired": false,
"ExtensionJson": "{\"inputMode\":\"count\",\"unitLabel\":\"个\",\"requiredAsCategory\":true}",
"ExtensionJson": "{\"inputMode\":\"count\",\"unitLabel\":\"个\"}",
"Sort": 40,
"DeleteMark": false,
"CreatedUserId": 1000,
@ -1307,13 +1307,13 @@
"ParentItemCode": null,
"UnitValue": 1,
"MinValue": 0,
"MaxValue": 50,
"MaxValue": 4,
"StepValue": 1,
"DefaultValue": 0,
"CalcMode": 0,
"ScoreDimension": 3,
"IsRequired": false,
"ExtensionJson": "{\"inputMode\":\"count\",\"unitLabel\":\"个\",\"requiredAsCategory\":true}",
"ExtensionJson": "{\"inputMode\":\"count\",\"unitLabel\":\"个\"}",
"Sort": 41,
"DeleteMark": false,
"CreatedUserId": 1000,
@ -1329,13 +1329,13 @@
"ParentItemCode": null,
"UnitValue": 1,
"MinValue": 0,
"MaxValue": 50,
"MaxValue": 4,
"StepValue": 1,
"DefaultValue": 0,
"CalcMode": 0,
"ScoreDimension": 3,
"IsRequired": false,
"ExtensionJson": "{\"inputMode\":\"count\",\"unitLabel\":\"个\",\"requiredAsCategory\":true}",
"ExtensionJson": "{\"inputMode\":\"count\",\"unitLabel\":\"个\"}",
"Sort": 42,
"DeleteMark": false,
"CreatedUserId": 1000,
@ -1351,13 +1351,13 @@
"ParentItemCode": null,
"UnitValue": 1,
"MinValue": 0,
"MaxValue": 50,
"MaxValue": 4,
"StepValue": 1,
"DefaultValue": 0,
"CalcMode": 0,
"ScoreDimension": 3,
"IsRequired": false,
"ExtensionJson": "{\"inputMode\":\"count\",\"unitLabel\":\"个\",\"requiredAsCategory\":true}",
"ExtensionJson": "{\"inputMode\":\"count\",\"unitLabel\":\"个\"}",
"Sort": 43,
"DeleteMark": false,
"CreatedUserId": 1000,
@ -1373,13 +1373,13 @@
"ParentItemCode": null,
"UnitValue": null,
"MinValue": 0,
"MaxValue": 4,
"MaxValue": 16,
"StepValue": 1,
"DefaultValue": 0,
"CalcMode": 1,
"ScoreDimension": 0,
"IsRequired": false,
"ExtensionJson": "{\"inputMode\":\"score\",\"isAuto\":true,\"unitLabel\":\"个\",\"requiredTarget\":4.0}",
"ExtensionJson": "{\"inputMode\":\"score\",\"isAuto\":true,\"unitLabel\":\"个\",\"requiredTarget\":16.0}",
"Sort": 44,
"DeleteMark": false,
"CreatedUserId": 1000,