feat(reward): 可结算列表改为从 reward-service 读取

将前端可结算奖励列表的数据源从 wallet-service 改为 reward-service:
- 后端:在 reward-service 添加 GET /rewards/settleable 接口
- 前端:修改 getSettleableRewards() 调用 /rewards/settleable
- 前端:更新 SettleableRewardItem 字段映射 (rightType, claimedAt, sourceOrderNo, memo)

解决权益收益(社区权益、市区域权益)无法在可结算列表显示的问题。
遵循单一数据源原则,reward-service 是奖励的权威数据源。

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
hailin 2025-12-17 06:55:41 -08:00
parent 834a1fc0b0
commit 36074948d7
4 changed files with 57 additions and 26 deletions

View File

@ -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);
}
}

View File

@ -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
*/

View File

@ -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<String, dynamic> 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<List<SettleableRewardItem>> 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] ================================');

View File

@ -2210,8 +2210,9 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
///
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<String> amountParts = [];
@ -2242,7 +2243,7 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
item.allocationTypeName,
item.rightTypeName,
style: const TextStyle(
fontSize: 14,
fontFamily: 'Inter',
@ -2289,8 +2290,9 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
///
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<String> amountParts = [];
@ -2323,7 +2325,7 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
item.allocationTypeName,
item.rightTypeName,
style: const TextStyle(
fontSize: 14,
fontFamily: 'Inter',
@ -2373,7 +2375,7 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
item.allocationTypeName,
item.rightTypeName,
style: const TextStyle(
fontSize: 13,
fontFamily: 'Inter',
@ -2552,7 +2554,7 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
item.allocationTypeName,
item.rightTypeName,
style: const TextStyle(
fontSize: 14,
fontFamily: 'Inter',
@ -2633,7 +2635,7 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
item.allocationTypeName,
item.rightTypeName,
style: const TextStyle(
fontSize: 14,
fontFamily: 'Inter',
@ -2683,7 +2685,7 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
item.allocationTypeName,
item.rightTypeName,
style: const TextStyle(
fontSize: 13,
fontFamily: 'Inter',