1.还原授权页 UI
2.还原扫码页 UI
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 6.5 KiB |
|
Before Width: | Height: | Size: 795 B |
|
Before Width: | Height: | Size: 1011 B |
|
After Width: | Height: | Size: 293 KiB |
|
After Width: | Height: | Size: 88 KiB |
@@ -15,9 +15,9 @@ class JwtDecodedData {
|
|||||||
int? deviceId;
|
int? deviceId;
|
||||||
String? deviceRole;
|
String? deviceRole;
|
||||||
String? eventName;
|
String? eventName;
|
||||||
double? oId;
|
String? oId;
|
||||||
List<double>? oIds;
|
List<String>? oIds;
|
||||||
double? organizerId;
|
String? organizerId;
|
||||||
|
|
||||||
JwtDecodedData({
|
JwtDecodedData({
|
||||||
this.authType,
|
this.authType,
|
||||||
@@ -36,11 +36,11 @@ class JwtDecodedData {
|
|||||||
deviceId: json["deviceId"],
|
deviceId: json["deviceId"],
|
||||||
deviceRole: json["deviceRole"],
|
deviceRole: json["deviceRole"],
|
||||||
eventName: json["eventName"],
|
eventName: json["eventName"],
|
||||||
oId: json["oId"]?.toDouble(),
|
oId: json["oId"]?.toString(),
|
||||||
oIds: json["oIds"] == null
|
oIds: json["oIds"] == null
|
||||||
? []
|
? []
|
||||||
: List<double>.from(json["oIds"]!.map((x) => x?.toDouble())),
|
: List<String>.from(json["oIds"]!.map((x) => x?.toString())),
|
||||||
organizerId: json["organizerId"]?.toDouble(),
|
organizerId: json["organizerId"]?.toString(),
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => {
|
Map<String, dynamic> toJson() => {
|
||||||
|
|||||||
@@ -8,7 +8,10 @@ import 'package:recording_tool/core/cache/storage_keys.dart';
|
|||||||
import 'package:recording_tool/core/utils/device_utils.dart';
|
import 'package:recording_tool/core/utils/device_utils.dart';
|
||||||
import 'package:recording_tool/features/auth/view_model_auth/view_model_auth.dart';
|
import 'package:recording_tool/features/auth/view_model_auth/view_model_auth.dart';
|
||||||
import 'package:recording_tool/features/scan_qrcode/pages/page_scan_qrcode.dart';
|
import 'package:recording_tool/features/scan_qrcode/pages/page_scan_qrcode.dart';
|
||||||
import 'package:recording_tool/shared/widgets/widgets.dart';
|
import 'package:recording_tool/gen/assets.gen.dart';
|
||||||
|
import 'package:recording_tool/shared/widgets/app_button.dart';
|
||||||
|
import 'package:recording_tool/shared/widgets/app_dialog.dart';
|
||||||
|
import 'package:recording_tool/shared/widgets/app_toast.dart';
|
||||||
|
|
||||||
class AuthPageWidget extends ConsumerStatefulWidget {
|
class AuthPageWidget extends ConsumerStatefulWidget {
|
||||||
const AuthPageWidget({super.key});
|
const AuthPageWidget({super.key});
|
||||||
@@ -18,13 +21,12 @@ class AuthPageWidget extends ConsumerStatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _AuthPageWidgetState extends ConsumerState<AuthPageWidget> {
|
class _AuthPageWidgetState extends ConsumerState<AuthPageWidget> {
|
||||||
late TextEditingController? _controller;
|
late final TextEditingController _controller;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
_controller = TextEditingController();
|
_controller = TextEditingController(text: '999779');
|
||||||
_controller?.text = '986570';
|
|
||||||
|
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
||||||
final token = AppStorage.getString(StorageKeys.authToken);
|
final token = AppStorage.getString(StorageKeys.authToken);
|
||||||
@@ -36,7 +38,7 @@ class _AuthPageWidgetState extends ConsumerState<AuthPageWidget> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
_controller?.dispose();
|
_controller.dispose();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,41 +46,79 @@ class _AuthPageWidgetState extends ConsumerState<AuthPageWidget> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final authState = ref.watch(authProvider);
|
final authState = ref.watch(authProvider);
|
||||||
|
|
||||||
return Center(
|
return AnnotatedRegion<SystemUiOverlayStyle>(
|
||||||
|
value: SystemUiOverlayStyle.dark.copyWith(
|
||||||
|
statusBarColor: Colors.transparent,
|
||||||
|
systemNavigationBarColor: Colors.white,
|
||||||
|
),
|
||||||
|
child: Scaffold(
|
||||||
|
backgroundColor: Colors.white,
|
||||||
|
body: Stack(
|
||||||
|
children: [
|
||||||
|
Positioned(
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
child: Image.asset(
|
||||||
|
_AuthAssets.pageBg,
|
||||||
|
width: double.infinity,
|
||||||
|
fit: BoxFit.fitWidth,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SafeArea(
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 32.w),
|
||||||
|
child: SingleChildScrollView(
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
SizedBox(height: 180.h),
|
SizedBox(height: 190.h),
|
||||||
AppText('裁判工作台', fontSize: 30.sp),
|
ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(24.r),
|
||||||
|
child: Image.asset(
|
||||||
|
_AuthAssets.appIcon,
|
||||||
|
width: 82.w,
|
||||||
|
height: 82.w,
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(height: 18.h),
|
||||||
|
Image.asset(
|
||||||
|
_AuthAssets.appNameText,
|
||||||
|
width: 132.w,
|
||||||
|
height: 28.w,
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
),
|
||||||
|
SizedBox(height: 78.h),
|
||||||
|
_PassCodeInput(controller: _controller),
|
||||||
SizedBox(height: 20.h),
|
SizedBox(height: 20.h),
|
||||||
Text(
|
_GradientConfirmButton(
|
||||||
'输入执裁口令',
|
isLoading: authState.isLoading,
|
||||||
style: TextStyle(fontSize: 18.sp, color: Colors.black),
|
onPressed: _handleSubmit,
|
||||||
),
|
),
|
||||||
SizedBox(height: 20.h),
|
SizedBox(height: 20.h),
|
||||||
|
AppButton(
|
||||||
Container(
|
onPressed: () async {
|
||||||
padding: EdgeInsets.symmetric(horizontal: 20.w),
|
final deviceCode = await DeviceUtils.deviceCode();
|
||||||
child: Column(
|
if (!mounted) return;
|
||||||
children: [
|
AppDialog.confirm(context, title: '设备码:$deviceCode');
|
||||||
AppTextField(
|
},
|
||||||
controller: _controller,
|
label: '获取设备码',
|
||||||
keyboardType: TextInputType.number,
|
),
|
||||||
maxLength: 6,
|
|
||||||
inputFormatters: [
|
|
||||||
FilteringTextInputFormatter.digitsOnly,
|
|
||||||
LengthLimitingTextInputFormatter(6),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
SizedBox(height: 20.h),
|
),
|
||||||
SizedBox(
|
),
|
||||||
width: double.maxFinite,
|
),
|
||||||
child: AppButton(
|
],
|
||||||
label: '确定',
|
),
|
||||||
onPressed: () async {
|
),
|
||||||
final code = _controller?.text;
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _handleSubmit() async {
|
||||||
final success = await ref
|
final success = await ref
|
||||||
.read(authProvider.notifier)
|
.read(authProvider.notifier)
|
||||||
.auth(code ?? '');
|
.auth(_controller.text);
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
if (success) {
|
if (success) {
|
||||||
AppNavigator.push(const ScanQrCodePage());
|
AppNavigator.push(const ScanQrCodePage());
|
||||||
@@ -88,44 +128,122 @@ class _AuthPageWidgetState extends ConsumerState<AuthPageWidget> {
|
|||||||
if (message != null && message.isNotEmpty) {
|
if (message != null && message.isNotEmpty) {
|
||||||
AppToast.show(message);
|
AppToast.show(message);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
variant: AppButtonVariant.secondary,
|
}
|
||||||
isLoading: authState.isLoading,
|
|
||||||
),
|
class _PassCodeInput extends StatelessWidget {
|
||||||
|
const _PassCodeInput({required this.controller});
|
||||||
|
|
||||||
|
final TextEditingController controller;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
height: 50.h,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.circular(12.r),
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: Colors.black.withValues(alpha: 0.08),
|
||||||
|
blurRadius: 10.r,
|
||||||
|
offset: Offset(0, 2.h),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
child: TextField(
|
||||||
..._buildTestArea(authState.isLoading),
|
controller: controller,
|
||||||
|
keyboardType: TextInputType.number,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
maxLength: 6,
|
||||||
|
inputFormatters: [
|
||||||
|
FilteringTextInputFormatter.digitsOnly,
|
||||||
|
LengthLimitingTextInputFormatter(6),
|
||||||
],
|
],
|
||||||
|
style: TextStyle(
|
||||||
|
color: const Color(0xFF2F3338),
|
||||||
|
fontSize: 16.sp,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
),
|
||||||
|
decoration: InputDecoration(
|
||||||
|
hintText: '请输入执裁口令',
|
||||||
|
hintStyle: TextStyle(
|
||||||
|
color: const Color(0xFFB6B9BF),
|
||||||
|
fontSize: 16.sp,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
),
|
||||||
|
counterText: '',
|
||||||
|
border: InputBorder.none,
|
||||||
|
contentPadding: EdgeInsets.symmetric(
|
||||||
|
horizontal: 16.w,
|
||||||
|
vertical: 14.h,
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// 测试区域
|
class _GradientConfirmButton extends StatelessWidget {
|
||||||
List<Widget> _buildTestArea(bool isLoading) {
|
const _GradientConfirmButton({
|
||||||
return [
|
required this.isLoading,
|
||||||
SizedBox(height: 20.h),
|
required this.onPressed,
|
||||||
Container(
|
|
||||||
padding: EdgeInsets.symmetric(horizontal: 20.w),
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
SizedBox(
|
|
||||||
width: double.maxFinite,
|
|
||||||
child: AppButton(
|
|
||||||
label: '获取设备码',
|
|
||||||
onPressed: () async {
|
|
||||||
DeviceUtils.deviceCode().then((code) {
|
|
||||||
AppDialog.confirm(context, title: '设备码', message: code);
|
|
||||||
});
|
});
|
||||||
},
|
|
||||||
variant: AppButtonVariant.secondary,
|
final bool isLoading;
|
||||||
isLoading: isLoading,
|
final VoidCallback onPressed;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Opacity(
|
||||||
|
opacity: isLoading ? 0.72 : 1,
|
||||||
|
child: GestureDetector(
|
||||||
|
onTap: isLoading ? null : onPressed,
|
||||||
|
child: Container(
|
||||||
|
height: 50.h,
|
||||||
|
width: double.infinity,
|
||||||
|
alignment: Alignment.center,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(25.r),
|
||||||
|
gradient: const LinearGradient(
|
||||||
|
colors: [Color(0xFF268DFF), Color(0xFF5DD4F6)],
|
||||||
),
|
),
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: const Color(0xFF2196F3).withValues(alpha: 0.28),
|
||||||
|
blurRadius: 14.r,
|
||||||
|
offset: Offset(0, 6.h),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
child: isLoading
|
||||||
|
? SizedBox.square(
|
||||||
|
dimension: 18.r,
|
||||||
|
child: CircularProgressIndicator(
|
||||||
|
strokeWidth: 2.r,
|
||||||
|
valueColor: const AlwaysStoppedAnimation<Color>(
|
||||||
|
Colors.white,
|
||||||
),
|
),
|
||||||
];
|
),
|
||||||
|
)
|
||||||
|
: Text(
|
||||||
|
'确定',
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontSize: 16.sp,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class _AuthAssets {
|
||||||
|
const _AuthAssets._();
|
||||||
|
|
||||||
|
static String pageBg = Assets.images.imagePageBg.path;
|
||||||
|
static String appIcon = Assets.images.imageAppIcon.path;
|
||||||
|
static String appNameText = Assets.images.imageAppNameText.path;
|
||||||
|
}
|
||||||
|
|||||||
@@ -50,8 +50,13 @@ class AuthViewModel extends StateNotifier<AuthState> {
|
|||||||
Future<bool> parseTokenSetState(String token) async {
|
Future<bool> parseTokenSetState(String token) async {
|
||||||
final decoded = JwtDecoder.decode(token);
|
final decoded = JwtDecoder.decode(token);
|
||||||
if (decoded['data'] != null && decoded['data'] is Map<String, dynamic>) {
|
if (decoded['data'] != null && decoded['data'] is Map<String, dynamic>) {
|
||||||
|
try {
|
||||||
final data = JwtDecodedData.fromJson(decoded['data']);
|
final data = JwtDecodedData.fromJson(decoded['data']);
|
||||||
state = state.copyWith(jwtDecodedData: data);
|
state = state.copyWith(jwtDecodedData: data);
|
||||||
|
} catch (error) {
|
||||||
|
state = const AuthState(errorMessage: '认证失败,请重试');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_easyloading/flutter_easyloading.dart';
|
import 'package:flutter_easyloading/flutter_easyloading.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';
|
||||||
@@ -12,8 +13,6 @@ import 'package:recording_tool/features/events/model/model_event_info.dart';
|
|||||||
import 'package:recording_tool/features/events/pages/page_event_info.dart';
|
import 'package:recording_tool/features/events/pages/page_event_info.dart';
|
||||||
import 'package:recording_tool/features/events/view_model/view_model_event_info.dart';
|
import 'package:recording_tool/features/events/view_model/view_model_event_info.dart';
|
||||||
import 'package:recording_tool/features/recording/model/model_recording_context.dart';
|
import 'package:recording_tool/features/recording/model/model_recording_context.dart';
|
||||||
import 'package:recording_tool/shared/widgets/app_bar.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';
|
||||||
|
|
||||||
@@ -34,10 +33,10 @@ class ScanQrCodePage extends ConsumerStatefulWidget {
|
|||||||
);
|
);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
ConsumerState<ScanQrCodePage> createState() => _AuthPageWidgetState();
|
ConsumerState<ScanQrCodePage> createState() => _ScanQrCodePageState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _AuthPageWidgetState extends ConsumerState<ScanQrCodePage> {
|
class _ScanQrCodePageState extends ConsumerState<ScanQrCodePage> {
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
@@ -58,60 +57,93 @@ class _AuthPageWidgetState extends ConsumerState<ScanQrCodePage> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final eventName = ref.watch(
|
||||||
|
authProvider.select(
|
||||||
|
(state) => state.jwtDecodedData?.eventName?.trim() ?? '',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
return PopScope(
|
return PopScope(
|
||||||
canPop: true,
|
canPop: true,
|
||||||
onPopInvokedWithResult: (didPop, result) async {
|
onPopInvokedWithResult: (didPop, result) async {
|
||||||
if (!didPop) return;
|
if (!didPop) return;
|
||||||
await ref.read(authProvider.notifier).clearAuth();
|
await ref.read(authProvider.notifier).clearAuth();
|
||||||
},
|
},
|
||||||
|
child: AnnotatedRegion<SystemUiOverlayStyle>(
|
||||||
|
value: SystemUiOverlayStyle.dark.copyWith(
|
||||||
|
statusBarColor: Colors.transparent,
|
||||||
|
systemNavigationBarColor: Colors.white,
|
||||||
|
),
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
appBar: myAppBar(context: context, title: '扫码'),
|
backgroundColor: Colors.white,
|
||||||
body: Center(
|
body: Stack(
|
||||||
child: Column(
|
|
||||||
children: [
|
children: [
|
||||||
SizedBox(height: 100.h),
|
Positioned(
|
||||||
Text(
|
top: 0,
|
||||||
'裁判工作台',
|
left: 0,
|
||||||
style: TextStyle(fontSize: 30, color: Colors.black),
|
right: 0,
|
||||||
|
child: Image.asset(
|
||||||
|
_ScanAssets.pageBg,
|
||||||
|
width: double.infinity,
|
||||||
|
fit: BoxFit.fitWidth,
|
||||||
),
|
),
|
||||||
SizedBox(height: 100.h),
|
),
|
||||||
|
SafeArea(
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.fromLTRB(16.w, 12.h, 16.w, 32.h),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
const _BrandHeader(),
|
||||||
|
SizedBox(height: 26.h),
|
||||||
Text(
|
Text(
|
||||||
|
eventName.isEmpty ? '赛事信息' : eventName,
|
||||||
|
maxLines: 2,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
style: TextStyle(
|
||||||
|
color: const Color(0xFF3C3F44),
|
||||||
|
fontSize: 24.sp,
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
height: 1.25,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Spacer(flex: 134),
|
||||||
|
Center(
|
||||||
|
child: GestureDetector(
|
||||||
|
behavior: HitTestBehavior.opaque,
|
||||||
|
onTap: _handleScan,
|
||||||
|
child: Image.asset(
|
||||||
|
_ScanAssets.scanQrcode,
|
||||||
|
width: 166.w,
|
||||||
|
height: 165.w,
|
||||||
|
fit: BoxFit.contain,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(height: 28.h),
|
||||||
|
Center(
|
||||||
|
child: Text(
|
||||||
'扫描选手参赛凭证进行执裁',
|
'扫描选手参赛凭证进行执裁',
|
||||||
style: TextStyle(fontSize: 30, color: Colors.black),
|
style: TextStyle(
|
||||||
|
color: const Color(0xFFABAFB6),
|
||||||
|
fontSize: 16.sp,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
height: 1.2,
|
||||||
),
|
),
|
||||||
SizedBox(height: 20.h),
|
),
|
||||||
|
),
|
||||||
// Consumer(
|
const Spacer(flex: 211),
|
||||||
// builder: (context, ref, child) {
|
Row(
|
||||||
// return SizedBox(
|
children: [
|
||||||
// width: 280.w,
|
Expanded(
|
||||||
// height: 80.h,
|
child: _BottomOutlineButton(
|
||||||
// child: AppButton(
|
label: '查看录像',
|
||||||
// label: '查看录像',
|
onPressed: _handleViewRecords,
|
||||||
// onPressed: () async {
|
),
|
||||||
// final data = ref.watch(
|
),
|
||||||
// authProvider.select((state) => state.jwtDecodedData),
|
SizedBox(width: 12.w),
|
||||||
// );
|
Expanded(
|
||||||
// if (data == null) return;
|
child: _BottomOutlineButton(
|
||||||
// debugPrint('赛事名字: ${data.eventName}');
|
|
||||||
// final eventName = data.eventName ?? '';
|
|
||||||
// await ref
|
|
||||||
// .read(authProvider.notifier)
|
|
||||||
// .getRecordList(eventName);
|
|
||||||
// },
|
|
||||||
// variant: AppButtonVariant.secondary,
|
|
||||||
// ),
|
|
||||||
// );
|
|
||||||
// },
|
|
||||||
// ),
|
|
||||||
SizedBox(height: 16.h),
|
|
||||||
|
|
||||||
Consumer(
|
|
||||||
builder: (context, ref, child) {
|
|
||||||
return SizedBox(
|
|
||||||
width: 280.w,
|
|
||||||
height: 80.h,
|
|
||||||
child: AppButton(
|
|
||||||
label: '参赛队伍',
|
label: '参赛队伍',
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
await AppNavigator.push(
|
await AppNavigator.push(
|
||||||
@@ -119,21 +151,23 @@ class _AuthPageWidgetState extends ConsumerState<ScanQrCodePage> {
|
|||||||
context: context,
|
context: context,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
variant: AppButtonVariant.secondary,
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
),
|
|
||||||
SizedBox(height: 16.h),
|
Future<void> _handleScan() async {
|
||||||
SizedBox(
|
final String? playerId = await AppQrScannerDialog.show(context);
|
||||||
width: 280.w,
|
|
||||||
height: 80.h,
|
|
||||||
child: AppButton(
|
|
||||||
label: '扫码',
|
|
||||||
onPressed: () async {
|
|
||||||
final String? playerId = await AppQrScannerDialog.show(
|
|
||||||
context,
|
|
||||||
);
|
|
||||||
if (playerId == null || playerId.isEmpty) {
|
if (playerId == null || playerId.isEmpty) {
|
||||||
AppToast.show('查询选手信息失败');
|
AppToast.show('查询选手信息失败');
|
||||||
return;
|
return;
|
||||||
@@ -143,9 +177,7 @@ class _AuthPageWidgetState extends ConsumerState<ScanQrCodePage> {
|
|||||||
final success = await ref
|
final success = await ref
|
||||||
.read(eventInfoProvider.notifier)
|
.read(eventInfoProvider.notifier)
|
||||||
.loadRegistrationList(
|
.loadRegistrationList(
|
||||||
request: PlayerRegistrationListReq(
|
request: PlayerRegistrationListReq(userId: playerId),
|
||||||
userId: playerId,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
EasyLoading.dismiss();
|
EasyLoading.dismiss();
|
||||||
if (!success) {
|
if (!success) {
|
||||||
@@ -156,17 +188,102 @@ class _AuthPageWidgetState extends ConsumerState<ScanQrCodePage> {
|
|||||||
|
|
||||||
AppNavigator.push(EventInfoPage(playerId: playerId));
|
AppNavigator.push(EventInfoPage(playerId: playerId));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
AppToast.show('查询选手信息失败');
|
|
||||||
EasyLoading.dismiss();
|
EasyLoading.dismiss();
|
||||||
|
AppToast.show('查询选手信息失败');
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
variant: AppButtonVariant.secondary,
|
|
||||||
|
Future<void> _handleViewRecords() async {
|
||||||
|
final eventName = ref.read(authProvider).jwtDecodedData?.eventName ?? '';
|
||||||
|
if (eventName.trim().isEmpty) {
|
||||||
|
AppToast.show('暂无赛事信息');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
EasyLoading.show(status: '查询录像...');
|
||||||
|
try {
|
||||||
|
final success = await ref
|
||||||
|
.read(authProvider.notifier)
|
||||||
|
.getRecordList(eventName);
|
||||||
|
EasyLoading.dismiss();
|
||||||
|
if (!success) {
|
||||||
|
AppToast.show('暂无录像');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
AppToast.show('录像列表已更新');
|
||||||
|
} catch (error) {
|
||||||
|
EasyLoading.dismiss();
|
||||||
|
AppToast.show('查询录像失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _BrandHeader extends StatelessWidget {
|
||||||
|
const _BrandHeader();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Image.asset(
|
||||||
|
_ScanAssets.appIcon,
|
||||||
|
width: 34.w,
|
||||||
|
height: 34.w,
|
||||||
|
fit: BoxFit.cover,
|
||||||
),
|
),
|
||||||
|
SizedBox(width: 8.w),
|
||||||
|
Image.asset(
|
||||||
|
_ScanAssets.appNameText,
|
||||||
|
width: 117.w,
|
||||||
|
height: 29.w,
|
||||||
|
fit: BoxFit.contain,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _BottomOutlineButton extends StatelessWidget {
|
||||||
|
const _BottomOutlineButton({required this.label, required this.onPressed});
|
||||||
|
|
||||||
|
final String label;
|
||||||
|
final VoidCallback onPressed;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return SizedBox(
|
||||||
|
height: 38.h,
|
||||||
|
child: Material(
|
||||||
|
color: Colors.white.withValues(alpha: 0.08),
|
||||||
|
shape: StadiumBorder(
|
||||||
|
side: BorderSide(color: const Color(0xFF9CCEFF), width: 1.r),
|
||||||
|
),
|
||||||
|
child: InkWell(
|
||||||
|
onTap: onPressed,
|
||||||
|
customBorder: const StadiumBorder(),
|
||||||
|
child: Center(
|
||||||
|
child: Text(
|
||||||
|
label,
|
||||||
|
style: TextStyle(
|
||||||
|
color: const Color(0xFF53A7F3),
|
||||||
|
fontSize: 14.sp,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
height: 1.2,
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class _ScanAssets {
|
||||||
|
const _ScanAssets._();
|
||||||
|
|
||||||
|
static const pageBg = 'assets/images/image_page_bg.png';
|
||||||
|
static const appIcon = 'assets/images/image_app_icon.png';
|
||||||
|
static const appNameText = 'assets/images/image_app_name_text.png';
|
||||||
|
static const scanQrcode = 'assets/images/image_scan_qrcode.png';
|
||||||
|
}
|
||||||
|
|||||||
@@ -24,13 +24,13 @@ class $AssetsHtmlGen {
|
|||||||
class $AssetsImagesGen {
|
class $AssetsImagesGen {
|
||||||
const $AssetsImagesGen();
|
const $AssetsImagesGen();
|
||||||
|
|
||||||
/// File path: assets/images/image_copy.png
|
/// File path: assets/images/image_app_icon.png
|
||||||
AssetGenImage get imageCopy =>
|
AssetGenImage get imageAppIcon =>
|
||||||
const AssetGenImage('assets/images/image_copy.png');
|
const AssetGenImage('assets/images/image_app_icon.png');
|
||||||
|
|
||||||
/// File path: assets/images/image_delete.png
|
/// File path: assets/images/image_app_name_text.png
|
||||||
AssetGenImage get imageDelete =>
|
AssetGenImage get imageAppNameText =>
|
||||||
const AssetGenImage('assets/images/image_delete.png');
|
const AssetGenImage('assets/images/image_app_name_text.png');
|
||||||
|
|
||||||
/// File path: assets/images/image_dialog_bg.png
|
/// File path: assets/images/image_dialog_bg.png
|
||||||
AssetGenImage get imageDialogBg =>
|
AssetGenImage get imageDialogBg =>
|
||||||
@@ -40,16 +40,26 @@ class $AssetsImagesGen {
|
|||||||
AssetGenImage get imageLogo =>
|
AssetGenImage get imageLogo =>
|
||||||
const AssetGenImage('assets/images/image_logo.png');
|
const AssetGenImage('assets/images/image_logo.png');
|
||||||
|
|
||||||
|
/// File path: assets/images/image_page_bg.png
|
||||||
|
AssetGenImage get imagePageBg =>
|
||||||
|
const AssetGenImage('assets/images/image_page_bg.png');
|
||||||
|
|
||||||
|
/// File path: assets/images/image_scan_qrcode.png
|
||||||
|
AssetGenImage get imageScanQrcode =>
|
||||||
|
const AssetGenImage('assets/images/image_scan_qrcode.png');
|
||||||
|
|
||||||
/// File path: assets/images/image_vs.png
|
/// File path: assets/images/image_vs.png
|
||||||
AssetGenImage get imageVs =>
|
AssetGenImage get imageVs =>
|
||||||
const AssetGenImage('assets/images/image_vs.png');
|
const AssetGenImage('assets/images/image_vs.png');
|
||||||
|
|
||||||
/// List of all assets
|
/// List of all assets
|
||||||
List<AssetGenImage> get values => [
|
List<AssetGenImage> get values => [
|
||||||
imageCopy,
|
imageAppIcon,
|
||||||
imageDelete,
|
imageAppNameText,
|
||||||
imageDialogBg,
|
imageDialogBg,
|
||||||
imageLogo,
|
imageLogo,
|
||||||
|
imagePageBg,
|
||||||
|
imageScanQrcode,
|
||||||
imageVs,
|
imageVs,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||