feat(mining-admin): display adoption order count in user management
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 <noreply@anthropic.com>
This commit is contained in:
parent
56ff8290c1
commit
2f3a0f3652
|
|
@ -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 <noreply@anthropic.com>\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": []
|
||||
|
|
|
|||
|
|
@ -103,15 +103,15 @@ export class UsersService {
|
|||
*/
|
||||
private async getAdoptionStatsForUsers(
|
||||
accountSequences: string[],
|
||||
): Promise<Map<string, { personalCount: number; teamCount: number }>> {
|
||||
): Promise<Map<string, { personalCount: number; personalOrders: number; teamCount: number; teamOrders: number }>> {
|
||||
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
|
||||
|
|
|
|||
|
|
@ -158,6 +158,11 @@ export default function UsersPage() {
|
|||
<TreePine className="h-3 w-3 text-green-600" />
|
||||
<span className="font-mono text-sm">
|
||||
{formatNumber(user.personalAdoptions ?? 0)}
|
||||
{(user.personalAdoptionOrders ?? 0) > 0 && (
|
||||
<span className="text-muted-foreground ml-1">
|
||||
({user.personalAdoptionOrders}单)
|
||||
</span>
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
</TableCell>
|
||||
|
|
@ -167,6 +172,11 @@ export default function UsersPage() {
|
|||
<Users className="h-3 w-3 text-blue-600" />
|
||||
<span className="font-mono text-sm">
|
||||
{formatNumber(user.teamAdoptions ?? 0)}
|
||||
{(user.teamAdoptionOrders ?? 0) > 0 && (
|
||||
<span className="text-muted-foreground ml-1">
|
||||
({user.teamAdoptionOrders}单)
|
||||
</span>
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
</TableCell>
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -13,7 +13,9 @@ export interface UserOverview {
|
|||
frozenBalance: string;
|
||||
// 从 admin-web 复用的字段
|
||||
personalAdoptions?: number;
|
||||
personalAdoptionOrders?: number; // 个人认种订单数
|
||||
teamAdoptions?: number;
|
||||
teamAdoptionOrders?: number; // 团队认种订单数
|
||||
teamAddresses?: number;
|
||||
provincialAdoptions?: {
|
||||
count: number;
|
||||
|
|
|
|||
Loading…
Reference in New Issue