fix(mining-admin): 用户列表API添加认种统计和推荐人信息
- 后端getUsers添加批量查询认种统计和推荐人信息 - 后端formatUserListItem返回adoption和referral字段 - 前端transformUserOverview映射新字段 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
3074748d15
commit
2025c6ce36
|
|
@ -36,6 +36,7 @@ export class UsersService {
|
|||
{ phone: { contains: search } },
|
||||
{ accountSequence: { contains: search } },
|
||||
{ realName: { contains: search } },
|
||||
{ nickname: { contains: search } },
|
||||
];
|
||||
}
|
||||
|
||||
|
|
@ -63,13 +64,31 @@ export class UsersService {
|
|||
contributionAccount: true,
|
||||
miningAccount: true,
|
||||
tradingAccount: true,
|
||||
referral: true,
|
||||
},
|
||||
}),
|
||||
this.prisma.syncedUser.count({ where }),
|
||||
]);
|
||||
|
||||
// 批量获取认种统计
|
||||
const accountSequences = users.map((u) => u.accountSequence);
|
||||
const adoptionStats = await this.getAdoptionStatsForUsers(accountSequences);
|
||||
|
||||
// 批量获取推荐人信息
|
||||
const referrerAccountSequences = users
|
||||
.map((u) => u.referral?.referrerAccountSequence)
|
||||
.filter((s): s is string => !!s);
|
||||
const referrers = await this.getReferrersInfo(referrerAccountSequences);
|
||||
|
||||
return {
|
||||
data: users.map((user) => this.formatUserListItem(user)),
|
||||
data: users.map((user) =>
|
||||
this.formatUserListItem(user, {
|
||||
adoptionStats: adoptionStats.get(user.accountSequence),
|
||||
referrerInfo: user.referral?.referrerAccountSequence
|
||||
? referrers.get(user.referral.referrerAccountSequence)
|
||||
: null,
|
||||
}),
|
||||
),
|
||||
pagination: {
|
||||
page,
|
||||
pageSize,
|
||||
|
|
@ -79,6 +98,102 @@ export class UsersService {
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量获取用户认种统计
|
||||
*/
|
||||
private async getAdoptionStatsForUsers(
|
||||
accountSequences: string[],
|
||||
): Promise<Map<string, { personalCount: number; teamCount: number }>> {
|
||||
const result = new Map<
|
||||
string,
|
||||
{ personalCount: number; teamCount: number }
|
||||
>();
|
||||
|
||||
if (accountSequences.length === 0) return result;
|
||||
|
||||
// 获取每个用户的个人认种数量
|
||||
const personalAdoptions = await this.prisma.syncedAdoption.groupBy({
|
||||
by: ['accountSequence'],
|
||||
where: { accountSequence: { in: accountSequences } },
|
||||
_sum: { treeCount: true },
|
||||
});
|
||||
|
||||
for (const stat of personalAdoptions) {
|
||||
result.set(stat.accountSequence, {
|
||||
personalCount: stat._sum.treeCount || 0,
|
||||
teamCount: 0,
|
||||
});
|
||||
}
|
||||
|
||||
// 确保所有用户都有记录
|
||||
for (const seq of accountSequences) {
|
||||
if (!result.has(seq)) {
|
||||
result.set(seq, { personalCount: 0, teamCount: 0 });
|
||||
}
|
||||
}
|
||||
|
||||
// 获取团队认种数量(通过 referral 的 originalUserId 和 ancestorPath)
|
||||
const referrals = await this.prisma.syncedReferral.findMany({
|
||||
where: { accountSequence: { in: accountSequences } },
|
||||
select: { accountSequence: true, originalUserId: true },
|
||||
});
|
||||
|
||||
for (const ref of referrals) {
|
||||
if (!ref.originalUserId) continue;
|
||||
|
||||
// 找所有下级
|
||||
const teamMembers = await this.prisma.syncedReferral.findMany({
|
||||
where: {
|
||||
ancestorPath: { contains: ref.originalUserId.toString() },
|
||||
},
|
||||
select: { accountSequence: true },
|
||||
});
|
||||
|
||||
if (teamMembers.length > 0) {
|
||||
const teamAdoptionStats = await this.prisma.syncedAdoption.aggregate({
|
||||
where: {
|
||||
accountSequence: { in: teamMembers.map((m) => m.accountSequence) },
|
||||
},
|
||||
_sum: { treeCount: true },
|
||||
});
|
||||
const stats = result.get(ref.accountSequence);
|
||||
if (stats) {
|
||||
stats.teamCount = teamAdoptionStats._sum.treeCount || 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量获取推荐人信息
|
||||
*/
|
||||
private async getReferrersInfo(
|
||||
accountSequences: string[],
|
||||
): Promise<Map<string, { nickname: string | null; phone: string }>> {
|
||||
const result = new Map<
|
||||
string,
|
||||
{ nickname: string | null; phone: string }
|
||||
>();
|
||||
|
||||
if (accountSequences.length === 0) return result;
|
||||
|
||||
const referrers = await this.prisma.syncedUser.findMany({
|
||||
where: { accountSequence: { in: accountSequences } },
|
||||
select: { accountSequence: true, nickname: true, phone: true },
|
||||
});
|
||||
|
||||
for (const ref of referrers) {
|
||||
result.set(ref.accountSequence, {
|
||||
nickname: ref.nickname,
|
||||
phone: ref.phone,
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户详情
|
||||
*/
|
||||
|
|
@ -430,7 +545,13 @@ export class UsersService {
|
|||
// 辅助方法
|
||||
// ===========================================================================
|
||||
|
||||
private formatUserListItem(user: any) {
|
||||
private formatUserListItem(
|
||||
user: any,
|
||||
extra?: {
|
||||
adoptionStats?: { personalCount: number; teamCount: number };
|
||||
referrerInfo?: { nickname: string | null; phone: string } | null;
|
||||
},
|
||||
) {
|
||||
return {
|
||||
accountSequence: user.accountSequence,
|
||||
phone: this.maskPhone(user.phone),
|
||||
|
|
@ -440,6 +561,22 @@ export class UsersService {
|
|||
realName: user.realName,
|
||||
isLegacyUser: user.isLegacyUser,
|
||||
createdAt: user.createdAt,
|
||||
// 认种统计
|
||||
adoption: {
|
||||
personalAdoptionCount: extra?.adoptionStats?.personalCount || 0,
|
||||
teamAdoptions: extra?.adoptionStats?.teamCount || 0,
|
||||
},
|
||||
// 推荐人信息
|
||||
referral: user.referral
|
||||
? {
|
||||
referrerAccountSequence: user.referral.referrerAccountSequence,
|
||||
referrerNickname:
|
||||
extra?.referrerInfo?.nickname ||
|
||||
(extra?.referrerInfo?.phone
|
||||
? this.maskPhone(extra.referrerInfo.phone)
|
||||
: null),
|
||||
}
|
||||
: null,
|
||||
contribution: user.contributionAccount
|
||||
? {
|
||||
totalContribution:
|
||||
|
|
|
|||
|
|
@ -25,9 +25,11 @@ function transformUserOverview(backendUser: any): UserOverview {
|
|||
miningBalance: backendUser.mining?.availableBalance || '0',
|
||||
tradingBalance: backendUser.trading?.shareBalance || '0',
|
||||
frozenBalance: '0',
|
||||
personalAdoptions: 0,
|
||||
teamAdoptions: 0,
|
||||
referrerId: null,
|
||||
// 认种数据 - 从后端 adoption 字段获取
|
||||
personalAdoptions: backendUser.adoption?.personalAdoptionCount || 0,
|
||||
teamAdoptions: backendUser.adoption?.teamAdoptions || 0,
|
||||
// 推荐人
|
||||
referrerId: backendUser.referral?.referrerAccountSequence || null,
|
||||
status: backendUser.status?.toLowerCase() as 'active' | 'frozen' | 'deactivated',
|
||||
isOnline: false,
|
||||
createdAt: backendUser.createdAt,
|
||||
|
|
|
|||
Loading…
Reference in New Issue