refactor(reward): 前端直接从 reward-service 查询奖励数据
移除 reward-service 和 wallet-service 之间的 Kafka 同步机制: - 屏蔽 reward-service 的 outbox 发布逻辑 - 屏蔽 wallet-service 的 RewardEventConsumerController 订阅 Flutter 前端改为直接调用 reward-service API: - 新增 RewardService 调用 /rewards/summary - profile_page 改用 rewardService.getMyRewardSummary() 这样简化了架构,数据从源头获取,避免同步问题。 🤖 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
a1ca490ff4
commit
7d9837fc22
|
|
@ -78,7 +78,8 @@ export class RewardApplicationService {
|
|||
}
|
||||
|
||||
// 4. 写入 Outbox 发送到 wallet-service 同步汇总数据
|
||||
await this.publishSummaryUpdatesToOutbox(updatedSummaries);
|
||||
// [已屏蔽] 前端直接从 reward-service 查询,不再同步到 wallet-service
|
||||
// await this.publishSummaryUpdatesToOutbox(updatedSummaries);
|
||||
|
||||
// 5. 发布领域事件
|
||||
for (const reward of rewards) {
|
||||
|
|
@ -123,9 +124,10 @@ export class RewardApplicationService {
|
|||
await this.rewardSummaryRepository.save(summary);
|
||||
|
||||
// 写入 Outbox 同步到 wallet-service
|
||||
if (claimedCount > 0) {
|
||||
await this.publishSummaryUpdatesToOutbox([summary]);
|
||||
}
|
||||
// [已屏蔽] 前端直接从 reward-service 查询,不再同步到 wallet-service
|
||||
// if (claimedCount > 0) {
|
||||
// await this.publishSummaryUpdatesToOutbox([summary]);
|
||||
// }
|
||||
|
||||
this.logger.log(`Claimed ${claimedCount} rewards for user ${userId}, total ${totalUsdtClaimed} USDT`);
|
||||
|
||||
|
|
@ -198,7 +200,8 @@ export class RewardApplicationService {
|
|||
await this.rewardSummaryRepository.save(summary);
|
||||
|
||||
// 写入 Outbox 同步到 wallet-service
|
||||
await this.publishSummaryUpdatesToOutbox([summary]);
|
||||
// [已屏蔽] 前端直接从 reward-service 查询,不再同步到 wallet-service
|
||||
// await this.publishSummaryUpdatesToOutbox([summary]);
|
||||
}
|
||||
|
||||
this.logger.log(`Settled ${totalUsdt} USDT for accountSequence ${params.accountSequence}`);
|
||||
|
|
@ -269,9 +272,10 @@ export class RewardApplicationService {
|
|||
}
|
||||
|
||||
// 写入 Outbox 同步到 wallet-service
|
||||
if (updatedSummaries.length > 0) {
|
||||
await this.publishSummaryUpdatesToOutbox(updatedSummaries);
|
||||
}
|
||||
// [已屏蔽] 前端直接从 reward-service 查询,不再同步到 wallet-service
|
||||
// if (updatedSummaries.length > 0) {
|
||||
// await this.publishSummaryUpdatesToOutbox(updatedSummaries);
|
||||
// }
|
||||
|
||||
this.logger.log(`Expired ${expiredRewards.length} rewards, total ${totalUsdtExpired} USDT`);
|
||||
|
||||
|
|
|
|||
|
|
@ -3,8 +3,9 @@ import { ConfigModule, ConfigService } from '@nestjs/config';
|
|||
import { ClientsModule, Transport } from '@nestjs/microservices';
|
||||
import { EventPublisherService } from './event-publisher.service';
|
||||
import { DepositEventConsumerService } from './deposit-event-consumer.service';
|
||||
import { RewardEventConsumerController } from './reward-event-consumer.controller';
|
||||
import { EventAckPublisher } from './event-ack.publisher';
|
||||
// [已屏蔽] 前端直接从 reward-service 查询,不再订阅 reward-service 消息
|
||||
// import { RewardEventConsumerController } from './reward-event-consumer.controller';
|
||||
// import { EventAckPublisher } from './event-ack.publisher';
|
||||
import { PrismaService } from '../persistence/prisma/prisma.service';
|
||||
|
||||
@Global()
|
||||
|
|
@ -30,8 +31,10 @@ import { PrismaService } from '../persistence/prisma/prisma.service';
|
|||
},
|
||||
]),
|
||||
],
|
||||
controllers: [RewardEventConsumerController],
|
||||
providers: [PrismaService, EventPublisherService, DepositEventConsumerService, EventAckPublisher],
|
||||
exports: [EventPublisherService, DepositEventConsumerService, EventAckPublisher, ClientsModule],
|
||||
// [已屏蔽] 前端直接从 reward-service 查询,不再订阅 reward-service 消息
|
||||
// controllers: [RewardEventConsumerController],
|
||||
controllers: [],
|
||||
providers: [PrismaService, EventPublisherService, DepositEventConsumerService],
|
||||
exports: [EventPublisherService, DepositEventConsumerService, ClientsModule],
|
||||
})
|
||||
export class KafkaModule {}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import '../services/authorization_service.dart';
|
|||
import '../services/deposit_service.dart';
|
||||
import '../services/wallet_service.dart';
|
||||
import '../services/planting_service.dart';
|
||||
import '../services/reward_service.dart';
|
||||
|
||||
// Storage Providers
|
||||
final secureStorageProvider = Provider<SecureStorage>((ref) {
|
||||
|
|
@ -65,6 +66,12 @@ final plantingServiceProvider = Provider<PlantingService>((ref) {
|
|||
return PlantingService(apiClient: apiClient);
|
||||
});
|
||||
|
||||
// Reward Service Provider (直接调用 reward-service)
|
||||
final rewardServiceProvider = Provider<RewardService>((ref) {
|
||||
final apiClient = ref.watch(apiClientProvider);
|
||||
return RewardService(apiClient: apiClient);
|
||||
});
|
||||
|
||||
// Override provider with initialized instance
|
||||
ProviderContainer createProviderContainer(LocalStorage localStorage) {
|
||||
return ProviderContainer(
|
||||
|
|
|
|||
|
|
@ -0,0 +1,110 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
import '../network/api_client.dart';
|
||||
|
||||
/// 奖励汇总信息 (从 reward-service 获取)
|
||||
class RewardSummary {
|
||||
final double pendingUsdt;
|
||||
final double pendingHashpower;
|
||||
final DateTime? pendingExpireAt;
|
||||
final int pendingRemainingTimeMs;
|
||||
final double settleableUsdt;
|
||||
final double settleableHashpower;
|
||||
final double settledTotalUsdt;
|
||||
final double settledTotalHashpower;
|
||||
final double expiredTotalUsdt;
|
||||
final double expiredTotalHashpower;
|
||||
|
||||
RewardSummary({
|
||||
required this.pendingUsdt,
|
||||
required this.pendingHashpower,
|
||||
this.pendingExpireAt,
|
||||
required this.pendingRemainingTimeMs,
|
||||
required this.settleableUsdt,
|
||||
required this.settleableHashpower,
|
||||
required this.settledTotalUsdt,
|
||||
required this.settledTotalHashpower,
|
||||
required this.expiredTotalUsdt,
|
||||
required this.expiredTotalHashpower,
|
||||
});
|
||||
|
||||
factory RewardSummary.fromJson(Map<String, dynamic> json) {
|
||||
return RewardSummary(
|
||||
pendingUsdt: (json['pendingUsdt'] ?? 0).toDouble(),
|
||||
pendingHashpower: (json['pendingHashpower'] ?? 0).toDouble(),
|
||||
pendingExpireAt: json['pendingExpireAt'] != null
|
||||
? DateTime.tryParse(json['pendingExpireAt'])
|
||||
: null,
|
||||
pendingRemainingTimeMs: (json['pendingRemainingTimeMs'] ?? 0).toInt(),
|
||||
settleableUsdt: (json['settleableUsdt'] ?? 0).toDouble(),
|
||||
settleableHashpower: (json['settleableHashpower'] ?? 0).toDouble(),
|
||||
settledTotalUsdt: (json['settledTotalUsdt'] ?? 0).toDouble(),
|
||||
settledTotalHashpower: (json['settledTotalHashpower'] ?? 0).toDouble(),
|
||||
expiredTotalUsdt: (json['expiredTotalUsdt'] ?? 0).toDouble(),
|
||||
expiredTotalHashpower: (json['expiredTotalHashpower'] ?? 0).toDouble(),
|
||||
);
|
||||
}
|
||||
|
||||
/// 计算剩余秒数
|
||||
int get pendingRemainingSeconds => (pendingRemainingTimeMs / 1000).round();
|
||||
}
|
||||
|
||||
/// 奖励服务
|
||||
///
|
||||
/// 直接调用 reward-service 的 API 获取奖励数据
|
||||
/// 不再通过 wallet-service 中转
|
||||
class RewardService {
|
||||
final ApiClient _apiClient;
|
||||
|
||||
RewardService({required ApiClient apiClient}) : _apiClient = apiClient;
|
||||
|
||||
/// 获取我的奖励汇总
|
||||
///
|
||||
/// 调用 GET /rewards/summary (reward-service)
|
||||
Future<RewardSummary> getMyRewardSummary() async {
|
||||
try {
|
||||
debugPrint('[RewardService] ========== 获取奖励汇总 ==========');
|
||||
debugPrint('[RewardService] 请求: GET /rewards/summary');
|
||||
|
||||
final response = await _apiClient.get('/rewards/summary');
|
||||
|
||||
debugPrint('[RewardService] 响应状态码: ${response.statusCode}');
|
||||
debugPrint('[RewardService] 响应数据类型: ${response.data.runtimeType}');
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final responseData = response.data as Map<String, dynamic>;
|
||||
debugPrint('[RewardService] 原始响应数据: $responseData');
|
||||
|
||||
// API 返回格式: { success: true, data: {...}, timestamp: "..." }
|
||||
// 需要解包内层的 data 字段
|
||||
final data = responseData['data'] as Map<String, dynamic>? ?? responseData;
|
||||
debugPrint('[RewardService] 解包后数据: $data');
|
||||
|
||||
final summary = RewardSummary.fromJson(data);
|
||||
debugPrint('[RewardService] -------- 解析结果 --------');
|
||||
debugPrint('[RewardService] pendingUsdt: ${summary.pendingUsdt}');
|
||||
debugPrint('[RewardService] pendingHashpower: ${summary.pendingHashpower}');
|
||||
debugPrint('[RewardService] pendingExpireAt: ${summary.pendingExpireAt}');
|
||||
debugPrint('[RewardService] pendingRemainingTimeMs: ${summary.pendingRemainingTimeMs}');
|
||||
debugPrint('[RewardService] pendingRemainingSeconds: ${summary.pendingRemainingSeconds}');
|
||||
debugPrint('[RewardService] settleableUsdt: ${summary.settleableUsdt}');
|
||||
debugPrint('[RewardService] settleableHashpower: ${summary.settleableHashpower}');
|
||||
debugPrint('[RewardService] settledTotalUsdt: ${summary.settledTotalUsdt}');
|
||||
debugPrint('[RewardService] settledTotalHashpower: ${summary.settledTotalHashpower}');
|
||||
debugPrint('[RewardService] expiredTotalUsdt: ${summary.expiredTotalUsdt}');
|
||||
debugPrint('[RewardService] expiredTotalHashpower: ${summary.expiredTotalHashpower}');
|
||||
debugPrint('[RewardService] ================================');
|
||||
|
||||
return summary;
|
||||
}
|
||||
|
||||
debugPrint('[RewardService] 请求失败,状态码: ${response.statusCode}');
|
||||
debugPrint('[RewardService] 响应内容: ${response.data}');
|
||||
throw Exception('获取奖励汇总失败: ${response.statusCode}');
|
||||
} catch (e, stackTrace) {
|
||||
debugPrint('[RewardService] !!!!!!!!!! 获取奖励汇总异常 !!!!!!!!!!');
|
||||
debugPrint('[RewardService] 错误: $e');
|
||||
debugPrint('[RewardService] 堆栈: $stackTrace');
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -58,7 +58,7 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
|
|||
int _communityMonthlyTarget = 10; // 月度考核目标
|
||||
int _communityMonthIndex = 0; // 当前考核月份
|
||||
|
||||
// 收益数据(从 wallet-service 获取)
|
||||
// 收益数据(从 reward-service 直接获取)
|
||||
double _pendingUsdt = 0.0;
|
||||
double _pendingPower = 0.0;
|
||||
double _settleableUsdt = 0.0;
|
||||
|
|
@ -344,41 +344,41 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
|
|||
}
|
||||
}
|
||||
|
||||
/// 加载钱包和收益数据 (from wallet-service)
|
||||
/// 加载收益数据 (直接从 reward-service 获取)
|
||||
Future<void> _loadWalletData() async {
|
||||
try {
|
||||
debugPrint('[ProfilePage] ========== 加载钱包数据 ==========');
|
||||
debugPrint('[ProfilePage] ========== 加载收益数据 ==========');
|
||||
debugPrint('[ProfilePage] mounted: $mounted');
|
||||
setState(() {
|
||||
_isLoadingWallet = true;
|
||||
_walletError = null;
|
||||
});
|
||||
|
||||
debugPrint('[ProfilePage] 获取 walletServiceProvider...');
|
||||
final walletService = ref.read(walletServiceProvider);
|
||||
debugPrint('[ProfilePage] 调用 getMyWallet()...');
|
||||
final wallet = await walletService.getMyWallet();
|
||||
debugPrint('[ProfilePage] 获取 rewardServiceProvider...');
|
||||
final rewardService = ref.read(rewardServiceProvider);
|
||||
debugPrint('[ProfilePage] 调用 getMyRewardSummary()...');
|
||||
final summary = await rewardService.getMyRewardSummary();
|
||||
|
||||
debugPrint('[ProfilePage] -------- 钱包数据加载成功 --------');
|
||||
debugPrint('[ProfilePage] 待领取 USDT: ${wallet.rewards.pendingUsdt}');
|
||||
debugPrint('[ProfilePage] 待领取 算力: ${wallet.rewards.pendingHashpower}');
|
||||
debugPrint('[ProfilePage] 可结算 USDT: ${wallet.rewards.settleableUsdt}');
|
||||
debugPrint('[ProfilePage] 已结算 USDT: ${wallet.rewards.settledTotalUsdt}');
|
||||
debugPrint('[ProfilePage] 已过期 USDT: ${wallet.rewards.expiredTotalUsdt}');
|
||||
debugPrint('[ProfilePage] 已过期 算力: ${wallet.rewards.expiredTotalHashpower}');
|
||||
debugPrint('[ProfilePage] 过期时间: ${wallet.rewards.pendingExpireAt}');
|
||||
debugPrint('[ProfilePage] 剩余秒数: ${wallet.rewards.pendingRemainingSeconds}');
|
||||
debugPrint('[ProfilePage] -------- 收益数据加载成功 --------');
|
||||
debugPrint('[ProfilePage] 待领取 USDT: ${summary.pendingUsdt}');
|
||||
debugPrint('[ProfilePage] 待领取 算力: ${summary.pendingHashpower}');
|
||||
debugPrint('[ProfilePage] 可结算 USDT: ${summary.settleableUsdt}');
|
||||
debugPrint('[ProfilePage] 已结算 USDT: ${summary.settledTotalUsdt}');
|
||||
debugPrint('[ProfilePage] 已过期 USDT: ${summary.expiredTotalUsdt}');
|
||||
debugPrint('[ProfilePage] 已过期 算力: ${summary.expiredTotalHashpower}');
|
||||
debugPrint('[ProfilePage] 过期时间: ${summary.pendingExpireAt}');
|
||||
debugPrint('[ProfilePage] 剩余秒数: ${summary.pendingRemainingSeconds}');
|
||||
|
||||
if (mounted) {
|
||||
debugPrint('[ProfilePage] 更新 UI 状态...');
|
||||
setState(() {
|
||||
_pendingUsdt = wallet.rewards.pendingUsdt;
|
||||
_pendingPower = wallet.rewards.pendingHashpower;
|
||||
_settleableUsdt = wallet.rewards.settleableUsdt;
|
||||
_settledUsdt = wallet.rewards.settledTotalUsdt;
|
||||
_expiredUsdt = wallet.rewards.expiredTotalUsdt;
|
||||
_expiredPower = wallet.rewards.expiredTotalHashpower;
|
||||
_remainingSeconds = wallet.rewards.pendingRemainingSeconds;
|
||||
_pendingUsdt = summary.pendingUsdt;
|
||||
_pendingPower = summary.pendingHashpower;
|
||||
_settleableUsdt = summary.settleableUsdt;
|
||||
_settledUsdt = summary.settledTotalUsdt;
|
||||
_expiredUsdt = summary.expiredTotalUsdt;
|
||||
_expiredPower = summary.expiredTotalHashpower;
|
||||
_remainingSeconds = summary.pendingRemainingSeconds;
|
||||
_isLoadingWallet = false;
|
||||
});
|
||||
|
||||
|
|
@ -398,7 +398,7 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
|
|||
}
|
||||
debugPrint('[ProfilePage] ================================');
|
||||
} catch (e, stackTrace) {
|
||||
debugPrint('[ProfilePage] !!!!!!!!!! 加载钱包数据失败 !!!!!!!!!!');
|
||||
debugPrint('[ProfilePage] !!!!!!!!!! 加载收益数据失败 !!!!!!!!!!');
|
||||
debugPrint('[ProfilePage] 错误类型: ${e.runtimeType}');
|
||||
debugPrint('[ProfilePage] 错误信息: $e');
|
||||
debugPrint('[ProfilePage] 堆栈跟踪:');
|
||||
|
|
|
|||
Loading…
Reference in New Issue