三人交互花样调整页面

This commit is contained in:
马梓彭 2026-10-10 13:56:23 +08:00
parent 43ae132b25
commit 37f531b3bf
5 changed files with 153 additions and 56 deletions

View File

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

View File

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

View File

@ -855,7 +855,7 @@ Future<void> showServerSubmissionResult({
const SizedBox(width: 10),
Expanded(
child: Text(
'${progress.roleName} ${progress.symbol}',
progress.roleName,
style: const TextStyle(
color: AppColors.textPrimary,
fontWeight: FontWeight.w700,

View File

@ -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: [],
),
);

View File

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