fix(contribution): 使用 upsert 替代 update 避免记录不存在错误
将 addContribution 方法改为 upsert,当系统账户不存在时自动创建, 存在时增加算力余额。 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
5ec310124d
commit
1d5e3ebff2
|
|
@ -285,8 +285,6 @@ export class ContributionCalculationService {
|
|||
(sum, u) => sum.add(u.amount),
|
||||
new ContributionAmount(0),
|
||||
);
|
||||
// 确保 HEADQUARTERS 账户存在
|
||||
await this.systemAccountRepository.ensureSystemAccountsExist();
|
||||
await this.systemAccountRepository.addContribution('HEADQUARTERS', totalUnallocatedAmount);
|
||||
|
||||
// 发布 HEADQUARTERS 账户同步事件
|
||||
|
|
|
|||
|
|
@ -81,9 +81,21 @@ export class SystemAccountRepository {
|
|||
accountType: SystemAccountType,
|
||||
amount: ContributionAmount,
|
||||
): Promise<void> {
|
||||
await this.client.systemAccount.update({
|
||||
const accountNames: Record<SystemAccountType, string> = {
|
||||
OPERATION: '运营账户',
|
||||
PROVINCE: '省公司账户',
|
||||
CITY: '市公司账户',
|
||||
HEADQUARTERS: '总部账户',
|
||||
};
|
||||
|
||||
await this.client.systemAccount.upsert({
|
||||
where: { accountType },
|
||||
data: {
|
||||
create: {
|
||||
accountType,
|
||||
name: accountNames[accountType],
|
||||
contributionBalance: amount.value,
|
||||
},
|
||||
update: {
|
||||
contributionBalance: { increment: amount.value },
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -21,9 +21,8 @@ class ContributionPage extends ConsumerWidget {
|
|||
final user = ref.watch(userNotifierProvider);
|
||||
final accountSequence = user.accountSequence ?? '';
|
||||
final contributionAsync = ref.watch(contributionProvider(accountSequence));
|
||||
// 获取预估收益
|
||||
// 获取预估收益(基于用户每秒收益计算)
|
||||
final estimatedEarnings = ref.watch(estimatedEarningsProvider(accountSequence));
|
||||
final statsAsync = ref.watch(contributionStatsProvider);
|
||||
// 获取积分股池余量
|
||||
final sharePoolAsync = ref.watch(sharePoolBalanceProvider);
|
||||
|
||||
|
|
@ -32,7 +31,6 @@ class ContributionPage extends ConsumerWidget {
|
|||
final contribution = contributionAsync.valueOrNull;
|
||||
final hasError = contributionAsync.hasError;
|
||||
final error = contributionAsync.error;
|
||||
final isStatsLoading = statsAsync.isLoading;
|
||||
final isSharePoolLoading = sharePoolAsync.isLoading;
|
||||
final sharePoolBalance = sharePoolAsync.valueOrNull;
|
||||
|
||||
|
|
@ -43,7 +41,6 @@ class ContributionPage extends ConsumerWidget {
|
|||
child: RefreshIndicator(
|
||||
onRefresh: () async {
|
||||
ref.invalidate(contributionProvider(accountSequence));
|
||||
ref.invalidate(contributionStatsProvider);
|
||||
ref.invalidate(sharePoolBalanceProvider);
|
||||
},
|
||||
child: hasError && contribution == null
|
||||
|
|
@ -78,7 +75,7 @@ class ContributionPage extends ConsumerWidget {
|
|||
_buildThreeColumnStats(context, ref, contribution, isLoading),
|
||||
const SizedBox(height: 16),
|
||||
// 今日预估收益
|
||||
_buildTodayEstimateCard(context, ref, estimatedEarnings, isLoading || isStatsLoading),
|
||||
_buildTodayEstimateCard(context, ref, estimatedEarnings, isLoading),
|
||||
const SizedBox(height: 16),
|
||||
// 贡献值明细(三类汇总)
|
||||
_buildContributionDetailCard(context, ref, contribution, isLoading),
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import '../../domain/repositories/contribution_repository.dart';
|
|||
import '../../core/di/injection.dart';
|
||||
import '../../core/network/api_client.dart';
|
||||
import '../../core/network/api_endpoints.dart';
|
||||
import 'mining_providers.dart';
|
||||
|
||||
final getUserContributionUseCaseProvider = Provider<GetUserContribution>((ref) {
|
||||
return getIt<GetUserContribution>();
|
||||
|
|
@ -118,8 +119,7 @@ final contributionStatsProvider = FutureProvider<ContributionStats?>((ref) async
|
|||
});
|
||||
|
||||
/// 计算用户今日预估收益
|
||||
/// 公式: (用户贡献值 / 全网总贡献值) × 每日发放量
|
||||
/// 每日发放量 = 每秒发放量 × 86400
|
||||
/// 公式: 用户每秒收益 × 60分钟 × 60秒 × 24小时
|
||||
class EstimatedEarnings {
|
||||
final String dailyShares;
|
||||
final String perSecondShares;
|
||||
|
|
@ -138,40 +138,27 @@ class EstimatedEarnings {
|
|||
);
|
||||
}
|
||||
|
||||
/// 每日发放总量配置(积分股)
|
||||
/// 第1纪元: 100M / (2年 × 365天) ≈ 136,986 积分股/天
|
||||
const double dailyAllocationTotal = 136986.0;
|
||||
|
||||
final estimatedEarningsProvider = Provider.family<EstimatedEarnings, String>((ref, accountSequence) {
|
||||
final contributionAsync = ref.watch(contributionProvider(accountSequence));
|
||||
final statsAsync = ref.watch(contributionStatsProvider);
|
||||
// 从 mining-service 获取用户每秒收益
|
||||
final shareAccountAsync = ref.watch(shareAccountProvider(accountSequence));
|
||||
final shareAccount = shareAccountAsync.valueOrNull;
|
||||
|
||||
final contribution = contributionAsync.valueOrNull;
|
||||
final stats = statsAsync.valueOrNull;
|
||||
|
||||
if (contribution == null || stats == null) {
|
||||
if (shareAccount == null) {
|
||||
return EstimatedEarnings.zero;
|
||||
}
|
||||
|
||||
final userContribution = double.tryParse(contribution.totalContribution) ?? 0;
|
||||
final totalContribution = double.tryParse(stats.totalContribution) ?? 0;
|
||||
final perSecondEarning = double.tryParse(shareAccount.perSecondEarning) ?? 0;
|
||||
|
||||
if (totalContribution <= 0 || userContribution <= 0) {
|
||||
if (perSecondEarning <= 0) {
|
||||
return EstimatedEarnings.zero;
|
||||
}
|
||||
|
||||
// 用户占比
|
||||
final ratio = userContribution / totalContribution;
|
||||
|
||||
// 每日预估
|
||||
final dailyShares = ratio * dailyAllocationTotal;
|
||||
|
||||
// 每秒预估
|
||||
final perSecondShares = dailyShares / 86400;
|
||||
// 每日预估 = 每秒收益 × 86400(60×60×24)
|
||||
final dailyShares = perSecondEarning * 86400;
|
||||
|
||||
return EstimatedEarnings(
|
||||
dailyShares: dailyShares.toStringAsFixed(4),
|
||||
perSecondShares: perSecondShares.toStringAsFixed(8),
|
||||
perSecondShares: perSecondEarning.toStringAsFixed(8),
|
||||
isValid: true,
|
||||
);
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue