个人花样计算逻辑调整

This commit is contained in:
马梓彭 2026-10-08 15:55:07 +08:00
parent cf61790109
commit 00f7da64e2
4 changed files with 47 additions and 44 deletions

View File

@ -802,13 +802,10 @@ class ScoringController extends GetxController {
int performanceMinusCount(String item) => performanceMinusCounts[item] ?? 0;
/// 个人及同步花样的减数量仅显示人工减;公式另外扣一次失误。
int get performanceLinkedErrorCount =>
profile.competition == CompetitionKind.individual
? 0
: performanceErrorCount.value;
/// 页面减数量同时展示人工减与失误联动减;持久化时仍分开保存,避免重复扣分。
int get performanceLinkedErrorCount => performanceErrorCount.value;
/// 其他花样项目仍展示人工减号与失误自动减号之和。
/// 所有花样项目展示人工减号与失误自动减号之和。
int performanceEffectiveMinusCount(String item) =>
performanceMinusCount(item) + performanceLinkedErrorCount;
@ -836,7 +833,9 @@ class ScoringController extends GetxController {
}
void setPerformanceEffectiveMinusCount(String item, int count) {
performanceMinusCounts[item] = count.clamp(0, 50).toInt();
performanceMinusCounts[item] = (count - performanceLinkedErrorCount)
.clamp(0, 50)
.toInt();
_syncPerformanceItemScore(item);
recalculate();
}

View File

@ -674,6 +674,7 @@ class _DifficultyPanel extends StatelessWidget {
: () async {
final value = await showQuantityPicker(
current: entry.value,
includeZero: true,
);
if (value != null) {
controller.setDifficultyCount(entry.key, value);
@ -788,6 +789,7 @@ class _DifficultyPanel extends StatelessWidget {
: () async {
final value = await showQuantityPicker(
current: entry.value,
includeZero: true,
);
if (value != null) {
controller.setDifficultyCount(entry.key, value);
@ -1177,17 +1179,8 @@ class _PerformancePanel extends StatelessWidget {
children: [
_PerformanceMarkCount(
value: minusCount,
semanticLabel:
controller.profile.competition ==
CompetitionKind.individual
? '${entry.key}人工减数量'
: '${entry.key}减数量(含失误自动扣减)',
color:
hasErrors &&
controller.profile.competition !=
CompetitionKind.individual
? AppColors.danger
: AppColors.primary,
semanticLabel: '${entry.key}减数量(含失误自动扣减)',
color: hasErrors ? AppColors.danger : AppColors.primary,
onTap: controller.isReadOnly
? null
: () async {
@ -2453,21 +2446,17 @@ List<SubmissionScoreDetail> _submissionScoreDetails(
),
];
case ScoreRole.presentation:
final isIndividual =
controller.profile.competition == CompetitionKind.individual;
return [
for (final item in controller.performanceItems.keys)
SubmissionScoreDetail(
label: item,
description: isIndividual
? '人工减 ${controller.performanceMinusCount(item)} / 加 ${controller.performancePlusCount(item)}'
: '人工减 ${controller.performanceMinusCount(item)}、失误自动减 ${controller.performanceErrorCount.value} / 加 ${controller.performancePlusCount(item)}',
description:
'人工减 ${controller.performanceMinusCount(item)}、失误自动减 ${controller.performanceErrorCount.value} / 加 ${controller.performancePlusCount(item)}',
),
SubmissionScoreDetail(
label: '失误',
description: isIndividual
? '已记录 ${controller.performanceErrorCount.value} 次;不计入表现分,单独参与最终扣分'
: '已记录 ${controller.performanceErrorCount.value} 次,计分时从五个表现类别各减去该次数',
description:
'已记录 ${controller.performanceErrorCount.value} 次,计分时从五个表现类别各减去该次数,并上传参与综合扣分',
),
];
case ScoreRole.creative:

View File

@ -2,43 +2,39 @@ import 'package:flutter_test/flutter_test.dart';
import 'package:yd_pattern_scoring_system/core/rule_engine/calculators/competition_rule_calculator.dart';
void main() {
test('个人花样失误独立记录,不改变表现维度分和未录入时的零分', () {
test('个人花样失误联动扣减五个表现维度', () {
const plus = {'音乐': 3, '完成质量': 3};
const minus = {'音乐': 1};
final withoutFailure = CompetitionRuleCalculator.performanceRecordedRaw(
plus,
minusCounts: minus,
errors: 0,
includeErrors: false,
);
final withFailure = CompetitionRuleCalculator.performanceRecordedRaw(
plus,
minusCounts: minus,
errors: 3,
includeErrors: false,
);
expect(withFailure, withoutFailure);
expect(withFailure, closeTo(withoutFailure - 3, .000001));
expect(
CompetitionRuleCalculator.performanceRecordedRaw(
const {},
minusCounts: const {},
errors: 3,
includeErrors: false,
),
0,
9,
);
expect(
CompetitionRuleCalculator.performanceItemScore(
plusCount: 3,
minusCount: 1,
errors: 3,
includeErrors: false,
),
14,
11,
);
});
test('表现裁判未录入显示0,失误一次联动减号后再独立扣一次', () {
test('表现裁判未录入显示0,失误一次使五个维度各减一分', () {
const empty = <String, int>{};
expect(
CompetitionRuleCalculator.performanceRecordedRaw(
@ -54,7 +50,7 @@ void main() {
minusCounts: empty,
errors: 1,
),
closeTo(10, .000001),
closeTo(11, .000001),
);
});
@ -65,18 +61,18 @@ void main() {
errors: 1,
);
expect(score, closeTo(13.4, .0001));
expect(score, closeTo(14.4, .0001));
});
test('表演赛表现裁判的手工减数量与失误次数分别扣减', () {
final score = CompetitionRuleCalculator.performanceRaw(
const {'音乐': 0, '完成质量': 0, '娱乐': 0, '创意': 0, '多样性': 0},
// 页面减数量已含两次失误联动,再按公式单独扣两次失误。
// minusCounts 只保存人工减,失误在公式中对每个维度扣一次。
minusCounts: const {'音乐': 1, '完成质量': 2, '娱乐': 2, '创意': 0, '多样性': 2},
errors: 2,
);
expect(score, closeTo(6.5, .000001));
expect(score, closeTo(8.5, .000001));
});
test('单项表现分按12加加号减页面减数量再减失误并限制在0至24', () {
@ -86,7 +82,7 @@ void main() {
minusCount: 2,
errors: 2,
),
9,
11,
);
expect(
CompetitionRuleCalculator.performanceItemScore(
@ -106,7 +102,7 @@ void main() {
);
});
test('已有手工减数量时,失误联动减号及独立失误项均扣减', () {
test('已有人工减数量时,失误仍对每个维度扣减一次', () {
final withoutError = CompetitionRuleCalculator.performanceRaw(
const {'音乐': 3, '完成质量': 3, '娱乐': 3, '创意': 3, '多样性': 3},
minusCounts: const {'音乐': 2, '完成质量': 2, '娱乐': 2, '创意': 2, '多样性': 2},
@ -118,17 +114,17 @@ void main() {
errors: 2,
);
expect(withoutError, closeTo(13, .000001));
expect(withTwoErrors, closeTo(9, .000001));
expect(withTwoErrors, closeTo(11, .000001));
});
test('人工减2且失误2时页面减数量为4,单项按6分计算', () {
test('人工减2且失误2时页面减数量为4,单项按8分计算', () {
expect(
CompetitionRuleCalculator.performanceItemScore(
plusCount: 0,
minusCount: 2,
errors: 2,
),
6,
8,
);
});

View File

@ -18,4 +18,23 @@ void main() {
expect(await result, 0);
});
testWidgets('难度数量选择器可以选择并返回 0', (tester) async {
Get.testMode = true;
await tester.pumpWidget(const GetMaterialApp(home: Scaffold()));
final result = showQuantityPicker(
current: 3,
maximum: 8,
includeZero: true,
);
await tester.pumpAndSettle();
expect(find.text('0'), findsOneWidget);
await tester.tap(find.text('0'));
await tester.tap(find.text('确认选择'));
await tester.pumpAndSettle();
expect(await result, 0);
});
}