refactor: 钱包状态轮询自动重试,移除手动重试按钮
设计原则:只要钱包不是 ready 状态,就持续轮询并自动重试生成 - 移除 failed 状态和重试按钮(用户无需手动操作) - 非 ready 时自动调用 retryWalletGeneration API(幂等) - 轮询间隔改为60秒(API 1-10分钟幂等) - 只有 ready 时停止轮询 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
ffd4fae0b6
commit
3e352dbcfe
|
|
@ -11,32 +11,27 @@ enum WalletGenerationStatus {
|
|||
unknown, // 未知状态
|
||||
generating, // 生成中
|
||||
ready, // 已就绪
|
||||
failed, // 生成失败
|
||||
}
|
||||
|
||||
/// 钱包状态信息
|
||||
class WalletStatusState {
|
||||
final WalletGenerationStatus status;
|
||||
final String? errorMessage;
|
||||
final DateTime? lastChecked;
|
||||
final bool isPolling;
|
||||
|
||||
const WalletStatusState({
|
||||
this.status = WalletGenerationStatus.unknown,
|
||||
this.errorMessage,
|
||||
this.lastChecked,
|
||||
this.isPolling = false,
|
||||
});
|
||||
|
||||
WalletStatusState copyWith({
|
||||
WalletGenerationStatus? status,
|
||||
String? errorMessage,
|
||||
DateTime? lastChecked,
|
||||
bool? isPolling,
|
||||
}) {
|
||||
return WalletStatusState(
|
||||
status: status ?? this.status,
|
||||
errorMessage: errorMessage,
|
||||
lastChecked: lastChecked ?? this.lastChecked,
|
||||
isPolling: isPolling ?? this.isPolling,
|
||||
);
|
||||
|
|
@ -44,10 +39,14 @@ class WalletStatusState {
|
|||
|
||||
bool get isGenerating => status == WalletGenerationStatus.generating;
|
||||
bool get isReady => status == WalletGenerationStatus.ready;
|
||||
bool get isFailed => status == WalletGenerationStatus.failed;
|
||||
}
|
||||
|
||||
/// 钱包状态管理器
|
||||
///
|
||||
/// 设计原则:只要钱包不是 ready 状态,就持续轮询并自动重试生成
|
||||
/// - 轮询间隔:1-10分钟(幂等)
|
||||
/// - 只有 ready 时停止轮询
|
||||
/// - 非 ready 时自动调用 retryWalletGeneration API 触发新的生成过程
|
||||
class WalletStatusNotifier extends StateNotifier<WalletStatusState> {
|
||||
final AccountService _accountService;
|
||||
final SecureStorage _secureStorage;
|
||||
|
|
@ -58,7 +57,7 @@ class WalletStatusNotifier extends StateNotifier<WalletStatusState> {
|
|||
|
||||
/// 开始轮询钱包状态
|
||||
///
|
||||
/// 每5秒检查一次,直到钱包就绪或失败
|
||||
/// 每60秒检查一次,直到钱包就绪
|
||||
Future<void> startPolling() async {
|
||||
if (state.isPolling) {
|
||||
debugPrint('[WalletStatusProvider] Already polling, skipping');
|
||||
|
|
@ -69,17 +68,12 @@ class WalletStatusNotifier extends StateNotifier<WalletStatusState> {
|
|||
state = state.copyWith(isPolling: true);
|
||||
|
||||
// 立即检查一次
|
||||
await _checkWalletStatus();
|
||||
await _checkAndRetryIfNeeded();
|
||||
|
||||
// 设置定时器,每5秒检查一次
|
||||
// 设置定时器,每60秒检查一次(幂等,1-10分钟间隔)
|
||||
_pollingTimer?.cancel();
|
||||
_pollingTimer = Timer.periodic(const Duration(seconds: 5), (_) async {
|
||||
await _checkWalletStatus();
|
||||
|
||||
// 如果钱包已就绪或失败,停止轮询
|
||||
if (state.isReady || state.isFailed) {
|
||||
stopPolling();
|
||||
}
|
||||
_pollingTimer = Timer.periodic(const Duration(seconds: 60), (_) async {
|
||||
await _checkAndRetryIfNeeded();
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -91,8 +85,8 @@ class WalletStatusNotifier extends StateNotifier<WalletStatusState> {
|
|||
state = state.copyWith(isPolling: false);
|
||||
}
|
||||
|
||||
/// 检查钱包状态
|
||||
Future<void> _checkWalletStatus() async {
|
||||
/// 检查钱包状态,非 ready 时自动重试
|
||||
Future<void> _checkAndRetryIfNeeded() async {
|
||||
try {
|
||||
debugPrint('[WalletStatusProvider] Checking wallet status...');
|
||||
|
||||
|
|
@ -112,62 +106,46 @@ class WalletStatusNotifier extends StateNotifier<WalletStatusState> {
|
|||
debugPrint(
|
||||
'[WalletStatusProvider] Wallet status: ${walletInfo.status}');
|
||||
|
||||
// 更新状态
|
||||
WalletGenerationStatus newStatus;
|
||||
if (walletInfo.isReady) {
|
||||
newStatus = WalletGenerationStatus.ready;
|
||||
|
||||
// 钱包已就绪,保存标记
|
||||
// 钱包已就绪,保存标记并停止轮询
|
||||
await _secureStorage.write(
|
||||
key: StorageKeys.isWalletReady,
|
||||
value: 'true',
|
||||
);
|
||||
debugPrint('[WalletStatusProvider] Wallet is ready, marked in storage');
|
||||
} else if (walletInfo.isGenerating) {
|
||||
newStatus = WalletGenerationStatus.generating;
|
||||
} else if (walletInfo.isFailed) {
|
||||
newStatus = WalletGenerationStatus.failed;
|
||||
} else {
|
||||
newStatus = WalletGenerationStatus.unknown;
|
||||
}
|
||||
debugPrint('[WalletStatusProvider] Wallet is ready, stopping polling');
|
||||
|
||||
state = state.copyWith(
|
||||
status: newStatus,
|
||||
lastChecked: DateTime.now(),
|
||||
errorMessage: null,
|
||||
);
|
||||
state = state.copyWith(
|
||||
status: WalletGenerationStatus.ready,
|
||||
lastChecked: DateTime.now(),
|
||||
);
|
||||
|
||||
stopPolling();
|
||||
} else {
|
||||
// 非 ready 状态,自动触发重试生成(API 是幂等的)
|
||||
debugPrint('[WalletStatusProvider] Wallet not ready, triggering retry...');
|
||||
|
||||
try {
|
||||
await _accountService.retryWalletGeneration();
|
||||
debugPrint('[WalletStatusProvider] Retry triggered successfully');
|
||||
} catch (e) {
|
||||
debugPrint('[WalletStatusProvider] Retry API call failed: $e');
|
||||
// 继续轮询,下次再试
|
||||
}
|
||||
|
||||
state = state.copyWith(
|
||||
status: WalletGenerationStatus.generating,
|
||||
lastChecked: DateTime.now(),
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('[WalletStatusProvider] Error checking wallet status: $e');
|
||||
// 出错不停止轮询,继续尝试
|
||||
state = state.copyWith(
|
||||
errorMessage: e.toString(),
|
||||
lastChecked: DateTime.now(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// 手动触发重试
|
||||
Future<void> retryWalletGeneration() async {
|
||||
try {
|
||||
debugPrint('[WalletStatusProvider] Manually retrying wallet generation');
|
||||
|
||||
// 调用重试 API
|
||||
await _accountService.retryWalletGeneration();
|
||||
|
||||
// 重新开始轮询
|
||||
state = state.copyWith(
|
||||
status: WalletGenerationStatus.generating,
|
||||
errorMessage: null,
|
||||
);
|
||||
|
||||
if (!state.isPolling) {
|
||||
await startPolling();
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('[WalletStatusProvider] Error retrying wallet generation: $e');
|
||||
state = state.copyWith(errorMessage: e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_pollingTimer?.cancel();
|
||||
|
|
|
|||
|
|
@ -13,10 +13,9 @@ enum MonitorStatus {
|
|||
|
||||
/// 钱包生成状态枚举
|
||||
enum WalletCreationStatus {
|
||||
unknown, // 未知
|
||||
unknown, // 未知(初始状态)
|
||||
creating, // 创建中(显示"创建账号审核中...")
|
||||
ready, // 已就绪
|
||||
failed, // 失败
|
||||
}
|
||||
|
||||
/// 监控页面 - 显示监控状态和控制
|
||||
|
|
@ -45,7 +44,6 @@ class _MiningPageState extends ConsumerState<MiningPage> {
|
|||
|
||||
// 钱包生成状态
|
||||
WalletCreationStatus _walletStatus = WalletCreationStatus.unknown;
|
||||
String? _walletError;
|
||||
Timer? _walletPollingTimer;
|
||||
|
||||
@override
|
||||
|
|
@ -170,19 +168,13 @@ class _MiningPageState extends ConsumerState<MiningPage> {
|
|||
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 {
|
||||
// 非 ready 状态(包括 failed、creating)都继续轮询
|
||||
_walletStatus = WalletCreationStatus.creating;
|
||||
_walletError = null;
|
||||
debugPrint('[MiningPage] 钱包创建中...');
|
||||
debugPrint('[MiningPage] 钱包创建中,继续轮询...');
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
|
|
@ -191,34 +183,6 @@ class _MiningPageState extends ConsumerState<MiningPage> {
|
|||
}
|
||||
}
|
||||
|
||||
/// 手动重试钱包生成
|
||||
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(
|
||||
|
|
@ -433,43 +397,6 @@ class _MiningPageState extends ConsumerState<MiningPage> {
|
|||
),
|
||||
],
|
||||
)
|
||||
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 if (_walletStatus == WalletCreationStatus.ready)
|
||||
Text(
|
||||
'序列号$_serialNumber',
|
||||
|
|
|
|||
|
|
@ -4079,52 +4079,7 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
|
|||
);
|
||||
}
|
||||
|
||||
// 如果钱包生成失败,显示失败状态和重试按钮
|
||||
if (walletStatus.isFailed) {
|
||||
return Row(
|
||||
children: [
|
||||
const Icon(
|
||||
Icons.error_outline,
|
||||
size: 16,
|
||||
color: Color(0xFFD32F2F),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
'钱包生成失败',
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
fontFamily: 'Inter',
|
||||
height: 1.5,
|
||||
color: Color(0xFFD32F2F),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
GestureDetector(
|
||||
onTap: () async {
|
||||
await ref.read(walletStatusProvider.notifier).retryWalletGeneration();
|
||||
},
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFD4AF37),
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
),
|
||||
child: const Text(
|
||||
'重试',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontFamily: 'Inter',
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
// 默认情况(unknown状态)显示"创建账号审核中..."
|
||||
// 默认情况(unknown/generating状态)显示"创建账号审核中..."
|
||||
return Row(
|
||||
children: [
|
||||
const SizedBox(
|
||||
|
|
|
|||
Loading…
Reference in New Issue