feat(admin): 引荐关系树节点增加个人/团队预种份数展示
后端: - ReferralNodeDto 新增 selfPrePlantingPortions, teamPrePlantingPortions - user-detail.controller: getReferralTree 中并行调用 ReferralProxyService 批量获取所有节点的预种统计 (当前用户用 getPrePlantingStats,祖先+下级用 batchGetPrePlantingStats) 前端: - ReferralNode 类型新增两个预种字段 - 引荐关系树节点(祖先链 + 递归展开节点)在"本人认种/团队认种" 下方新增一行"个人预种: X份 / 团队预种: Y份" Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
eb425b0f92
commit
1621b75a47
|
|
@ -138,11 +138,12 @@ export class UserDetailController {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取引荐信息和实时统计
|
// 获取引荐信息和实时统计
|
||||||
const [referralInfo, personalAdoptionCount, directReferralCount, teamStats] = await Promise.all([
|
const [referralInfo, personalAdoptionCount, directReferralCount, teamStats, prePlantingStats] = await Promise.all([
|
||||||
this.userDetailRepository.getReferralInfo(accountSequence),
|
this.userDetailRepository.getReferralInfo(accountSequence),
|
||||||
this.userDetailRepository.getPersonalAdoptionCount(accountSequence),
|
this.userDetailRepository.getPersonalAdoptionCount(accountSequence),
|
||||||
this.userDetailRepository.getDirectReferralCount(accountSequence),
|
this.userDetailRepository.getDirectReferralCount(accountSequence),
|
||||||
this.userDetailRepository.getBatchUserStats([accountSequence]),
|
this.userDetailRepository.getBatchUserStats([accountSequence]),
|
||||||
|
this.referralProxyService.getPrePlantingStats(accountSequence),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const currentUserStats = teamStats.get(accountSequence);
|
const currentUserStats = teamStats.get(accountSequence);
|
||||||
|
|
@ -153,6 +154,8 @@ export class UserDetailController {
|
||||||
avatar: user.avatarUrl,
|
avatar: user.avatarUrl,
|
||||||
personalAdoptions: personalAdoptionCount,
|
personalAdoptions: personalAdoptionCount,
|
||||||
teamAdoptions: currentUserStats?.teamAdoptionCount || 0,
|
teamAdoptions: currentUserStats?.teamAdoptionCount || 0,
|
||||||
|
selfPrePlantingPortions: prePlantingStats.selfPrePlantingPortions,
|
||||||
|
teamPrePlantingPortions: prePlantingStats.teamPrePlantingPortions,
|
||||||
depth: referralInfo?.depth || 0,
|
depth: referralInfo?.depth || 0,
|
||||||
directReferralCount: directReferralCount,
|
directReferralCount: directReferralCount,
|
||||||
isCurrentUser: true,
|
isCurrentUser: true,
|
||||||
|
|
@ -161,34 +164,56 @@ export class UserDetailController {
|
||||||
let ancestors: ReferralNodeDto[] = [];
|
let ancestors: ReferralNodeDto[] = [];
|
||||||
let directReferrals: ReferralNodeDto[] = [];
|
let directReferrals: ReferralNodeDto[] = [];
|
||||||
|
|
||||||
|
// 收集所有需要查预种的 accountSequences
|
||||||
|
const allNodeSeqs: string[] = [];
|
||||||
|
|
||||||
// 向上查询
|
// 向上查询
|
||||||
|
let ancestorNodes: typeof ancestors extends (infer T)[] ? any[] : never = [];
|
||||||
if (query.direction === 'up' || query.direction === 'both') {
|
if (query.direction === 'up' || query.direction === 'both') {
|
||||||
const ancestorNodes = await this.userDetailRepository.getAncestors(
|
ancestorNodes = await this.userDetailRepository.getAncestors(
|
||||||
accountSequence,
|
accountSequence,
|
||||||
query.depth || 1,
|
query.depth || 1,
|
||||||
);
|
);
|
||||||
ancestors = ancestorNodes.map((node) => ({
|
allNodeSeqs.push(...ancestorNodes.map((n: any) => n.accountSequence));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 向下查询
|
||||||
|
let referralNodes: typeof directReferrals extends (infer T)[] ? any[] : never = [];
|
||||||
|
if (query.direction === 'down' || query.direction === 'both') {
|
||||||
|
referralNodes = await this.userDetailRepository.getDirectReferrals(accountSequence);
|
||||||
|
allNodeSeqs.push(...referralNodes.map((n: any) => n.accountSequence));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 批量获取所有节点的预种统计
|
||||||
|
const batchPrePlanting = allNodeSeqs.length > 0
|
||||||
|
? await this.referralProxyService.batchGetPrePlantingStats(allNodeSeqs)
|
||||||
|
: {};
|
||||||
|
|
||||||
|
if (ancestorNodes.length > 0) {
|
||||||
|
ancestors = ancestorNodes.map((node: any) => ({
|
||||||
accountSequence: node.accountSequence,
|
accountSequence: node.accountSequence,
|
||||||
userId: node.userId.toString(),
|
userId: node.userId.toString(),
|
||||||
nickname: node.nickname,
|
nickname: node.nickname,
|
||||||
avatar: node.avatarUrl,
|
avatar: node.avatarUrl,
|
||||||
personalAdoptions: node.personalAdoptionCount,
|
personalAdoptions: node.personalAdoptionCount,
|
||||||
teamAdoptions: node.teamAdoptionCount,
|
teamAdoptions: node.teamAdoptionCount,
|
||||||
|
selfPrePlantingPortions: batchPrePlanting[node.accountSequence]?.selfPrePlantingPortions ?? 0,
|
||||||
|
teamPrePlantingPortions: batchPrePlanting[node.accountSequence]?.teamPrePlantingPortions ?? 0,
|
||||||
depth: node.depth,
|
depth: node.depth,
|
||||||
directReferralCount: node.directReferralCount,
|
directReferralCount: node.directReferralCount,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 向下查询
|
if (referralNodes.length > 0) {
|
||||||
if (query.direction === 'down' || query.direction === 'both') {
|
directReferrals = referralNodes.map((node: any) => ({
|
||||||
const referralNodes = await this.userDetailRepository.getDirectReferrals(accountSequence);
|
|
||||||
directReferrals = referralNodes.map((node) => ({
|
|
||||||
accountSequence: node.accountSequence,
|
accountSequence: node.accountSequence,
|
||||||
userId: node.userId.toString(),
|
userId: node.userId.toString(),
|
||||||
nickname: node.nickname,
|
nickname: node.nickname,
|
||||||
avatar: node.avatarUrl,
|
avatar: node.avatarUrl,
|
||||||
personalAdoptions: node.personalAdoptionCount,
|
personalAdoptions: node.personalAdoptionCount,
|
||||||
teamAdoptions: node.teamAdoptionCount,
|
teamAdoptions: node.teamAdoptionCount,
|
||||||
|
selfPrePlantingPortions: batchPrePlanting[node.accountSequence]?.selfPrePlantingPortions ?? 0,
|
||||||
|
teamPrePlantingPortions: batchPrePlanting[node.accountSequence]?.teamPrePlantingPortions ?? 0,
|
||||||
depth: node.depth,
|
depth: node.depth,
|
||||||
directReferralCount: node.directReferralCount,
|
directReferralCount: node.directReferralCount,
|
||||||
}));
|
}));
|
||||||
|
|
|
||||||
|
|
@ -74,6 +74,8 @@ export class ReferralNodeDto {
|
||||||
avatar!: string | null;
|
avatar!: string | null;
|
||||||
personalAdoptions!: number;
|
personalAdoptions!: number;
|
||||||
teamAdoptions!: number; // 团队认种量
|
teamAdoptions!: number; // 团队认种量
|
||||||
|
selfPrePlantingPortions!: number; // 个人预种份数
|
||||||
|
teamPrePlantingPortions!: number; // 团队预种份数
|
||||||
depth!: number;
|
depth!: number;
|
||||||
directReferralCount!: number;
|
directReferralCount!: number;
|
||||||
isCurrentUser?: boolean;
|
isCurrentUser?: boolean;
|
||||||
|
|
|
||||||
|
|
@ -490,6 +490,9 @@ export default function UserDetailPage() {
|
||||||
<span className={styles.referralTree__nodeAdoptions}>
|
<span className={styles.referralTree__nodeAdoptions}>
|
||||||
本人认种: {formatNumber(ancestor.personalAdoptions)} / 团队认种: {formatNumber(ancestor.teamAdoptions)}
|
本人认种: {formatNumber(ancestor.personalAdoptions)} / 团队认种: {formatNumber(ancestor.teamAdoptions)}
|
||||||
</span>
|
</span>
|
||||||
|
<span className={styles.referralTree__nodeAdoptions}>
|
||||||
|
个人预种: {formatNumber(ancestor.selfPrePlantingPortions)}份 / 团队预种: {formatNumber(ancestor.teamPrePlantingPortions)}份
|
||||||
|
</span>
|
||||||
</button>
|
</button>
|
||||||
{index < referralTree.ancestors.length - 1 && (
|
{index < referralTree.ancestors.length - 1 && (
|
||||||
<div className={styles.referralTree__connector}>↓</div>
|
<div className={styles.referralTree__connector}>↓</div>
|
||||||
|
|
@ -1198,6 +1201,9 @@ function ReferralNodeItem({
|
||||||
<span className={styles.referralTree__nodeAdoptions}>
|
<span className={styles.referralTree__nodeAdoptions}>
|
||||||
本人认种: {formatNumber(node.personalAdoptions)} / 团队认种: {formatNumber(node.teamAdoptions)}
|
本人认种: {formatNumber(node.personalAdoptions)} / 团队认种: {formatNumber(node.teamAdoptions)}
|
||||||
</span>
|
</span>
|
||||||
|
<span className={styles.referralTree__nodeAdoptions}>
|
||||||
|
个人预种: {formatNumber(node.selfPrePlantingPortions)}份 / 团队预种: {formatNumber(node.teamPrePlantingPortions)}份
|
||||||
|
</span>
|
||||||
{node.directReferralCount > 0 && (
|
{node.directReferralCount > 0 && (
|
||||||
<span className={styles.referralTree__nodeCount}>
|
<span className={styles.referralTree__nodeCount}>
|
||||||
引荐: {formatNumber(node.directReferralCount)}
|
引荐: {formatNumber(node.directReferralCount)}
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,8 @@ export interface ReferralNode {
|
||||||
avatar: string | null;
|
avatar: string | null;
|
||||||
personalAdoptions: number;
|
personalAdoptions: number;
|
||||||
teamAdoptions: number; // 团队认种量
|
teamAdoptions: number; // 团队认种量
|
||||||
|
selfPrePlantingPortions: number; // 个人预种份数
|
||||||
|
teamPrePlantingPortions: number; // 团队预种份数
|
||||||
depth: number;
|
depth: number;
|
||||||
directReferralCount: number;
|
directReferralCount: number;
|
||||||
isCurrentUser?: boolean;
|
isCurrentUser?: boolean;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue