From 62cb2d8657c559b33b2cebd7bacff63294b02735 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A9=AC=E6=A2=93=E5=BD=AD?= Date: Tue, 22 Sep 2026 08:44:12 +0800 Subject: [PATCH] =?UTF-8?q?=E8=AF=84=E5=88=86=E5=8D=95=E8=AE=A1=E7=AE=97?= =?UTF-8?q?=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/core/network/score_item_key_matcher.dart | 11 ++++- .../controllers/scoring_controller.dart | 24 +++++++---- test/score_item_key_matcher_test.dart | 40 +++++++++++++++++++ 3 files changed, 67 insertions(+), 8 deletions(-) diff --git a/lib/core/network/score_item_key_matcher.dart b/lib/core/network/score_item_key_matcher.dart index 6ac8ba2..7bd055c 100644 --- a/lib/core/network/score_item_key_matcher.dart +++ b/lib/core/network/score_item_key_matcher.dart @@ -1,12 +1,21 @@ /// Maps server labels to the existing scoring controls without allowing a /// shorter label (e.g. 违例) to shadow a more specific one (e.g. 空间违例). abstract final class ScoreItemKeyMatcher { - static String? match(Iterable keys, String source) { + static String? match( + Iterable keys, + String source, { + Map aliases = const {}, + }) { String normalize(String value) => value.replaceAll(RegExp(r'[\s()()_+\-]'), '').toLowerCase(); final text = normalize(source); if (text.isEmpty) return null; + for (final alias in aliases.entries) { + if (text.contains(normalize(alias.key)) && keys.contains(alias.value)) { + return alias.value; + } + } final candidates = { for (final key in keys) if (normalize(key).isNotEmpty) key: normalize(key), diff --git a/lib/modules/scoring/controllers/scoring_controller.dart b/lib/modules/scoring/controllers/scoring_controller.dart index bfe5127..fa401a5 100644 --- a/lib/modules/scoring/controllers/scoring_controller.dart +++ b/lib/modules/scoring/controllers/scoring_controller.dart @@ -289,13 +289,14 @@ class ScoringController extends GetxController { } if (profile.competition == CompetitionKind.individual) { - if (profile.role == ScoreRole.difficulty || - (profile.role == ScoreRole.technical && - taskVariant != EliteScoringRuleCatalog.individualSolo)) { + if (profile.role == ScoreRole.difficulty) { requiredElementCounts.assignAll({ EliteScoringRuleCatalog.requiredLevel3AndAbove: 0, EliteScoringRuleCatalog.requiredLevel2AndBelow: 0, }); + } else if (profile.role == ScoreRole.technical && + taskVariant != EliteScoringRuleCatalog.individualSolo) { + requiredElementCounts.assignAll({'互动配合': 0}); } } else if (profile.competition == CompetitionKind.wheel && profile.role == ScoreRole.technical) { @@ -369,10 +370,7 @@ class ScoringController extends GetxController { } if (item.itemType == 2 || item.scoreDimension == 3) { - final key = _matchingKey( - requiredElementCounts.keys, - '${item.subjectName ?? ''}${item.name}${item.code}', - ); + final key = _requiredElementKeyOf(item); if (key != null) { requiredElementCounts[key] = count; _itemUiKeys[item.code] = key; @@ -466,6 +464,18 @@ class ScoringController extends GetxController { return ScoreItemKeyMatcher.match(keys, source); } + String? _requiredElementKeyOf(JudgeScoreItem item) { + return ScoreItemKeyMatcher.match( + requiredElementCounts.keys, + '${item.subjectName ?? ''}${item.name}${item.code}', + aliases: const { + 'REQUIRED_N3_PLUS': EliteScoringRuleCatalog.requiredLevel3AndAbove, + 'REQUIRED_N2_MINUS': EliteScoringRuleCatalog.requiredLevel2AndBelow, + 'REQ_INTERACTION': '互动配合', + }, + ); + } + Future _restoreLatestScore() async { final saved = await _repository.loadLatest( judgeId: profile.account, diff --git a/test/score_item_key_matcher_test.dart b/test/score_item_key_matcher_test.dart index 2519e76..3d6d5f2 100644 --- a/test/score_item_key_matcher_test.dart +++ b/test/score_item_key_matcher_test.dart @@ -1,6 +1,7 @@ import 'package:flutter_test/flutter_test.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/models/elite_scoring_rule.dart'; import 'package:yd_pattern_scoring_system/core/network/score_item_key_matcher.dart'; void main() { @@ -47,4 +48,43 @@ void main() { expect(ScoreItemKeyMatcher.match(keys, '未知项目'), isNull); expect(ScoreItemKeyMatcher.match(keys, '违例'), '违例'); }); + + test('个人花样规定元素按稳定编码映射到平板控件', () { + const requiredKeys = [ + EliteScoringRuleCatalog.requiredLevel3AndAbove, + EliteScoringRuleCatalog.requiredLevel2AndBelow, + ]; + const aliases = { + 'REQUIRED_N3_PLUS': EliteScoringRuleCatalog.requiredLevel3AndAbove, + 'REQUIRED_N2_MINUS': EliteScoringRuleCatalog.requiredLevel2AndBelow, + }; + + expect( + ScoreItemKeyMatcher.match( + requiredKeys, + '3级及以上规定元素数REQUIRED_N3_PLUS', + aliases: aliases, + ), + EliteScoringRuleCatalog.requiredLevel3AndAbove, + ); + expect( + ScoreItemKeyMatcher.match( + requiredKeys, + '2级及以下规定元素数REQUIRED_N2_MINUS', + aliases: aliases, + ), + EliteScoringRuleCatalog.requiredLevel2AndBelow, + ); + }); + + test('同步花样互动配合按稳定编码映射到主裁控件', () { + expect( + ScoreItemKeyMatcher.match( + const ['互动配合'], + 'REQ_INTERACTION', + aliases: const {'REQ_INTERACTION': '互动配合'}, + ), + '互动配合', + ); + }); }