diff --git a/lib/modules/scoring/views/scoring_page.dart b/lib/modules/scoring/views/scoring_page.dart index a3bbf62..3d98199 100644 --- a/lib/modules/scoring/views/scoring_page.dart +++ b/lib/modules/scoring/views/scoring_page.dart @@ -20,6 +20,7 @@ import '../widgets/competition_header.dart'; import '../widgets/drawing_board_dialog.dart'; import '../widgets/record_button.dart'; import '../widgets/scoring_dialogs.dart'; +import '../widgets/submission_score_details.dart'; class ScoringPage extends StatefulWidget { const ScoringPage({super.key}); @@ -101,7 +102,7 @@ class _ScoringPageState extends State with WidgetsBindingObserver { } final correctionSubmission = controller.isCorrectionMode.value; final confirmed = await showSubmitConfirmation( - details: _submissionScoreDetails(controller), + details: buildSubmissionScoreDetails(controller), correctionMode: controller.isCorrectionMode.value, ); if (confirmed != true) return; @@ -2419,81 +2420,6 @@ String _formatScore(num value) { return fixed.replaceFirst(RegExp(r'\.?0+$'), ''); } -List _submissionScoreDetails( - ScoringController controller, -) { - switch (controller.profile.role) { - case ScoreRole.difficulty: - if (controller.usesShowDifficultyMatrix) { - return [ - for (final category in controller.showDifficultyCategories) - SubmissionScoreDetail( - label: category, - description: _showDifficultyCountSummary(controller, category), - ), - ]; - } - return [ - for (final entry in controller.requiredElementCounts.entries) - SubmissionScoreDetail( - label: entry.key, - description: '规定元素完成数量:${entry.value} 个', - ), - for (final entry in controller.difficultyCounts.entries) - SubmissionScoreDetail( - label: '${entry.key}级难度', - description: '记录数量:${entry.value}', - ), - ]; - case ScoreRole.presentation: - return [ - for (final item in controller.performanceItems.keys) - SubmissionScoreDetail( - label: item, - description: - '人工减 ${controller.performanceMinusCount(item)}、失误自动减 ${controller.performanceErrorCount.value} / 加 ${controller.performancePlusCount(item)}', - ), - SubmissionScoreDetail( - label: '失误', - description: - '已记录 ${controller.performanceErrorCount.value} 次,计分时从五个表现类别各减去该次数,并上传参与综合扣分', - ), - ]; - case ScoreRole.creative: - case ScoreRole.execution: - return [ - for (final entry in controller.performanceItems.entries) - SubmissionScoreDetail(label: entry.key, description: '评分项已完成录入'), - ]; - case ScoreRole.technical: - return [ - for (final entry in controller.requiredElementCounts.entries) - SubmissionScoreDetail( - label: entry.key, - description: '规定元素完成数量:${entry.value} 个', - ), - for (final rule in controller.deductionRules) - SubmissionScoreDetail( - label: rule.key, - description: - '已记录 ${controller.deductionCounts[rule.key] ?? 0} 次 · ${rule.standard}', - ), - ]; - } -} - -String _showDifficultyCountSummary( - ScoringController controller, - String category, -) { - final recorded = []; - for (final level in controller.showDifficultyLevels) { - final count = controller.showDifficultyCount(category, level); - if (count > 0) recorded.add('$level级×$count'); - } - return recorded.isEmpty ? '尚未记录动作' : recorded.join('、'); -} - class _TableRow extends StatelessWidget { const _TableRow({required this.cells, this.statusColor}); final List cells; diff --git a/lib/modules/scoring/widgets/scoring_dialogs.dart b/lib/modules/scoring/widgets/scoring_dialogs.dart index 1ae2475..c546f9d 100644 --- a/lib/modules/scoring/widgets/scoring_dialogs.dart +++ b/lib/modules/scoring/widgets/scoring_dialogs.dart @@ -328,38 +328,19 @@ class _SubmissionDetailCard extends StatelessWidget { ), ], ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Expanded( - child: Text( - detail.label, - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: const TextStyle( - color: AppColors.textPrimary, - fontSize: 13, - fontWeight: FontWeight.w800, - ), - ), - ), - ], + child: Align( + alignment: Alignment.centerLeft, + child: Text( + detail.description, + maxLines: 3, + overflow: TextOverflow.ellipsis, + style: const TextStyle( + color: AppColors.textPrimary, + fontSize: 14, + height: 1.3, + fontWeight: FontWeight.w700, ), - const SizedBox(height: 7), - Text( - detail.description, - maxLines: 2, - overflow: TextOverflow.ellipsis, - style: const TextStyle( - color: AppColors.textSecondary, - fontSize: 11, - height: 1.25, - fontWeight: FontWeight.w600, - ), - ), - ], + ), ), ); } diff --git a/lib/modules/scoring/widgets/submission_score_details.dart b/lib/modules/scoring/widgets/submission_score_details.dart new file mode 100644 index 0000000..b7dfc22 --- /dev/null +++ b/lib/modules/scoring/widgets/submission_score_details.dart @@ -0,0 +1,105 @@ +import '../../../core/models/judge_account.dart'; +import '../controllers/scoring_controller.dart'; +import 'scoring_dialogs.dart'; + +/// 提交前复核各评分项的原始录入,不展示裁判合计分或平台最终成绩。 +List buildSubmissionScoreDetails( + ScoringController controller, +) { + switch (controller.profile.role) { + case ScoreRole.difficulty: + if (controller.usesShowDifficultyMatrix) { + return [ + for (final category in controller.showDifficultyCategories) + SubmissionScoreDetail( + label: category, + description: _showDifficultyCountSummary(controller, category), + ), + ]; + } + return [ + for (final entry in controller.requiredElementCounts.entries) + SubmissionScoreDetail( + label: entry.key, + description: '${entry.key}:${entry.value}个', + ), + for (final entry in controller.difficultyCounts.entries) + SubmissionScoreDetail( + label: '${entry.key}级难度', + description: '${entry.key}级难度:${entry.value}个', + ), + ]; + case ScoreRole.presentation: + return [ + for (final item in controller.performanceItems.keys) + SubmissionScoreDetail( + label: item, + description: + '$item:加${controller.performancePlusCount(item)}次、人工减${controller.performanceMinusCount(item)}次、失误联动减${controller.performanceErrorCount.value}次', + ), + SubmissionScoreDetail( + label: '失误', + description: '失误:${controller.performanceErrorCount.value}次', + ), + ]; + case ScoreRole.creative: + case ScoreRole.execution: + return [ + for (final entry in controller.performanceItems.entries) + SubmissionScoreDetail( + label: entry.key, + description: '${entry.key}:${_formatInputValue(entry.value)}分', + ), + ]; + case ScoreRole.technical: + return [ + for (final entry in controller.requiredElementCounts.entries) + SubmissionScoreDetail( + label: entry.key, + description: '${entry.key}:${entry.value}个', + ), + for (final rule in controller.deductionRules) + SubmissionScoreDetail( + label: rule.key, + description: + '${rule.key}:${controller.deductionCounts[rule.key] ?? 0}次', + ), + if (controller.disqualified.value) + SubmissionScoreDetail( + label: '取消比赛资格', + description: + '取消比赛资格:1项(${_disqualificationDescription(controller)})', + ), + ]; + } +} + +String _formatInputValue(double value) { + final fixed = value.toStringAsFixed(2); + return fixed.replaceFirst(RegExp(r'\.?0+$'), ''); +} + +String _disqualificationDescription(ScoringController controller) { + final code = controller.selectedDisqualifyReasonCode; + var label = code ?? '已选择原因'; + for (final item in controller.disqualifyReasonItems) { + if (item.code == code) { + label = item.name; + break; + } + } + final remark = controller.disqualifyRemark; + return remark == null || remark.isEmpty ? label : '$label · $remark'; +} + +String _showDifficultyCountSummary( + ScoringController controller, + String category, +) { + var total = 0; + for (final level in controller.showDifficultyLevels) { + final count = controller.showDifficultyCount(category, level); + total += count; + } + return '$category:$total个'; +} diff --git a/test/submission_dialog_test.dart b/test/submission_dialog_test.dart index 2bf42da..38e0340 100644 --- a/test/submission_dialog_test.dart +++ b/test/submission_dialog_test.dart @@ -16,8 +16,11 @@ void main() { onPressed: () => showSubmitConfirmation( correctionMode: false, details: const [ - SubmissionScoreDetail(label: '音乐', description: '减 1 / 加 2'), - SubmissionScoreDetail(label: '完成质量', description: '评分项已完成录入'), + SubmissionScoreDetail(label: '音乐', description: '音乐:加2次、减1次'), + SubmissionScoreDetail( + label: '完成质量', + description: '完成质量:12.5分', + ), ], ), child: const Text('打开'), @@ -32,8 +35,8 @@ void main() { expect(find.text('确认提交成绩'), findsOneWidget); expect(find.text('评分内容(2项)'), findsOneWidget); - expect(find.text('音乐'), findsOneWidget); - expect(find.text('完成质量'), findsOneWidget); + expect(find.text('音乐:加2次、减1次'), findsOneWidget); + expect(find.text('完成质量:12.5分'), findsOneWidget); expect(find.textContaining('裁判总分'), findsNothing); expect(find.textContaining('本次裁判得分'), findsNothing); }); diff --git a/test/submission_score_details_test.dart b/test/submission_score_details_test.dart new file mode 100644 index 0000000..ba0825f --- /dev/null +++ b/test/submission_score_details_test.dart @@ -0,0 +1,123 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:get/get.dart'; +import 'package:yd_pattern_scoring_system/core/models/deduction_rule_item.dart'; +import 'package:yd_pattern_scoring_system/core/models/judge_account.dart'; +import 'package:yd_pattern_scoring_system/core/storage/local_storage_service.dart'; +import 'package:yd_pattern_scoring_system/modules/scoring/controllers/scoring_controller.dart'; +import 'package:yd_pattern_scoring_system/modules/scoring/repositories/score_repository.dart'; +import 'package:yd_pattern_scoring_system/modules/scoring/widgets/submission_score_details.dart'; + +class _ScoreRepository extends Fake implements ScoreRepository {} + +class _Storage extends Fake implements LocalStorageService {} + +ScoringController _controller(ScoreRole role, CompetitionKind competition) { + final controller = ScoringController(_ScoreRepository(), _Storage()); + controller.profile = JudgeAccount( + account: 'test', + name: '测试裁判', + competition: competition, + role: role, + roleCode: role == ScoreRole.technical ? 'T' : 'P', + seat: 1, + ); + return controller; +} + +void main() { + test('规定赛创意编排与完成质量逐项展示实际录入分值,包括零分', () { + final creative = _controller( + ScoreRole.creative, + CompetitionKind.prescribed, + ); + creative.performanceItems.assignAll({'过渡连接、成套创编、场地运用': 3.5, '现场表现效果': 0}); + final creativeDetails = buildSubmissionScoreDetails(creative); + expect(creativeDetails.map((item) => item.description), [ + '过渡连接、成套创编、场地运用:3.5分', + '现场表现效果:0分', + ]); + + final execution = _controller( + ScoreRole.execution, + CompetitionKind.prescribed, + ); + execution.performanceItems.assignAll({'动作准确性': 24, '动作熟练性': 12.5}); + final executionDetails = buildSubmissionScoreDetails(execution); + expect(executionDetails.map((item) => item.label), ['动作准确性', '动作熟练性']); + expect(executionDetails.map((item) => item.description), [ + '动作准确性:24分', + '动作熟练性:12.5分', + ]); + expect( + executionDetails.any((item) => item.description == '评分项已完成录入'), + isFalse, + ); + }); + + test('难度裁判列出规定元素与各等级的原始数量', () { + final controller = _controller( + ScoreRole.difficulty, + CompetitionKind.individual, + ); + controller.requiredElementCounts.assignAll({'n3+(3级及以上)': 2}); + controller.difficultyCounts.assignAll({'3': 4, '4': 0}); + final details = buildSubmissionScoreDetails(controller); + expect(details.map((item) => item.description), [ + 'n3+(3级及以上):2个', + '3级难度:4个', + '4级难度:0个', + ]); + }); + + test('表现裁判展示加减和失误次数,主裁展示规定元素、扣分及取消资格原因', () { + final performance = _controller( + ScoreRole.presentation, + CompetitionKind.individual, + ); + performance.performanceItems['音乐'] = 12; + performance.performancePlusCounts['音乐'] = 3; + performance.performanceMinusCounts['音乐'] = 1; + performance.performanceErrorCount.value = 2; + final performanceDetails = buildSubmissionScoreDetails(performance); + expect(performanceDetails.first.description, '音乐:加3次、人工减1次、失误联动减2次'); + expect(performanceDetails.last.description, '失误:2次'); + + final chief = _controller(ScoreRole.technical, CompetitionKind.individual); + chief.requiredElementCounts['互动配合'] = 1; + chief.deductionRules = DeductionRuleCatalog.forCompetition( + CompetitionKind.individual, + ); + chief.deductionCounts['失误'] = 2; + chief.disqualified.value = true; + chief.selectedDisqualifyReasonCode = 'GENERIC_NO_SHOW'; + chief.disqualifyRemark = '未到场'; + final chiefDetails = buildSubmissionScoreDetails(chief); + expect(chiefDetails.first.description, '互动配合:1个'); + expect( + chiefDetails.firstWhere((item) => item.label == '失误').description, + '失误:2次', + ); + expect(chiefDetails.last.description, '取消比赛资格:1项(GENERIC_NO_SHOW · 未到场)'); + }); + + test('表演赛难度 A 组按类别显示动作总数', () { + final controller = _controller(ScoreRole.difficulty, CompetitionKind.show); + controller.profile = const JudgeAccount( + account: 'show-a', + name: 'A组裁判', + competition: CompetitionKind.show, + role: ScoreRole.difficulty, + roleCode: 'DGA', + seat: 1, + ); + final category = controller.showDifficultyCategories.first; + controller.difficultyCategoryCounts['$category::3'] = 2; + controller.difficultyCategoryCounts['$category::4'] = 1; + final details = buildSubmissionScoreDetails(controller); + expect(details.first.description, '$category:3个'); + expect( + details[1].description, + '${controller.showDifficultyCategories[1]}:0个', + ); + }); +}