fix(mining-admin-service): 实现getReferralTree返回真实推荐关系数据
- 从synced_referrals和synced_adoptions获取数据 - 实现getAncestors获取向上引荐人链 - 实现getDirectReferrals获取直推下级 - 实现getUserAdoptionStats获取认种统计 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
2025c6ce36
commit
9e9a7364b9
|
|
@ -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({
|
const user = await this.prisma.syncedUser.findUnique({
|
||||||
where: { accountSequence },
|
where: { accountSequence },
|
||||||
include: { contributionAccount: true },
|
include: {
|
||||||
|
contributionAccount: true,
|
||||||
|
referral: true,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
throw new NotFoundException(`用户 ${accountSequence} 不存在`);
|
throw new NotFoundException(`用户 ${accountSequence} 不存在`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 返回基础结构,数据需要从 identity-service 同步
|
// 获取当前用户的认种统计
|
||||||
return {
|
const currentUserAdoptions = await this.getUserAdoptionStats(accountSequence);
|
||||||
currentUser: {
|
|
||||||
accountSequence: user.accountSequence,
|
// 构建当前用户节点
|
||||||
nickname: user.realName || null,
|
const currentUser = {
|
||||||
avatar: null,
|
accountSequence: user.accountSequence,
|
||||||
personalAdoptions: 0,
|
nickname: user.nickname || user.realName || null,
|
||||||
teamAdoptions: 0,
|
avatar: null,
|
||||||
directReferralCount: user.contributionAccount?.directReferralCount || 0,
|
personalAdoptions: currentUserAdoptions.personal,
|
||||||
},
|
teamAdoptions: currentUserAdoptions.team,
|
||||||
ancestors: [],
|
directReferralCount: 0,
|
||||||
directReferrals: [],
|
|
||||||
note: '推荐关系数据需要从 identity-service 同步',
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 获取直推下级数量
|
||||||
|
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<any[]> {
|
||||||
|
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<any[]> {
|
||||||
|
// 获取所有直推下级
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue