更新 devtools_options.yaml 以启用 riverpod 和 shared_preferences 扩展;更新 AuthApi 枚举以添加 playerRegistrationList API;重构 Auth 页面以在用户已登录时直接导航到扫码页面;重构 EventInfoPage 以使用新的状态管理和加载赛事报名信息;更新扫码页面以导航到 EventInfoPage。
This commit is contained in:
@@ -0,0 +1,356 @@
|
||||
import 'package:recording_tool/features/recording/model/model_recording_context.dart';
|
||||
|
||||
class PlayerRegistrationListReq {
|
||||
const PlayerRegistrationListReq({required this.userId, this.status = ''});
|
||||
|
||||
final String userId;
|
||||
final String status;
|
||||
|
||||
Map<String, dynamic> toFormDataMap() {
|
||||
return {'userId': userId, 'status': status};
|
||||
}
|
||||
}
|
||||
|
||||
class StreamKeyReq {
|
||||
const StreamKeyReq({
|
||||
required this.eventId,
|
||||
required this.itemId,
|
||||
required this.userId,
|
||||
});
|
||||
|
||||
final String eventId;
|
||||
final String itemId;
|
||||
final String userId;
|
||||
|
||||
Map<String, dynamic> toFormDataMap() {
|
||||
return {'eventId': eventId, 'itemId': itemId, 'userId': userId};
|
||||
}
|
||||
}
|
||||
|
||||
class EventProfile {
|
||||
const EventProfile({
|
||||
required this.name,
|
||||
required this.phone,
|
||||
required this.eventTitle,
|
||||
this.avatarUrl = '',
|
||||
this.avatarLabel = '头像',
|
||||
});
|
||||
|
||||
final String name;
|
||||
final String phone;
|
||||
final String eventTitle;
|
||||
final String avatarUrl;
|
||||
final String avatarLabel;
|
||||
}
|
||||
|
||||
class EventRegistrationList {
|
||||
const EventRegistrationList({
|
||||
required this.userId,
|
||||
required this.name,
|
||||
required this.avatar,
|
||||
required this.total,
|
||||
required this.items,
|
||||
});
|
||||
|
||||
final String userId;
|
||||
final String name;
|
||||
final String avatar;
|
||||
final int total;
|
||||
final List<EventRegistrationItem> items;
|
||||
|
||||
factory EventRegistrationList.fromJson(dynamic json) {
|
||||
final map = _extractObject(json);
|
||||
final rawItems = _extractList(json);
|
||||
final userId = _readString(map, const ['userId']);
|
||||
final name = _readString(map, const [
|
||||
'name',
|
||||
'playerName',
|
||||
'userName',
|
||||
'realName',
|
||||
]);
|
||||
final avatar = _readString(map, const ['avatar', 'avatarUrl']);
|
||||
return EventRegistrationList(
|
||||
userId: userId,
|
||||
name: name,
|
||||
avatar: avatar,
|
||||
total: _readInt(map, const ['total'], fallback: rawItems.length),
|
||||
items: rawItems
|
||||
.whereType<Map>()
|
||||
.map(
|
||||
(item) => EventRegistrationItem.fromJson(
|
||||
item,
|
||||
userId: userId,
|
||||
playerName: name,
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
);
|
||||
}
|
||||
|
||||
EventProfile toProfile() {
|
||||
return EventProfile(
|
||||
name: name,
|
||||
phone: '',
|
||||
eventTitle: items.isEmpty ? '赛事信息' : items.first.eventTitle,
|
||||
avatarUrl: avatar,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class EventRegistrationItem {
|
||||
const EventRegistrationItem({
|
||||
required this.eventId,
|
||||
required this.itemId,
|
||||
required this.userId,
|
||||
required this.eventTitle,
|
||||
required this.name,
|
||||
required this.group,
|
||||
required this.venue,
|
||||
required this.time,
|
||||
required this.playerName,
|
||||
required this.playerPhone,
|
||||
this.avatarLabel = '头像',
|
||||
this.matchStartTime = '',
|
||||
this.matchEndTime = '',
|
||||
this.completed = false,
|
||||
this.laneNo,
|
||||
this.status,
|
||||
this.rawData = const {},
|
||||
});
|
||||
|
||||
final String eventId;
|
||||
final String itemId;
|
||||
final String userId;
|
||||
final String eventTitle;
|
||||
final String name;
|
||||
final String group;
|
||||
final String venue;
|
||||
final String time;
|
||||
final String playerName;
|
||||
final String playerPhone;
|
||||
final String avatarLabel;
|
||||
final String matchStartTime;
|
||||
final String matchEndTime;
|
||||
final bool completed;
|
||||
final String? laneNo;
|
||||
final String? status;
|
||||
final Map<String, dynamic> rawData;
|
||||
|
||||
factory EventRegistrationItem.fromJson(
|
||||
Map<dynamic, dynamic> json, {
|
||||
String userId = '',
|
||||
String playerName = '',
|
||||
}) {
|
||||
final map = Map<String, dynamic>.from(json);
|
||||
final startTime = _readString(map, const ['matchStartTime', 'startTime']);
|
||||
final endTime = _readString(map, const ['matchEndTime', 'endTime']);
|
||||
final completed = _readBool(map, const ['completed']);
|
||||
return EventRegistrationItem(
|
||||
eventId: _readString(map, const ['eventId', 'eventsId', 'eventID']),
|
||||
itemId: _readString(map, const ['itemId', 'eventItemId', 'itemID']),
|
||||
userId: _readString(map, const [
|
||||
'userId',
|
||||
'playerId',
|
||||
'registrationId',
|
||||
], fallback: userId),
|
||||
eventTitle: _readString(map, const [
|
||||
'eventTitle',
|
||||
'eventName',
|
||||
'competitionName',
|
||||
'matchTitle',
|
||||
], fallback: '赛事信息'),
|
||||
name: _readString(map, const [
|
||||
'name',
|
||||
'itemName',
|
||||
'eventItemName',
|
||||
'matchName',
|
||||
'projectName',
|
||||
], fallback: '未命名项目'),
|
||||
group: _readString(map, const [
|
||||
'group',
|
||||
'groupName',
|
||||
'categoryName',
|
||||
'levelName',
|
||||
]),
|
||||
venue: _readString(map, const [
|
||||
'matchPlace',
|
||||
'venue',
|
||||
'venueName',
|
||||
'siteName',
|
||||
'fieldName',
|
||||
'placeName',
|
||||
]),
|
||||
time: _readScheduleTime(map, startTime, endTime),
|
||||
playerName: _readString(map, const [
|
||||
'playerName',
|
||||
'userName',
|
||||
'nameCn',
|
||||
'realName',
|
||||
'athleteName',
|
||||
], fallback: playerName),
|
||||
playerPhone: _readString(map, const [
|
||||
'playerPhone',
|
||||
'phone',
|
||||
'mobile',
|
||||
'telephone',
|
||||
'userPhone',
|
||||
]),
|
||||
laneNo: _readNullableString(map, const [
|
||||
'laneNo',
|
||||
'laneNumber',
|
||||
'trackNo',
|
||||
'number',
|
||||
'serialNo',
|
||||
]),
|
||||
matchStartTime: startTime,
|
||||
matchEndTime: endTime,
|
||||
completed: completed,
|
||||
status: completed ? '已完成' : null,
|
||||
rawData: map,
|
||||
);
|
||||
}
|
||||
|
||||
EventProfile toProfile() {
|
||||
return EventProfile(
|
||||
avatarLabel: avatarLabel,
|
||||
name: playerName,
|
||||
phone: playerPhone,
|
||||
eventTitle: eventTitle,
|
||||
);
|
||||
}
|
||||
|
||||
RecordingContext toRecordingContext({EventProfile? profile}) {
|
||||
return RecordingContext(
|
||||
eventTitle: eventTitle,
|
||||
matchName: name,
|
||||
group: group,
|
||||
venue: venue,
|
||||
time: time,
|
||||
playerName: profile?.name ?? playerName,
|
||||
playerPhone: profile?.phone ?? playerPhone,
|
||||
laneNo: laneNo,
|
||||
status: status,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class StreamKeyResponse {
|
||||
const StreamKeyResponse({required this.rawData});
|
||||
|
||||
final Map<String, dynamic> rawData;
|
||||
|
||||
factory StreamKeyResponse.fromJson(dynamic json) {
|
||||
if (json is Map) {
|
||||
return StreamKeyResponse(rawData: Map<String, dynamic>.from(json));
|
||||
}
|
||||
return StreamKeyResponse(rawData: {'value': json});
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() => rawData.toString();
|
||||
}
|
||||
|
||||
List<dynamic> _extractList(dynamic json) {
|
||||
if (json is List) return json;
|
||||
if (json is Map) {
|
||||
for (final key in const ['records', 'items', 'rows', 'list', 'data']) {
|
||||
final value = json[key];
|
||||
if (value is List) return value;
|
||||
if (value is Map) {
|
||||
final nested = _extractList(value);
|
||||
if (nested.isNotEmpty) return nested;
|
||||
}
|
||||
}
|
||||
}
|
||||
return const [];
|
||||
}
|
||||
|
||||
Map<String, dynamic> _extractObject(dynamic json) {
|
||||
if (json is Map) {
|
||||
final map = Map<String, dynamic>.from(json);
|
||||
final data = map['data'];
|
||||
if (data is Map) return Map<String, dynamic>.from(data);
|
||||
return map;
|
||||
}
|
||||
return const {};
|
||||
}
|
||||
|
||||
String _readString(
|
||||
Map<String, dynamic> map,
|
||||
List<String> keys, {
|
||||
String fallback = '',
|
||||
}) {
|
||||
return _readNullableString(map, keys) ?? fallback;
|
||||
}
|
||||
|
||||
String _readScheduleTime(
|
||||
Map<String, dynamic> map,
|
||||
String startTime,
|
||||
String endTime,
|
||||
) {
|
||||
if (startTime.isNotEmpty && endTime.isNotEmpty) {
|
||||
return '$startTime-$endTime';
|
||||
}
|
||||
if (startTime.isNotEmpty) return startTime;
|
||||
if (endTime.isNotEmpty) return endTime;
|
||||
return _readString(map, const [
|
||||
'time',
|
||||
'competitionTime',
|
||||
'matchTime',
|
||||
'scheduleTime',
|
||||
]);
|
||||
}
|
||||
|
||||
int _readInt(Map<String, dynamic> map, List<String> keys, {int fallback = 0}) {
|
||||
for (final key in keys) {
|
||||
final value = _findValue(map, key);
|
||||
if (value is int) return value;
|
||||
if (value is num) return value.toInt();
|
||||
if (value is String) {
|
||||
final parsed = int.tryParse(value.trim());
|
||||
if (parsed != null) return parsed;
|
||||
}
|
||||
}
|
||||
return fallback;
|
||||
}
|
||||
|
||||
bool _readBool(Map<String, dynamic> map, List<String> keys) {
|
||||
for (final key in keys) {
|
||||
final value = _findValue(map, key);
|
||||
if (value is bool) return value;
|
||||
if (value is num) return value != 0;
|
||||
if (value is String) {
|
||||
final text = value.trim().toLowerCase();
|
||||
if (text == 'true' || text == '1') return true;
|
||||
if (text == 'false' || text == '0') return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
String? _readNullableString(Map<String, dynamic> map, List<String> keys) {
|
||||
for (final key in keys) {
|
||||
final value = _findValue(map, key);
|
||||
if (value == null) continue;
|
||||
final text = value.toString().trim();
|
||||
if (text.isNotEmpty) return text;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
dynamic _findValue(dynamic value, String key) {
|
||||
if (value is Map) {
|
||||
if (value.containsKey(key)) return value[key];
|
||||
for (final child in value.values) {
|
||||
final found = _findValue(child, key);
|
||||
if (found != null) return found;
|
||||
}
|
||||
}
|
||||
if (value is List) {
|
||||
for (final child in value) {
|
||||
final found = _findValue(child, key);
|
||||
if (found != null) return found;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
Reference in New Issue
Block a user