import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/flutter_svg.dart'; import '../../../../core/di/injection_container.dart'; /// 挖矿状态枚举 enum MiningStatus { pending, // 待开启 mining, // 挖矿中 paused, // 已暂停 } /// 矿机页面 - 显示挖矿状态和控制 /// 展示用户序列号、社区信息和挖矿开关 class MiningPage extends ConsumerStatefulWidget { const MiningPage({super.key}); @override ConsumerState createState() => _MiningPageState(); } class _MiningPageState extends ConsumerState { // 当前挖矿状态 MiningStatus _miningStatus = MiningStatus.pending; // 用户数据(从存储加载) String _serialNumber = '--'; String? _avatarSvg; String? _avatarUrl; String? _localAvatarPath; // 本地头像文件路径 // 授权数据(从 authorization-service 获取) String _community = '--'; String _province = '--'; String _city = '--'; @override void initState() { super.initState(); // 先同步检查本地头像,再异步加载其他数据 _checkLocalAvatarSync(); _loadUserData(); _loadAuthorizationData(); } /// 同步检查本地头像文件(在 build 之前快速获取) void _checkLocalAvatarSync() { WidgetsBinding.instance.addPostFrameCallback((_) async { final accountService = ref.read(accountServiceProvider); final localPath = await accountService.getLocalAvatarPath(); if (mounted && localPath != null && _localAvatarPath == null) { setState(() { _localAvatarPath = localPath; }); } }); } /// 加载用户数据 Future _loadUserData() async { final accountService = ref.read(accountServiceProvider); // 并行加载所有数据 final results = await Future.wait([ accountService.getUserSerialNum(), accountService.getAvatarSvg(), accountService.getAvatarUrl(), accountService.getLocalAvatarPath(), ]); final serialNum = results[0] as int?; final avatarSvg = results[1] as String?; final avatarUrl = results[2] as String?; final localAvatarPath = results[3] as String?; if (mounted) { setState(() { _serialNumber = serialNum?.toString() ?? '--'; _avatarSvg = avatarSvg; _avatarUrl = avatarUrl; _localAvatarPath = localAvatarPath; }); // 如果有远程URL但没有本地缓存,后台下载并缓存 if (avatarUrl != null && avatarUrl.isNotEmpty && localAvatarPath == null) { _downloadAndCacheAvatar(avatarUrl); } } } /// 后台下载并缓存头像 Future _downloadAndCacheAvatar(String url) async { final accountService = ref.read(accountServiceProvider); final localPath = await accountService.downloadAndCacheAvatar(url); if (mounted && localPath != null) { setState(() { _localAvatarPath = localPath; }); } } /// 加载授权数据(社区、省、市) Future _loadAuthorizationData() async { try { debugPrint('[MiningPage] 开始加载授权数据...'); final authorizationService = ref.read(authorizationServiceProvider); final summary = await authorizationService.getMyAuthorizationSummary(); if (mounted) { setState(() { _community = summary.communityName ?? '--'; _city = summary.cityCompanyName ?? '--'; _province = summary.provinceCompanyName ?? '--'; }); debugPrint('[MiningPage] 授权数据加载成功:'); debugPrint('[MiningPage] 社区: $_community'); debugPrint('[MiningPage] 市公司: $_city'); debugPrint('[MiningPage] 省公司: $_province'); } } catch (e, stackTrace) { debugPrint('[MiningPage] 加载授权数据失败: $e'); debugPrint('[MiningPage] 堆栈: $stackTrace'); // 失败时保持默认值 '--' } } /// 显示帮助信息 void _showHelpInfo() { showDialog( context: context, builder: (context) => AlertDialog( title: const Text('矿机说明'), content: const Text('矿机是您参与挖矿的核心工具。\n\n' '开启挖矿后,您将开始获得收益。\n\n' '收益与您的算力和团队规模相关。'), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: const Text('知道了'), ), ], ), ); } /// 切换挖矿状态 void _toggleMining() { setState(() { if (_miningStatus == MiningStatus.pending) { _miningStatus = MiningStatus.mining; } else if (_miningStatus == MiningStatus.mining) { _miningStatus = MiningStatus.paused; } else { _miningStatus = MiningStatus.mining; } }); } /// 获取状态文本 String _getStatusText() { switch (_miningStatus) { case MiningStatus.pending: return '挖矿待开启'; case MiningStatus.mining: return '挖矿中'; case MiningStatus.paused: return '挖矿已暂停'; } } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.white, body: Container( width: double.infinity, height: double.infinity, decoration: const BoxDecoration( gradient: LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [ Color(0xFFFFF5E6), Color(0xFFFFE4B5), ], ), ), child: SafeArea( child: Column( children: [ // 顶部标题栏 _buildAppBar(), // 用户信息区域 _buildUserInfo(), const SizedBox(height: 24), // 挖矿状态区域 Expanded( child: _buildMiningStatusArea(), ), ], ), ), ), ); } /// 构建顶部标题栏 Widget _buildAppBar() { return Container( height: 56, padding: const EdgeInsets.symmetric(horizontal: 16), child: Row( children: [ // 占位 const SizedBox(width: 48), // 标题 const Expanded( child: Text( '矿机', style: TextStyle( fontSize: 18, fontFamily: 'Inter', fontWeight: FontWeight.w700, height: 1.25, letterSpacing: -0.27, color: Color(0xFF5D4037), ), textAlign: TextAlign.center, ), ), // 帮助按钮 GestureDetector( onTap: _showHelpInfo, child: Container( width: 48, height: 48, alignment: Alignment.center, child: Container( width: 24, height: 24, decoration: BoxDecoration( shape: BoxShape.circle, border: Border.all( color: const Color(0xFF8B5A2B), width: 2, ), ), child: const Center( child: Text( 'i', style: TextStyle( fontSize: 14, fontWeight: FontWeight.w600, color: Color(0xFF8B5A2B), ), ), ), ), ), ), ], ), ); } /// 构建用户信息区域 Widget _buildUserInfo() { // 构建省市显示文本 String locationText = ''; if (_province != '--' && _city != '--') { locationText = '$_province · $_city'; } else if (_province != '--') { locationText = _province; } else if (_city != '--') { locationText = _city; } return Padding( padding: const EdgeInsets.symmetric(horizontal: 16), child: Row( children: [ // 头像 Container( width: 80, height: 80, decoration: BoxDecoration( borderRadius: BorderRadius.circular(40), color: const Color(0xFFFFF5E6), ), child: ClipRRect( borderRadius: BorderRadius.circular(40), child: _buildAvatarContent(), ), ), const SizedBox(width: 16), // 用户信息 Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( '序列号$_serialNumber', style: const TextStyle( fontSize: 20, fontFamily: 'Inter', fontWeight: FontWeight.w700, height: 1.25, letterSpacing: -0.3, color: Color(0xFF5D4037), ), ), const SizedBox(height: 4), Text( '社区: $_community${locationText.isNotEmpty ? ' / $locationText' : ''}', style: const TextStyle( fontSize: 14, fontFamily: 'Inter', height: 1.5, color: Color(0xFF8B5A2B), ), overflow: TextOverflow.ellipsis, ), ], ), ), ], ), ); } /// 构建挖矿状态区域 Widget _buildMiningStatusArea() { return Padding( padding: const EdgeInsets.all(16), child: Container( width: double.infinity, decoration: BoxDecoration( color: const Color(0x66FFFFFF), borderRadius: BorderRadius.circular(12), ), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ // 挖矿开关按钮 GestureDetector( onTap: _toggleMining, child: Container( width: 100, height: 100, decoration: BoxDecoration( shape: BoxShape.circle, color: _miningStatus == MiningStatus.mining ? const Color(0xFFD4AF37) : Colors.transparent, border: Border.all( color: _miningStatus == MiningStatus.mining ? const Color(0xFFD4AF37) : const Color(0xFFD4AF37).withOpacity(0.5), width: 3, ), ), child: Icon( Icons.power_settings_new, size: 48, color: _miningStatus == MiningStatus.mining ? Colors.white : const Color(0xFFD4AF37).withOpacity(0.5), ), ), ), const SizedBox(height: 16), // 状态文本 Text( _getStatusText(), style: const TextStyle( fontSize: 18, fontFamily: 'Inter', fontWeight: FontWeight.w500, height: 1.56, color: Color(0xFF8B5A2B), ), ), // 挖矿中显示额外信息 if (_miningStatus == MiningStatus.mining) ...[ const SizedBox(height: 24), _buildMiningStats(), ], ], ), ), ); } /// 构建挖矿统计信息 Widget _buildMiningStats() { return Container( padding: const EdgeInsets.all(16), margin: const EdgeInsets.symmetric(horizontal: 16), decoration: BoxDecoration( color: const Color(0x33D4AF37), borderRadius: BorderRadius.circular(8), ), child: Column( children: [ _buildStatRow('个人算力', '100 H/s'), const SizedBox(height: 8), _buildStatRow('团队算力', '1,000 H/s'), const SizedBox(height: 8), _buildStatRow('今日收益', '0.00 DST'), const SizedBox(height: 8), _buildStatRow('累计收益', '0.00 DST'), ], ), ); } /// 构建统计行 Widget _buildStatRow(String label, String value) { return Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( label, style: const TextStyle( fontSize: 14, fontFamily: 'Inter', height: 1.5, color: Color(0xFF8B5A2B), ), ), Text( value, style: const TextStyle( fontSize: 14, fontFamily: 'Inter', fontWeight: FontWeight.w600, height: 1.5, color: Color(0xFF5D4037), ), ), ], ); } /// 构建头像内容(优先本地文件,其次网络URL,最后SVG) Widget _buildAvatarContent() { // 1. 优先显示本地缓存的头像文件 if (_localAvatarPath != null && _localAvatarPath!.isNotEmpty) { final file = File(_localAvatarPath!); // 同步检查文件是否存在 if (file.existsSync()) { return Image.file( file, width: 80, height: 80, fit: BoxFit.cover, gaplessPlayback: true, // 防止图片切换时闪烁 errorBuilder: (context, error, stackTrace) { // 本地文件加载失败,尝试网络URL return _buildNetworkOrSvgAvatar(); }, ); } } // 2. 没有本地缓存,尝试网络URL或SVG return _buildNetworkOrSvgAvatar(); } /// 构建网络URL或SVG头像 Widget _buildNetworkOrSvgAvatar() { // 尝试显示网络图片URL if (_avatarUrl != null && _avatarUrl!.isNotEmpty) { return Image.network( _avatarUrl!, width: 80, height: 80, fit: BoxFit.cover, loadingBuilder: (context, child, loadingProgress) { if (loadingProgress == null) return child; return const Center( child: SizedBox( width: 24, height: 24, child: CircularProgressIndicator( strokeWidth: 2, valueColor: AlwaysStoppedAnimation(Color(0xFFD4AF37)), ), ), ); }, errorBuilder: (context, error, stackTrace) { // 加载失败时显示SVG或默认头像 return _buildSvgOrDefaultAvatar(); }, ); } // 显示SVG或默认头像 return _buildSvgOrDefaultAvatar(); } /// 构建SVG或默认头像 /// 注意:_avatarSvg 可能存储的是 URL(用户上传的图片)或 SVG 字符串(随机生成的头像) Widget _buildSvgOrDefaultAvatar() { if (_avatarSvg != null && _avatarSvg!.isNotEmpty) { // 检测是否是 URL(用户上传的头像图片) if (_avatarSvg!.startsWith('http://') || _avatarSvg!.startsWith('https://')) { return Image.network( _avatarSvg!, width: 80, height: 80, fit: BoxFit.cover, loadingBuilder: (context, child, loadingProgress) { if (loadingProgress == null) return child; return const Center( child: SizedBox( width: 24, height: 24, child: CircularProgressIndicator( strokeWidth: 2, valueColor: AlwaysStoppedAnimation(Color(0xFFD4AF37)), ), ), ); }, errorBuilder: (context, error, stackTrace) { return const Icon( Icons.person, size: 40, color: Color(0xFF8B5A2B), ); }, ); } // 检测是否是 SVG 字符串(随机生成的 SVG 头像) if (_avatarSvg!.contains('