diff --git a/backend/services/wallet-service/src/application/services/wallet-application.service.ts b/backend/services/wallet-service/src/application/services/wallet-application.service.ts index 28fa2e9c..b7d6e03f 100644 --- a/backend/services/wallet-service/src/application/services/wallet-application.service.ts +++ b/backend/services/wallet-service/src/application/services/wallet-application.service.ts @@ -2697,7 +2697,11 @@ export class WalletApplicationService { const amount = Number(entry.amount); // 只计算非临时性流水的收支统计 - if (!excludeFromStats.has(entry.entryType)) { + // 兼容历史数据:老的批量转换记录 entry_type 仍为 REWARD_TO_SETTLEABLE, + // 通过 memo 中 "pending rewards settled" 识别并排除 + const isExcluded = excludeFromStats.has(entry.entryType) || + (entry.entryType === 'REWARD_TO_SETTLEABLE' && entry.memo?.includes('pending rewards settled')); + if (!isExcluded) { if (amount > 0) { totalIncome += amount; } else { @@ -2791,8 +2795,10 @@ export class WalletApplicationService { const amount = Number(entry.amount); const existing = dailyMap.get(dateStr) || { income: 0, expense: 0, count: 0 }; - // 只计算非临时性流水的收支统计 - if (!excludeFromStats.has(entry.entryType)) { + // 只计算非临时性流水的收支统计(兼容历史批量转换数据) + const isExcluded = excludeFromStats.has(entry.entryType) || + (entry.entryType === 'REWARD_TO_SETTLEABLE' && entry.memo?.includes('pending rewards settled')); + if (!isExcluded) { if (amount > 0) { existing.income += amount; periodIncome += amount; diff --git a/frontend/mobile-app/lib/core/services/wallet_service.dart b/frontend/mobile-app/lib/core/services/wallet_service.dart index 51091980..039e5e2d 100644 --- a/frontend/mobile-app/lib/core/services/wallet_service.dart +++ b/frontend/mobile-app/lib/core/services/wallet_service.dart @@ -1522,6 +1522,13 @@ class LedgerEntry { return baseName; } + /// 从 memo 中提取来源用户ID(格式如:"来源: D26022600016") + String? get sourceAccountFromMemo { + if (memo == null) return null; + final match = RegExp(r'来源:\s*(D\d+)').firstMatch(memo!); + return match?.group(1); + } + /// 是否为收入 bool get isIncome => amount > 0; } diff --git a/frontend/mobile-app/lib/features/trading/presentation/pages/ledger_detail_page.dart b/frontend/mobile-app/lib/features/trading/presentation/pages/ledger_detail_page.dart index c185b033..2cd881c1 100644 --- a/frontend/mobile-app/lib/features/trading/presentation/pages/ledger_detail_page.dart +++ b/frontend/mobile-app/lib/features/trading/presentation/pages/ledger_detail_page.dart @@ -1002,6 +1002,16 @@ class _LedgerDetailPageState extends ConsumerState color: Color(0xFF5D4037), ), ), + if (entry.sourceAccountFromMemo != null) ...[ + const SizedBox(height: 2), + Text( + '来自 ${entry.sourceAccountFromMemo}', + style: const TextStyle( + fontSize: 11, + color: Color(0xFFD4AF37), + ), + ), + ], const SizedBox(height: 4), Text( _formatDate(entry.createdAt), @@ -1715,11 +1725,15 @@ class _RewardDetailSheet extends StatelessWidget { ), _buildDetailRow('权益类型', entry.displayName), _buildDetailRow('流水类型', entry.entryTypeName), + if (entry.sourceAccountFromMemo != null) + _buildDetailRow('来源用户', entry.sourceAccountFromMemo!), if (entry.balanceAfter != null) _buildDetailRow('入账后余额', '${_formatAmount(entry.balanceAfter!)} 绿积分'), _buildDetailRow('入账时间', _formatDateTime(entry.createdAt)), if (entry.refOrderId != null && entry.refOrderId!.isNotEmpty) _buildDetailRow('关联订单', entry.refOrderId!), + if (entry.memo != null && entry.memo!.isNotEmpty) + _buildDetailRow('备注', entry.memo!), ], ), ),