YD_Event.Admin/YD_Event.Application/Scoring/ScoreRuleConfigService.cs

85 lines
4.1 KiB
C#

using YD_Event.Application.Scoring.Dtos;
namespace YD_Event.Application.Scoring;
/// <summary>
/// 计分规则配置解析服务
/// </summary>
public static class ScoreRuleConfigService
{
/// <summary>
/// 解析计分规则配置,配置缺失或格式不合法时回退到规定赛的默认配置,避免整场比赛因一处配置错误无法计分。
/// </summary>
public static ScoreRuleConfig Parse(string? configJson)
{
var config = new ScoreRuleConfig();
if (string.IsNullOrWhiteSpace(configJson)) return Fallback(config);
JObject root;
try { root = JObject.Parse(configJson); } catch (JsonException) { return Fallback(config); }
// 配置由人工维护,字段写成非数字等非法值时按默认值处理,不能让整场比赛无法计分。
try
{
config.RuleType = root["ruleType"]?.ToString() ?? config.RuleType;
config.BaseScore = root["baseScore"]?.Value<decimal?>() ?? config.BaseScore;
config.ScoreDecimals = Math.Clamp(root["scoreDecimals"]?.Value<int?>() ?? config.ScoreDecimals, 0, 4);
config.DeductionUnit = root["deductionUnit"]?.Value<decimal?>() ?? config.DeductionUnit;
config.CorrectionNeedApproval = root["correctionNeedApproval"]?.Value<bool?>() ?? false;
}
catch (Exception ex) when (ex is FormatException or InvalidCastException or OverflowException)
{
return Fallback(new ScoreRuleConfig());
}
foreach (var node in root["roleAggregations"] as JArray ?? new JArray())
{
var roleType = node["roleType"]?.ToString();
if (string.IsNullOrWhiteSpace(roleType)) continue;
config.RoleAggregations.Add(new RoleAggregationConfig
{
RoleType = roleType!.Trim().ToUpperInvariant(),
Symbol = node["symbol"]?.ToString() ?? roleType!,
Label = node["label"]?.ToString() ?? roleType!,
SourceField = node["sourceField"]?.ToString() ?? nameof(EventJudgeScoreSheet.TotalScore),
TargetField = node["targetField"]?.ToString() ?? node["sourceField"]?.ToString() ?? nameof(EventResult.TotalScore),
Aggregate = (node["aggregate"]?.ToString() ?? ScoreRuleConfig.AggregateAvg).Trim().ToLowerInvariant(),
Sign = ReadSign(node["sign"])
});
}
var tieBreakers = (root["tieBreakers"] as JArray ?? new JArray())
.Select(x => x.ToString()).Where(x => !string.IsNullOrWhiteSpace(x)).ToList();
if (tieBreakers.Count > 0) config.TieBreakers = tieBreakers;
return Fallback(config);
}
/// <summary>
/// 读取参与总分的符号,非法值按加分处理
/// </summary>
private static int ReadSign(JToken? node)
{
try { return node?.Value<int?>() == -1 ? -1 : 1; }
catch (Exception ex) when (ex is FormatException or InvalidCastException or OverflowException) { return 1; }
}
/// <summary>
/// 未配置聚合方式时按规定赛的 T1/T2/T3 兜底
/// </summary>
private static ScoreRuleConfig Fallback(ScoreRuleConfig config)
{
if (config.RoleAggregations.Count > 0) return config;
config.RoleAggregations.AddRange(new[]
{
new RoleAggregationConfig { RoleType = "CJ", Symbol = "T1", Label = "创意分",
SourceField = nameof(EventJudgeScoreSheet.PerformanceScore), TargetField = nameof(EventResult.PerformanceScore), Aggregate = ScoreRuleConfig.AggregateAvg, Sign = 1 },
new RoleAggregationConfig { RoleType = "CQ", Symbol = "T2", Label = "完成分",
SourceField = nameof(EventJudgeScoreSheet.RequiredScore), TargetField = nameof(EventResult.RequiredScore), Aggregate = ScoreRuleConfig.AggregateAvg, Sign = 1 },
new RoleAggregationConfig { RoleType = "T", Symbol = "T3", Label = "扣分",
SourceField = nameof(EventJudgeScoreSheet.DeductionScore), TargetField = nameof(EventResult.DeductionScore), Aggregate = ScoreRuleConfig.AggregateSum, Sign = -1 }
});
return config;
}
}