新增人工设置晋级/淘汰功能,更新相关数据模型和API接口;重构比赛页面以支持新逻辑,优化用户交互体验。
This commit is contained in:
@@ -14,6 +14,9 @@ enum AuthApi {
|
|||||||
/// 参赛队伍详情
|
/// 参赛队伍详情
|
||||||
getTeamDetail('/api/events/device/schedule/pending'),
|
getTeamDetail('/api/events/device/schedule/pending'),
|
||||||
|
|
||||||
|
/// 人工设置晋级/淘汰
|
||||||
|
setTeamStatus('/api/events/device/schedule/team/score'),
|
||||||
|
|
||||||
/// 获取选手的赛事信息
|
/// 获取选手的赛事信息
|
||||||
playerRegistrationList('/api/events/device/player/registration/list');
|
playerRegistrationList('/api/events/device/player/registration/list');
|
||||||
|
|
||||||
|
|||||||
@@ -169,161 +169,3 @@ 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,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -0,0 +1,174 @@
|
|||||||
|
/// 参赛队伍详情
|
||||||
|
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;
|
||||||
|
String? opponentId;
|
||||||
|
List<Team>? teamA;
|
||||||
|
List<Team>? teamB;
|
||||||
|
|
||||||
|
Matchup({this.matchTitle, this.opponentId, this.teamA, this.teamB});
|
||||||
|
|
||||||
|
factory Matchup.fromJson(Map<String, dynamic> json) => Matchup(
|
||||||
|
matchTitle: json['matchTitle']?.toString(),
|
||||||
|
opponentId: json['opponentId']?.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,
|
||||||
|
'opponentId': opponentId,
|
||||||
|
'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? teamName;
|
||||||
|
List<Player>? players;
|
||||||
|
|
||||||
|
Team({this.teamName, this.players});
|
||||||
|
|
||||||
|
String get playerNames => (players ?? const <Player>[])
|
||||||
|
.map((player) => player.name?.trim() ?? '')
|
||||||
|
.where((name) => name.isNotEmpty)
|
||||||
|
.join('、');
|
||||||
|
|
||||||
|
/// 队长 Player.id;无队长则取首个选手
|
||||||
|
String? get leaderUserId {
|
||||||
|
final list = players ?? const <Player>[];
|
||||||
|
for (final player in list) {
|
||||||
|
final id = player.id?.trim() ?? '';
|
||||||
|
if (player.isLeader == true && id.isNotEmpty) return id;
|
||||||
|
}
|
||||||
|
if (list.isEmpty) return null;
|
||||||
|
final firstId = list.first.id?.trim() ?? '';
|
||||||
|
return firstId.isEmpty ? null : firstId;
|
||||||
|
}
|
||||||
|
|
||||||
|
factory Team.fromJson(Map<String, dynamic> json) => Team(
|
||||||
|
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() => {
|
||||||
|
'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,
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,8 +1,12 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||||
|
import 'package:recording_tool/core/network/api_exception.dart';
|
||||||
import 'package:recording_tool/features/competition_teams/model/model_competition_team.dart';
|
import 'package:recording_tool/features/competition_teams/model/model_competition_team.dart';
|
||||||
|
import 'package:recording_tool/features/competition_teams/model/model_competition_team_detail.dart';
|
||||||
import 'package:recording_tool/features/competition_teams/widgets/widget_manual_winner_dialog.dart';
|
import 'package:recording_tool/features/competition_teams/widgets/widget_manual_winner_dialog.dart';
|
||||||
|
import 'package:recording_tool/features/events/request_model/request_model_event.dart';
|
||||||
|
import 'package:recording_tool/features/events/server/server_events.dart';
|
||||||
import 'package:recording_tool/shared/widgets/app_empty_view.dart';
|
import 'package:recording_tool/shared/widgets/app_empty_view.dart';
|
||||||
import 'package:recording_tool/shared/widgets/app_toast.dart';
|
import 'package:recording_tool/shared/widgets/app_toast.dart';
|
||||||
|
|
||||||
@@ -18,8 +22,8 @@ class CompetitionTeamDetailPage extends ConsumerStatefulWidget {
|
|||||||
|
|
||||||
class _CompetitionTeamDetailPageState
|
class _CompetitionTeamDetailPageState
|
||||||
extends ConsumerState<CompetitionTeamDetailPage> {
|
extends ConsumerState<CompetitionTeamDetailPage> {
|
||||||
/// matchupIndex -> winnerTeamId
|
/// matchupIndex -> winner side index(0=teamA,1=teamB)
|
||||||
final Map<int, String> _winners = {};
|
final Map<int, int> _winners = {};
|
||||||
|
|
||||||
CompetitionTeamDetail get _detail => widget.detail;
|
CompetitionTeamDetail get _detail => widget.detail;
|
||||||
|
|
||||||
@@ -32,9 +36,9 @@ class _CompetitionTeamDetailPageState
|
|||||||
|
|
||||||
List<Matchup> get _matchups => _detail.matchups ?? const <Matchup>[];
|
List<Matchup> get _matchups => _detail.matchups ?? const <Matchup>[];
|
||||||
|
|
||||||
CompetitionTeam _toCompetitionTeam(Team team) {
|
CompetitionTeam _toCompetitionTeam(Team team, {required String fallbackId}) {
|
||||||
return CompetitionTeam(
|
return CompetitionTeam(
|
||||||
id: team.id?.trim().isNotEmpty == true ? team.id! : 'unknown-team',
|
id: team.leaderUserId ?? fallbackId,
|
||||||
name: team.teamName?.trim().isNotEmpty == true ? team.teamName! : '未命名队伍',
|
name: team.teamName?.trim().isNotEmpty == true ? team.teamName! : '未命名队伍',
|
||||||
players: (team.players ?? const <Player>[])
|
players: (team.players ?? const <Player>[])
|
||||||
.map(
|
.map(
|
||||||
@@ -55,11 +59,18 @@ class _CompetitionTeamDetailPageState
|
|||||||
if (teamA == null || teamA.isEmpty || teamB == null || teamB.isEmpty) {
|
if (teamA == null || teamA.isEmpty || teamB == null || teamB.isEmpty) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
final winnerSide = _winners[index];
|
||||||
|
final convertedA = _toCompetitionTeam(teamA.first, fallbackId: 'team-a');
|
||||||
|
final convertedB = _toCompetitionTeam(teamB.first, fallbackId: 'team-b');
|
||||||
return CompetitionMatchup(
|
return CompetitionMatchup(
|
||||||
id: '${_detail.scheduleId ?? _detail.itemId ?? 'match'}-$index',
|
id: '${_detail.scheduleId ?? _detail.itemId ?? 'match'}-$index',
|
||||||
teamA: _toCompetitionTeam(teamA.first),
|
teamA: convertedA,
|
||||||
teamB: _toCompetitionTeam(teamB.first),
|
teamB: convertedB,
|
||||||
winnerTeamId: _winners[index],
|
winnerTeamId: winnerSide == 0
|
||||||
|
? convertedA.id
|
||||||
|
: winnerSide == 1
|
||||||
|
? convertedB.id
|
||||||
|
: null,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,28 +97,80 @@ class _CompetitionTeamDetailPageState
|
|||||||
matchup: matchup,
|
matchup: matchup,
|
||||||
index: index,
|
index: index,
|
||||||
matchTitle: raw.matchTitle?.trim() ?? '',
|
matchTitle: raw.matchTitle?.trim() ?? '',
|
||||||
onManualProcess: () => _handleManualProcess(matchup, index),
|
onManualProcess: () => _handleManualProcess(raw, index),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _handleManualProcess(
|
Team? _sideTeam(Matchup matchup, {required bool isTeamA}) {
|
||||||
CompetitionMatchup matchup,
|
final list = isTeamA ? matchup.teamA : matchup.teamB;
|
||||||
int index,
|
if (list == null || list.isEmpty) return null;
|
||||||
) async {
|
return list.first;
|
||||||
final winnerTeamId = await ManualWinnerDialog.show(
|
}
|
||||||
context,
|
|
||||||
matchup: matchup,
|
|
||||||
);
|
|
||||||
if (winnerTeamId == null || !mounted) return;
|
|
||||||
|
|
||||||
setState(() => _winners[index] = winnerTeamId);
|
Future<void> _handleManualProcess(Matchup raw, int index) async {
|
||||||
final winnerName = winnerTeamId == matchup.teamA.id
|
final winnerSide = await ManualWinnerDialog.show(
|
||||||
? matchup.teamA.name
|
context,
|
||||||
: matchup.teamB.name;
|
matchup: raw,
|
||||||
|
initialWinnerSideIndex: _winners[index],
|
||||||
|
);
|
||||||
|
if (winnerSide == null || !mounted) return;
|
||||||
|
|
||||||
|
final teamA = _sideTeam(raw, isTeamA: true);
|
||||||
|
final teamB = _sideTeam(raw, isTeamA: false);
|
||||||
|
final winnerTeam = winnerSide == 0 ? teamA : teamB;
|
||||||
|
final loserTeam = winnerSide == 0 ? teamB : teamA;
|
||||||
|
|
||||||
|
final winnerLeaderId = winnerTeam?.leaderUserId;
|
||||||
|
final loserLeaderId = loserTeam?.leaderUserId;
|
||||||
|
if (winnerLeaderId == null ||
|
||||||
|
winnerLeaderId.isEmpty ||
|
||||||
|
loserLeaderId == null ||
|
||||||
|
loserLeaderId.isEmpty) {
|
||||||
|
AppToast.show('无法识别双方队长');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await ref
|
||||||
|
.read(eventsServerProvider)
|
||||||
|
.setTeamStatus(
|
||||||
|
req: SetTeamStatusReq(
|
||||||
|
scheduleId: _detail.scheduleId ?? '',
|
||||||
|
opponentId: raw.opponentId ?? '',
|
||||||
|
teamScore: [
|
||||||
|
TeamScore(
|
||||||
|
userId: winnerLeaderId,
|
||||||
|
firstHalfScore: 0,
|
||||||
|
secondHalfScore: 0,
|
||||||
|
decisiveScore: 0,
|
||||||
|
ifWithdraw: true,
|
||||||
|
),
|
||||||
|
TeamScore(
|
||||||
|
userId: loserLeaderId,
|
||||||
|
firstHalfScore: 0,
|
||||||
|
secondHalfScore: 0,
|
||||||
|
decisiveScore: 0,
|
||||||
|
ifWithdraw: false,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
if (!mounted) return;
|
||||||
|
setState(() => _winners[index] = winnerSide);
|
||||||
|
final winnerName = winnerTeam?.teamName?.trim().isNotEmpty == true
|
||||||
|
? winnerTeam!.teamName!
|
||||||
|
: '胜方';
|
||||||
AppToast.show('已设置$winnerName直接获胜');
|
AppToast.show('已设置$winnerName直接获胜');
|
||||||
|
} catch (error) {
|
||||||
|
if (!mounted) return;
|
||||||
|
final message = error is ApiException && error.message.isNotEmpty
|
||||||
|
? error.message
|
||||||
|
: '设置失败,请重试';
|
||||||
|
AppToast.show(message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,15 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||||
import 'package:recording_tool/app/config/app_config.dart';
|
import 'package:recording_tool/app/config/app_config.dart';
|
||||||
import 'package:recording_tool/app/router/app_navigator.dart';
|
import 'package:recording_tool/app/router/app_navigator.dart';
|
||||||
|
import 'package:recording_tool/core/network/api_exception.dart';
|
||||||
import 'package:recording_tool/features/competition_teams/model/model_competition_team.dart';
|
import 'package:recording_tool/features/competition_teams/model/model_competition_team.dart';
|
||||||
|
import 'package:recording_tool/features/competition_teams/model/model_competition_team_detail.dart';
|
||||||
import 'package:recording_tool/features/competition_teams/widgets/widget_manual_winner_dialog.dart';
|
import 'package:recording_tool/features/competition_teams/widgets/widget_manual_winner_dialog.dart';
|
||||||
import 'package:recording_tool/features/events/model/model_event_info.dart';
|
import 'package:recording_tool/features/events/model/model_event_info.dart';
|
||||||
|
import 'package:recording_tool/features/events/request_model/request_model_event.dart';
|
||||||
|
import 'package:recording_tool/features/events/server/server_events.dart';
|
||||||
import 'package:recording_tool/shared/widgets/app_button.dart';
|
import 'package:recording_tool/shared/widgets/app_button.dart';
|
||||||
import 'package:recording_tool/shared/widgets/app_qr_scanner_dialog.dart';
|
import 'package:recording_tool/shared/widgets/app_qr_scanner_dialog.dart';
|
||||||
import 'package:recording_tool/shared/widgets/app_toast.dart';
|
import 'package:recording_tool/shared/widgets/app_toast.dart';
|
||||||
@@ -12,7 +17,7 @@ import 'package:recording_tool/shared/widgets/app_webview.dart';
|
|||||||
|
|
||||||
typedef TeamQrScanner = Future<String?> Function(BuildContext context);
|
typedef TeamQrScanner = Future<String?> Function(BuildContext context);
|
||||||
|
|
||||||
class EventTeamMatchPage extends StatefulWidget {
|
class EventTeamMatchPage extends ConsumerStatefulWidget {
|
||||||
const EventTeamMatchPage({
|
const EventTeamMatchPage({
|
||||||
super.key,
|
super.key,
|
||||||
required this.playerId,
|
required this.playerId,
|
||||||
@@ -27,12 +32,14 @@ class EventTeamMatchPage extends StatefulWidget {
|
|||||||
final EventRegistrationItem item;
|
final EventRegistrationItem item;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<EventTeamMatchPage> createState() => _EventTeamMatchPageState();
|
ConsumerState<EventTeamMatchPage> createState() => _EventTeamMatchPageState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _EventTeamMatchPageState extends State<EventTeamMatchPage> {
|
class _EventTeamMatchPageState extends ConsumerState<EventTeamMatchPage> {
|
||||||
final Set<String> _verifiedUserIds = <String>{};
|
final Set<String> _verifiedUserIds = <String>{};
|
||||||
String? _winnerTeamId;
|
|
||||||
|
/// 0 = 红队(teamA),1 = 蓝队(teamB)
|
||||||
|
int? _winnerSideIndex;
|
||||||
|
|
||||||
CompetitionTeamDetail get _detail => widget.detail;
|
CompetitionTeamDetail get _detail => widget.detail;
|
||||||
|
|
||||||
@@ -75,23 +82,12 @@ class _EventTeamMatchPageState extends State<EventTeamMatchPage> {
|
|||||||
List<EventTeamMember> get _blueMembers =>
|
List<EventTeamMember> get _blueMembers =>
|
||||||
_toEventMembers(_blueRawTeam?.players);
|
_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,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
CompetitionTeam _toCompetitionTeam(
|
CompetitionTeam _toCompetitionTeam(
|
||||||
Team? team, {
|
Team? team, {
|
||||||
required String fallbackId,
|
required String fallbackId,
|
||||||
required String fallbackName,
|
required String fallbackName,
|
||||||
}) {
|
}) {
|
||||||
final id = team?.id?.trim() ?? '';
|
final id = team?.leaderUserId ?? '';
|
||||||
final name = team?.teamName?.trim() ?? '';
|
final name = team?.teamName?.trim() ?? '';
|
||||||
final players = (team?.players ?? const <Player>[])
|
final players = (team?.players ?? const <Player>[])
|
||||||
.map(
|
.map(
|
||||||
@@ -162,16 +158,70 @@ class _EventTeamMatchPageState extends State<EventTeamMatchPage> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _manualProcess() async {
|
Future<void> _manualProcess() async {
|
||||||
final winnerTeamId = await ManualWinnerDialog.show(
|
final matchup = _firstMatchup;
|
||||||
|
if (matchup == null) {
|
||||||
|
AppToast.show('暂无对阵信息');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final winnerSide = await ManualWinnerDialog.show(
|
||||||
context,
|
context,
|
||||||
matchup: _matchup,
|
matchup: matchup,
|
||||||
|
initialWinnerSideIndex: _winnerSideIndex,
|
||||||
);
|
);
|
||||||
if (!mounted || winnerTeamId == null) return;
|
if (!mounted || winnerSide == null) return;
|
||||||
setState(() => _winnerTeamId = winnerTeamId);
|
|
||||||
final winnerName = winnerTeamId == _redTeam.id
|
final winnerTeam = winnerSide == 0 ? _redRawTeam : _blueRawTeam;
|
||||||
? _redTeam.name
|
final loserTeam = winnerSide == 0 ? _blueRawTeam : _redRawTeam;
|
||||||
: _blueTeam.name;
|
|
||||||
|
final winnerLeaderId = winnerTeam?.leaderUserId;
|
||||||
|
final loserLeaderId = loserTeam?.leaderUserId;
|
||||||
|
if (winnerLeaderId == null ||
|
||||||
|
winnerLeaderId.isEmpty ||
|
||||||
|
loserLeaderId == null ||
|
||||||
|
loserLeaderId.isEmpty) {
|
||||||
|
AppToast.show('无法识别双方队长');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await ref
|
||||||
|
.read(eventsServerProvider)
|
||||||
|
.setTeamStatus(
|
||||||
|
req: SetTeamStatusReq(
|
||||||
|
scheduleId: _detail.scheduleId ?? '',
|
||||||
|
opponentId: widget.item.opponentId,
|
||||||
|
teamScore: [
|
||||||
|
TeamScore(
|
||||||
|
userId: winnerLeaderId,
|
||||||
|
firstHalfScore: 0,
|
||||||
|
secondHalfScore: 0,
|
||||||
|
decisiveScore: 0,
|
||||||
|
ifWithdraw: true,
|
||||||
|
),
|
||||||
|
TeamScore(
|
||||||
|
userId: loserLeaderId,
|
||||||
|
firstHalfScore: 0,
|
||||||
|
secondHalfScore: 0,
|
||||||
|
decisiveScore: 0,
|
||||||
|
ifWithdraw: false,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
if (!mounted) return;
|
||||||
|
setState(() => _winnerSideIndex = winnerSide);
|
||||||
|
final winnerName = winnerTeam?.teamName?.trim().isNotEmpty == true
|
||||||
|
? winnerTeam!.teamName!
|
||||||
|
: (winnerSide == 0 ? _redTeam.name : _blueTeam.name);
|
||||||
AppToast.show('已设置$winnerName直接获胜');
|
AppToast.show('已设置$winnerName直接获胜');
|
||||||
|
} catch (error) {
|
||||||
|
if (!mounted) return;
|
||||||
|
final message = error is ApiException && error.message.isNotEmpty
|
||||||
|
? error.message
|
||||||
|
: '设置失败,请重试';
|
||||||
|
AppToast.show(message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _startDirectly() {
|
void _startDirectly() {
|
||||||
@@ -224,7 +274,7 @@ class _EventTeamMatchPageState extends State<EventTeamMatchPage> {
|
|||||||
backgroundColor: const Color(0xFFFFEEF0),
|
backgroundColor: const Color(0xFFFFEEF0),
|
||||||
accentColor: const Color(0xFFE84B5B),
|
accentColor: const Color(0xFFE84B5B),
|
||||||
verifiedUserIds: _verifiedUserIds,
|
verifiedUserIds: _verifiedUserIds,
|
||||||
winner: _winnerTeamId == redTeam.id,
|
winner: _winnerSideIndex == 0,
|
||||||
),
|
),
|
||||||
SizedBox(height: 16.h),
|
SizedBox(height: 16.h),
|
||||||
_TeamCard(
|
_TeamCard(
|
||||||
@@ -234,7 +284,7 @@ class _EventTeamMatchPageState extends State<EventTeamMatchPage> {
|
|||||||
backgroundColor: const Color(0xFFEDF5FF),
|
backgroundColor: const Color(0xFFEDF5FF),
|
||||||
accentColor: const Color(0xFF287FDD),
|
accentColor: const Color(0xFF287FDD),
|
||||||
verifiedUserIds: _verifiedUserIds,
|
verifiedUserIds: _verifiedUserIds,
|
||||||
winner: _winnerTeamId == blueTeam.id,
|
winner: _winnerSideIndex == 1,
|
||||||
emptyMessage: '暂无蓝队成员数据',
|
emptyMessage: '暂无蓝队成员数据',
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import 'package:recording_tool/app/config/api_common.dart';
|
|||||||
import 'package:recording_tool/core/network/api_client.dart';
|
import 'package:recording_tool/core/network/api_client.dart';
|
||||||
import 'package:recording_tool/core/network/providers/dio_providers.dart';
|
import 'package:recording_tool/core/network/providers/dio_providers.dart';
|
||||||
import 'package:recording_tool/features/competition_teams/model/model_competition_team.dart';
|
import 'package:recording_tool/features/competition_teams/model/model_competition_team.dart';
|
||||||
|
import 'package:recording_tool/features/competition_teams/model/model_competition_team_detail.dart';
|
||||||
|
|
||||||
final competitionTeamsServerProvider = Provider<CompetitionTeamsServer>((ref) {
|
final competitionTeamsServerProvider = Provider<CompetitionTeamsServer>((ref) {
|
||||||
return CompetitionTeamsServer(ref.watch(apiClientProvider));
|
return CompetitionTeamsServer(ref.watch(apiClientProvider));
|
||||||
|
|||||||
@@ -1,21 +1,31 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_screenutil/flutter_screenutil.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/model/model_competition_team_detail.dart';
|
||||||
import 'package:recording_tool/shared/widgets/app_button.dart';
|
import 'package:recording_tool/shared/widgets/app_button.dart';
|
||||||
|
|
||||||
|
/// 弹窗回传选中侧索引:0 = teamA(红队),1 = teamB(蓝队)
|
||||||
class ManualWinnerDialog extends StatefulWidget {
|
class ManualWinnerDialog extends StatefulWidget {
|
||||||
const ManualWinnerDialog({super.key, required this.matchup});
|
const ManualWinnerDialog({
|
||||||
|
super.key,
|
||||||
|
required this.matchup,
|
||||||
|
this.initialWinnerSideIndex,
|
||||||
|
});
|
||||||
|
|
||||||
final CompetitionMatchup matchup;
|
final Matchup matchup;
|
||||||
|
final int? initialWinnerSideIndex;
|
||||||
|
|
||||||
static Future<String?> show(
|
static Future<int?> show(
|
||||||
BuildContext context, {
|
BuildContext context, {
|
||||||
required CompetitionMatchup matchup,
|
required Matchup matchup,
|
||||||
|
int? initialWinnerSideIndex,
|
||||||
}) {
|
}) {
|
||||||
return showDialog<String>(
|
return showDialog<int>(
|
||||||
context: context,
|
context: context,
|
||||||
barrierDismissible: false,
|
barrierDismissible: false,
|
||||||
builder: (_) => ManualWinnerDialog(matchup: matchup),
|
builder: (_) => ManualWinnerDialog(
|
||||||
|
matchup: matchup,
|
||||||
|
initialWinnerSideIndex: initialWinnerSideIndex,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -24,16 +34,35 @@ class ManualWinnerDialog extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _ManualWinnerDialogState extends State<ManualWinnerDialog> {
|
class _ManualWinnerDialogState extends State<ManualWinnerDialog> {
|
||||||
String? _selectedTeamId;
|
/// 0 = teamA,1 = teamB
|
||||||
|
int? _selectedSideIndex;
|
||||||
|
|
||||||
|
Team? get _teamA {
|
||||||
|
final teams = widget.matchup.teamA;
|
||||||
|
if (teams == null || teams.isEmpty) return null;
|
||||||
|
return teams.first;
|
||||||
|
}
|
||||||
|
|
||||||
|
Team? get _teamB {
|
||||||
|
final teams = widget.matchup.teamB;
|
||||||
|
if (teams == null || teams.isEmpty) return null;
|
||||||
|
return teams.first;
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
_selectedTeamId = widget.matchup.winnerTeamId;
|
final initial = widget.initialWinnerSideIndex;
|
||||||
|
if (initial == 0 || initial == 1) {
|
||||||
|
_selectedSideIndex = initial;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final teamA = _teamA;
|
||||||
|
final teamB = _teamB;
|
||||||
|
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
insetPadding: EdgeInsets.symmetric(horizontal: 22.w),
|
insetPadding: EdgeInsets.symmetric(horizontal: 22.w),
|
||||||
contentPadding: EdgeInsets.zero,
|
contentPadding: EdgeInsets.zero,
|
||||||
@@ -65,22 +94,23 @@ class _ManualWinnerDialogState extends State<ManualWinnerDialog> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(height: 16.h),
|
SizedBox(height: 16.h),
|
||||||
|
if (teamA != null) ...[
|
||||||
_TeamChoice(
|
_TeamChoice(
|
||||||
team: widget.matchup.teamA,
|
team: teamA,
|
||||||
|
sideIndex: 0,
|
||||||
color: const Color(0xFFFF6B75),
|
color: const Color(0xFFFF6B75),
|
||||||
selected: _selectedTeamId == widget.matchup.teamA.id,
|
selected: _selectedSideIndex == 0,
|
||||||
onTap: () => setState(
|
onTap: () => setState(() => _selectedSideIndex = 0),
|
||||||
() => _selectedTeamId = widget.matchup.teamA.id,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
SizedBox(height: 10.h),
|
SizedBox(height: 10.h),
|
||||||
|
],
|
||||||
|
if (teamB != null)
|
||||||
_TeamChoice(
|
_TeamChoice(
|
||||||
team: widget.matchup.teamB,
|
team: teamB,
|
||||||
|
sideIndex: 1,
|
||||||
color: const Color(0xFF20BFA9),
|
color: const Color(0xFF20BFA9),
|
||||||
selected: _selectedTeamId == widget.matchup.teamB.id,
|
selected: _selectedSideIndex == 1,
|
||||||
onTap: () => setState(
|
onTap: () => setState(() => _selectedSideIndex = 1),
|
||||||
() => _selectedTeamId = widget.matchup.teamB.id,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
SizedBox(height: 20.h),
|
SizedBox(height: 20.h),
|
||||||
Row(
|
Row(
|
||||||
@@ -96,11 +126,11 @@ class _ManualWinnerDialogState extends State<ManualWinnerDialog> {
|
|||||||
Expanded(
|
Expanded(
|
||||||
child: AppButton(
|
child: AppButton(
|
||||||
label: '确定',
|
label: '确定',
|
||||||
onPressed: _selectedTeamId == null
|
onPressed: _selectedSideIndex == null
|
||||||
? null
|
? null
|
||||||
: () => Navigator.of(
|
: () => Navigator.of(
|
||||||
context,
|
context,
|
||||||
).pop(_selectedTeamId),
|
).pop(_selectedSideIndex),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -119,27 +149,33 @@ class _ManualWinnerDialogState extends State<ManualWinnerDialog> {
|
|||||||
class _TeamChoice extends StatelessWidget {
|
class _TeamChoice extends StatelessWidget {
|
||||||
const _TeamChoice({
|
const _TeamChoice({
|
||||||
required this.team,
|
required this.team,
|
||||||
|
required this.sideIndex,
|
||||||
required this.color,
|
required this.color,
|
||||||
required this.selected,
|
required this.selected,
|
||||||
required this.onTap,
|
required this.onTap,
|
||||||
});
|
});
|
||||||
|
|
||||||
final CompetitionTeam team;
|
final Team team;
|
||||||
|
final int sideIndex;
|
||||||
final Color color;
|
final Color color;
|
||||||
final bool selected;
|
final bool selected;
|
||||||
final VoidCallback onTap;
|
final VoidCallback onTap;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final name = team.teamName?.trim().isNotEmpty == true
|
||||||
|
? team.teamName!
|
||||||
|
: '未命名队伍';
|
||||||
|
final players = team.playerNames;
|
||||||
return Semantics(
|
return Semantics(
|
||||||
selected: selected,
|
selected: selected,
|
||||||
button: true,
|
button: true,
|
||||||
label: '选择${team.name}直接获胜',
|
label: '选择$name直接获胜',
|
||||||
child: Material(
|
child: Material(
|
||||||
color: color.withValues(alpha: selected ? 0.16 : 0.08),
|
color: color.withValues(alpha: selected ? 0.16 : 0.08),
|
||||||
borderRadius: BorderRadius.circular(12.r),
|
borderRadius: BorderRadius.circular(12.r),
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
key: ValueKey('winner-choice-${team.id}'),
|
key: ValueKey('winner-choice-side-$sideIndex'),
|
||||||
onTap: onTap,
|
onTap: onTap,
|
||||||
borderRadius: BorderRadius.circular(12.r),
|
borderRadius: BorderRadius.circular(12.r),
|
||||||
child: Container(
|
child: Container(
|
||||||
@@ -173,22 +209,24 @@ class _TeamChoice extends StatelessWidget {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
team.name,
|
name,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 17.sp,
|
fontSize: 17.sp,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
color: const Color(0xFF20242B),
|
color: const Color(0xFF20242B),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
if (players.isNotEmpty) ...[
|
||||||
SizedBox(height: 4.h),
|
SizedBox(height: 4.h),
|
||||||
Text(
|
Text(
|
||||||
team.playerNames,
|
players,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 14.sp,
|
fontSize: 14.sp,
|
||||||
color: const Color(0xFF606874),
|
color: const Color(0xFF606874),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(width: 8.w),
|
SizedBox(width: 8.w),
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|||||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||||
import 'package:recording_tool/app/config/app_config.dart';
|
import 'package:recording_tool/app/config/app_config.dart';
|
||||||
import 'package:recording_tool/app/router/app_navigator.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/model/model_competition_team_detail.dart';
|
||||||
import 'package:recording_tool/features/competition_teams/pages/page_event_team_match.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/competition_teams/server/server_competition_teams.dart';
|
||||||
import 'package:recording_tool/features/events/model/model_event_info.dart';
|
import 'package:recording_tool/features/events/model/model_event_info.dart';
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
class SetTeamStatusReq {
|
||||||
|
final String scheduleId;
|
||||||
|
final String opponentId;
|
||||||
|
final List<TeamScore> teamScore;
|
||||||
|
|
||||||
|
SetTeamStatusReq({
|
||||||
|
required this.scheduleId,
|
||||||
|
required this.opponentId,
|
||||||
|
required this.teamScore,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory SetTeamStatusReq.fromJson(Map<String, dynamic> json) =>
|
||||||
|
SetTeamStatusReq(
|
||||||
|
scheduleId: json['scheduleId'],
|
||||||
|
opponentId: json['opponentId'],
|
||||||
|
teamScore: List<TeamScore>.from(
|
||||||
|
json['teamScore'].map((x) => TeamScore.fromJson(x)),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() => {
|
||||||
|
'scheduleId': scheduleId,
|
||||||
|
'opponentId': opponentId,
|
||||||
|
'teamScore': List<dynamic>.from(teamScore.map((x) => x.toJson())),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
class TeamScore {
|
||||||
|
final String userId;
|
||||||
|
final int firstHalfScore;
|
||||||
|
final int secondHalfScore;
|
||||||
|
final int decisiveScore;
|
||||||
|
final bool ifWithdraw;
|
||||||
|
|
||||||
|
TeamScore({
|
||||||
|
required this.userId,
|
||||||
|
required this.firstHalfScore,
|
||||||
|
required this.secondHalfScore,
|
||||||
|
required this.decisiveScore,
|
||||||
|
required this.ifWithdraw,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory TeamScore.fromJson(Map<String, dynamic> json) => TeamScore(
|
||||||
|
userId: json['userId'],
|
||||||
|
firstHalfScore: json['firstHalfScore'],
|
||||||
|
secondHalfScore: json['secondHalfScore'],
|
||||||
|
decisiveScore: json['decisiveScore'],
|
||||||
|
ifWithdraw: json['ifWithdraw'],
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() => {
|
||||||
|
'userId': userId,
|
||||||
|
'firstHalfScore': firstHalfScore,
|
||||||
|
'secondHalfScore': secondHalfScore,
|
||||||
|
'decisiveScore': decisiveScore,
|
||||||
|
'ifWithdraw': ifWithdraw,
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ import 'package:recording_tool/core/network/api_client.dart';
|
|||||||
import 'package:recording_tool/core/network/http_method.dart';
|
import 'package:recording_tool/core/network/http_method.dart';
|
||||||
import 'package:recording_tool/core/network/providers/dio_providers.dart';
|
import 'package:recording_tool/core/network/providers/dio_providers.dart';
|
||||||
import 'package:recording_tool/features/events/model/model_event_info.dart';
|
import 'package:recording_tool/features/events/model/model_event_info.dart';
|
||||||
|
import 'package:recording_tool/features/events/request_model/request_model_event.dart';
|
||||||
|
|
||||||
final eventsServerProvider = Provider<EventsServer>((ref) {
|
final eventsServerProvider = Provider<EventsServer>((ref) {
|
||||||
return EventsServer(ref.watch(apiClientProvider));
|
return EventsServer(ref.watch(apiClientProvider));
|
||||||
@@ -34,4 +35,14 @@ class EventsServer {
|
|||||||
parser: StreamKeyResponse.fromJson,
|
parser: StreamKeyResponse.fromJson,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 人工设置晋级/淘汰
|
||||||
|
Future<void> setTeamStatus({required SetTeamStatusReq req}) {
|
||||||
|
print('req: ${req.toJson()}');
|
||||||
|
return _apiClient.post(
|
||||||
|
AuthApi.setTeamStatus.path,
|
||||||
|
data: req.toJson(),
|
||||||
|
parser: (json) => json,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user