From 37f531b3bfd6ce23fb69ad18abbf6529d7de6fec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A9=AC=E6=A2=93=E5=BD=AD?= Date: Sat, 10 Oct 2026 13:56:23 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=89=E4=BA=BA=E4=BA=A4=E4=BA=92=E8=8A=B1?= =?UTF-8?q?=E6=A0=B7=E8=B0=83=E6=95=B4=E9=A1=B5=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/core/models/judge_account.dart | 18 ++- lib/core/network/remote_scoring_adapter.dart | 24 ++- .../scoring/widgets/scoring_dialogs.dart | 2 +- test/remote_scoring_adapter_test.dart | 139 ++++++++++++------ test/submission_dialog_test.dart | 26 +++- 5 files changed, 153 insertions(+), 56 deletions(-) diff --git a/lib/core/models/judge_account.dart b/lib/core/models/judge_account.dart index 06d9253..9fa0dac 100644 --- a/lib/core/models/judge_account.dart +++ b/lib/core/models/judge_account.dart @@ -12,6 +12,7 @@ class JudgeAccount { required this.role, required this.roleCode, required this.seat, + this.roleLabel, }); final String account; @@ -20,6 +21,7 @@ class JudgeAccount { final ScoreRole role; final String roleCode; final int seat; + final String? roleLabel; String get password => '123456'; String get storageKey => '${competition.name}-$roleCode-$seat'; @@ -39,13 +41,15 @@ class JudgeAccount { CompetitionKind.show => '表演赛(精英级)', }; - String get roleName => switch (role) { - ScoreRole.creative => '创意编排裁判-$seat', - ScoreRole.execution => '完成质量裁判-$seat', - ScoreRole.presentation => '表现裁判-$seat', - ScoreRole.technical => '主裁判-T', - ScoreRole.difficulty => '$roleCode 难度裁判-$seat', - }; + String get roleName => + roleLabel ?? + switch (role) { + ScoreRole.creative => '创意编排裁判-$seat', + ScoreRole.execution => '完成质量裁判-$seat', + ScoreRole.presentation => '表现裁判-$seat', + ScoreRole.technical => '主裁判-T', + ScoreRole.difficulty => '$roleCode 难度裁判-$seat', + }; bool get isElite => competition != CompetitionKind.prescribed; } diff --git a/lib/core/network/remote_scoring_adapter.dart b/lib/core/network/remote_scoring_adapter.dart index 12fc0bb..a49752c 100644 --- a/lib/core/network/remote_scoring_adapter.dart +++ b/lib/core/network/remote_scoring_adapter.dart @@ -21,8 +21,22 @@ abstract final class RemoteScoringAdapter { }; static String roleLabelForSession(JudgeSession session) { - final roleName = roleNameForType(session.judgeRoleType); - final seat = session.judgeRole.trim().toUpperCase(); + return _roleLabel( + session.judgeRoleType, + session.judgeRoleName, + session.judgeRole, + ); + } + + static String _roleLabel( + String roleType, + String configuredName, + String role, + ) { + final roleName = configuredName.trim().isEmpty + ? roleNameForType(roleType) + : configuredName.trim(); + final seat = role.trim().toUpperCase(); return seat.isEmpty ? roleName : '$roleName · $seat'; } @@ -92,6 +106,7 @@ abstract final class RemoteScoringAdapter { role: role, roleCode: roleCode, seat: int.tryParse(seatMatch?.group(1) ?? '') ?? 1, + roleLabel: roleLabelForSession(session), ); } @@ -116,6 +131,11 @@ abstract final class RemoteScoringAdapter { role: role, roleCode: roleCode, seat: int.tryParse(seatMatch?.group(1) ?? '') ?? 1, + roleLabel: _roleLabel( + sheet.header.judgeRoleType, + sheet.header.judgeRoleName, + sheet.header.judgeRole, + ), ); } diff --git a/lib/modules/scoring/widgets/scoring_dialogs.dart b/lib/modules/scoring/widgets/scoring_dialogs.dart index b415a85..1ae2475 100644 --- a/lib/modules/scoring/widgets/scoring_dialogs.dart +++ b/lib/modules/scoring/widgets/scoring_dialogs.dart @@ -855,7 +855,7 @@ Future showServerSubmissionResult({ const SizedBox(width: 10), Expanded( child: Text( - '${progress.roleName} ${progress.symbol}', + progress.roleName, style: const TextStyle( color: AppColors.textPrimary, fontWeight: FontWeight.w700, diff --git a/test/remote_scoring_adapter_test.dart b/test/remote_scoring_adapter_test.dart index 3eceba6..cf2e957 100644 --- a/test/remote_scoring_adapter_test.dart +++ b/test/remote_scoring_adapter_test.dart @@ -44,6 +44,10 @@ void main() { ScoreRole.technical, ]); expect(profiles.map((profile) => profile.storageKey).toSet().length, 3); + expect( + profiles.map((profile) => profile.roleName), + sessions.map(RemoteScoringAdapter.roleLabelForSession), + ); }); test('进入任务后以评分表角色覆盖列表中的旧席位', () { @@ -59,6 +63,7 @@ void main() { ); expect(profile.role, ScoreRole.presentation); expect(profile.roleCode, 'P'); + expect(profile.roleName, '表现裁判 · P1'); }); test('单角色账号仍显示具体角色和席位', () { @@ -98,6 +103,46 @@ void main() { }); }); + test('规则配置名称在任务列表和评分页保持一致且不改变评分存储身份', () { + final session = _session( + id: 'session-dm', + role: 'DM2', + roleType: 'DM', + roleName: ' 难度裁判-DM(多摇裁判) ', + ); + final profile = RemoteScoringAdapter.accountForSession( + session, + userId: 'judge-1', + userName: '测试裁判', + ); + final sheetProfile = RemoteScoringAdapter.accountFor( + _sheet(role: 'DM2', roleType: 'DM', roleName: session.judgeRoleName), + userId: 'judge-1', + userName: '测试裁判', + ); + expect(profile.roleName, '难度裁判-DM(多摇裁判) · DM2'); + expect(profile.roleName, RemoteScoringAdapter.roleLabelForSession(session)); + expect(sheetProfile.roleName, profile.roleName); + expect(sheetProfile.storageKey, 'individual-DM-2'); + expect(sheetProfile.storageKey, profile.storageKey); + expect(sheetProfile.role, ScoreRole.difficulty); + }); + + test('旧接口缺少名称时主裁保留实际席位,缺少席位时不虚构编号', () { + final profile = RemoteScoringAdapter.accountFor( + _sheet(role: 'T', roleType: 'T', roleName: ' '), + userId: 'judge-1', + userName: '测试裁判', + ); + expect(profile.roleName, '主裁判 · T'); + expect( + RemoteScoringAdapter.roleLabelForSession( + _session(id: 'session-p', role: '', roleType: 'P'), + ), + '表现裁判', + ); + }); + test('服务端裁判类型映射到现有专用页面角色', () { const header = JudgeSheetHeader( eventName: '测试赛事', @@ -181,6 +226,7 @@ JudgeSession _session({ required String id, required String role, required String roleType, + String roleName = '', }) => JudgeSession( sessionId: id, eventId: 'event-1', @@ -195,52 +241,55 @@ JudgeSession _session({ sessionStatusName: '进行中', judgeRole: role, judgeRoleType: roleType, - judgeRoleName: '', + judgeRoleName: roleName, entryCount: 2, scoredCount: 0, ); -JudgeScoreSheet _sheet({required String role, required String roleType}) => - JudgeScoreSheet( - sessionEntryId: 'entry-1', - sessionId: 'session-p', - judgeTaskId: 'task-1', - scoreSheetId: 'sheet-1', - sheetVersion: 1, - sheetStatus: 0, - canEdit: true, - isCorrection: false, - idempotencyKey: 'key-1', - header: JudgeSheetHeader( - eventName: '测试赛事', - projectName: '个人花样(精英级)', - ruleName: '2025-2028规则', - groupName: '青年组', - sessionVenue: '第二场-1号场地', - entryNo: 'A01', - participantName: '测试队', - memberNames: const [], - judgeRole: role, - judgeRoleType: roleType, - judgeRoleName: '', - ruleType: 'FREESTYLE', - totalMode: 'factor', - formula: '', - scope: 'personal', - baseScore: 0, - scoreDecimals: 2, - ), - items: const [], - preview: const JudgeScorePreview( - difficultyScore: 0, - performanceScore: 0, - requiredScore: 0, - deductionScore: 0, - totalScore: 0, - totalScoreText: '', - isDisqualified: false, - requiredCompletedCount: 0, - requiredMissingCount: 0, - steps: [], - ), - ); +JudgeScoreSheet _sheet({ + required String role, + required String roleType, + String roleName = '', +}) => JudgeScoreSheet( + sessionEntryId: 'entry-1', + sessionId: 'session-p', + judgeTaskId: 'task-1', + scoreSheetId: 'sheet-1', + sheetVersion: 1, + sheetStatus: 0, + canEdit: true, + isCorrection: false, + idempotencyKey: 'key-1', + header: JudgeSheetHeader( + eventName: '测试赛事', + projectName: '个人花样(精英级)', + ruleName: '2025-2028规则', + groupName: '青年组', + sessionVenue: '第二场-1号场地', + entryNo: 'A01', + participantName: '测试队', + memberNames: const [], + judgeRole: role, + judgeRoleType: roleType, + judgeRoleName: roleName, + ruleType: 'FREESTYLE', + totalMode: 'factor', + formula: '', + scope: 'personal', + baseScore: 0, + scoreDecimals: 2, + ), + items: const [], + preview: const JudgeScorePreview( + difficultyScore: 0, + performanceScore: 0, + requiredScore: 0, + deductionScore: 0, + totalScore: 0, + totalScoreText: '', + isDisqualified: false, + requiredCompletedCount: 0, + requiredMissingCount: 0, + steps: [], + ), +); diff --git a/test/submission_dialog_test.dart b/test/submission_dialog_test.dart index 5de1a2b..2bf42da 100644 --- a/test/submission_dialog_test.dart +++ b/test/submission_dialog_test.dart @@ -50,7 +50,24 @@ void main() { myScore: '13.88', resultCompleted: true, totalScore: '88.66', - progress: [], + progress: [ + JudgeRoleProgress( + roleType: 'DM', + roleName: '难度裁判-DM(多摇裁判)', + symbol: 'dDM', + expectedCount: 2, + submittedCount: 1, + pendingJudges: ['DM2'], + ), + JudgeRoleProgress( + roleType: 'T', + roleName: '主裁判-T', + symbol: 'M', + expectedCount: 1, + submittedCount: 1, + pendingJudges: [], + ), + ], ), ), child: const Text('上传'), @@ -63,5 +80,12 @@ void main() { expect(find.text('提交成功'), findsOneWidget); expect(find.text('13.88'), findsNothing); expect(find.text('88.66'), findsNothing); + expect(find.text('难度裁判-DM(多摇裁判)'), findsOneWidget); + expect(find.text('主裁判-T'), findsOneWidget); + expect(find.textContaining('dDM'), findsNothing); + expect(find.text('主裁判-T M'), findsNothing); + expect(find.text('1/2'), findsOneWidget); + expect(find.text('1/1'), findsOneWidget); + expect(find.text('待提交:DM2'), findsOneWidget); }); }