diff --git a/backend/services/admin-service/src/api/controllers/user-detail.controller.ts b/backend/services/admin-service/src/api/controllers/user-detail.controller.ts index 5f778432..01f11640 100644 --- a/backend/services/admin-service/src/api/controllers/user-detail.controller.ts +++ b/backend/services/admin-service/src/api/controllers/user-detail.controller.ts @@ -138,11 +138,12 @@ export class UserDetailController { } // 获取引荐信息和实时统计 - const [referralInfo, personalAdoptionCount, directReferralCount, teamStats] = await Promise.all([ + const [referralInfo, personalAdoptionCount, directReferralCount, teamStats, prePlantingStats] = await Promise.all([ this.userDetailRepository.getReferralInfo(accountSequence), this.userDetailRepository.getPersonalAdoptionCount(accountSequence), this.userDetailRepository.getDirectReferralCount(accountSequence), this.userDetailRepository.getBatchUserStats([accountSequence]), + this.referralProxyService.getPrePlantingStats(accountSequence), ]); const currentUserStats = teamStats.get(accountSequence); @@ -153,6 +154,8 @@ export class UserDetailController { avatar: user.avatarUrl, personalAdoptions: personalAdoptionCount, teamAdoptions: currentUserStats?.teamAdoptionCount || 0, + selfPrePlantingPortions: prePlantingStats.selfPrePlantingPortions, + teamPrePlantingPortions: prePlantingStats.teamPrePlantingPortions, depth: referralInfo?.depth || 0, directReferralCount: directReferralCount, isCurrentUser: true, @@ -161,34 +164,56 @@ export class UserDetailController { let ancestors: ReferralNodeDto[] = []; let directReferrals: ReferralNodeDto[] = []; + // 收集所有需要查预种的 accountSequences + const allNodeSeqs: string[] = []; + // 向上查询 + let ancestorNodes: typeof ancestors extends (infer T)[] ? any[] : never = []; if (query.direction === 'up' || query.direction === 'both') { - const ancestorNodes = await this.userDetailRepository.getAncestors( + ancestorNodes = await this.userDetailRepository.getAncestors( accountSequence, query.depth || 1, ); - ancestors = ancestorNodes.map((node) => ({ + allNodeSeqs.push(...ancestorNodes.map((n: any) => n.accountSequence)); + } + + // 向下查询 + let referralNodes: typeof directReferrals extends (infer T)[] ? any[] : never = []; + if (query.direction === 'down' || query.direction === 'both') { + referralNodes = await this.userDetailRepository.getDirectReferrals(accountSequence); + allNodeSeqs.push(...referralNodes.map((n: any) => n.accountSequence)); + } + + // 批量获取所有节点的预种统计 + const batchPrePlanting = allNodeSeqs.length > 0 + ? await this.referralProxyService.batchGetPrePlantingStats(allNodeSeqs) + : {}; + + if (ancestorNodes.length > 0) { + ancestors = ancestorNodes.map((node: any) => ({ accountSequence: node.accountSequence, userId: node.userId.toString(), nickname: node.nickname, avatar: node.avatarUrl, personalAdoptions: node.personalAdoptionCount, teamAdoptions: node.teamAdoptionCount, + selfPrePlantingPortions: batchPrePlanting[node.accountSequence]?.selfPrePlantingPortions ?? 0, + teamPrePlantingPortions: batchPrePlanting[node.accountSequence]?.teamPrePlantingPortions ?? 0, depth: node.depth, directReferralCount: node.directReferralCount, })); } - // 向下查询 - if (query.direction === 'down' || query.direction === 'both') { - const referralNodes = await this.userDetailRepository.getDirectReferrals(accountSequence); - directReferrals = referralNodes.map((node) => ({ + if (referralNodes.length > 0) { + directReferrals = referralNodes.map((node: any) => ({ accountSequence: node.accountSequence, userId: node.userId.toString(), nickname: node.nickname, avatar: node.avatarUrl, personalAdoptions: node.personalAdoptionCount, teamAdoptions: node.teamAdoptionCount, + selfPrePlantingPortions: batchPrePlanting[node.accountSequence]?.selfPrePlantingPortions ?? 0, + teamPrePlantingPortions: batchPrePlanting[node.accountSequence]?.teamPrePlantingPortions ?? 0, depth: node.depth, directReferralCount: node.directReferralCount, })); diff --git a/backend/services/admin-service/src/api/dto/response/user-detail.dto.ts b/backend/services/admin-service/src/api/dto/response/user-detail.dto.ts index 37ea0707..2e544b28 100644 --- a/backend/services/admin-service/src/api/dto/response/user-detail.dto.ts +++ b/backend/services/admin-service/src/api/dto/response/user-detail.dto.ts @@ -74,6 +74,8 @@ export class ReferralNodeDto { avatar!: string | null; personalAdoptions!: number; teamAdoptions!: number; // 团队认种量 + selfPrePlantingPortions!: number; // 个人预种份数 + teamPrePlantingPortions!: number; // 团队预种份数 depth!: number; directReferralCount!: number; isCurrentUser?: boolean; diff --git a/frontend/admin-web/src/app/(dashboard)/users/[id]/page.tsx b/frontend/admin-web/src/app/(dashboard)/users/[id]/page.tsx index a19b13a0..318c4fec 100644 --- a/frontend/admin-web/src/app/(dashboard)/users/[id]/page.tsx +++ b/frontend/admin-web/src/app/(dashboard)/users/[id]/page.tsx @@ -490,6 +490,9 @@ export default function UserDetailPage() { 本人认种: {formatNumber(ancestor.personalAdoptions)} / 团队认种: {formatNumber(ancestor.teamAdoptions)} + + 个人预种: {formatNumber(ancestor.selfPrePlantingPortions)}份 / 团队预种: {formatNumber(ancestor.teamPrePlantingPortions)}份 + {index < referralTree.ancestors.length - 1 && (
@@ -1198,6 +1201,9 @@ function ReferralNodeItem({ 本人认种: {formatNumber(node.personalAdoptions)} / 团队认种: {formatNumber(node.teamAdoptions)} + + 个人预种: {formatNumber(node.selfPrePlantingPortions)}份 / 团队预种: {formatNumber(node.teamPrePlantingPortions)}份 + {node.directReferralCount > 0 && ( 引荐: {formatNumber(node.directReferralCount)} diff --git a/frontend/admin-web/src/types/userDetail.types.ts b/frontend/admin-web/src/types/userDetail.types.ts index 97427761..2bbd346d 100644 --- a/frontend/admin-web/src/types/userDetail.types.ts +++ b/frontend/admin-web/src/types/userDetail.types.ts @@ -64,6 +64,8 @@ export interface ReferralNode { avatar: string | null; personalAdoptions: number; teamAdoptions: number; // 团队认种量 + selfPrePlantingPortions: number; // 个人预种份数 + teamPrePlantingPortions: number; // 团队预种份数 depth: number; directReferralCount: number; isCurrentUser?: boolean;