fix(admin-service): 引荐关系树实时统计本人认种和直推数量

问题:
- 引荐节点的"本人认种"和"引荐"显示为0
- user_query_view.personal_adoption_count 和
  referral_query_view.direct_referral_count 没有被CDC更新

解决方案:
- getAncestors: 实时统计每个祖先的认种订单数和直推数
- getDirectReferrals: 实时统计每个下级的认种订单数和直推数
- getReferralTree API: 实时获取当前用户的统计数据
- 新增 getDirectReferralCount 方法

实时统计方式:
- 本人认种 = planting_order_query_view 中状态为 MINING_ENABLED 的订单数
- 直推数量 = referral_query_view 中 referrer_id 等于该用户的记录数

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
hailin 2026-01-07 22:30:38 -08:00
parent 3ed72499a0
commit d303cf076b
3 changed files with 84 additions and 20 deletions

View File

@ -131,16 +131,21 @@ export class UserDetailController {
throw new NotFoundException(`用户 ${accountSequence} 不存在`);
}
const referralInfo = await this.userDetailRepository.getReferralInfo(accountSequence);
// 获取引荐信息和实时统计
const [referralInfo, personalAdoptionCount, directReferralCount] = await Promise.all([
this.userDetailRepository.getReferralInfo(accountSequence),
this.userDetailRepository.getPersonalAdoptionCount(accountSequence),
this.userDetailRepository.getDirectReferralCount(accountSequence),
]);
const currentUser: ReferralNodeDto = {
accountSequence: user.accountSequence,
userId: user.userId.toString(),
nickname: user.nickname,
avatar: user.avatarUrl,
personalAdoptions: user.personalAdoptionCount,
personalAdoptions: personalAdoptionCount,
depth: referralInfo?.depth || 0,
directReferralCount: referralInfo?.directReferralCount || 0,
directReferralCount: directReferralCount,
isCurrentUser: true,
};

View File

@ -251,6 +251,11 @@ export interface IUserDetailQueryRepository {
*/
getPersonalAdoptionCount(accountSequence: string): Promise<number>;
/**
*
*/
getDirectReferralCount(accountSequence: string): Promise<number>;
/**
*
*

View File

@ -60,7 +60,7 @@ export class UserDetailQueryRepositoryImpl implements IUserDetailQueryRepository
const ancestorIds = referral.ancestorPath.slice(0, depth);
if (ancestorIds.length === 0) return [];
// 获取祖先用户信息
// 获取祖先用户信息和引荐关系
const [users, referrals] = await Promise.all([
this.prisma.userQueryView.findMany({
where: { userId: { in: ancestorIds } },
@ -69,19 +69,41 @@ export class UserDetailQueryRepositoryImpl implements IUserDetailQueryRepository
accountSequence: true,
nickname: true,
avatarUrl: true,
personalAdoptionCount: true,
},
}),
this.prisma.referralQueryView.findMany({
where: { userId: { in: ancestorIds } },
select: {
userId: true,
accountSequence: true,
depth: true,
directReferralCount: true,
},
}),
]);
// 实时统计:获取每个祖先的认种数量和直推数量
const accountSequences = users.map(u => u.accountSequence);
const [adoptionCounts, directReferralCounts] = await Promise.all([
// 统计每个用户的认种订单数量(状态为 MINING_ENABLED
this.prisma.plantingOrderQueryView.groupBy({
by: ['accountSequence'],
where: {
accountSequence: { in: accountSequences },
status: 'MINING_ENABLED',
},
_count: { id: true },
}),
// 统计每个用户的直推数量
this.prisma.referralQueryView.groupBy({
by: ['referrerId'],
where: { referrerId: { in: ancestorIds } },
_count: { userId: true },
}),
]);
const adoptionCountMap = new Map(adoptionCounts.map(a => [a.accountSequence, a._count.id]));
const directCountMap = new Map(directReferralCounts.map(d => [d.referrerId.toString(), d._count.userId]));
// 合并数据
const referralMap = new Map(referrals.map((r) => [r.userId.toString(), r]));
const userMap = new Map(users.map((u) => [u.userId.toString(), u]));
@ -94,9 +116,9 @@ export class UserDetailQueryRepositoryImpl implements IUserDetailQueryRepository
accountSequence: user?.accountSequence || '',
nickname: user?.nickname || null,
avatarUrl: user?.avatarUrl || null,
personalAdoptionCount: user?.personalAdoptionCount || 0,
personalAdoptionCount: adoptionCountMap.get(user?.accountSequence || '') || 0,
depth: ref?.depth || index,
directReferralCount: ref?.directReferralCount || 0,
directReferralCount: directCountMap.get(id.toString()) || 0,
};
});
}
@ -115,24 +137,45 @@ export class UserDetailQueryRepositoryImpl implements IUserDetailQueryRepository
userId: true,
accountSequence: true,
depth: true,
directReferralCount: true,
},
});
if (directReferrals.length === 0) return [];
// 获取用户信息
const userIds = directReferrals.map((r) => r.userId);
const users = await this.prisma.userQueryView.findMany({
where: { userId: { in: directReferrals.map((r) => r.userId) } },
where: { userId: { in: userIds } },
select: {
userId: true,
accountSequence: true,
nickname: true,
avatarUrl: true,
personalAdoptionCount: true,
},
});
// 实时统计:获取每个用户的认种数量和直推数量
const userAccountSequences = directReferrals.map(r => r.accountSequence);
const [adoptionCounts, directReferralCounts] = await Promise.all([
// 统计每个用户的认种订单数量(状态为 MINING_ENABLED
this.prisma.plantingOrderQueryView.groupBy({
by: ['accountSequence'],
where: {
accountSequence: { in: userAccountSequences },
status: 'MINING_ENABLED',
},
_count: { id: true },
}),
// 统计每个用户的直推数量
this.prisma.referralQueryView.groupBy({
by: ['referrerId'],
where: { referrerId: { in: userIds } },
_count: { userId: true },
}),
]);
const adoptionCountMap = new Map(adoptionCounts.map(a => [a.accountSequence, a._count.id]));
const directCountMap = new Map(directReferralCounts.map(d => [d.referrerId.toString(), d._count.userId]));
const userMap = new Map(users.map((u) => [u.userId.toString(), u]));
return directReferrals.map((ref) => {
@ -142,9 +185,9 @@ export class UserDetailQueryRepositoryImpl implements IUserDetailQueryRepository
accountSequence: ref.accountSequence,
nickname: user?.nickname || null,
avatarUrl: user?.avatarUrl || null,
personalAdoptionCount: user?.personalAdoptionCount || 0,
personalAdoptionCount: adoptionCountMap.get(ref.accountSequence) || 0,
depth: ref.depth,
directReferralCount: ref.directReferralCount,
directReferralCount: directCountMap.get(ref.userId.toString()) || 0,
};
});
}
@ -428,21 +471,32 @@ export class UserDetailQueryRepositoryImpl implements IUserDetailQueryRepository
}
async getPersonalAdoptionCount(accountSequence: string): Promise<number> {
// 统计用户的认种订单数量(状态为 MINING_ENABLED
const count = await this.prisma.plantingOrderQueryView.count({
where: {
accountSequence,
status: 'MINING_ENABLED',
},
});
return count;
}
async getDirectReferralCount(accountSequence: string): Promise<number> {
// 先获取用户的 userId
const user = await this.prisma.userQueryView.findUnique({
const referral = await this.prisma.referralQueryView.findUnique({
where: { accountSequence },
select: { userId: true },
});
if (!user) return 0;
if (!referral) return 0;
// 从 PlantingPositionQueryView 获取有效认种树数
const position = await this.prisma.plantingPositionQueryView.findUnique({
where: { userId: user.userId },
select: { effectiveTreeCount: true },
// 统计以该用户为 referrerId 的用户数量
const count = await this.prisma.referralQueryView.count({
where: { referrerId: referral.userId },
});
return position?.effectiveTreeCount || 0;
return count;
}
async getTeamStats(accountSequence: string): Promise<{ teamAddressCount: number; teamAdoptionCount: number }> {