1、删除失误打分区域的 计分计算 提示

2、表现分计算有误
3、所有项目类型的 表现裁判打的 加数量/减数量 也统一用 选择数量  的形式
This commit is contained in:
马梓彭 2026-09-23 09:30:02 +08:00
parent 7c1063f707
commit 01b19bdcbf
4 changed files with 47 additions and 152 deletions

View File

@ -11,15 +11,6 @@ class CompetitionRuleCalculator {
'多样性': .15,
};
static double performance(
Map<String, int> plusCounts, {
required Map<String, int> minusCounts,
required int errors,
required double multiplier,
}) =>
performanceRaw(plusCounts, minusCounts: minusCounts, errors: errors) *
multiplier;
/// 单项表现分:12 + 加号数 - 减号数 - 失误数,最终限制为0至24的整数。
static int performanceItemScore({
required int plusCount,

View File

@ -636,11 +636,7 @@ class ScoringController extends GetxController {
ScoreRole.difficulty => _difficultyScore(),
ScoreRole.creative || ScoreRole.execution =>
performanceItems.values.fold<double>(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 = <String, String>{
'音乐': '音',
'完成质量': '质',
'娱乐': '娱',
'创意': '创',
'多样性': '多',
};
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,
);
}

View File

@ -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,

View File

@ -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);