diff --git a/frontend/mobile-app/lib/features/auth/presentation/pages/guide_page.dart b/frontend/mobile-app/lib/features/auth/presentation/pages/guide_page.dart index b3f1917e..8eeda837 100644 --- a/frontend/mobile-app/lib/features/auth/presentation/pages/guide_page.dart +++ b/frontend/mobile-app/lib/features/auth/presentation/pages/guide_page.dart @@ -3,6 +3,7 @@ import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:go_router/go_router.dart'; +import 'package:image_picker/image_picker.dart'; import 'package:mobile_scanner/mobile_scanner.dart'; import '../../../../routes/route_paths.dart'; import '../providers/auth_provider.dart'; @@ -596,6 +597,7 @@ class _QrScannerPageState extends State<_QrScannerPage> { MobileScannerController? _controller; bool _hasScanned = false; bool _torchOn = false; + bool _isProcessingImage = false; @override void initState() { @@ -632,6 +634,84 @@ class _QrScannerPageState extends State<_QrScannerPage> { }); } + /// 从相册选择图片并扫描二维码 + Future _pickImageAndScan() async { + if (_isProcessingImage || _hasScanned) return; + + setState(() { + _isProcessingImage = true; + }); + + try { + final ImagePicker picker = ImagePicker(); + final XFile? image = await picker.pickImage(source: ImageSource.gallery); + + if (image == null) { + setState(() { + _isProcessingImage = false; + }); + return; + } + + // 使用 MobileScannerController 分析图片 + final BarcodeCapture? result = await _controller?.analyzeImage(image.path); + + if (result != null && result.barcodes.isNotEmpty) { + for (final barcode in result.barcodes) { + if (barcode.rawValue != null && barcode.rawValue!.isNotEmpty) { + _hasScanned = true; + if (mounted) { + Navigator.of(context).pop(barcode.rawValue); + } + return; + } + } + } + + // 未识别到二维码 + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text( + '未能识别图片中的二维码,请重新选择', + style: TextStyle(fontSize: 14.sp), + ), + backgroundColor: const Color(0xFF6F6354), + behavior: SnackBarBehavior.floating, + margin: EdgeInsets.all(16.w), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8.r), + ), + ), + ); + } + } catch (e) { + debugPrint('扫描图片失败: $e'); + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text( + '图片扫描失败,请重试', + style: TextStyle(fontSize: 14.sp), + ), + backgroundColor: Colors.red, + behavior: SnackBarBehavior.floating, + margin: EdgeInsets.all(16.w), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8.r), + ), + ), + ); + } + } finally { + if (mounted) { + setState(() { + _isProcessingImage = false; + }); + } + } + } + @override Widget build(BuildContext context) { return Scaffold( @@ -669,18 +749,66 @@ class _QrScannerPageState extends State<_QrScannerPage> { ), // 扫描框遮罩 _buildScanOverlay(), - // 底部提示 + // 底部区域:提示文字和相册按钮 Positioned( - bottom: 100.h, + bottom: 60.h, left: 0, right: 0, - child: Text( - '将二维码放入框内,即可自动扫描', - style: TextStyle( - fontSize: 14.sp, - color: Colors.white70, - ), - textAlign: TextAlign.center, + child: Column( + children: [ + Text( + '将二维码放入框内,即可自动扫描', + style: TextStyle( + fontSize: 14.sp, + color: Colors.white70, + ), + textAlign: TextAlign.center, + ), + SizedBox(height: 32.h), + // 相册按钮 + GestureDetector( + onTap: _isProcessingImage ? null : _pickImageAndScan, + child: Container( + padding: EdgeInsets.symmetric(horizontal: 24.w, vertical: 12.h), + decoration: BoxDecoration( + color: Colors.white.withValues(alpha: 0.15), + borderRadius: BorderRadius.circular(24.r), + border: Border.all( + color: Colors.white.withValues(alpha: 0.3), + width: 1, + ), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + if (_isProcessingImage) + SizedBox( + width: 18.sp, + height: 18.sp, + child: const CircularProgressIndicator( + strokeWidth: 2, + valueColor: AlwaysStoppedAnimation(Colors.white), + ), + ) + else + Icon( + Icons.photo_library_outlined, + size: 18.sp, + color: Colors.white, + ), + SizedBox(width: 8.w), + Text( + _isProcessingImage ? '识别中...' : '从相册选择', + style: TextStyle( + fontSize: 14.sp, + color: Colors.white, + ), + ), + ], + ), + ), + ), + ], ), ), ],