fix(frontend): 修复资产页面1秒实时刷新问题

- 使用 mining-service 的 perSecondEarning 替代 assetGrowthPerSecond
- 添加 _timerStarted 标志防止定时器重复启动
- 修复页面进入时定时器可能未启动的问题
- 下拉刷新时同步刷新 shareAccountProvider
- 正确显示每秒增长值

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
hailin 2026-01-17 22:42:23 -08:00
parent 5c633b9979
commit d8dd38e91b
1 changed files with 45 additions and 18 deletions

View File

@ -7,6 +7,7 @@ import '../../../core/utils/format_utils.dart';
import '../../../domain/entities/asset_display.dart'; import '../../../domain/entities/asset_display.dart';
import '../../providers/user_providers.dart'; import '../../providers/user_providers.dart';
import '../../providers/asset_providers.dart'; import '../../providers/asset_providers.dart';
import '../../providers/mining_providers.dart';
import '../../widgets/shimmer_loading.dart'; import '../../widgets/shimmer_loading.dart';
class AssetPage extends ConsumerStatefulWidget { class AssetPage extends ConsumerStatefulWidget {
@ -36,6 +37,7 @@ class _AssetPageState extends ConsumerState<AssetPage> {
double _initialShareBalance = 0; double _initialShareBalance = 0;
double _growthPerSecond = 0; double _growthPerSecond = 0;
String? _lastAccountSequence; String? _lastAccountSequence;
bool _timerStarted = false;
@override @override
void dispose() { void dispose() {
@ -43,13 +45,18 @@ class _AssetPageState extends ConsumerState<AssetPage> {
super.dispose(); super.dispose();
} }
/// /// 使
void _startTimer(AssetDisplay asset) { void _startTimerWithGrowth(AssetDisplay asset, String perSecondEarning) {
//
if (_timerStarted && _refreshTimer != null) return;
_refreshTimer?.cancel(); _refreshTimer?.cancel();
_elapsedSeconds = 0; _elapsedSeconds = 0;
_initialDisplayValue = double.tryParse(asset.displayAssetValue) ?? 0; _initialDisplayValue = double.tryParse(asset.displayAssetValue) ?? 0;
_initialShareBalance = double.tryParse(asset.shareBalance) ?? 0; _initialShareBalance = double.tryParse(asset.shareBalance) ?? 0;
_growthPerSecond = AssetValueCalculator.calculateGrowthPerSecond(asset.assetGrowthPerSecond); // 使 mining-service
_growthPerSecond = double.tryParse(perSecondEarning) ?? 0;
_timerStarted = true;
_refreshTimer = Timer.periodic(const Duration(seconds: 1), (timer) { _refreshTimer = Timer.periodic(const Duration(seconds: 1), (timer) {
if (mounted) { if (mounted) {
@ -63,7 +70,9 @@ class _AssetPageState extends ConsumerState<AssetPage> {
/// ///
void _resetTimer() { void _resetTimer() {
_refreshTimer?.cancel(); _refreshTimer?.cancel();
_refreshTimer = null;
_elapsedSeconds = 0; _elapsedSeconds = 0;
_timerStarted = false;
} }
/// ///
@ -84,18 +93,37 @@ class _AssetPageState extends ConsumerState<AssetPage> {
final accountSequence = user.accountSequence ?? ''; final accountSequence = user.accountSequence ?? '';
// 使 public API JWT token // 使 public API JWT token
final assetAsync = ref.watch(accountAssetProvider(accountSequence)); final assetAsync = ref.watch(accountAssetProvider(accountSequence));
// mining-service
final shareAccountAsync = ref.watch(shareAccountProvider(accountSequence));
// //
final isLoading = assetAsync.isLoading || accountSequence.isEmpty; final isLoading = assetAsync.isLoading || accountSequence.isEmpty;
final asset = assetAsync.valueOrNull; final asset = assetAsync.valueOrNull;
final shareAccount = shareAccountAsync.valueOrNull;
// 使 mining-service
final perSecondEarning = shareAccount?.perSecondEarning ?? '0';
final hasValidGrowth = (double.tryParse(perSecondEarning) ?? 0) > 0;
// //
if (asset != null && (_lastAsset == null || _lastAccountSequence != accountSequence)) { if (asset != null && hasValidGrowth) {
_lastAccountSequence = accountSequence; //
_lastAsset = asset; if (_lastAccountSequence != accountSequence) {
WidgetsBinding.instance.addPostFrameCallback((_) { _lastAccountSequence = accountSequence;
_startTimer(asset); _lastAsset = asset;
}); _resetTimer();
WidgetsBinding.instance.addPostFrameCallback((_) {
if (mounted) _startTimerWithGrowth(asset, perSecondEarning);
});
} else if (!_timerStarted) {
//
_lastAsset = asset;
WidgetsBinding.instance.addPostFrameCallback((_) {
if (mounted) _startTimerWithGrowth(asset, perSecondEarning);
});
} else {
_lastAsset = asset;
}
} else if (asset != null) { } else if (asset != null) {
_lastAsset = asset; _lastAsset = asset;
} }
@ -111,6 +139,7 @@ class _AssetPageState extends ConsumerState<AssetPage> {
_resetTimer(); _resetTimer();
_lastAsset = null; _lastAsset = null;
ref.invalidate(accountAssetProvider(accountSequence)); ref.invalidate(accountAssetProvider(accountSequence));
ref.invalidate(shareAccountProvider(accountSequence));
}, },
child: SingleChildScrollView( child: SingleChildScrollView(
physics: const AlwaysScrollableScrollPhysics(), physics: const AlwaysScrollableScrollPhysics(),
@ -127,13 +156,13 @@ class _AssetPageState extends ConsumerState<AssetPage> {
children: [ children: [
const SizedBox(height: 8), const SizedBox(height: 8),
// - // -
_buildTotalAssetCard(asset, isLoading, _currentDisplayValue), _buildTotalAssetCard(asset, isLoading, _currentDisplayValue, perSecondEarning),
const SizedBox(height: 24), const SizedBox(height: 24),
// //
_buildQuickActions(context), _buildQuickActions(context),
const SizedBox(height: 24), const SizedBox(height: 24),
// - // -
_buildAssetList(asset, isLoading, _currentShareBalance), _buildAssetList(asset, isLoading, _currentShareBalance, perSecondEarning),
const SizedBox(height: 24), const SizedBox(height: 24),
// //
_buildEarningsCard(asset, isLoading), _buildEarningsCard(asset, isLoading),
@ -172,11 +201,9 @@ class _AssetPageState extends ConsumerState<AssetPage> {
); );
} }
Widget _buildTotalAssetCard(AssetDisplay? asset, bool isLoading, double currentDisplayValue) { Widget _buildTotalAssetCard(AssetDisplay? asset, bool isLoading, double currentDisplayValue, String perSecondEarning) {
// // 使 mining-service
final growthPerSecond = asset != null final growthPerSecond = double.tryParse(perSecondEarning) ?? 0.0;
? AssetValueCalculator.calculateGrowthPerSecond(asset.assetGrowthPerSecond)
: 0.0;
// 使 // 使
final displayValue = asset != null && currentDisplayValue > 0 final displayValue = asset != null && currentDisplayValue > 0
@ -372,7 +399,7 @@ class _AssetPageState extends ConsumerState<AssetPage> {
); );
} }
Widget _buildAssetList(AssetDisplay? asset, bool isLoading, double currentShareBalance) { Widget _buildAssetList(AssetDisplay? asset, bool isLoading, double currentShareBalance, String perSecondEarning) {
// 使 // 使
final shareBalance = asset != null && currentShareBalance > 0 final shareBalance = asset != null && currentShareBalance > 0
? currentShareBalance ? currentShareBalance
@ -395,7 +422,7 @@ class _AssetPageState extends ConsumerState<AssetPage> {
? '¥${formatAmount((shareBalance * currentPrice).toString())}' ? '¥${formatAmount((shareBalance * currentPrice).toString())}'
: null, : null,
tag: asset != null ? '含倍数资产: ${formatCompact(multipliedAsset.toString())}' : null, tag: asset != null ? '含倍数资产: ${formatCompact(multipliedAsset.toString())}' : null,
growthText: asset != null ? '每秒 +${formatDecimal(asset.assetGrowthPerSecond, 8)}' : null, growthText: asset != null ? '每秒 +${formatDecimal(perSecondEarning, 8)}' : null,
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
// //