diff --git a/lib/core/rule_engine/calculators/competition_rule_calculator.dart b/lib/core/rule_engine/calculators/competition_rule_calculator.dart index 65218f5..12d02a5 100644 --- a/lib/core/rule_engine/calculators/competition_rule_calculator.dart +++ b/lib/core/rule_engine/calculators/competition_rule_calculator.dart @@ -11,15 +11,6 @@ class CompetitionRuleCalculator { '多样性': .15, }; - static double performance( - Map plusCounts, { - required Map minusCounts, - required int errors, - required double multiplier, - }) => - performanceRaw(plusCounts, minusCounts: minusCounts, errors: errors) * - multiplier; - /// 单项表现分:12 + 加号数 - 减号数 - 失误数,最终限制为0至24的整数。 static int performanceItemScore({ required int plusCount, diff --git a/lib/modules/scoring/controllers/scoring_controller.dart b/lib/modules/scoring/controllers/scoring_controller.dart index 4e1991e..26cbd5c 100644 --- a/lib/modules/scoring/controllers/scoring_controller.dart +++ b/lib/modules/scoring/controllers/scoring_controller.dart @@ -636,11 +636,7 @@ class ScoringController extends GetxController { ScoreRole.difficulty => _difficultyScore(), ScoreRole.creative || ScoreRole.execution => performanceItems.values.fold(0, (sum, value) => sum + value), - ScoreRole.presentation => CompetitionRuleCalculator.performanceRaw( - performancePlusCounts, - minusCounts: performanceMinusCounts, - errors: performanceErrorCount.value, - ), + ScoreRole.presentation => _performanceScore(), ScoreRole.technical => disqualified.value ? 0.0 @@ -779,70 +775,23 @@ class ScoringController extends GetxController { errors: performanceErrorCount.value, ); - void addPerformanceMark(String item, {required bool isPlus}) { - final target = isPlus ? performancePlusCounts : performanceMinusCounts; - target[item] = ((target[item] ?? 0) + 1).clamp(0, 99).toInt(); - _syncPerformanceItemScore(item); - recalculate(); - } - void setPerformanceMarkCount( String item, { required bool isPlus, required int count, }) { final target = isPlus ? performancePlusCounts : performanceMinusCounts; - target[item] = count.clamp(0, 99).toInt(); + target[item] = count.clamp(0, 50).toInt(); _syncPerformanceItemScore(item); recalculate(); } void setPerformanceEffectiveMinusCount(String item, int count) { - performanceMinusCounts[item] = count.clamp(0, 99).toInt(); + performanceMinusCounts[item] = count.clamp(0, 50).toInt(); _syncPerformanceItemScore(item); recalculate(); } - String get performanceCalculationDetail { - const shortNames = { - '音乐': '音', - '完成质量': '质', - '娱乐': '娱', - '创意': '创', - '多样性': '多', - }; - final markDetails = performanceItems.keys - .map((item) { - final shortName = shortNames[item] ?? item; - return '$shortName${performanceEffectiveMinusCount(item)}/' - '${performancePlusCount(item)}'; - }) - .join('|'); - final itemScores = performanceItems.keys - .map((item) { - final shortName = shortNames[item] ?? item; - return '$shortName${performanceCalculatedItemScore(item)}'; - }) - .join('|'); - final weightedValues = performanceItems.keys - .map((item) { - final weight = - CompetitionRuleCalculator.performanceWeights[item] ?? 0; - return '${performanceCalculatedItemScore(item)}×' - '${weight.toStringAsFixed(2)}'; - }) - .join('+'); - return '单项=加数量+12-人工减数量-失误数量(限0~24整数)\n' - '失误${performanceErrorCount.value}次 → 公式中五项各自额外减' - '${performanceErrorCount.value}\n' - '当前减/加:$markDetails\n' - '单项分:$itemScores\n' - '加权:$weightedValues=${_compactScore(currentJudgeScore)}'; - } - - String _compactScore(num value) => - value.toStringAsFixed(2).replaceFirst(RegExp(r'\.?0+$'), ''); - void _syncPerformanceItemScore(String item) { performanceItems[item] = performanceCalculatedItemScore(item).toDouble(); } @@ -1028,13 +977,11 @@ class ScoringController extends GetxController { ); } if (profile.role != ScoreRole.presentation) return 0; - return CompetitionRuleCalculator.performance( + // 项目系数必须由平台在收齐评分单后统一处理,平板不能用当前一人代替多人平均。 + return CompetitionRuleCalculator.performanceRaw( performancePlusCounts, minusCounts: performanceMinusCounts, errors: performanceErrorCount.value, - multiplier: profile.competition == CompetitionKind.doubleDutch - ? .033 - : .05, ); } diff --git a/lib/modules/scoring/views/scoring_page.dart b/lib/modules/scoring/views/scoring_page.dart index c8d40ba..c8e10b0 100644 --- a/lib/modules/scoring/views/scoring_page.dart +++ b/lib/modules/scoring/views/scoring_page.dart @@ -1177,7 +1177,7 @@ class _PerformancePanel extends StatelessWidget { final value = await showQuantityPicker( current: minusCount, includeZero: true, - maximum: 99, + maximum: 50, ); if (value != null) { controller.setPerformanceEffectiveMinusCount( @@ -1207,7 +1207,7 @@ class _PerformancePanel extends StatelessWidget { final value = await showQuantityPicker( current: plusCount, includeZero: true, - maximum: 99, + maximum: 50, ); if (value != null) { controller.setPerformanceMarkCount( @@ -1227,20 +1227,40 @@ class _PerformancePanel extends StatelessWidget { label: '减数量', onTap: controller.isReadOnly ? null - : () => controller.addPerformanceMark( - entry.key, - isPlus: false, - ), + : () async { + final value = await showQuantityPicker( + current: minusCount, + includeZero: true, + maximum: 50, + ); + if (value != null) { + controller.setPerformanceMarkCount( + entry.key, + isPlus: false, + count: value, + ); + } + }, ), const SizedBox(width: 8), _ActionButton( label: '加数量', onTap: controller.isReadOnly ? null - : () => controller.addPerformanceMark( - entry.key, - isPlus: true, - ), + : () async { + final value = await showQuantityPicker( + current: plusCount, + includeZero: true, + maximum: 50, + ); + if (value != null) { + controller.setPerformanceMarkCount( + entry.key, + isPlus: true, + count: value, + ); + } + }, ), ], ), @@ -1373,13 +1393,7 @@ class _PerformancePanel extends StatelessWidget { statusColor: errorColor, ), headers: const ['失误项目', '次数', '计数操作'], - rows: [ - errorRow, - _PerformanceCalculationNote( - calculation: controller.performanceCalculationDetail, - hasErrors: hasErrors, - ), - ], + rows: [errorRow], ), ), const SizedBox(width: 16), @@ -2063,54 +2077,6 @@ class _CompactLaurelScore extends StatelessWidget { ); } -class _PerformanceCalculationNote extends StatelessWidget { - const _PerformanceCalculationNote({ - required this.calculation, - required this.hasErrors, - }); - - final String calculation; - final bool hasErrors; - - @override - Widget build(BuildContext context) { - final color = hasErrors ? AppColors.danger : AppColors.primary; - return Container( - width: double.infinity, - margin: const EdgeInsets.only(top: 16), - padding: const EdgeInsets.fromLTRB(16, 12, 16, 14), - decoration: BoxDecoration( - color: color.withValues(alpha: .055), - borderRadius: BorderRadius.circular(8), - border: Border.all(color: color.withValues(alpha: .22)), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - '计分计算', - style: TextStyle( - color: color, - fontSize: 12, - fontWeight: FontWeight.w800, - ), - ), - const SizedBox(height: 5), - Text( - calculation, - style: const TextStyle( - color: Color(0xFF52637A), - fontSize: 10, - height: 1.35, - fontWeight: FontWeight.w600, - ), - ), - ], - ), - ); - } -} - class _DesignScoringCard extends StatelessWidget { const _DesignScoringCard({ required this.rows, diff --git a/test/competition_rule_calculator_test.dart b/test/competition_rule_calculator_test.dart index f570261..bebd923 100644 --- a/test/competition_rule_calculator_test.dart +++ b/test/competition_rule_calculator_test.dart @@ -2,16 +2,6 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:yd_pattern_scoring_system/core/rule_engine/calculators/competition_rule_calculator.dart'; void main() { - test('个人花样表现按五项权重与0.05系数计算', () { - final result = CompetitionRuleCalculator.performance( - const {'音乐': 8, '完成质量': 8, '娱乐': 8, '创意': 8, '多样性': 8}, - minusCounts: const {'音乐': 1, '完成质量': 1, '娱乐': 1, '创意': 1, '多样性': 1}, - errors: 1, - multiplier: .05, - ); - expect(result, closeTo(.9, .000001)); - }); - test('裁判端展示当前表现裁判原始加权分,不乘平台系数', () { final score = CompetitionRuleCalculator.performanceRaw( const {'音乐': 8, '完成质量': 6, '娱乐': 4, '创意': 2, '多样性': 0}, @@ -33,16 +23,6 @@ void main() { expect(score, closeTo(8.5, .000001)); }); - test('交互绳表现使用0.033系数', () { - final result = CompetitionRuleCalculator.performance( - const {'音乐': 0, '完成质量': 0, '娱乐': 0, '创意': 0, '多样性': 0}, - minusCounts: const {}, - errors: 0, - multiplier: .033, - ); - expect(result, closeTo(.396, .000001)); - }); - test('单项表现分按12加加号减减号减失误并限制在0至24', () { expect( CompetitionRuleCalculator.performanceItemScore( @@ -85,6 +65,17 @@ void main() { expect(withTwoErrors, closeTo(11, .000001)); }); + test('人工减2且失误2时单项按8分计算', () { + expect( + CompetitionRuleCalculator.performanceItemScore( + plusCount: 0, + minusCount: 2, + errors: 2, + ), + 8, + ); + }); + test('失误依次扣5%、7.5%、其后每次10%', () { expect(CompetitionRuleCalculator.mistakePenalty(1), .05); expect(CompetitionRuleCalculator.mistakePenalty(2), .125);