From 728728bee34b0688af0c146e684ed63147ce6665 Mon Sep 17 00:00:00 2001 From: hailin Date: Tue, 3 Mar 2026 22:29:32 -0800 Subject: [PATCH] =?UTF-8?q?fix(admin-service):=20=E4=B8=AA=E4=BA=BA/?= =?UTF-8?q?=E5=9B=A2=E9=98=9F=E8=AE=A4=E7=A7=8D=E6=95=B0=E9=87=8F=E6=94=B9?= =?UTF-8?q?=E4=B8=BA=E7=BB=9F=E8=AE=A1=E6=A3=B5=E6=95=B0=E8=80=8C=E9=9D=9E?= =?UTF-8?q?=E8=AE=A2=E5=8D=95=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 【问题】 getUserList 及推荐树节点中「个人认种」「团队认种」显示的是订单条数 (_count: { id }),而非实际认种棵数。一笔订单可认种多棵,导致多棵 合并下单的用户数量严重偏低。 【修复】 将以下方法中的所有 count(orders) 改为 sum(treeCount): - getPersonalAdoptionCount — 用户详情页个人认种数 - getTeamStats — 用户详情页团队认种数 - getBatchUserStats — 用户列表批量统计(个人/团队/省/市认种数) - getAncestors — 推荐树祖先节点认种数 - getDirectReferrals — 推荐树直推节点认种数 【影响范围】 仅影响 admin-web 管理后台的展示数据,不涉及业务逻辑和数据存储。 省市认种百分比计算基准同步修正(teamAdoptions 也改为棵数), 比例结果不变,但基数更准确。 Co-Authored-By: Claude Sonnet 4.6 --- .../user-detail-query.repository.impl.ts | 61 ++++++++++++------- 1 file changed, 39 insertions(+), 22 deletions(-) diff --git a/backend/services/admin-service/src/infrastructure/persistence/repositories/user-detail-query.repository.impl.ts b/backend/services/admin-service/src/infrastructure/persistence/repositories/user-detail-query.repository.impl.ts index 17e757fd..0bc44d61 100644 --- a/backend/services/admin-service/src/infrastructure/persistence/repositories/user-detail-query.repository.impl.ts +++ b/backend/services/admin-service/src/infrastructure/persistence/repositories/user-detail-query.repository.impl.ts @@ -86,14 +86,16 @@ export class UserDetailQueryRepositoryImpl implements IUserDetailQueryRepository // 注意:优先从 referrals 获取 accountSequences,因为用户可能不存在于 user_query_view const referralAccountSequences = referrals.map(r => r.accountSequence); const [adoptionCounts, directReferralCounts, teamStats] = await Promise.all([ - // 统计每个用户的认种订单数量(状态为 MINING_ENABLED) + // 统计每个用户的认种棵数(状态为 MINING_ENABLED) + // 注意:使用 _sum.treeCount 而非 _count.id,因为一笔订单可以认种多棵, + // 显示的是棵数(认种数量),不是订单条数。 this.prisma.plantingOrderQueryView.groupBy({ by: ['accountSequence'], where: { accountSequence: { in: referralAccountSequences }, status: 'MINING_ENABLED', }, - _count: { id: true }, + _sum: { treeCount: true }, }), // 统计每个用户的直推数量 this.prisma.referralQueryView.groupBy({ @@ -105,7 +107,7 @@ export class UserDetailQueryRepositoryImpl implements IUserDetailQueryRepository 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( directReferralCounts .filter(d => d.referrerId !== null) @@ -169,14 +171,16 @@ export class UserDetailQueryRepositoryImpl implements IUserDetailQueryRepository // 实时统计:获取每个用户的认种数量、团队认种量和直推数量 const userAccountSequences = directReferrals.map(r => r.accountSequence); const [adoptionCounts, directReferralCounts, teamStats] = await Promise.all([ - // 统计每个用户的认种订单数量(状态为 MINING_ENABLED) + // 统计每个用户的认种棵数(状态为 MINING_ENABLED) + // 注意:使用 _sum.treeCount 而非 _count.id,因为一笔订单可以认种多棵, + // 显示的是棵数(认种数量),不是订单条数。 this.prisma.plantingOrderQueryView.groupBy({ by: ['accountSequence'], where: { accountSequence: { in: userAccountSequences }, status: 'MINING_ENABLED', }, - _count: { id: true }, + _sum: { treeCount: true }, }), // 统计每个用户的直推数量 this.prisma.referralQueryView.groupBy({ @@ -188,7 +192,7 @@ export class UserDetailQueryRepositoryImpl implements IUserDetailQueryRepository 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( directReferralCounts .filter(d => d.referrerId !== null) @@ -528,15 +532,18 @@ export class UserDetailQueryRepositoryImpl implements IUserDetailQueryRepository } async getPersonalAdoptionCount(accountSequence: string): Promise { - // 统计用户的认种订单数量(状态为 MINING_ENABLED) - const count = await this.prisma.plantingOrderQueryView.count({ + // 统计用户的认种棵数(状态为 MINING_ENABLED) + // 注意:使用 aggregate._sum.treeCount 而非 count(),因为一笔订单可以认种多棵, + // 返回的是总棵数(认种数量),不是订单条数。 + const result = await this.prisma.plantingOrderQueryView.aggregate({ where: { accountSequence, status: 'MINING_ENABLED', }, + _sum: { treeCount: true }, }); - return count; + return result._sum.treeCount ?? 0; } async getDirectReferralCount(accountSequence: string): Promise { @@ -578,17 +585,19 @@ export class UserDetailQueryRepositoryImpl implements IUserDetailQueryRepository const teamAddressCount = teamMembers.length; - // 2. 获取团队认种量:汇总所有团队成员的有效认种订单数 + // 2. 获取团队认种量:汇总所有团队成员的有效认种棵数 + // 注意:使用 aggregate._sum.treeCount 而非 count(),因为一笔订单可以认种多棵。 let teamAdoptionCount = 0; if (teamMembers.length > 0) { - const count = await this.prisma.plantingOrderQueryView.count({ + const result = await this.prisma.plantingOrderQueryView.aggregate({ where: { accountSequence: { in: teamMembers.map((m) => m.accountSequence) }, status: 'MINING_ENABLED', }, + _sum: { treeCount: true }, }); - teamAdoptionCount = count; + teamAdoptionCount = result._sum.treeCount ?? 0; } return { teamAddressCount, teamAdoptionCount }; @@ -611,17 +620,19 @@ export class UserDetailQueryRepositoryImpl implements IUserDetailQueryRepository if (accountSequences.length === 0) return result; - // 1. 批量获取个人认种量 + // 1. 批量获取个人认种棵数 + // 注意:使用 _sum.treeCount 而非 _count.id,因为一笔订单可以认种多棵, + // 显示的是棵数(认种数量),不是订单条数。 const personalAdoptionCounts = await this.prisma.plantingOrderQueryView.groupBy({ by: ['accountSequence'], where: { accountSequence: { in: accountSequences }, status: 'MINING_ENABLED', }, - _count: { id: true }, + _sum: { treeCount: true }, }); const personalAdoptionMap = new Map( - personalAdoptionCounts.map(p => [p.accountSequence, p._count.id]) + personalAdoptionCounts.map(p => [p.accountSequence, p._sum.treeCount ?? 0]) ); // 2. 批量获取用户的省市信息(从认种订单中获取第一个订单的省市) @@ -674,35 +685,41 @@ export class UserDetailQueryRepositoryImpl implements IUserDetailQueryRepository if (teamMembers.length > 0) { const teamAccountSequences = teamMembers.map(m => m.accountSequence); - // 团队总认种量 - teamAdoptionCount = await this.prisma.plantingOrderQueryView.count({ + // 团队总认种棵数(使用 sum treeCount,不是 count orders) + const teamResult = await this.prisma.plantingOrderQueryView.aggregate({ where: { accountSequence: { in: teamAccountSequences }, status: 'MINING_ENABLED', }, + _sum: { treeCount: true }, }); + teamAdoptionCount = teamResult._sum.treeCount ?? 0; - // 如果用户有省市信息,统计同省同市的认种量 + // 如果用户有省市信息,统计同省同市的认种棵数 if (userLocation?.province) { - // 同省认种量 - provinceAdoptionCount = await this.prisma.plantingOrderQueryView.count({ + // 同省认种棵数 + const provinceResult = await this.prisma.plantingOrderQueryView.aggregate({ where: { accountSequence: { in: teamAccountSequences }, status: 'MINING_ENABLED', selectedProvince: userLocation.province, }, + _sum: { treeCount: true }, }); + provinceAdoptionCount = provinceResult._sum.treeCount ?? 0; - // 同市认种量 + // 同市认种棵数 if (userLocation.city) { - cityAdoptionCount = await this.prisma.plantingOrderQueryView.count({ + const cityResult = await this.prisma.plantingOrderQueryView.aggregate({ where: { accountSequence: { in: teamAccountSequences }, status: 'MINING_ENABLED', selectedProvince: userLocation.province, selectedCity: userLocation.city, }, + _sum: { treeCount: true }, }); + cityAdoptionCount = cityResult._sum.treeCount ?? 0; } } }