diff --git a/YD_Event.Application/Scoring/ScoreSheetCalculationService.cs b/YD_Event.Application/Scoring/ScoreSheetCalculationService.cs index ead6a76..5ed31e5 100644 --- a/YD_Event.Application/Scoring/ScoreSheetCalculationService.cs +++ b/YD_Event.Application/Scoring/ScoreSheetCalculationService.cs @@ -173,7 +173,7 @@ public static class ScoreSheetCalculationService /// /// 按计分规则计算一张评分单。 /// requireAll 为 true(正式提交)时校验必填项与取值范围;为 false(保存草稿)时允许留空,只算已录入的部分。 - /// 花样赛的表现维度分、失误自动减分、规定元素缺失数一律由服务端联动生成,客户端传来的自动项不参与计算。 + /// 花样赛的表现维度分、失误联动项、规定元素缺失数一律由服务端生成,客户端传来的自动项不参与计算。 /// public static ScoreSheetCalculationResult Calculate(List definitions, List inputs, ScoreRuleConfig config, bool requireAll) @@ -213,8 +213,7 @@ public static class ScoreSheetCalculationService // 表现维度的加减项、递增扣分项、规定元素计数项各有专门算法,不按小计直接累加。 if (definition.DimensionCode != null && definition.AdjustSign != 0) continue; if (definition.StepDeductions is { Count: > 0 }) continue; - if (definition.Item.ScoreDimension == ScoreDimensionCode.Required - && definition.Item.ItemType == ScoreItemTypeCode.RequiredElement) continue; + if (definition.Item.ItemType == ScoreItemTypeCode.RequiredElement) continue; switch (definition.Item.ScoreDimension) { @@ -239,11 +238,17 @@ public static class ScoreSheetCalculationService result.RequiredScore = config.Round(result.RequiredScore); result.DeductionScore = config.Round(result.DeductionScore); } - // 花样赛的规定元素完成量只用于跨裁判聚合时计算 Q,不能加进单张评分单的本裁判得分。 - // 最终 R 仍由跨裁判聚合按 D×(1+P)×Q×M 计算;规定赛保留原有加总口径。 + // 难度裁判的规定元素完成量仅作为独立记录,不能计入本裁判难度分。 + // 同时兼容尚未配置 factor 模式的个人花样规则;规定赛完成质量裁判仍保留 RequiredScore 加总。 + var isDifficultySheet = definitions.Any(x => !x.IsAuto && + x.Item.ItemType != ScoreItemTypeCode.RequiredElement && + (x.Item.ItemType == ScoreItemTypeCode.DifficultyCount || + x.Item.ScoreDimension == ScoreDimensionCode.Difficulty)); + var requiredContribution = isDifficultySheet ? 0m : result.RequiredScore; + // 花样赛最终 R 仍由跨裁判聚合按 D×(1+P)×Q×M 计算。 result.TotalScore = config.IsFactorTotal ? config.Round(result.DifficultyScore + result.PerformanceScore) - : config.Round(result.DifficultyScore + result.PerformanceScore + result.RequiredScore - result.DeductionScore); + : config.Round(result.DifficultyScore + result.PerformanceScore + requiredContribution - result.DeductionScore); return result; } @@ -257,7 +262,9 @@ public static class ScoreSheetCalculationService var mode = definitions.Select(x => x.DifficultyAggregate).FirstOrDefault(x => !string.IsNullOrEmpty(x)); if (mode == null) return; var difficultyLines = result.Lines - .Where(x => x.ScoreDimension == ScoreDimensionCode.Difficulty && x.CountValue is > 0m).ToList(); + .Where(x => x.ItemType != ScoreItemTypeCode.RequiredElement && + x.ScoreDimension == ScoreDimensionCode.Difficulty && + x.CountValue is > 0m).ToList(); var actionCount = difficultyLines.Sum(x => x.CountValue!.Value); if (actionCount <= 0m) { @@ -296,7 +303,8 @@ public static class ScoreSheetCalculationService } /// - /// 表现维度计算。页面减数量 = 人工减 + 失误自动减;按规则公式还需单独减失误次数。 + /// 表现维度计算。个人花样的失误单独参与总成绩扣分,不进入表现分; + /// 其他花样项目沿用失误联动表现维度的既有口径。 /// 每个维度 = 基准分 + 人工加 - (人工减 + 失误自动减) - 失误次数,限制在上下限内, /// 再按各维度权重加权求和得到本裁判的表现分。失误自动减分作为自动项落明细,裁判不可直接修改。 /// @@ -308,11 +316,16 @@ public static class ScoreSheetCalculationService .ToList(); if (dimensions.Count == 0) return; - // 失误数联动五个维度各自动减 1 次。 + // 个人花样的失误由成绩汇总中的 M 系数单独处理,不能再降低本裁判的表现分。 var failure = definitions.FirstOrDefault(x => x.IsFailureCount); var failureCount = failure == null ? 0m : result.Lines.FirstOrDefault(x => string.Equals(x.ItemCode, failure.ItemCode, StringComparison.OrdinalIgnoreCase))?.CountValue ?? 0m; + var isIndividualFreestyle = string.Equals(config.RuleType, "FREESTYLE_SINGLE", StringComparison.OrdinalIgnoreCase); + var performanceFailureCount = isIndividualFreestyle ? 0m : failureCount; + var hasPerformanceMarks = definitions.Any(x => !x.IsAuto && x.AdjustSign != 0 && + result.Lines.Any(line => string.Equals(line.ItemCode, x.ItemCode, StringComparison.OrdinalIgnoreCase) + && line.CountValue is > 0m)); var weighted = 0m; foreach (var dimension in dimensions) @@ -328,10 +341,12 @@ public static class ScoreSheetCalculationService .FirstOrDefault(x => string.Equals(x.ItemCode, adjust.ItemCode, StringComparison.OrdinalIgnoreCase))?.CountValue ?? 0m; raw += adjust.AdjustSign * count * (adjust.Item.UnitValue ?? 1m); } - // 失误同时增加页面减数量,并作为公式中的独立失误项再扣一次。 - raw -= failureCount * 2m * (dimension.Item.UnitValue ?? 1m); + // 其他花样项目沿用失误联动;个人花样这里不扣,汇总时由 M 系数处理。 + raw -= performanceFailureCount * 2m * (dimension.Item.UnitValue ?? 1m); // 维度分限制在规则给出的上下限内(规程为 0~24)并取整。 - var value = Math.Clamp(Math.Round(raw, 0, MidpointRounding.AwayFromZero), dimension.MinValue, dimension.MaxValue); + var value = isIndividualFreestyle && !hasPerformanceMarks + ? 0m + : Math.Clamp(Math.Round(raw, 0, MidpointRounding.AwayFromZero), dimension.MinValue, dimension.MaxValue); weighted += value * dimension.DimensionWeight!.Value; result.Lines.Add(new ScoreSheetLine @@ -341,12 +356,16 @@ public static class ScoreSheetCalculationService InputValue = value, UnitValue = dimension.Item.UnitValue, Subtotal = value, Sort = dimension.Item.Sort, IsAutoGenerated = true, SubjectCode = dimension.SubjectCode, - ParentItemCode = failure?.ItemCode + ParentItemCode = performanceFailureCount > 0m ? failure?.ItemCode : null }); result.Steps.Add(new ScoreSheetStep { Code = $"DIM_{dimension.DimensionCode}", Label = dimension.Item.ItemName, - Formula = $"{Trim(dimension.BaseValue ?? 0m)} + 人工加 - (人工减 + 失误联动减{Trim(failureCount)}) - 失误{Trim(failureCount)}次", + Formula = isIndividualFreestyle && !hasPerformanceMarks + ? "尚未录入表现加减,表现分为 0;失误单独计入扣分" + : isIndividualFreestyle + ? $"{Trim(dimension.BaseValue ?? 0m)} + 人工加 - 人工减(失误单独计入扣分)" + : $"{Trim(dimension.BaseValue ?? 0m)} + 人工加 - (人工减 + 失误联动减{Trim(performanceFailureCount)}) - 失误{Trim(performanceFailureCount)}次", Value = value }); }