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 11484902..e9774bde 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 @@ -450,32 +450,214 @@ export class UsersService { /** * 获取用户引荐关系树 - * TODO: 从 identity-service 同步推荐关系数据 */ - async getReferralTree(accountSequence: string, direction: string, depth: number) { + async getReferralTree( + accountSequence: string, + direction: string, + depth: number, + ) { const user = await this.prisma.syncedUser.findUnique({ where: { accountSequence }, - include: { contributionAccount: true }, + include: { + contributionAccount: true, + referral: true, + }, }); if (!user) { throw new NotFoundException(`用户 ${accountSequence} 不存在`); } - // 返回基础结构,数据需要从 identity-service 同步 - return { - currentUser: { - accountSequence: user.accountSequence, - nickname: user.realName || null, - avatar: null, - personalAdoptions: 0, - teamAdoptions: 0, - directReferralCount: user.contributionAccount?.directReferralCount || 0, - }, - ancestors: [], - directReferrals: [], - note: '推荐关系数据需要从 identity-service 同步', + // 获取当前用户的认种统计 + const currentUserAdoptions = await this.getUserAdoptionStats(accountSequence); + + // 构建当前用户节点 + const currentUser = { + accountSequence: user.accountSequence, + nickname: user.nickname || user.realName || null, + avatar: null, + personalAdoptions: currentUserAdoptions.personal, + teamAdoptions: currentUserAdoptions.team, + directReferralCount: 0, }; + + // 获取直推下级数量 + const directReferralCount = await this.prisma.syncedReferral.count({ + where: { referrerAccountSequence: accountSequence }, + }); + currentUser.directReferralCount = directReferralCount; + + // 获取向上的引荐人链 (ancestors) + let ancestors: any[] = []; + if (direction === 'up' || direction === 'both') { + ancestors = await this.getAncestors(accountSequence, depth); + } + + // 获取直推下级 (directReferrals) + let directReferrals: any[] = []; + if (direction === 'down' || direction === 'both') { + directReferrals = await this.getDirectReferrals(accountSequence); + } + + return { + currentUser, + ancestors, + directReferrals, + }; + } + + /** + * 获取用户认种统计 + */ + private async getUserAdoptionStats( + accountSequence: string, + ): Promise<{ personal: number; team: number }> { + // 个人认种 + const personalStats = await this.prisma.syncedAdoption.aggregate({ + where: { accountSequence }, + _sum: { treeCount: true }, + }); + + // 获取用户的 originalUserId + const referral = await this.prisma.syncedReferral.findUnique({ + where: { accountSequence }, + select: { originalUserId: true }, + }); + + let teamCount = 0; + if (referral?.originalUserId) { + // 团队认种 = 所有下级的认种总和 + const teamMembers = await this.prisma.syncedReferral.findMany({ + where: { + ancestorPath: { contains: referral.originalUserId.toString() }, + }, + select: { accountSequence: true }, + }); + + if (teamMembers.length > 0) { + const teamStats = await this.prisma.syncedAdoption.aggregate({ + where: { + accountSequence: { in: teamMembers.map((m) => m.accountSequence) }, + }, + _sum: { treeCount: true }, + }); + teamCount = teamStats._sum.treeCount || 0; + } + } + + return { + personal: personalStats._sum.treeCount || 0, + team: teamCount, + }; + } + + /** + * 获取向上的引荐人链 + */ + private async getAncestors( + accountSequence: string, + maxDepth: number = 10, + ): Promise { + const ancestors: any[] = []; + + // 获取当前用户的推荐关系 + const referral = await this.prisma.syncedReferral.findUnique({ + where: { accountSequence }, + select: { referrerAccountSequence: true, ancestorPath: true }, + }); + + if (!referral?.referrerAccountSequence) { + return ancestors; + } + + // 通过 ancestorPath 解析祖先链 + // ancestorPath 格式类似: "123,456,789" 其中 123 是直接上级的 originalUserId + if (referral.ancestorPath) { + const ancestorUserIds = referral.ancestorPath + .split(',') + .filter((id) => id.trim()) + .slice(0, maxDepth); + + // 获取所有祖先的 referral 记录以获取 accountSequence + const ancestorReferrals = await this.prisma.syncedReferral.findMany({ + where: { + originalUserId: { in: ancestorUserIds.map((id) => BigInt(id)) }, + }, + select: { accountSequence: true, originalUserId: true }, + }); + + const userIdToSeq = new Map( + ancestorReferrals.map((r) => [r.originalUserId.toString(), r.accountSequence]), + ); + + // 按顺序获取每个祖先的详细信息 + for (const userId of ancestorUserIds) { + const seq = userIdToSeq.get(userId); + if (!seq) continue; + + const user = await this.prisma.syncedUser.findUnique({ + where: { accountSequence: seq }, + select: { accountSequence: true, nickname: true, realName: true }, + }); + + if (user) { + const adoptionStats = await this.getUserAdoptionStats(seq); + const directCount = await this.prisma.syncedReferral.count({ + where: { referrerAccountSequence: seq }, + }); + + ancestors.push({ + accountSequence: user.accountSequence, + nickname: user.nickname || user.realName || null, + avatar: null, + personalAdoptions: adoptionStats.personal, + teamAdoptions: adoptionStats.team, + directReferralCount: directCount, + }); + } + } + } + + // 反转使得最近的祖先在最后(靠近当前用户) + return ancestors.reverse(); + } + + /** + * 获取直推下级 + */ + private async getDirectReferrals(accountSequence: string): Promise { + // 获取所有直推下级 + const directReferrals = await this.prisma.syncedReferral.findMany({ + where: { referrerAccountSequence: accountSequence }, + select: { accountSequence: true }, + }); + + const results: any[] = []; + + for (const ref of directReferrals) { + const user = await this.prisma.syncedUser.findUnique({ + where: { accountSequence: ref.accountSequence }, + select: { accountSequence: true, nickname: true, realName: true }, + }); + + if (user) { + const adoptionStats = await this.getUserAdoptionStats(ref.accountSequence); + const directCount = await this.prisma.syncedReferral.count({ + where: { referrerAccountSequence: ref.accountSequence }, + }); + + results.push({ + accountSequence: user.accountSequence, + nickname: user.nickname || user.realName || null, + avatar: null, + personalAdoptions: adoptionStats.personal, + teamAdoptions: adoptionStats.team, + directReferralCount: directCount, + }); + } + } + + return results; } /**