diff --git a/backend/services/reward-service/src/api/controllers/reward.controller.ts b/backend/services/reward-service/src/api/controllers/reward.controller.ts index 9874ada1..5ebb336a 100644 --- a/backend/services/reward-service/src/api/controllers/reward.controller.ts +++ b/backend/services/reward-service/src/api/controllers/reward.controller.ts @@ -58,4 +58,12 @@ export class RewardController { const accountSequence = req.user.accountSequence; return this.rewardService.getPendingRewards(accountSequence); } + + @Get('settleable') + @ApiOperation({ summary: '获取可结算奖励列表' }) + @ApiResponse({ status: 200, description: '成功' }) + async getSettleable(@Request() req) { + const accountSequence = req.user.accountSequence; + return this.rewardService.getSettleableRewards(accountSequence); + } } diff --git a/backend/services/reward-service/src/application/services/reward-application.service.ts b/backend/services/reward-service/src/application/services/reward-application.service.ts index cb8bf89c..9375ca44 100644 --- a/backend/services/reward-service/src/application/services/reward-application.service.ts +++ b/backend/services/reward-service/src/application/services/reward-application.service.ts @@ -444,6 +444,24 @@ export class RewardApplicationService { })); } + /** + * 获取可结算奖励列表 + */ + async getSettleableRewards(accountSequence: string) { + const rewards = await this.rewardLedgerEntryRepository.findSettleableByAccountSequence(accountSequence); + + return rewards.map(r => ({ + id: r.id?.toString(), + rightType: r.rewardSource.rightType, + usdtAmount: r.usdtAmount.amount, + hashpowerAmount: r.hashpowerAmount.value, + createdAt: r.createdAt, + claimedAt: r.claimedAt, + sourceOrderNo: r.sourceOrderNo, + memo: r.memo, + })); + } + /** * 发布汇总更新到 Outbox(同步到 wallet-service) */ diff --git a/frontend/mobile-app/lib/core/services/reward_service.dart b/frontend/mobile-app/lib/core/services/reward_service.dart index 03a659c6..8c7698bb 100644 --- a/frontend/mobile-app/lib/core/services/reward_service.dart +++ b/frontend/mobile-app/lib/core/services/reward_service.dart @@ -63,40 +63,43 @@ class PendingRewardItem { String get rightTypeName => getAllocationTypeName(rightType); } -/// 可结算奖励条目 (从 GET /wallet/settleable-rewards 获取) +/// 可结算奖励条目 (从 GET /rewards/settleable 获取) class SettleableRewardItem { final String id; - final String allocationType; + final String rightType; final double usdtAmount; final double hashpowerAmount; final DateTime createdAt; - final DateTime settledAt; - final String sourceOrderId; + final DateTime? claimedAt; + final String sourceOrderNo; + final String memo; SettleableRewardItem({ required this.id, - required this.allocationType, + required this.rightType, required this.usdtAmount, required this.hashpowerAmount, required this.createdAt, - required this.settledAt, - required this.sourceOrderId, + this.claimedAt, + required this.sourceOrderNo, + required this.memo, }); factory SettleableRewardItem.fromJson(Map json) { return SettleableRewardItem( id: json['id']?.toString() ?? '', - allocationType: json['allocationType'] ?? '', + rightType: json['rightType'] ?? '', usdtAmount: (json['usdtAmount'] ?? 0).toDouble(), hashpowerAmount: (json['hashpowerAmount'] ?? 0).toDouble(), createdAt: DateTime.tryParse(json['createdAt'] ?? '') ?? DateTime.now(), - settledAt: DateTime.tryParse(json['settledAt'] ?? '') ?? DateTime.now(), - sourceOrderId: json['sourceOrderId'] ?? '', + claimedAt: json['claimedAt'] != null ? DateTime.tryParse(json['claimedAt']) : null, + sourceOrderNo: json['sourceOrderNo'] ?? '', + memo: json['memo'] ?? '', ); } /// 获取权益类型的中文名称 - String get allocationTypeName => getAllocationTypeName(allocationType); + String get rightTypeName => getAllocationTypeName(rightType); } /// 已过期奖励条目 (从 GET /wallet/expired-rewards 获取) @@ -297,14 +300,14 @@ class RewardService { /// 获取可结算奖励列表 /// - /// 调用 GET /wallet/settleable-rewards (wallet-service) - /// 返回所有已领取待结算的奖励条目 + /// 调用 GET /rewards/settleable (reward-service) + /// 返回所有可结算的奖励条目(包括权益收益和分享收益) Future> getSettleableRewards() async { try { debugPrint('[RewardService] ========== 获取可结算奖励列表 =========='); - debugPrint('[RewardService] 请求: GET /wallet/settleable-rewards'); + debugPrint('[RewardService] 请求: GET /rewards/settleable'); - final response = await _apiClient.get('/wallet/settleable-rewards'); + final response = await _apiClient.get('/rewards/settleable'); debugPrint('[RewardService] 响应状态码: ${response.statusCode}'); debugPrint('[RewardService] 响应数据类型: ${response.data.runtimeType}'); @@ -330,7 +333,7 @@ class RewardService { .toList(); for (var item in items) { - debugPrint('[RewardService] - ${item.allocationTypeName}: ${item.usdtAmount} USDT, ${item.hashpowerAmount} 算力'); + debugPrint('[RewardService] - ${item.rightTypeName}: ${item.usdtAmount} USDT, ${item.hashpowerAmount} 贡献值'); } debugPrint('[RewardService] ================================'); diff --git a/frontend/mobile-app/lib/features/profile/presentation/pages/profile_page.dart b/frontend/mobile-app/lib/features/profile/presentation/pages/profile_page.dart index 2d51b6f5..ab623c56 100644 --- a/frontend/mobile-app/lib/features/profile/presentation/pages/profile_page.dart +++ b/frontend/mobile-app/lib/features/profile/presentation/pages/profile_page.dart @@ -2210,8 +2210,9 @@ class _ProfilePageState extends ConsumerState { /// 构建单条可结算奖励项 Widget _buildSettleableRewardItem(SettleableRewardItem item) { - // 格式化结算时间 - final settledDate = '${item.settledAt.month}/${item.settledAt.day} ${item.settledAt.hour.toString().padLeft(2, '0')}:${item.settledAt.minute.toString().padLeft(2, '0')}'; + // 格式化时间(优先使用 claimedAt,否则使用 createdAt) + final displayDate = item.claimedAt ?? item.createdAt; + final settledDate = '${displayDate.month}/${displayDate.day} ${displayDate.hour.toString().padLeft(2, '0')}:${displayDate.minute.toString().padLeft(2, '0')}'; // 构建金额显示文本 final List amountParts = []; @@ -2242,7 +2243,7 @@ class _ProfilePageState extends ConsumerState { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( - item.allocationTypeName, + item.rightTypeName, style: const TextStyle( fontSize: 14, fontFamily: 'Inter', @@ -2289,8 +2290,9 @@ class _ProfilePageState extends ConsumerState { /// 构建堆叠卡片样式的可结算奖励项 Widget _buildStackedSettleableRewardCard(SettleableRewardItem item, bool isSelected) { - // 格式化结算时间 - final settledDate = '${item.settledAt.month}/${item.settledAt.day} ${item.settledAt.hour.toString().padLeft(2, '0')}:${item.settledAt.minute.toString().padLeft(2, '0')}'; + // 格式化时间(优先使用 claimedAt,否则使用 createdAt) + final displayDate = item.claimedAt ?? item.createdAt; + final settledDate = '${displayDate.month}/${displayDate.day} ${displayDate.hour.toString().padLeft(2, '0')}:${displayDate.minute.toString().padLeft(2, '0')}'; // 构建金额显示文本 final List amountParts = []; @@ -2323,7 +2325,7 @@ class _ProfilePageState extends ConsumerState { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( - item.allocationTypeName, + item.rightTypeName, style: const TextStyle( fontSize: 14, fontFamily: 'Inter', @@ -2373,7 +2375,7 @@ class _ProfilePageState extends ConsumerState { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( - item.allocationTypeName, + item.rightTypeName, style: const TextStyle( fontSize: 13, fontFamily: 'Inter', @@ -2552,7 +2554,7 @@ class _ProfilePageState extends ConsumerState { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( - item.allocationTypeName, + item.rightTypeName, style: const TextStyle( fontSize: 14, fontFamily: 'Inter', @@ -2633,7 +2635,7 @@ class _ProfilePageState extends ConsumerState { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( - item.allocationTypeName, + item.rightTypeName, style: const TextStyle( fontSize: 14, fontFamily: 'Inter', @@ -2683,7 +2685,7 @@ class _ProfilePageState extends ConsumerState { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( - item.allocationTypeName, + item.rightTypeName, style: const TextStyle( fontSize: 13, fontFamily: 'Inter',