From 08ec49322d385ec32cad790b00f5c06219bbc38e Mon Sep 17 00:00:00 2001 From: hailin Date: Sat, 20 Dec 2025 23:24:43 -0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=B8=BB=E9=A1=B5=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E9=92=B1=E5=8C=85=E7=94=9F=E6=88=90=E7=8A=B6=E6=80=81=E8=BD=AE?= =?UTF-8?q?=E8=AF=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 手机号注册后跳转到主页,在主页后台轮询钱包生成状态: 功能实现: - 添加钱包生成状态枚举(unknown/creating/ready/failed) - 每5秒调用 GET /user/wallet 检查钱包状态 - 钱包就绪或失败后停止轮询 UI 显示: - 钱包创建中:显示"创建账号审核中..."加载动画 - 钱包创建失败:显示错误信息和"重试"按钮 - 钱包已就绪:显示正常序列号 重试机制: - 用户可点击"重试"按钮手动触发钱包生成 - 调用 POST /user/wallet/retry API - 重新开始轮询直到成功 流程: 手机号注册 → 设置密码 → 跳转主页 → 后台轮询钱包状态 → 完成 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 --- .../presentation/pages/mining_page.dart | 177 +++++++++++++++++- 1 file changed, 167 insertions(+), 10 deletions(-) diff --git a/frontend/mobile-app/lib/features/mining/presentation/pages/mining_page.dart b/frontend/mobile-app/lib/features/mining/presentation/pages/mining_page.dart index d56ff8cf..6ed03f49 100644 --- a/frontend/mobile-app/lib/features/mining/presentation/pages/mining_page.dart +++ b/frontend/mobile-app/lib/features/mining/presentation/pages/mining_page.dart @@ -1,3 +1,4 @@ +import 'dart:async'; import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; @@ -10,6 +11,14 @@ enum MonitorStatus { active, // 监控中 } +/// 钱包生成状态枚举 +enum WalletCreationStatus { + unknown, // 未知 + creating, // 创建中(显示"创建账号审核中...") + ready, // 已就绪 + failed, // 失败 +} + /// 监控页面 - 显示监控状态和控制 /// 展示用户序列号、社区信息,未来将接入实时监控视频流 class MiningPage extends ConsumerStatefulWidget { @@ -34,6 +43,11 @@ class _MiningPageState extends ConsumerState { String _province = '--'; String _city = '--'; + // 钱包生成状态 + WalletCreationStatus _walletStatus = WalletCreationStatus.unknown; + String? _walletError; + Timer? _walletPollingTimer; + @override void initState() { super.initState(); @@ -41,6 +55,14 @@ class _MiningPageState extends ConsumerState { _checkLocalAvatarSync(); _loadUserData(); _loadAuthorizationData(); + // 开始轮询钱包状态 + _startWalletPolling(); + } + + @override + void dispose() { + _walletPollingTimer?.cancel(); + super.dispose(); } /// 同步检查本地头像文件(在 build 之前快速获取) @@ -124,6 +146,79 @@ class _MiningPageState extends ConsumerState { } } + /// 开始轮询钱包生成状态 + void _startWalletPolling() { + debugPrint('[MiningPage] 开始轮询钱包生成状态...'); + + // 立即检查一次 + _checkWalletStatus(); + + // 每5秒检查一次 + _walletPollingTimer = Timer.periodic(const Duration(seconds: 5), (_) { + _checkWalletStatus(); + }); + } + + /// 检查钱包生成状态 + Future _checkWalletStatus() async { + try { + final accountService = ref.read(accountServiceProvider); + final walletInfo = await accountService.getWalletInfo(_serialNumber); + + if (!mounted) return; + + setState(() { + if (walletInfo.isReady) { + _walletStatus = WalletCreationStatus.ready; + _walletError = null; + // 钱包已就绪,停止轮询 + _walletPollingTimer?.cancel(); + debugPrint('[MiningPage] 钱包已就绪,停止轮询'); + } else if (walletInfo.isFailed) { + _walletStatus = WalletCreationStatus.failed; + _walletError = '账号创建失败'; + _walletPollingTimer?.cancel(); + debugPrint('[MiningPage] 钱包创建失败'); + } else { + _walletStatus = WalletCreationStatus.creating; + _walletError = null; + debugPrint('[MiningPage] 钱包创建中...'); + } + }); + } catch (e) { + debugPrint('[MiningPage] 检查钱包状态失败: $e'); + // 不改变状态,继续轮询 + } + } + + /// 手动重试钱包生成 + Future _retryWalletGeneration() async { + try { + debugPrint('[MiningPage] 手动重试钱包生成...'); + final accountService = ref.read(accountServiceProvider); + await accountService.retryWalletGeneration(); + + if (!mounted) return; + + // 重置状态并重新开始轮询 + setState(() { + _walletStatus = WalletCreationStatus.creating; + _walletError = null; + }); + + // 重新开始轮询 + _walletPollingTimer?.cancel(); + _startWalletPolling(); + } catch (e) { + debugPrint('[MiningPage] 重试钱包生成失败: $e'); + if (mounted) { + setState(() { + _walletError = '重试失败: $e'; + }); + } + } + } + /// 显示帮助信息 void _showHelpInfo() { showDialog( @@ -314,17 +409,79 @@ class _MiningPageState extends ConsumerState { 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), + // 根据钱包状态显示不同内容 + if (_walletStatus == WalletCreationStatus.creating) + Row( + children: [ + const SizedBox( + width: 16, + height: 16, + child: CircularProgressIndicator( + strokeWidth: 2, + valueColor: AlwaysStoppedAnimation(Color(0xFF8B5A2B)), + ), + ), + const SizedBox(width: 8), + Text( + '创建账号审核中...', + style: const TextStyle( + fontSize: 16, + fontFamily: 'Inter', + fontWeight: FontWeight.w600, + color: Color(0xFF8B5A2B), + ), + ), + ], + ) + else if (_walletStatus == WalletCreationStatus.failed) + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + _walletError ?? '账号创建失败', + style: const TextStyle( + fontSize: 16, + fontFamily: 'Inter', + fontWeight: FontWeight.w600, + color: Colors.red, + ), + ), + const SizedBox(height: 4), + GestureDetector( + onTap: _retryWalletGeneration, + child: Container( + padding: const EdgeInsets.symmetric( + horizontal: 12, + vertical: 6, + ), + decoration: BoxDecoration( + color: const Color(0xFF8B5A2B), + borderRadius: BorderRadius.circular(4), + ), + child: const Text( + '重试', + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w600, + color: Colors.white, + ), + ), + ), + ), + ], + ) + else + 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' : ''}',