feat: 主页添加钱包生成状态轮询

手机号注册后跳转到主页,在主页后台轮询钱包生成状态:

功能实现:
- 添加钱包生成状态枚举(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 <noreply@anthropic.com>
This commit is contained in:
hailin 2025-12-20 23:24:43 -08:00
parent 636a06c241
commit 08ec49322d
1 changed files with 167 additions and 10 deletions

View File

@ -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<MiningPage> {
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<MiningPage> {
_checkLocalAvatarSync();
_loadUserData();
_loadAuthorizationData();
//
_startWalletPolling();
}
@override
void dispose() {
_walletPollingTimer?.cancel();
super.dispose();
}
/// build
@ -124,6 +146,79 @@ class _MiningPageState extends ConsumerState<MiningPage> {
}
}
///
void _startWalletPolling() {
debugPrint('[MiningPage] 开始轮询钱包生成状态...');
//
_checkWalletStatus();
// 5
_walletPollingTimer = Timer.periodic(const Duration(seconds: 5), (_) {
_checkWalletStatus();
});
}
///
Future<void> _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<void> _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<MiningPage> {
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>(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' : ''}',