1.重构参赛队伍详情页面,更新数据模型以支持新结构;

2.优化比赛信息展示逻辑,增强用户交互体验;
3.修复API请求以获取队伍详情并处理异常情况。
This commit is contained in:
2026-07-23 11:44:47 +08:00
parent 1264ebdd7c
commit 8c127dd0e7
8 changed files with 460 additions and 149 deletions
+1 -1
View File
@@ -12,7 +12,7 @@ enum AuthApi {
getTeamList('/api/events/device/item/group'),
/// 参赛队伍详情
getTeamDetail('/api/events/device/schedule/pending/score'),
getTeamDetail('/api/events/device/schedule/pending'),
/// 获取选手的赛事信息
playerRegistrationList('/api/events/device/player/registration/list');
+11 -2
View File
@@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:recording_tool/app/router/app_navigator.dart';
@@ -23,7 +24,7 @@ class _AuthPageWidgetState extends ConsumerState<AuthPageWidget> {
void initState() {
super.initState();
_controller = TextEditingController();
// _controller?.text = '299689';
_controller?.text = '986570';
WidgetsBinding.instance.addPostFrameCallback((_) async {
final token = AppStorage.getString(StorageKeys.authToken);
@@ -59,7 +60,15 @@ class _AuthPageWidgetState extends ConsumerState<AuthPageWidget> {
padding: EdgeInsets.symmetric(horizontal: 20.w),
child: Column(
children: [
AppTextField(controller: _controller),
AppTextField(
controller: _controller,
keyboardType: TextInputType.number,
maxLength: 6,
inputFormatters: [
FilteringTextInputFormatter.digitsOnly,
LengthLimitingTextInputFormatter(6),
],
),
SizedBox(height: 20.h),
SizedBox(
width: double.maxFinite,
@@ -169,3 +169,161 @@ class CompetitionTeamPageResult {
);
}
}
/// 参赛队伍详情
class CompetitionTeamDetail {
String? scheduleId;
String? itemId;
String? eventId;
String? itemName;
String? groupName;
String? matchPlace;
String? matchStartTime;
String? matchEndTime;
List<Matchup>? matchups;
CompetitionTeamDetail({
this.scheduleId,
this.itemId,
this.eventId,
this.itemName,
this.groupName,
this.matchPlace,
this.matchStartTime,
this.matchEndTime,
this.matchups,
});
factory CompetitionTeamDetail.fromJson(Map<String, dynamic> json) =>
CompetitionTeamDetail(
scheduleId: json['scheduleId']?.toString(),
itemId: json['itemId']?.toString(),
eventId: json['eventId']?.toString(),
itemName: json['itemName']?.toString(),
groupName: json['groupName']?.toString(),
matchPlace: json['matchPlace']?.toString(),
matchStartTime: json['matchStartTime']?.toString(),
matchEndTime: json['matchEndTime']?.toString(),
matchups: json['matchups'] == null
? const []
: List<Matchup>.from(
(json['matchups'] as List).whereType<Map>().map(
(x) => Matchup.fromJson(Map<String, dynamic>.from(x)),
),
),
);
/// 兼容 data 为对象或数组(取首项)
factory CompetitionTeamDetail.fromResponse(dynamic json) {
if (json is List) {
if (json.isEmpty) return CompetitionTeamDetail(matchups: const []);
final first = json.first;
if (first is Map) {
return CompetitionTeamDetail.fromJson(Map<String, dynamic>.from(first));
}
return CompetitionTeamDetail(matchups: const []);
}
if (json is Map) {
return CompetitionTeamDetail.fromJson(Map<String, dynamic>.from(json));
}
return CompetitionTeamDetail(matchups: const []);
}
Map<String, dynamic> toJson() => {
'scheduleId': scheduleId,
'itemId': itemId,
'eventId': eventId,
'itemName': itemName,
'groupName': groupName,
'matchPlace': matchPlace,
'matchStartTime': matchStartTime,
'matchEndTime': matchEndTime,
'matchups': matchups == null
? []
: List<dynamic>.from(matchups!.map((x) => x.toJson())),
};
}
class Matchup {
String? matchTitle;
List<Team>? teamA;
List<Team>? teamB;
Matchup({this.matchTitle, this.teamA, this.teamB});
factory Matchup.fromJson(Map<String, dynamic> json) => Matchup(
matchTitle: json['matchTitle']?.toString(),
teamA: json['teamA'] == null
? const []
: List<Team>.from(
(json['teamA'] as List).whereType<Map>().map(
(x) => Team.fromJson(Map<String, dynamic>.from(x)),
),
),
teamB: json['teamB'] == null
? const []
: List<Team>.from(
(json['teamB'] as List).whereType<Map>().map(
(x) => Team.fromJson(Map<String, dynamic>.from(x)),
),
),
);
Map<String, dynamic> toJson() => {
'matchTitle': matchTitle,
'teamA': teamA == null
? []
: List<dynamic>.from(teamA!.map((x) => x.toJson())),
'teamB': teamB == null
? []
: List<dynamic>.from(teamB!.map((x) => x.toJson())),
};
}
class Team {
String? id;
String? teamName;
List<Player>? players;
Team({this.id, this.teamName, this.players});
factory Team.fromJson(Map<String, dynamic> json) => Team(
id: json['id']?.toString(),
teamName: json['teamName']?.toString(),
players: json['players'] == null
? const []
: List<Player>.from(
(json['players'] as List).whereType<Map>().map(
(x) => Player.fromJson(Map<String, dynamic>.from(x)),
),
),
);
Map<String, dynamic> toJson() => {
'id': id,
'teamName': teamName,
'players': players == null
? []
: List<dynamic>.from(players!.map((x) => x.toJson())),
};
}
class Player {
String? id;
String? name;
bool? isLeader;
Player({this.id, this.name, this.isLeader});
factory Player.fromJson(Map<String, dynamic> json) => Player(
id: json['id']?.toString(),
name: json['name']?.toString(),
isLeader: json['isLeader'] as bool?,
);
Map<String, dynamic> toJson() => {
'id': id,
'name': name,
'isLeader': isLeader,
};
}
@@ -2,56 +2,91 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:recording_tool/features/competition_teams/model/model_competition_team.dart';
import 'package:recording_tool/features/competition_teams/view_model/view_model_competition_teams.dart';
import 'package:recording_tool/features/competition_teams/widgets/widget_manual_winner_dialog.dart';
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,
required this.eventId,
});
class CompetitionTeamDetailPage extends ConsumerStatefulWidget {
const CompetitionTeamDetailPage({super.key, required this.detail});
final String itemId;
final String eventId;
final CompetitionTeamDetail detail;
@override
Widget build(BuildContext context, WidgetRef ref) {
final items = ref.watch(
competitionTeamsProvider.select((state) => state.items),
ConsumerState<CompetitionTeamDetailPage> createState() =>
_CompetitionTeamDetailPageState();
}
class _CompetitionTeamDetailPageState
extends ConsumerState<CompetitionTeamDetailPage> {
/// matchupIndex -> winnerTeamId
final Map<int, String> _winners = {};
CompetitionTeamDetail get _detail => widget.detail;
String get _title {
final name = _detail.itemName?.trim() ?? '';
final group = _detail.groupName?.trim() ?? '';
if (name.isEmpty) return '参赛队伍';
return group.isEmpty ? name : '$name $group';
}
List<Matchup> get _matchups => _detail.matchups ?? const <Matchup>[];
CompetitionTeam _toCompetitionTeam(Team team) {
return CompetitionTeam(
id: team.id?.trim().isNotEmpty == true ? team.id! : 'unknown-team',
name: team.teamName?.trim().isNotEmpty == true ? team.teamName! : '未命名队伍',
players: (team.players ?? const <Player>[])
.map(
(player) => CompetitionPlayer(
id: player.id?.trim() ?? '',
name: player.name?.trim().isNotEmpty == true
? player.name!
: '选手',
),
)
.toList(growable: false),
);
CompetitionTeamListItem? item;
for (final candidate in items) {
if (candidate.itemId == itemId) {
item = candidate;
break;
}
}
CompetitionMatchup? _toCompetitionMatchup(Matchup matchup, int index) {
final teamA = matchup.teamA;
final teamB = matchup.teamB;
if (teamA == null || teamA.isEmpty || teamB == null || teamB.isEmpty) {
return null;
}
return CompetitionMatchup(
id: '${_detail.scheduleId ?? _detail.itemId ?? 'match'}-$index',
teamA: _toCompetitionTeam(teamA.first),
teamB: _toCompetitionTeam(teamB.first),
winnerTeamId: _winners[index],
);
}
@override
Widget build(BuildContext context) {
final matchups = _matchups;
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(title: Text(item?.title ?? '参赛队伍')),
body: item == null
? const AppEmptyView(message: '未找到对阵信息')
: item.matchups.isEmpty
appBar: AppBar(title: Text(_title)),
body: matchups.isEmpty
? const AppEmptyView(message: '暂无对阵信息')
: ListView.separated(
padding: EdgeInsets.fromLTRB(20.w, 24.h, 20.w, 36.h),
itemCount: item.matchups.length,
itemCount: matchups.length,
separatorBuilder: (_, _) => SizedBox(height: 22.h),
itemBuilder: (context, index) {
final matchup = item!.matchups[index];
final raw = matchups[index];
final matchup = _toCompetitionMatchup(raw, index);
if (matchup == null) {
return const SizedBox.shrink();
}
return _MatchupCard(
matchup: matchup,
index: index,
onManualProcess: () => _handleManualProcess(
context,
ref,
itemId: item!.itemId,
matchup: matchup,
),
matchTitle: raw.matchTitle?.trim() ?? '',
onManualProcess: () => _handleManualProcess(matchup, index),
);
},
),
@@ -59,24 +94,16 @@ class CompetitionTeamDetailPage extends ConsumerWidget {
}
Future<void> _handleManualProcess(
BuildContext context,
WidgetRef ref, {
required String itemId,
required CompetitionMatchup matchup,
}) async {
CompetitionMatchup matchup,
int index,
) async {
final winnerTeamId = await ManualWinnerDialog.show(
context,
matchup: matchup,
);
if (winnerTeamId == null || !context.mounted) return;
if (winnerTeamId == null || !mounted) return;
ref
.read(competitionTeamsProvider.notifier)
.selectWinner(
itemId: itemId,
matchupId: matchup.id,
winnerTeamId: winnerTeamId,
);
setState(() => _winners[index] = winnerTeamId);
final winnerName = winnerTeamId == matchup.teamA.id
? matchup.teamA.name
: matchup.teamB.name;
@@ -88,15 +115,18 @@ class _MatchupCard extends StatelessWidget {
const _MatchupCard({
required this.matchup,
required this.index,
required this.matchTitle,
required this.onManualProcess,
});
final CompetitionMatchup matchup;
final int index;
final String matchTitle;
final VoidCallback onManualProcess;
@override
Widget build(BuildContext context) {
final title = matchTitle.isEmpty ? '${index + 1}' : matchTitle;
return Container(
key: ValueKey('competition-matchup-${matchup.id}'),
padding: EdgeInsets.fromLTRB(16.w, 10.h, 16.w, 18.h),
@@ -109,14 +139,17 @@ class _MatchupCard extends StatelessWidget {
children: [
Row(
children: [
Text(
'${index + 1}',
style: TextStyle(
fontSize: 14.sp,
color: const Color(0xFF7A828E),
Expanded(
child: Text(
title,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 14.sp,
color: const Color(0xFF7A828E),
),
),
),
const Spacer(),
TextButton(
key: ValueKey('manual-process-${matchup.id}'),
onPressed: onManualProcess,
@@ -4,11 +4,13 @@ import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:recording_tool/app/router/app_navigator.dart';
import 'package:recording_tool/features/competition_teams/model/model_competition_team.dart';
import 'package:recording_tool/features/competition_teams/pages/page_competition_team_detail.dart';
import 'package:recording_tool/features/competition_teams/server/server_competition_teams.dart';
import 'package:recording_tool/features/competition_teams/view_model/view_model_competition_teams.dart';
import 'package:recording_tool/shared/widgets/app_empty_view.dart';
import 'package:recording_tool/shared/widgets/app_error_view.dart';
import 'package:recording_tool/shared/widgets/app_loading_view.dart';
import 'package:recording_tool/shared/widgets/app_refresh_list.dart';
import 'package:recording_tool/shared/widgets/app_toast.dart';
class CompetitionTeamListPage extends ConsumerStatefulWidget {
const CompetitionTeamListPage({super.key});
@@ -60,13 +62,23 @@ class _CompetitionTeamListPageState
itemBuilder: (context, item, index) {
return _CompetitionScheduleCard(
item: item,
onTap: () => AppNavigator.push(
CompetitionTeamDetailPage(
itemId: item.itemId,
eventId: item.eventId,
),
context: context,
),
onTap: () async {
try {
final detail = await ref
.read(competitionTeamsServerProvider)
.fetchTeamDetail(
itemId: item.itemId,
eventId: item.eventId,
);
if (!context.mounted) return;
AppNavigator.push(
CompetitionTeamDetailPage(detail: detail),
context: context,
);
} catch (error) {
AppToast.show('对阵详情加载失败,请重试');
}
},
);
},
);
@@ -15,12 +15,12 @@ typedef TeamQrScanner = Future<String?> Function(BuildContext context);
class EventTeamMatchPage extends StatefulWidget {
const EventTeamMatchPage({
super.key,
required this.item,
required this.playerId,
this.qrScanner,
required this.detail,
});
final EventRegistrationItem item;
final CompetitionTeamDetail detail;
final String playerId;
final TeamQrScanner? qrScanner;
@@ -32,55 +32,113 @@ class _EventTeamMatchPageState extends State<EventTeamMatchPage> {
final Set<String> _verifiedUserIds = <String>{};
String? _winnerTeamId;
CompetitionTeam get _homeTeam {
final leader = widget.item.teamLeader;
final teamId = leader?.userId.isNotEmpty == true
? leader!.userId
: widget.item.userId.isNotEmpty
? widget.item.userId
: 'home-team';
final teamName = leader?.name.isNotEmpty == true
? leader!.name
: widget.item.playerName.isNotEmpty
? widget.item.playerName
: '本方队伍';
return CompetitionTeam(
id: teamId,
name: teamName,
players: widget.item.teamMembers
.map(
(member) => CompetitionPlayer(id: member.userId, name: member.name),
)
.toList(growable: false),
);
CompetitionTeamDetail get _detail => widget.detail;
/// 备注:teamA 为红队,teamB 为蓝队。
Matchup? get _firstMatchup {
final matchups = _detail.matchups;
if (matchups == null || matchups.isEmpty) return null;
return matchups.first;
}
CompetitionTeam get _opponentTeam {
final opponentId = widget.item.opponentId.isNotEmpty
? widget.item.opponentId
: 'opponent-team';
final opponentName = widget.item.opponentName.isNotEmpty
? widget.item.opponentName
: '对方队伍';
return CompetitionTeam(
id: opponentId,
name: opponentName,
players:
widget.item.opponentId.isEmpty && widget.item.opponentName.isEmpty
? const []
: [CompetitionPlayer(id: opponentId, name: opponentName)],
);
/// 红队(teamA
Team? get _redRawTeam {
final teams = _firstMatchup?.teamA;
if (teams == null || teams.isEmpty) return null;
return teams.first;
}
CompetitionMatchup get _matchup => CompetitionMatchup(
id: widget.item.scheduleId.isNotEmpty
? widget.item.scheduleId
: '${widget.item.itemId}-team-match',
teamA: _homeTeam,
teamB: _opponentTeam,
winnerTeamId: _winnerTeamId,
/// 蓝队(teamB
Team? get _blueRawTeam {
final teams = _firstMatchup?.teamB;
if (teams == null || teams.isEmpty) return null;
return teams.first;
}
CompetitionTeam get _redTeam => _toCompetitionTeam(
_redRawTeam,
fallbackId: 'red-team',
fallbackName: '红队',
);
CompetitionTeam get _blueTeam => _toCompetitionTeam(
_blueRawTeam,
fallbackId: 'blue-team',
fallbackName: '蓝队',
);
List<EventTeamMember> get _redMembers =>
_toEventMembers(_redRawTeam?.players);
List<EventTeamMember> get _blueMembers =>
_toEventMembers(_blueRawTeam?.players);
CompetitionMatchup get _matchup {
final scheduleId = _detail.scheduleId?.trim() ?? '';
final itemId = _detail.itemId?.trim() ?? '';
return CompetitionMatchup(
id: scheduleId.isNotEmpty ? scheduleId : '$itemId-team-match',
teamA: _redTeam,
teamB: _blueTeam,
winnerTeamId: _winnerTeamId,
);
}
/// H5 bridge 仍需要 EventRegistrationItem,从 detail 组装最小对象。
/// 备注:红队成员写入 teamMembers,蓝队写入 opponent。
EventRegistrationItem get _scoreBridgeItem {
final blue = _blueTeam;
return EventRegistrationItem(
eventId: _detail.eventId?.trim() ?? '',
itemId: _detail.itemId?.trim() ?? '',
scheduleId: _detail.scheduleId?.trim() ?? '',
eventName: '',
itemName: _detail.itemName?.trim() ?? '',
groupName: _detail.groupName?.trim() ?? '',
matchPlace: _detail.matchPlace?.trim() ?? '',
matchStartTime: _detail.matchStartTime?.trim() ?? '',
matchEndTime: _detail.matchEndTime?.trim() ?? '',
opponentId: blue.id == 'blue-team' ? '' : blue.id,
opponentName: blue.name == '蓝队' ? '' : blue.name,
teamMembers: _redMembers,
);
}
CompetitionTeam _toCompetitionTeam(
Team? team, {
required String fallbackId,
required String fallbackName,
}) {
final id = team?.id?.trim() ?? '';
final name = team?.teamName?.trim() ?? '';
final players = (team?.players ?? const <Player>[])
.map(
(player) => CompetitionPlayer(
id: player.id?.trim() ?? '',
name: player.name?.trim() ?? '',
),
)
.toList(growable: false);
return CompetitionTeam(
id: id.isNotEmpty ? id : fallbackId,
name: name.isNotEmpty ? name : fallbackName,
players: players,
);
}
List<EventTeamMember> _toEventMembers(List<Player>? players) {
if (players == null || players.isEmpty) return const [];
return players
.map(
(player) => EventTeamMember(
userId: player.id?.trim() ?? '',
name: player.name?.trim() ?? '',
isLeader: player.isLeader ?? false,
),
)
.toList(growable: false);
}
@override
void initState() {
super.initState();
@@ -92,18 +150,15 @@ class _EventTeamMatchPageState extends State<EventTeamMatchPage> {
bool _isKnownMember(String userId) {
if (userId.isEmpty) return false;
if (userId == widget.item.opponentId) return true;
return widget.item.teamMembers.any((member) => member.userId == userId);
return _redMembers.any((member) => member.userId == userId) ||
_blueMembers.any((member) => member.userId == userId);
}
String _memberNameOf(String userId) {
if (userId == widget.item.opponentId) {
return widget.item.opponentName.isEmpty
? '对方队长'
: widget.item.opponentName;
}
for (final member in widget.item.teamMembers) {
if (member.userId == userId) return member.name;
for (final member in [..._redMembers, ..._blueMembers]) {
if (member.userId == userId) {
return member.name.isEmpty ? '参赛成员' : member.name;
}
}
return '';
}
@@ -131,23 +186,23 @@ class _EventTeamMatchPageState extends State<EventTeamMatchPage> {
);
if (!mounted || winnerTeamId == null) return;
setState(() => _winnerTeamId = winnerTeamId);
final winnerName = winnerTeamId == _homeTeam.id
? _homeTeam.name
: _opponentTeam.name;
final winnerName = winnerTeamId == _redTeam.id
? _redTeam.name
: _blueTeam.name;
AppToast.show('已设置$winnerName直接获胜');
}
void _startDirectly() {
AppNavigator.push(
buildTeamScorePage(item: widget.item, playerId: widget.playerId),
buildTeamScorePage(item: _scoreBridgeItem, playerId: widget.playerId),
context: context,
);
}
@override
Widget build(BuildContext context) {
final homeTeam = _homeTeam;
final opponentTeam = _opponentTeam;
final redTeam = _redTeam;
final blueTeam = _blueTeam;
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(),
@@ -161,8 +216,16 @@ class _EventTeamMatchPageState extends State<EventTeamMatchPage> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_MatchMetadata(item: widget.item),
SizedBox(height: 16.h),
_MatchMetadata(detail: _detail),
SizedBox(height: 10.h),
Text(
'备注:上方红队(teamA),下方蓝队(teamB)',
style: TextStyle(
fontSize: 14.sp,
color: const Color(0xFF7A828E),
),
),
SizedBox(height: 8.h),
Align(
alignment: Alignment.centerRight,
child: TextButton(
@@ -179,28 +242,24 @@ class _EventTeamMatchPageState extends State<EventTeamMatchPage> {
),
),
_TeamCard(
team: homeTeam,
members: widget.item.teamMembers,
teamLabel: '红队',
team: redTeam,
members: _redMembers,
backgroundColor: const Color(0xFFFFEEF0),
accentColor: const Color(0xFFE84B5B),
verifiedUserIds: _verifiedUserIds,
winner: _winnerTeamId == homeTeam.id,
winner: _winnerTeamId == redTeam.id,
),
SizedBox(height: 16.h),
_TeamCard(
team: opponentTeam,
members: [
EventTeamMember(
userId: widget.item.opponentId,
name: widget.item.opponentName,
isLeader: true,
),
],
teamLabel: '蓝队',
team: blueTeam,
members: _blueMembers,
backgroundColor: const Color(0xFFEDF5FF),
accentColor: const Color(0xFF287FDD),
verifiedUserIds: _verifiedUserIds,
winner: _winnerTeamId == opponentTeam.id,
emptyMessage: '暂无对方成员数据',
winner: _winnerTeamId == blueTeam.id,
emptyMessage: '暂无蓝队成员数据',
),
],
),
@@ -245,12 +304,15 @@ WebviewPage buildTeamScorePage({
}
class _MatchMetadata extends StatelessWidget {
const _MatchMetadata({required this.item});
const _MatchMetadata({required this.detail});
final EventRegistrationItem item;
final CompetitionTeamDetail detail;
@override
Widget build(BuildContext context) {
final itemName = detail.itemName?.trim() ?? '';
final matchPlace = detail.matchPlace?.trim() ?? '';
final groupName = detail.groupName?.trim() ?? '';
return Container(
width: double.infinity,
padding: EdgeInsets.all(18.r),
@@ -264,14 +326,14 @@ class _MatchMetadata extends StatelessWidget {
Row(
children: [
Expanded(
child: _MetadataText(label: '比赛项目', value: item.itemName),
child: _MetadataText(label: '比赛项目', value: itemName),
),
SizedBox(width: 16.w),
_MetadataText(label: '场地', value: item.matchPlace),
_MetadataText(label: '场地', value: matchPlace),
],
),
SizedBox(height: 14.h),
_MetadataText(label: '组别', value: item.groupName),
_MetadataText(label: '组别', value: groupName),
],
),
);
@@ -302,6 +364,7 @@ class _MetadataText extends StatelessWidget {
class _TeamCard extends StatelessWidget {
const _TeamCard({
required this.teamLabel,
required this.team,
required this.members,
required this.backgroundColor,
@@ -311,6 +374,7 @@ class _TeamCard extends StatelessWidget {
this.emptyMessage = '暂无成员数据',
});
final String teamLabel;
final CompetitionTeam team;
final List<EventTeamMember> members;
final Color backgroundColor;
@@ -343,7 +407,7 @@ class _TeamCard extends StatelessWidget {
children: [
Expanded(
child: Text(
'队长${team.name}',
'$teamLabel${team.name}',
style: TextStyle(
fontSize: 19.sp,
fontWeight: FontWeight.w700,
@@ -28,13 +28,21 @@ class CompetitionTeamsServer {
);
}
Future<dynamic> fetchTeamDetail({
Future<CompetitionTeamDetail> fetchTeamDetail({
required String itemId,
required String eventId,
String? scheduleId,
String? opponentId,
}) {
return _apiClient.get(
return _apiClient.post(
AuthApi.getTeamDetail.path,
queryParameters: {'itemId': itemId, 'eventId': eventId},
data: {
'itemId': itemId,
'eventId': eventId,
'scheduleId': scheduleId,
'opponentId': opponentId,
},
parser: (json) => CompetitionTeamDetail.fromResponse(json),
);
}
}
+33 -6
View File
@@ -3,7 +3,9 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:recording_tool/app/config/app_config.dart';
import 'package:recording_tool/app/router/app_navigator.dart';
import 'package:recording_tool/features/competition_teams/model/model_competition_team.dart';
import 'package:recording_tool/features/competition_teams/pages/page_event_team_match.dart';
import 'package:recording_tool/features/competition_teams/server/server_competition_teams.dart';
import 'package:recording_tool/features/events/model/model_event_info.dart';
import 'package:recording_tool/features/events/state/state_event_info.dart';
import 'package:recording_tool/features/events/view_model/view_model_event_info.dart';
@@ -25,13 +27,37 @@ class _EventInfoPageState extends ConsumerState<EventInfoPage> {
}
Future<void> onItemTap(EventRegistrationItem item) async {
// debugPrint('item tapped: ${item.itemName}');
// await ref.read(eventInfoProvider.notifier).requestStreamKey(item);
if (!mounted) return;
// final profile = ref.read(eventInfoProvider).profile;
CompetitionTeamDetail? detail;
if (item.opponentId.isNotEmpty && item.opponentId != '0') {
detail = await ref
.read(competitionTeamsServerProvider)
.fetchTeamDetail(
itemId: item.itemId,
eventId: item.eventId,
scheduleId: item.scheduleId,
opponentId: item.opponentId,
);
if (!mounted) return;
AppNavigator.push(
buildEventRegistrationDestination(
item: item,
playerId: widget.playerId,
detail: detail,
),
context: context,
);
return;
}
if (!mounted) return;
AppNavigator.push(
buildEventRegistrationDestination(item: item, playerId: widget.playerId),
buildEventRegistrationDestination(
item: item,
playerId: widget.playerId,
detail: null,
),
context: context,
);
}
@@ -89,9 +115,10 @@ class _EventInfoPageState extends ConsumerState<EventInfoPage> {
Widget buildEventRegistrationDestination({
required EventRegistrationItem item,
required String playerId,
required CompetitionTeamDetail? detail,
}) {
if (item.opponentId.isNotEmpty && item.opponentId != '0') {
return EventTeamMatchPage(item: item, playerId: playerId);
if (detail != null) {
return EventTeamMatchPage(playerId: playerId, detail: detail);
}
return WebviewPage(
url: AppConfig.current.mainRefereeScoreH5Url,