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 '../../providers/user_providers.dart';
import '../../providers/asset_providers.dart';
import '../../providers/mining_providers.dart';
import '../../widgets/shimmer_loading.dart';
class AssetPage extends ConsumerStatefulWidget {
@ -36,6 +37,7 @@ class _AssetPageState extends ConsumerState<AssetPage> {
double _initialShareBalance = 0;
double _growthPerSecond = 0;
String? _lastAccountSequence;
bool _timerStarted = false;
@override
void dispose() {
@ -43,13 +45,18 @@ class _AssetPageState extends ConsumerState<AssetPage> {
super.dispose();
}
///
void _startTimer(AssetDisplay asset) {
/// 使
void _startTimerWithGrowth(AssetDisplay asset, String perSecondEarning) {
//
if (_timerStarted && _refreshTimer != null) return;
_refreshTimer?.cancel();
_elapsedSeconds = 0;
_initialDisplayValue = double.tryParse(asset.displayAssetValue) ?? 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) {
if (mounted) {
@ -63,7 +70,9 @@ class _AssetPageState extends ConsumerState<AssetPage> {
///
void _resetTimer() {
_refreshTimer?.cancel();
_refreshTimer = null;
_elapsedSeconds = 0;
_timerStarted = false;
}
///
@ -84,18 +93,37 @@ class _AssetPageState extends ConsumerState<AssetPage> {
final accountSequence = user.accountSequence ?? '';
// 使 public API JWT token
final assetAsync = ref.watch(accountAssetProvider(accountSequence));
// mining-service
final shareAccountAsync = ref.watch(shareAccountProvider(accountSequence));
//
final isLoading = assetAsync.isLoading || accountSequence.isEmpty;
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)) {
_lastAccountSequence = accountSequence;
_lastAsset = asset;
WidgetsBinding.instance.addPostFrameCallback((_) {
_startTimer(asset);
});
if (asset != null && hasValidGrowth) {
//
if (_lastAccountSequence != accountSequence) {
_lastAccountSequence = accountSequence;
_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) {
_lastAsset = asset;
}
@ -111,6 +139,7 @@ class _AssetPageState extends ConsumerState<AssetPage> {
_resetTimer();
_lastAsset = null;
ref.invalidate(accountAssetProvider(accountSequence));
ref.invalidate(shareAccountProvider(accountSequence));
},
child: SingleChildScrollView(
physics: const AlwaysScrollableScrollPhysics(),
@ -127,13 +156,13 @@ class _AssetPageState extends ConsumerState<AssetPage> {
children: [
const SizedBox(height: 8),
// -
_buildTotalAssetCard(asset, isLoading, _currentDisplayValue),
_buildTotalAssetCard(asset, isLoading, _currentDisplayValue, perSecondEarning),
const SizedBox(height: 24),
//
_buildQuickActions(context),
const SizedBox(height: 24),
// -
_buildAssetList(asset, isLoading, _currentShareBalance),
_buildAssetList(asset, isLoading, _currentShareBalance, perSecondEarning),
const SizedBox(height: 24),
//
_buildEarningsCard(asset, isLoading),
@ -172,11 +201,9 @@ class _AssetPageState extends ConsumerState<AssetPage> {
);
}
Widget _buildTotalAssetCard(AssetDisplay? asset, bool isLoading, double currentDisplayValue) {
//
final growthPerSecond = asset != null
? AssetValueCalculator.calculateGrowthPerSecond(asset.assetGrowthPerSecond)
: 0.0;
Widget _buildTotalAssetCard(AssetDisplay? asset, bool isLoading, double currentDisplayValue, String perSecondEarning) {
// 使 mining-service
final growthPerSecond = double.tryParse(perSecondEarning) ?? 0.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
? currentShareBalance
@ -395,7 +422,7 @@ class _AssetPageState extends ConsumerState<AssetPage> {
? '¥${formatAmount((shareBalance * currentPrice).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),
//