From 2f3a0f36527b6070c0338b91f8fa1b4ccda79ea3 Mon Sep 17 00:00:00 2001 From: hailin Date: Tue, 13 Jan 2026 01:03:59 -0800 Subject: [PATCH] feat(mining-admin): display adoption order count in user management MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Backend: - Add personalOrders and teamOrders to adoption stats - Return order count alongside tree count in user list API Frontend: - Add personalAdoptionOrders and teamAdoptionOrders to UserOverview type - Display format: "树数量(订单数)" e.g. "6(3单)" Co-Authored-By: Claude Opus 4.5 --- .claude/settings.local.json | 3 ++- .../src/application/services/users.service.ts | 17 ++++++++++++----- .../src/app/(dashboard)/users/page.tsx | 10 ++++++++++ .../src/features/users/api/users.api.ts | 2 ++ frontend/mining-admin-web/src/types/user.ts | 2 ++ 5 files changed, 28 insertions(+), 6 deletions(-) diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 7100229b..a6c815b3 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -767,7 +767,8 @@ "Bash(git -C \"c:\\\\Users\\\\dong\\\\Desktop\\\\rwadurian\" commit -m \"$\\(cat <<''EOF''\nfix\\(mining-app\\): update splash page theme and fix token refresh\n\n- Update splash_page.dart to orange theme \\(#FF6B00\\) matching other pages\n- Change app name from \"榴莲挖矿\" to \"榴莲生态\"\n- Fix refreshTokenIfNeeded to properly throw on failure instead of\n silently calling logout \\(which caused Riverpod ref errors\\)\n- Clear local storage directly on refresh failure without remote API call\n\nCo-Authored-By: Claude Opus 4.5 \nEOF\n\\)\")", "Bash(python3 -c \" import sys content = sys.stdin.read\\(\\) old = '''''' done # 清空 processed_cdc_events 表(因为 migration 时可能已经消费了一些消息) # 这是事务性幂等消费的关键:重置 Kafka offset 后必须同时清空幂等记录 log_info \"\"Truncating processed_cdc_events tables to allow re-consumption...\"\" for db in \"\"rwa_contribution\"\" \"\"rwa_auth\"\"; do if run_psql \"\"$db\"\" \"\"TRUNCATE TABLE processed_cdc_events;\"\" 2>/dev/null; then log_success \"\"Truncated processed_cdc_events in $db\"\" else log_warn \"\"Could not truncate processed_cdc_events in $db \\(table may not exist yet\\)\"\" fi done log_step \"\"Step 9/18: Starting 2.0 services...\"\"'''''' new = '''''' done # 清空 processed_cdc_events 表(因为 migration 时可能已经消费了一些消息) # 这是事务性幂等消费的关键:重置 Kafka offset 后必须同时清空幂等记录 log_info \"\"Truncating processed_cdc_events tables to allow re-consumption...\"\" for db in \"\"rwa_contribution\"\" \"\"rwa_auth\"\"; do if run_psql \"\"$db\"\" \"\"TRUNCATE TABLE processed_cdc_events;\"\" 2>/dev/null; then log_success \"\"Truncated processed_cdc_events in $db\"\" else log_warn \"\"Could not truncate processed_cdc_events in $db \\(table may not exist yet\\)\"\" fi done log_step \"\"Step 9/18: Starting 2.0 services...\"\"'''''' print\\(content.replace\\(old, new\\)\\) \")", "Bash(git rm:*)", - "Bash(echo \"请在服务器运行以下命令检查 outbox 事件:\n\ndocker exec -it rwa-postgres psql -U rwa_user -d rwa_contribution -c \"\"\nSELECT id, event_type, aggregate_id, \n payload->>''sourceType'' as source_type,\n payload->>''accountSequence'' as account_seq,\n payload->>''sourceAccountSequence'' as source_account_seq,\n payload->>''bonusTier'' as bonus_tier\nFROM outbox_events \nWHERE payload->>''accountSequence'' = ''D25122900007''\nORDER BY id;\n\"\"\")" + "Bash(echo \"请在服务器运行以下命令检查 outbox 事件:\n\ndocker exec -it rwa-postgres psql -U rwa_user -d rwa_contribution -c \"\"\nSELECT id, event_type, aggregate_id, \n payload->>''sourceType'' as source_type,\n payload->>''accountSequence'' as account_seq,\n payload->>''sourceAccountSequence'' as source_account_seq,\n payload->>''bonusTier'' as bonus_tier\nFROM outbox_events \nWHERE payload->>''accountSequence'' = ''D25122900007''\nORDER BY id;\n\"\"\")", + "Bash(ssh -o ConnectTimeout=10 ceshi@14.215.128.96 'find /home/ceshi/rwadurian/frontend/mining-admin-web -name \"\"*.tsx\"\" -o -name \"\"*.ts\"\" | xargs grep -l \"\"用户管理\\\\|users\"\" 2>/dev/null | head -10')" ], "deny": [], "ask": [] diff --git a/backend/services/mining-admin-service/src/application/services/users.service.ts b/backend/services/mining-admin-service/src/application/services/users.service.ts index 1ac3c00b..266b05eb 100644 --- a/backend/services/mining-admin-service/src/application/services/users.service.ts +++ b/backend/services/mining-admin-service/src/application/services/users.service.ts @@ -103,15 +103,15 @@ export class UsersService { */ private async getAdoptionStatsForUsers( accountSequences: string[], - ): Promise> { + ): Promise> { const result = new Map< string, - { personalCount: number; teamCount: number } + { personalCount: number; personalOrders: number; teamCount: number; teamOrders: number } >(); if (accountSequences.length === 0) return result; - // 获取每个用户的个人认种数量(只统计 MINING_ENABLED 状态) + // 获取每个用户的个人认种数量和订单数(只统计 MINING_ENABLED 状态) const personalAdoptions = await this.prisma.syncedAdoption.groupBy({ by: ['accountSequence'], where: { @@ -119,19 +119,22 @@ export class UsersService { status: 'MINING_ENABLED', }, _sum: { treeCount: true }, + _count: { id: true }, }); for (const stat of personalAdoptions) { result.set(stat.accountSequence, { personalCount: stat._sum.treeCount || 0, + personalOrders: stat._count.id || 0, teamCount: 0, + teamOrders: 0, }); } // 确保所有用户都有记录 for (const seq of accountSequences) { if (!result.has(seq)) { - result.set(seq, { personalCount: 0, teamCount: 0 }); + result.set(seq, { personalCount: 0, personalOrders: 0, teamCount: 0, teamOrders: 0 }); } } @@ -159,10 +162,12 @@ export class UsersService { status: 'MINING_ENABLED', }, _sum: { treeCount: true }, + _count: { id: true }, }); const stats = result.get(ref.accountSequence); if (stats) { stats.teamCount = teamAdoptionStats._sum.treeCount || 0; + stats.teamOrders = teamAdoptionStats._count.id || 0; } } } @@ -883,7 +888,7 @@ export class UsersService { private formatUserListItem( user: any, extra?: { - adoptionStats?: { personalCount: number; teamCount: number }; + adoptionStats?: { personalCount: number; personalOrders: number; teamCount: number; teamOrders: number }; referrerInfo?: { nickname: string | null; phone: string } | null; }, ) { @@ -899,7 +904,9 @@ export class UsersService { // 认种统计 adoption: { personalAdoptionCount: extra?.adoptionStats?.personalCount || 0, + personalAdoptionOrders: extra?.adoptionStats?.personalOrders || 0, teamAdoptions: extra?.adoptionStats?.teamCount || 0, + teamAdoptionOrders: extra?.adoptionStats?.teamOrders || 0, }, // 推荐人信息 referral: user.referral diff --git a/frontend/mining-admin-web/src/app/(dashboard)/users/page.tsx b/frontend/mining-admin-web/src/app/(dashboard)/users/page.tsx index afda18d6..02ad7045 100644 --- a/frontend/mining-admin-web/src/app/(dashboard)/users/page.tsx +++ b/frontend/mining-admin-web/src/app/(dashboard)/users/page.tsx @@ -158,6 +158,11 @@ export default function UsersPage() { {formatNumber(user.personalAdoptions ?? 0)} + {(user.personalAdoptionOrders ?? 0) > 0 && ( + + ({user.personalAdoptionOrders}单) + + )} @@ -167,6 +172,11 @@ export default function UsersPage() { {formatNumber(user.teamAdoptions ?? 0)} + {(user.teamAdoptionOrders ?? 0) > 0 && ( + + ({user.teamAdoptionOrders}单) + + )} diff --git a/frontend/mining-admin-web/src/features/users/api/users.api.ts b/frontend/mining-admin-web/src/features/users/api/users.api.ts index cda456f0..ea126419 100644 --- a/frontend/mining-admin-web/src/features/users/api/users.api.ts +++ b/frontend/mining-admin-web/src/features/users/api/users.api.ts @@ -27,7 +27,9 @@ function transformUserOverview(backendUser: any): UserOverview { frozenBalance: '0', // 认种数据 - 从后端 adoption 字段获取 personalAdoptions: backendUser.adoption?.personalAdoptionCount || 0, + personalAdoptionOrders: backendUser.adoption?.personalAdoptionOrders || 0, teamAdoptions: backendUser.adoption?.teamAdoptions || 0, + teamAdoptionOrders: backendUser.adoption?.teamAdoptionOrders || 0, // 推荐人 referrerId: backendUser.referral?.referrerAccountSequence || null, status: backendUser.status?.toLowerCase() as 'active' | 'frozen' | 'deactivated', diff --git a/frontend/mining-admin-web/src/types/user.ts b/frontend/mining-admin-web/src/types/user.ts index e96ae300..99163ccd 100644 --- a/frontend/mining-admin-web/src/types/user.ts +++ b/frontend/mining-admin-web/src/types/user.ts @@ -13,7 +13,9 @@ export interface UserOverview { frozenBalance: string; // 从 admin-web 复用的字段 personalAdoptions?: number; + personalAdoptionOrders?: number; // 个人认种订单数 teamAdoptions?: number; + teamAdoptionOrders?: number; // 团队认种订单数 teamAddresses?: number; provincialAdoptions?: { count: number;