From 4df9895863e6815def302098ef31921d08edf75e Mon Sep 17 00:00:00 2001 From: hailin Date: Tue, 6 Jan 2026 20:11:09 -0800 Subject: [PATCH] =?UTF-8?q?feat(admin-web):=20=E5=AE=8C=E5=96=84=E7=B3=BB?= =?UTF-8?q?=E7=BB=9F=E8=B4=A6=E6=88=B7=E6=8A=A5=E8=A1=A8=E6=94=B6=E7=9B=8A?= =?UTF-8?q?=E7=BB=9F=E8=AE=A1=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 分享引荐收益汇总:显示所有状态(PENDING/SETTLEABLE/SETTLED/EXPIRED)的完整数据 - 面对面结算:改为从 wallet_ledger_entries 表查询 SPECIAL_DEDUCTION 类型 - 新增按状态分组统计表格和详细分类卡片 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- .../reward-service/reward-service.client.ts | 20 ++++ .../services/reward-application.service.ts | 95 ++++++++++++++++++- .../services/wallet-application.service.ts | 30 +++--- .../SystemAccountsTab.module.scss | 16 ++++ .../SystemAccountsTab.tsx | 68 +++++++++++-- .../src/types/system-account.types.ts | 15 +++ 6 files changed, 221 insertions(+), 23 deletions(-) diff --git a/backend/services/reporting-service/src/infrastructure/external/reward-service/reward-service.client.ts b/backend/services/reporting-service/src/infrastructure/external/reward-service/reward-service.client.ts index 831e5aea..1b0facd9 100644 --- a/backend/services/reporting-service/src/infrastructure/external/reward-service/reward-service.client.ts +++ b/backend/services/reporting-service/src/infrastructure/external/reward-service/reward-service.client.ts @@ -26,11 +26,24 @@ export interface ExpiredRewardsSummary { } // [2026-01-06] 新增:收益类型汇总接口类型 +// [2026-01-06] 更新:添加全量统计字段(包含所有状态) export interface RewardTypeSummary { totalAmount: number; totalCount: number; totalSettleableAmount: number; totalSettledAmount: number; + // [2026-01-06] 新增:全量统计(包含所有状态) + allStatusTotalAmount: number; + allStatusTotalCount: number; + pendingAmount: number; + pendingCount: number; + expiredAmount: number; + expiredCount: number; + byStatus: Array<{ + status: string; + amount: number; + count: number; + }>; byMonth: Array<{ month: string; amount: number; @@ -149,6 +162,13 @@ export class RewardServiceClient { totalCount: 0, totalSettleableAmount: 0, totalSettledAmount: 0, + allStatusTotalAmount: 0, + allStatusTotalCount: 0, + pendingAmount: 0, + pendingCount: 0, + expiredAmount: 0, + expiredCount: 0, + byStatus: [], byMonth: [], }; return { 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 8e770864..fd84edb7 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 @@ -911,7 +911,7 @@ export class RewardApplicationService { /** * 获取按权益类型的收益统计汇总 - * 统计所有已发放(SETTLEABLE + SETTLED)的奖励按权益类型分组 + * [2026-01-06] 更新:统计所有状态的奖励,包括 PENDING、SETTLEABLE、SETTLED、EXPIRED * * @param rightType 权益类型 */ @@ -920,6 +920,18 @@ export class RewardApplicationService { totalCount: number; totalSettleableAmount: number; totalSettledAmount: number; + // [2026-01-06] 新增:全量统计(包含所有状态) + allStatusTotalAmount: number; + allStatusTotalCount: number; + pendingAmount: number; + pendingCount: number; + expiredAmount: number; + expiredCount: number; + byStatus: Array<{ + status: string; + amount: number; + count: number; + }>; byMonth: Array<{ month: string; amount: number; @@ -928,7 +940,20 @@ export class RewardApplicationService { }> { this.logger.log(`[getRewardsSummaryByType] 查询权益类型收益统计: ${rightType}`); - // 查询总计(SETTLEABLE + SETTLED 状态) + // [2026-01-06] 新增:查询所有状态的总计 + const allStatusResult = await this.prisma.rewardLedgerEntry.aggregate({ + where: { + rightType: rightType, + }, + _sum: { + usdtAmount: true, + }, + _count: { + id: true, + }, + }); + + // 查询总计(SETTLEABLE + SETTLED 状态)- 有效收益 const aggregateResult = await this.prisma.rewardLedgerEntry.aggregate({ where: { rightType: rightType, @@ -951,6 +976,9 @@ export class RewardApplicationService { _sum: { usdtAmount: true, }, + _count: { + id: true, + }, }); // 查询已结算金额 @@ -962,8 +990,43 @@ export class RewardApplicationService { _sum: { usdtAmount: true, }, + _count: { + id: true, + }, }); + // [2026-01-06] 新增:查询待领取金额 + const pendingResult = await this.prisma.rewardLedgerEntry.aggregate({ + where: { + rightType: rightType, + rewardStatus: 'PENDING', + }, + _sum: { + usdtAmount: true, + }, + _count: { + id: true, + }, + }); + + // [2026-01-06] 新增:查询已过期金额 + const expiredResult = await this.prisma.rewardLedgerEntry.aggregate({ + where: { + rightType: rightType, + rewardStatus: 'EXPIRED', + }, + _sum: { + usdtAmount: true, + }, + _count: { + id: true, + }, + }); + + const allStatusTotalAmount = allStatusResult._sum.usdtAmount + ? Number(allStatusResult._sum.usdtAmount) + : 0; + const allStatusTotalCount = allStatusResult._count.id || 0; const totalAmount = aggregateResult._sum.usdtAmount ? Number(aggregateResult._sum.usdtAmount) : 0; @@ -971,11 +1034,21 @@ export class RewardApplicationService { const totalSettleableAmount = settleableResult._sum.usdtAmount ? Number(settleableResult._sum.usdtAmount) : 0; + const settleableCount = settleableResult._count.id || 0; const totalSettledAmount = settledResult._sum.usdtAmount ? Number(settledResult._sum.usdtAmount) : 0; + const settledCount = settledResult._count.id || 0; + const pendingAmount = pendingResult._sum.usdtAmount + ? Number(pendingResult._sum.usdtAmount) + : 0; + const pendingCount = pendingResult._count.id || 0; + const expiredAmount = expiredResult._sum.usdtAmount + ? Number(expiredResult._sum.usdtAmount) + : 0; + const expiredCount = expiredResult._count.id || 0; - // 查询按月统计 + // [2026-01-06] 修改:查询按月统计(所有状态) const byMonth = await this.prisma.$queryRaw ({ month: row.month, amount: Number(row.amount) || 0, 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 6a7187c2..d27c3aad 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 @@ -3060,6 +3060,8 @@ export class WalletApplicationService { /** * 获取面对面(线下)结算统计汇总 * 用于系统账户报表展示面对面结算收益总额 + * [2026-01-06] 修改:从 wallet_ledger_entries 表查询 SPECIAL_DEDUCTION 类型 + * 回滚方式:恢复原来从 offline_settlement_deductions 表查询的逻辑 */ async getOfflineSettlementSummary(params: { startDate?: Date; @@ -3073,10 +3075,12 @@ export class WalletApplicationService { count: number; }>; }> { - this.logger.log(`[getOfflineSettlementSummary] 查询面对面结算统计`); + this.logger.log(`[getOfflineSettlementSummary] 查询面对面结算统计(从 SPECIAL_DEDUCTION 流水)`); - // 构建日期筛选条件 - const whereClause: any = {}; + // 构建日期筛选条件,包含 entryType 过滤 + const whereClause: any = { + entryType: 'SPECIAL_DEDUCTION', + }; if (params.startDate || params.endDate) { whereClause.createdAt = {}; if (params.startDate) { @@ -3087,23 +3091,24 @@ export class WalletApplicationService { } } - // 查询总计 - const aggregateResult = await this.prisma.offlineSettlementDeduction.aggregate({ + // 查询总计(从 wallet_ledger_entries 表) + const aggregateResult = await this.prisma.ledgerEntry.aggregate({ where: whereClause, _sum: { - deductedAmount: true, + amount: true, }, _count: { id: true, }, }); - const totalAmount = aggregateResult._sum.deductedAmount - ? Number(aggregateResult._sum.deductedAmount) + // SPECIAL_DEDUCTION 的 amount 是负数,取绝对值 + const totalAmount = aggregateResult._sum.amount + ? Math.abs(Number(aggregateResult._sum.amount)) : 0; const totalCount = aggregateResult._count.id || 0; - // 查询按月统计(简化版本,不使用日期筛选) + // 查询按月统计(从 wallet_ledger_entries 表,SPECIAL_DEDUCTION 类型) const byMonth = await this.prisma.$queryRaw>` SELECT TO_CHAR(created_at, 'YYYY-MM') as month, - SUM(deducted_amount) as amount, + ABS(SUM(amount)) as amount, COUNT(*) as count - FROM offline_settlement_deductions + FROM wallet_ledger_entries + WHERE entry_type = 'SPECIAL_DEDUCTION' GROUP BY TO_CHAR(created_at, 'YYYY-MM') ORDER BY month DESC LIMIT 12 `; + this.logger.log(`[getOfflineSettlementSummary] 查询结果: totalAmount=${totalAmount}, totalCount=${totalCount}`); + return { totalAmount, totalCount, diff --git a/frontend/admin-web/src/components/features/system-account-report/SystemAccountsTab.module.scss b/frontend/admin-web/src/components/features/system-account-report/SystemAccountsTab.module.scss index b2c78544..99f3417e 100644 --- a/frontend/admin-web/src/components/features/system-account-report/SystemAccountsTab.module.scss +++ b/frontend/admin-web/src/components/features/system-account-report/SystemAccountsTab.module.scss @@ -275,6 +275,22 @@ background-color: #dcfce7; color: #166534; } + + /* [2026-01-06] 新增:收益状态样式 */ + &.settled { + background-color: #dcfce7; + color: #166534; + } + + &.expired { + background-color: #fee2e2; + color: #991b1b; + } + + &.pending { + background-color: #fef3c7; + color: #92400e; + } } /* 页脚 */ diff --git a/frontend/admin-web/src/components/features/system-account-report/SystemAccountsTab.tsx b/frontend/admin-web/src/components/features/system-account-report/SystemAccountsTab.tsx index efbc5f92..04849c97 100644 --- a/frontend/admin-web/src/components/features/system-account-report/SystemAccountsTab.tsx +++ b/frontend/admin-web/src/components/features/system-account-report/SystemAccountsTab.tsx @@ -1053,30 +1053,82 @@ function RewardTypeSummarySection({ - {/* 汇总卡片 */} + {/* [2026-01-06] 更新:全量汇总卡片(所有状态) */}
- 总金额 + 全部总金额 + {formatAmount(data.allStatusTotalAmount ?? data.totalAmount)} 绿积分 +
+
+ 全部总笔数 + {data.allStatusTotalCount ?? data.totalCount} +
+
+ 有效收益金额 {formatAmount(data.totalAmount)} 绿积分
- 总笔数 + 有效收益笔数 {data.totalCount}
+
+ + {/* [2026-01-06] 新增:按状态分组统计 */} + {data.byStatus && data.byStatus.length > 0 && ( + <> +

按状态统计

+
+ + + + + + + + + + {data.byStatus.map((item) => ( + + + + + + ))} + +
状态金额 (绿积分)笔数
+ + {REWARD_STATUS_LABELS[item.status] || item.status} + + {formatAmount(item.amount)}{item.count}
+
+ + )} + + {/* 详细分类卡片 */} +

详细分类

+
- 可结算金额 - {formatAmount(data.totalSettleableAmount)} 绿积分 + 待领取 + {formatAmount(data.pendingAmount ?? 0)} ({data.pendingCount ?? 0}笔)
- 已结算金额 - {formatAmount(data.totalSettledAmount)} 绿积分 + 可结算 + {formatAmount(data.totalSettleableAmount)} ({(data.byStatus?.find(s => s.status === 'SETTLEABLE')?.count) ?? 0}笔) +
+
+ 已结算 + {formatAmount(data.totalSettledAmount)} ({(data.byStatus?.find(s => s.status === 'SETTLED')?.count) ?? 0}笔) +
+
+ 已过期 + {formatAmount(data.expiredAmount ?? 0)} ({data.expiredCount ?? 0}笔)
{/* 按月统计 */} {data.byMonth && data.byMonth.length > 0 ? ( <> -

按月统计

+

按月统计(全部状态)

diff --git a/frontend/admin-web/src/types/system-account.types.ts b/frontend/admin-web/src/types/system-account.types.ts index a039631c..cb8cfbe3 100644 --- a/frontend/admin-web/src/types/system-account.types.ts +++ b/frontend/admin-web/src/types/system-account.types.ts @@ -188,6 +188,7 @@ export const ENTRY_TYPE_LABELS: Record = { }; // [2026-01-06] 新增:收益类型汇总统计类型 +// [2026-01-06] 更新:添加全量统计字段(包含所有状态) /** * 收益类型汇总 */ @@ -196,6 +197,18 @@ export interface RewardTypeSummary { totalCount: number; totalSettleableAmount: number; totalSettledAmount: number; + // [2026-01-06] 新增:全量统计(包含所有状态) + allStatusTotalAmount: number; + allStatusTotalCount: number; + pendingAmount: number; + pendingCount: number; + expiredAmount: number; + expiredCount: number; + byStatus: Array<{ + status: string; + amount: number; + count: number; + }>; byMonth: Array<{ month: string; amount: number; @@ -281,8 +294,10 @@ export const REWARD_RIGHT_TYPE_LABELS: Record = { /** * 收益状态显示名称映射 + * [2026-01-06] 更新:添加 PENDING 状态 */ export const REWARD_STATUS_LABELS: Record = { + PENDING: '待领取', SETTLEABLE: '可结算', SETTLED: '已结算', EXPIRED: '已过期',