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 } },
|
{ phone: { contains: search } },
|
||||||
{ accountSequence: { contains: search } },
|
{ accountSequence: { contains: search } },
|
||||||
{ realName: { contains: search } },
|
{ realName: { contains: search } },
|
||||||
|
{ nickname: { contains: search } },
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -63,13 +64,31 @@ export class UsersService {
|
||||||
contributionAccount: true,
|
contributionAccount: true,
|
||||||
miningAccount: true,
|
miningAccount: true,
|
||||||
tradingAccount: true,
|
tradingAccount: true,
|
||||||
|
referral: true,
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
this.prisma.syncedUser.count({ where }),
|
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 {
|
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: {
|
pagination: {
|
||||||
page,
|
page,
|
||||||
pageSize,
|
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 {
|
return {
|
||||||
accountSequence: user.accountSequence,
|
accountSequence: user.accountSequence,
|
||||||
phone: this.maskPhone(user.phone),
|
phone: this.maskPhone(user.phone),
|
||||||
|
|
@ -440,6 +561,22 @@ export class UsersService {
|
||||||
realName: user.realName,
|
realName: user.realName,
|
||||||
isLegacyUser: user.isLegacyUser,
|
isLegacyUser: user.isLegacyUser,
|
||||||
createdAt: user.createdAt,
|
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
|
contribution: user.contributionAccount
|
||||||
? {
|
? {
|
||||||
totalContribution:
|
totalContribution:
|
||||||
|
|
|
||||||
|
|
@ -25,9 +25,11 @@ function transformUserOverview(backendUser: any): UserOverview {
|
||||||
miningBalance: backendUser.mining?.availableBalance || '0',
|
miningBalance: backendUser.mining?.availableBalance || '0',
|
||||||
tradingBalance: backendUser.trading?.shareBalance || '0',
|
tradingBalance: backendUser.trading?.shareBalance || '0',
|
||||||
frozenBalance: '0',
|
frozenBalance: '0',
|
||||||
personalAdoptions: 0,
|
// 认种数据 - 从后端 adoption 字段获取
|
||||||
teamAdoptions: 0,
|
personalAdoptions: backendUser.adoption?.personalAdoptionCount || 0,
|
||||||
referrerId: null,
|
teamAdoptions: backendUser.adoption?.teamAdoptions || 0,
|
||||||
|
// 推荐人
|
||||||
|
referrerId: backendUser.referral?.referrerAccountSequence || null,
|
||||||
status: backendUser.status?.toLowerCase() as 'active' | 'frozen' | 'deactivated',
|
status: backendUser.status?.toLowerCase() as 'active' | 'frozen' | 'deactivated',
|
||||||
isOnline: false,
|
isOnline: false,
|
||||||
createdAt: backendUser.createdAt,
|
createdAt: backendUser.createdAt,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue