fix(admin-service): 个人/团队认种数量改为统计棵数而非订单数
【问题】
getUserList 及推荐树节点中「个人认种」「团队认种」显示的是订单条数
(_count: { id }),而非实际认种棵数。一笔订单可认种多棵,导致多棵
合并下单的用户数量严重偏低。
【修复】
将以下方法中的所有 count(orders) 改为 sum(treeCount):
- getPersonalAdoptionCount — 用户详情页个人认种数
- getTeamStats — 用户详情页团队认种数
- getBatchUserStats — 用户列表批量统计(个人/团队/省/市认种数)
- getAncestors — 推荐树祖先节点认种数
- getDirectReferrals — 推荐树直推节点认种数
【影响范围】
仅影响 admin-web 管理后台的展示数据,不涉及业务逻辑和数据存储。
省市认种百分比计算基准同步修正(teamAdoptions 也改为棵数),
比例结果不变,但基数更准确。
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
f8f37a2e33
commit
728728bee3
|
|
@ -86,14 +86,16 @@ export class UserDetailQueryRepositoryImpl implements IUserDetailQueryRepository
|
||||||
// 注意:优先从 referrals 获取 accountSequences,因为用户可能不存在于 user_query_view
|
// 注意:优先从 referrals 获取 accountSequences,因为用户可能不存在于 user_query_view
|
||||||
const referralAccountSequences = referrals.map(r => r.accountSequence);
|
const referralAccountSequences = referrals.map(r => r.accountSequence);
|
||||||
const [adoptionCounts, directReferralCounts, teamStats] = await Promise.all([
|
const [adoptionCounts, directReferralCounts, teamStats] = await Promise.all([
|
||||||
// 统计每个用户的认种订单数量(状态为 MINING_ENABLED)
|
// 统计每个用户的认种棵数(状态为 MINING_ENABLED)
|
||||||
|
// 注意:使用 _sum.treeCount 而非 _count.id,因为一笔订单可以认种多棵,
|
||||||
|
// 显示的是棵数(认种数量),不是订单条数。
|
||||||
this.prisma.plantingOrderQueryView.groupBy({
|
this.prisma.plantingOrderQueryView.groupBy({
|
||||||
by: ['accountSequence'],
|
by: ['accountSequence'],
|
||||||
where: {
|
where: {
|
||||||
accountSequence: { in: referralAccountSequences },
|
accountSequence: { in: referralAccountSequences },
|
||||||
status: 'MINING_ENABLED',
|
status: 'MINING_ENABLED',
|
||||||
},
|
},
|
||||||
_count: { id: true },
|
_sum: { treeCount: true },
|
||||||
}),
|
}),
|
||||||
// 统计每个用户的直推数量
|
// 统计每个用户的直推数量
|
||||||
this.prisma.referralQueryView.groupBy({
|
this.prisma.referralQueryView.groupBy({
|
||||||
|
|
@ -105,7 +107,7 @@ export class UserDetailQueryRepositoryImpl implements IUserDetailQueryRepository
|
||||||
this.getBatchUserStats(referralAccountSequences),
|
this.getBatchUserStats(referralAccountSequences),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const adoptionCountMap = new Map(adoptionCounts.map(a => [a.accountSequence, a._count.id]));
|
const adoptionCountMap = new Map(adoptionCounts.map(a => [a.accountSequence, a._sum.treeCount ?? 0]));
|
||||||
const directCountMap = new Map(
|
const directCountMap = new Map(
|
||||||
directReferralCounts
|
directReferralCounts
|
||||||
.filter(d => d.referrerId !== null)
|
.filter(d => d.referrerId !== null)
|
||||||
|
|
@ -169,14 +171,16 @@ export class UserDetailQueryRepositoryImpl implements IUserDetailQueryRepository
|
||||||
// 实时统计:获取每个用户的认种数量、团队认种量和直推数量
|
// 实时统计:获取每个用户的认种数量、团队认种量和直推数量
|
||||||
const userAccountSequences = directReferrals.map(r => r.accountSequence);
|
const userAccountSequences = directReferrals.map(r => r.accountSequence);
|
||||||
const [adoptionCounts, directReferralCounts, teamStats] = await Promise.all([
|
const [adoptionCounts, directReferralCounts, teamStats] = await Promise.all([
|
||||||
// 统计每个用户的认种订单数量(状态为 MINING_ENABLED)
|
// 统计每个用户的认种棵数(状态为 MINING_ENABLED)
|
||||||
|
// 注意:使用 _sum.treeCount 而非 _count.id,因为一笔订单可以认种多棵,
|
||||||
|
// 显示的是棵数(认种数量),不是订单条数。
|
||||||
this.prisma.plantingOrderQueryView.groupBy({
|
this.prisma.plantingOrderQueryView.groupBy({
|
||||||
by: ['accountSequence'],
|
by: ['accountSequence'],
|
||||||
where: {
|
where: {
|
||||||
accountSequence: { in: userAccountSequences },
|
accountSequence: { in: userAccountSequences },
|
||||||
status: 'MINING_ENABLED',
|
status: 'MINING_ENABLED',
|
||||||
},
|
},
|
||||||
_count: { id: true },
|
_sum: { treeCount: true },
|
||||||
}),
|
}),
|
||||||
// 统计每个用户的直推数量
|
// 统计每个用户的直推数量
|
||||||
this.prisma.referralQueryView.groupBy({
|
this.prisma.referralQueryView.groupBy({
|
||||||
|
|
@ -188,7 +192,7 @@ export class UserDetailQueryRepositoryImpl implements IUserDetailQueryRepository
|
||||||
this.getBatchUserStats(userAccountSequences),
|
this.getBatchUserStats(userAccountSequences),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const adoptionCountMap = new Map(adoptionCounts.map(a => [a.accountSequence, a._count.id]));
|
const adoptionCountMap = new Map(adoptionCounts.map(a => [a.accountSequence, a._sum.treeCount ?? 0]));
|
||||||
const directCountMap = new Map(
|
const directCountMap = new Map(
|
||||||
directReferralCounts
|
directReferralCounts
|
||||||
.filter(d => d.referrerId !== null)
|
.filter(d => d.referrerId !== null)
|
||||||
|
|
@ -528,15 +532,18 @@ export class UserDetailQueryRepositoryImpl implements IUserDetailQueryRepository
|
||||||
}
|
}
|
||||||
|
|
||||||
async getPersonalAdoptionCount(accountSequence: string): Promise<number> {
|
async getPersonalAdoptionCount(accountSequence: string): Promise<number> {
|
||||||
// 统计用户的认种订单数量(状态为 MINING_ENABLED)
|
// 统计用户的认种棵数(状态为 MINING_ENABLED)
|
||||||
const count = await this.prisma.plantingOrderQueryView.count({
|
// 注意:使用 aggregate._sum.treeCount 而非 count(),因为一笔订单可以认种多棵,
|
||||||
|
// 返回的是总棵数(认种数量),不是订单条数。
|
||||||
|
const result = await this.prisma.plantingOrderQueryView.aggregate({
|
||||||
where: {
|
where: {
|
||||||
accountSequence,
|
accountSequence,
|
||||||
status: 'MINING_ENABLED',
|
status: 'MINING_ENABLED',
|
||||||
},
|
},
|
||||||
|
_sum: { treeCount: true },
|
||||||
});
|
});
|
||||||
|
|
||||||
return count;
|
return result._sum.treeCount ?? 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getDirectReferralCount(accountSequence: string): Promise<number> {
|
async getDirectReferralCount(accountSequence: string): Promise<number> {
|
||||||
|
|
@ -578,17 +585,19 @@ export class UserDetailQueryRepositoryImpl implements IUserDetailQueryRepository
|
||||||
|
|
||||||
const teamAddressCount = teamMembers.length;
|
const teamAddressCount = teamMembers.length;
|
||||||
|
|
||||||
// 2. 获取团队认种量:汇总所有团队成员的有效认种订单数
|
// 2. 获取团队认种量:汇总所有团队成员的有效认种棵数
|
||||||
|
// 注意:使用 aggregate._sum.treeCount 而非 count(),因为一笔订单可以认种多棵。
|
||||||
let teamAdoptionCount = 0;
|
let teamAdoptionCount = 0;
|
||||||
if (teamMembers.length > 0) {
|
if (teamMembers.length > 0) {
|
||||||
const count = await this.prisma.plantingOrderQueryView.count({
|
const result = await this.prisma.plantingOrderQueryView.aggregate({
|
||||||
where: {
|
where: {
|
||||||
accountSequence: { in: teamMembers.map((m) => m.accountSequence) },
|
accountSequence: { in: teamMembers.map((m) => m.accountSequence) },
|
||||||
status: 'MINING_ENABLED',
|
status: 'MINING_ENABLED',
|
||||||
},
|
},
|
||||||
|
_sum: { treeCount: true },
|
||||||
});
|
});
|
||||||
|
|
||||||
teamAdoptionCount = count;
|
teamAdoptionCount = result._sum.treeCount ?? 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return { teamAddressCount, teamAdoptionCount };
|
return { teamAddressCount, teamAdoptionCount };
|
||||||
|
|
@ -611,17 +620,19 @@ export class UserDetailQueryRepositoryImpl implements IUserDetailQueryRepository
|
||||||
|
|
||||||
if (accountSequences.length === 0) return result;
|
if (accountSequences.length === 0) return result;
|
||||||
|
|
||||||
// 1. 批量获取个人认种量
|
// 1. 批量获取个人认种棵数
|
||||||
|
// 注意:使用 _sum.treeCount 而非 _count.id,因为一笔订单可以认种多棵,
|
||||||
|
// 显示的是棵数(认种数量),不是订单条数。
|
||||||
const personalAdoptionCounts = await this.prisma.plantingOrderQueryView.groupBy({
|
const personalAdoptionCounts = await this.prisma.plantingOrderQueryView.groupBy({
|
||||||
by: ['accountSequence'],
|
by: ['accountSequence'],
|
||||||
where: {
|
where: {
|
||||||
accountSequence: { in: accountSequences },
|
accountSequence: { in: accountSequences },
|
||||||
status: 'MINING_ENABLED',
|
status: 'MINING_ENABLED',
|
||||||
},
|
},
|
||||||
_count: { id: true },
|
_sum: { treeCount: true },
|
||||||
});
|
});
|
||||||
const personalAdoptionMap = new Map(
|
const personalAdoptionMap = new Map(
|
||||||
personalAdoptionCounts.map(p => [p.accountSequence, p._count.id])
|
personalAdoptionCounts.map(p => [p.accountSequence, p._sum.treeCount ?? 0])
|
||||||
);
|
);
|
||||||
|
|
||||||
// 2. 批量获取用户的省市信息(从认种订单中获取第一个订单的省市)
|
// 2. 批量获取用户的省市信息(从认种订单中获取第一个订单的省市)
|
||||||
|
|
@ -674,35 +685,41 @@ export class UserDetailQueryRepositoryImpl implements IUserDetailQueryRepository
|
||||||
if (teamMembers.length > 0) {
|
if (teamMembers.length > 0) {
|
||||||
const teamAccountSequences = teamMembers.map(m => m.accountSequence);
|
const teamAccountSequences = teamMembers.map(m => m.accountSequence);
|
||||||
|
|
||||||
// 团队总认种量
|
// 团队总认种棵数(使用 sum treeCount,不是 count orders)
|
||||||
teamAdoptionCount = await this.prisma.plantingOrderQueryView.count({
|
const teamResult = await this.prisma.plantingOrderQueryView.aggregate({
|
||||||
where: {
|
where: {
|
||||||
accountSequence: { in: teamAccountSequences },
|
accountSequence: { in: teamAccountSequences },
|
||||||
status: 'MINING_ENABLED',
|
status: 'MINING_ENABLED',
|
||||||
},
|
},
|
||||||
|
_sum: { treeCount: true },
|
||||||
});
|
});
|
||||||
|
teamAdoptionCount = teamResult._sum.treeCount ?? 0;
|
||||||
|
|
||||||
// 如果用户有省市信息,统计同省同市的认种量
|
// 如果用户有省市信息,统计同省同市的认种棵数
|
||||||
if (userLocation?.province) {
|
if (userLocation?.province) {
|
||||||
// 同省认种量
|
// 同省认种棵数
|
||||||
provinceAdoptionCount = await this.prisma.plantingOrderQueryView.count({
|
const provinceResult = await this.prisma.plantingOrderQueryView.aggregate({
|
||||||
where: {
|
where: {
|
||||||
accountSequence: { in: teamAccountSequences },
|
accountSequence: { in: teamAccountSequences },
|
||||||
status: 'MINING_ENABLED',
|
status: 'MINING_ENABLED',
|
||||||
selectedProvince: userLocation.province,
|
selectedProvince: userLocation.province,
|
||||||
},
|
},
|
||||||
|
_sum: { treeCount: true },
|
||||||
});
|
});
|
||||||
|
provinceAdoptionCount = provinceResult._sum.treeCount ?? 0;
|
||||||
|
|
||||||
// 同市认种量
|
// 同市认种棵数
|
||||||
if (userLocation.city) {
|
if (userLocation.city) {
|
||||||
cityAdoptionCount = await this.prisma.plantingOrderQueryView.count({
|
const cityResult = await this.prisma.plantingOrderQueryView.aggregate({
|
||||||
where: {
|
where: {
|
||||||
accountSequence: { in: teamAccountSequences },
|
accountSequence: { in: teamAccountSequences },
|
||||||
status: 'MINING_ENABLED',
|
status: 'MINING_ENABLED',
|
||||||
selectedProvince: userLocation.province,
|
selectedProvince: userLocation.province,
|
||||||
selectedCity: userLocation.city,
|
selectedCity: userLocation.city,
|
||||||
},
|
},
|
||||||
|
_sum: { treeCount: true },
|
||||||
});
|
});
|
||||||
|
cityAdoptionCount = cityResult._sum.treeCount ?? 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue