diff --git a/build-apk-split.sh b/build-apk-split.sh index b35f315..d1da17d 100644 --- a/build-apk-split.sh +++ b/build-apk-split.sh @@ -1,6 +1,8 @@ #!/bin/sh set -e -flutter build apk --release --split-per-abi +# flutter build apk --release --split-per-abi -echo "构建完成时间: $(date '+%Y-%m-%d %H:%M:%S')" +# echo "构建完成时间: $(date '+%Y-%m-%d %H:%M:%S')" + +pgyer upload build/app/outputs/flutter-apk/app-arm64-v8a-release.apk --build-update-description "新增可视化请求插件" \ No newline at end of file diff --git a/lib/app/config/api_common.dart b/lib/app/config/api_common.dart index b818cb9..54871bc 100644 --- a/lib/app/config/api_common.dart +++ b/lib/app/config/api_common.dart @@ -11,6 +11,9 @@ enum AuthApi { /// 获取参赛队伍列表 getTeamList('/api/events/device/item/group'), + /// 参赛队伍详情 + getTeamDetail('/api/events/device/schedule/pending/score'), + /// 获取选手的赛事信息 playerRegistrationList('/api/events/device/player/registration/list'); diff --git a/lib/features/auth/pages/page_auth.dart b/lib/features/auth/pages/page_auth.dart index 57eed95..93aa8e0 100644 --- a/lib/features/auth/pages/page_auth.dart +++ b/lib/features/auth/pages/page_auth.dart @@ -23,7 +23,7 @@ class _AuthPageWidgetState extends ConsumerState { void initState() { super.initState(); _controller = TextEditingController(); - _controller?.text = '555'; + // _controller?.text = '299689'; WidgetsBinding.instance.addPostFrameCallback((_) async { final token = AppStorage.getString(StorageKeys.authToken); diff --git a/lib/features/competition_teams/model/model_competition_team.dart b/lib/features/competition_teams/model/model_competition_team.dart index 5afa5ce..499961f 100644 --- a/lib/features/competition_teams/model/model_competition_team.dart +++ b/lib/features/competition_teams/model/model_competition_team.dart @@ -42,44 +42,59 @@ class CompetitionMatchup { } } +/// 参赛项目/组别列表项(来自 /api/events/device/item/group) class CompetitionTeamListItem { const CompetitionTeamListItem({ - required this.id, - required this.eventName, - required this.itemName, + required this.eventId, + required this.itemId, + required this.name, required this.groupName, - required this.matchPlace, - required this.matchStartTime, - required this.matchEndTime, - required this.matchups, - this.completed = false, + this.matchStartTime = '', + this.matchEndTime = '', + this.matchups = const [], }); - final String id; - final String eventName; - final String itemName; + final String eventId; + final String itemId; + final String name; final String groupName; - final String matchPlace; final String matchStartTime; final String matchEndTime; + + /// 对阵明细暂未由列表接口返回,默认空 final List matchups; - final bool completed; - String get title => groupName.isEmpty ? itemName : '$itemName ($groupName)'; + String get title => groupName.isEmpty ? name : '$name ($groupName)'; - String get scheduleTime => '$matchStartTime-$matchEndTime'; + String get scheduleTime { + if (matchStartTime.isEmpty && matchEndTime.isEmpty) return ''; + if (matchStartTime.isNotEmpty && matchEndTime.isNotEmpty) { + return '$matchStartTime-$matchEndTime'; + } + if (matchStartTime.isNotEmpty) return matchStartTime; + return matchEndTime; + } + + factory CompetitionTeamListItem.fromJson(Map json) { + return CompetitionTeamListItem( + eventId: (json['eventId'] ?? '').toString(), + itemId: (json['itemId'] ?? '').toString(), + name: (json['name'] ?? '').toString(), + groupName: (json['groupName'] ?? '').toString(), + matchStartTime: (json['matchStartTime'] ?? '').toString(), + matchEndTime: (json['matchEndTime'] ?? '').toString(), + ); + } CompetitionTeamListItem copyWith({List? matchups}) { return CompetitionTeamListItem( - id: id, - eventName: eventName, - itemName: itemName, + eventId: eventId, + itemId: itemId, + name: name, groupName: groupName, - matchPlace: matchPlace, matchStartTime: matchStartTime, matchEndTime: matchEndTime, matchups: matchups ?? this.matchups, - completed: completed, ); } } @@ -98,4 +113,59 @@ class CompetitionTeamPageResult { final int pageSize; bool get hasMore => page * pageSize < total; + + factory CompetitionTeamPageResult.fromJson( + dynamic json, { + required int page, + required int pageSize, + }) { + if (json is List) { + // 整表无分页:本页即全部,hasMore = false + final items = json + .whereType() + .map( + (item) => CompetitionTeamListItem.fromJson( + Map.from(item), + ), + ) + .toList(growable: false); + final effectivePageSize = items.isEmpty ? pageSize : items.length; + return CompetitionTeamPageResult( + items: items, + total: items.length, + page: page, + pageSize: effectivePageSize, + ); + } + + if (json is Map) { + final map = Map.from(json); + final rawItems = + map['items'] ?? map['rows'] ?? map['list'] ?? map['records']; + final items = rawItems is List + ? rawItems + .whereType() + .map( + (item) => CompetitionTeamListItem.fromJson( + Map.from(item), + ), + ) + .toList(growable: false) + : const []; + final total = (map['total'] as num?)?.toInt() ?? items.length; + return CompetitionTeamPageResult( + items: items, + total: total, + page: page, + pageSize: pageSize, + ); + } + + return CompetitionTeamPageResult( + items: const [], + total: 0, + page: page, + pageSize: pageSize, + ); + } } diff --git a/lib/features/competition_teams/pages/page_competition_team_detail.dart b/lib/features/competition_teams/pages/page_competition_team_detail.dart index 398b103..89a2a90 100644 --- a/lib/features/competition_teams/pages/page_competition_team_detail.dart +++ b/lib/features/competition_teams/pages/page_competition_team_detail.dart @@ -8,9 +8,14 @@ import 'package:recording_tool/shared/widgets/app_empty_view.dart'; import 'package:recording_tool/shared/widgets/app_toast.dart'; class CompetitionTeamDetailPage extends ConsumerWidget { - const CompetitionTeamDetailPage({super.key, required this.itemId}); + const CompetitionTeamDetailPage({ + super.key, + required this.itemId, + required this.eventId, + }); final String itemId; + final String eventId; @override Widget build(BuildContext context, WidgetRef ref) { @@ -19,7 +24,7 @@ class CompetitionTeamDetailPage extends ConsumerWidget { ); CompetitionTeamListItem? item; for (final candidate in items) { - if (candidate.id == itemId) { + if (candidate.itemId == itemId) { item = candidate; break; } @@ -30,6 +35,8 @@ class CompetitionTeamDetailPage extends ConsumerWidget { appBar: AppBar(title: Text(item?.title ?? '参赛队伍')), body: item == null ? const AppEmptyView(message: '未找到对阵信息') + : item.matchups.isEmpty + ? const AppEmptyView(message: '暂无对阵信息') : ListView.separated( padding: EdgeInsets.fromLTRB(20.w, 24.h, 20.w, 36.h), itemCount: item.matchups.length, @@ -42,7 +49,7 @@ class CompetitionTeamDetailPage extends ConsumerWidget { onManualProcess: () => _handleManualProcess( context, ref, - itemId: item!.id, + itemId: item!.itemId, matchup: matchup, ), ); diff --git a/lib/features/competition_teams/pages/page_competition_team_list.dart b/lib/features/competition_teams/pages/page_competition_team_list.dart index 98f5d86..668d74a 100644 --- a/lib/features/competition_teams/pages/page_competition_team_list.dart +++ b/lib/features/competition_teams/pages/page_competition_team_list.dart @@ -61,7 +61,10 @@ class _CompetitionTeamListPageState return _CompetitionScheduleCard( item: item, onTap: () => AppNavigator.push( - CompetitionTeamDetailPage(itemId: item.id), + CompetitionTeamDetailPage( + itemId: item.itemId, + eventId: item.eventId, + ), context: context, ), ); @@ -82,8 +85,10 @@ class _CompetitionScheduleCard extends StatelessWidget { @override Widget build(BuildContext context) { + final scheduleText = item.scheduleTime.isEmpty ? '时间待定' : item.scheduleTime; + return Material( - key: ValueKey('competition-team-item-${item.id}'), + key: ValueKey('competition-team-item-${item.itemId}'), color: Colors.white, borderRadius: BorderRadius.circular(14.r), child: InkWell( @@ -120,40 +125,18 @@ class _CompetitionScheduleCard extends StatelessWidget { ), ), SizedBox(height: 18.h), - _InfoLine( - icon: Icons.location_on_outlined, - text: item.matchPlace, - ), - SizedBox(height: 12.h), _InfoLine( icon: Icons.schedule_outlined, - text: item.scheduleTime, + text: scheduleText, ), ], ), ), SizedBox(width: 14.w), - Container( - width: 72.w, - height: 72.h, - alignment: Alignment.center, - decoration: BoxDecoration( - color: item.completed - ? const Color(0xFFF1F3F6) - : const Color(0xFFEAF3FF), - borderRadius: BorderRadius.circular(16.r), - ), - child: Text( - item.completed ? '已完成' : item.matchPlace, - textAlign: TextAlign.center, - style: TextStyle( - fontSize: item.completed ? 14.sp : 20.sp, - fontWeight: FontWeight.w700, - color: item.completed - ? const Color(0xFF69717D) - : const Color(0xFF147FEA), - ), - ), + Icon( + Icons.chevron_right, + size: 28.r, + color: const Color(0xFF9AA3AF), ), ], ), diff --git a/lib/features/competition_teams/server/server_competition_teams.dart b/lib/features/competition_teams/server/server_competition_teams.dart index 3404f48..9e062bb 100644 --- a/lib/features/competition_teams/server/server_competition_teams.dart +++ b/lib/features/competition_teams/server/server_competition_teams.dart @@ -1,118 +1,40 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:recording_tool/app/config/api_common.dart'; +import 'package:recording_tool/core/network/api_client.dart'; +import 'package:recording_tool/core/network/providers/dio_providers.dart'; import 'package:recording_tool/features/competition_teams/model/model_competition_team.dart'; final competitionTeamsServerProvider = Provider((ref) { - return const CompetitionTeamsServer(); + return CompetitionTeamsServer(ref.watch(apiClientProvider)); }); class CompetitionTeamsServer { - const CompetitionTeamsServer(); + CompetitionTeamsServer(this._apiClient); - static const totalCount = 10; + final ApiClient _apiClient; Future fetchPage({ required int page, required int pageSize, - }) async { - final start = (page - 1) * pageSize; - if (start >= totalCount) { - return CompetitionTeamPageResult( - items: const [], - total: totalCount, + }) { + return _apiClient.get( + AuthApi.getTeamList.path, + queryParameters: {'page': page, 'pageSize': pageSize}, + parser: (json) => CompetitionTeamPageResult.fromJson( + json, page: page, pageSize: pageSize, - ); - } - - final end = (start + pageSize).clamp(0, totalCount); - final items = List.generate( - end - start, - (index) => _buildItem(start + index), - ); - return CompetitionTeamPageResult( - items: items, - total: totalCount, - page: page, - pageSize: pageSize, - ); - } - - CompetitionTeamListItem _buildItem(int index) { - final number = index + 1; - final group = index.isEven ? '小学组' : '初中组'; - final hour = 9 + index ~/ 2; - return CompetitionTeamListItem( - id: 'competition-$number', - eventName: '全国青少年无人机大赛', - itemName: index % 3 == 0 ? '空中足球赛' : '空中格斗赛', - groupName: group, - matchPlace: '场地 ${index % 4 + 1}', - matchStartTime: '${hour.toString().padLeft(2, '0')}:00', - matchEndTime: '${hour.toString().padLeft(2, '0')}:30', - completed: index == totalCount - 1, - matchups: [ - _buildMatchup(itemNumber: number, matchNumber: 1), - _buildMatchup(itemNumber: number, matchNumber: 2), - ], - ); - } - - CompetitionMatchup _buildMatchup({ - required int itemNumber, - required int matchNumber, - }) { - final matchupId = 'match-$itemNumber-$matchNumber'; - final teamAIndex = (itemNumber + matchNumber - 2) % _teamNames.length; - final teamBIndex = (teamAIndex + 1) % _teamNames.length; - return CompetitionMatchup( - id: matchupId, - teamA: _buildTeam( - id: '$matchupId-team-a', - name: _teamNames[teamAIndex], - playerOffset: teamAIndex * 3, - ), - teamB: _buildTeam( - id: '$matchupId-team-b', - name: _teamNames[teamBIndex], - playerOffset: teamBIndex * 3, ), ); } - CompetitionTeam _buildTeam({ - required String id, - required String name, - required int playerOffset, + Future fetchTeamDetail({ + required String itemId, + required String eventId, }) { - return CompetitionTeam( - id: id, - name: name, - players: List.generate(3, (index) { - final playerIndex = (playerOffset + index) % _playerNames.length; - return CompetitionPlayer( - id: '$id-player-$index', - name: _playerNames[playerIndex], - ); - }), + return _apiClient.get( + AuthApi.getTeamDetail.path, + queryParameters: {'itemId': itemId, 'eventId': eventId}, ); } - - static const _teamNames = ['王多鱼队', '钱多多队', '逐风少年队', '蓝翼飞行队', '星火队']; - static const _playerNames = [ - '王伟', - '李庆超', - '王大亮', - '韩宁政', - '阮晴桦', - '刘美玲', - '陈子航', - '周白芷', - '林培伦', - '蔡依婷', - '夏志豪', - '赵云飞', - '孙雨泽', - '吴佳琪', - '郑凯文', - ]; } diff --git a/lib/features/competition_teams/view_model/view_model_competition_teams.dart b/lib/features/competition_teams/view_model/view_model_competition_teams.dart index b57a4de..ce7ebc5 100644 --- a/lib/features/competition_teams/view_model/view_model_competition_teams.dart +++ b/lib/features/competition_teams/view_model/view_model_competition_teams.dart @@ -47,7 +47,7 @@ class CompetitionTeamsViewModel extends StateNotifier { }) { final updatedItems = state.items .map((item) { - if (item.id != itemId) return item; + if (item.itemId != itemId) return item; final updatedMatchups = item.matchups .map((matchup) { if (matchup.id != matchupId) return matchup; @@ -67,7 +67,7 @@ class CompetitionTeamsViewModel extends StateNotifier { CompetitionTeamListItem? findItem(String itemId) { for (final item in state.items) { - if (item.id == itemId) return item; + if (item.itemId == itemId) return item; } return null; }