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:
parent
636a06c241
commit
08ec49322d
|
|
@ -1,3 +1,4 @@
|
||||||
|
import 'dart:async';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
|
@ -10,6 +11,14 @@ enum MonitorStatus {
|
||||||
active, // 监控中
|
active, // 监控中
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 钱包生成状态枚举
|
||||||
|
enum WalletCreationStatus {
|
||||||
|
unknown, // 未知
|
||||||
|
creating, // 创建中(显示"创建账号审核中...")
|
||||||
|
ready, // 已就绪
|
||||||
|
failed, // 失败
|
||||||
|
}
|
||||||
|
|
||||||
/// 监控页面 - 显示监控状态和控制
|
/// 监控页面 - 显示监控状态和控制
|
||||||
/// 展示用户序列号、社区信息,未来将接入实时监控视频流
|
/// 展示用户序列号、社区信息,未来将接入实时监控视频流
|
||||||
class MiningPage extends ConsumerStatefulWidget {
|
class MiningPage extends ConsumerStatefulWidget {
|
||||||
|
|
@ -34,6 +43,11 @@ class _MiningPageState extends ConsumerState<MiningPage> {
|
||||||
String _province = '--';
|
String _province = '--';
|
||||||
String _city = '--';
|
String _city = '--';
|
||||||
|
|
||||||
|
// 钱包生成状态
|
||||||
|
WalletCreationStatus _walletStatus = WalletCreationStatus.unknown;
|
||||||
|
String? _walletError;
|
||||||
|
Timer? _walletPollingTimer;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
|
@ -41,6 +55,14 @@ class _MiningPageState extends ConsumerState<MiningPage> {
|
||||||
_checkLocalAvatarSync();
|
_checkLocalAvatarSync();
|
||||||
_loadUserData();
|
_loadUserData();
|
||||||
_loadAuthorizationData();
|
_loadAuthorizationData();
|
||||||
|
// 开始轮询钱包状态
|
||||||
|
_startWalletPolling();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_walletPollingTimer?.cancel();
|
||||||
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 同步检查本地头像文件(在 build 之前快速获取)
|
/// 同步检查本地头像文件(在 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() {
|
void _showHelpInfo() {
|
||||||
showDialog(
|
showDialog(
|
||||||
|
|
@ -314,17 +409,79 @@ class _MiningPageState extends ConsumerState<MiningPage> {
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
// 根据钱包状态显示不同内容
|
||||||
'序列号$_serialNumber',
|
if (_walletStatus == WalletCreationStatus.creating)
|
||||||
style: const TextStyle(
|
Row(
|
||||||
fontSize: 20,
|
children: [
|
||||||
fontFamily: 'Inter',
|
const SizedBox(
|
||||||
fontWeight: FontWeight.w700,
|
width: 16,
|
||||||
height: 1.25,
|
height: 16,
|
||||||
letterSpacing: -0.3,
|
child: CircularProgressIndicator(
|
||||||
color: Color(0xFF5D4037),
|
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),
|
const SizedBox(height: 4),
|
||||||
Text(
|
Text(
|
||||||
'社区: $_community${locationText.isNotEmpty ? ' / $locationText' : ''}',
|
'社区: $_community${locationText.isNotEmpty ? ' / $locationText' : ''}',
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue