rwadurian/backend/services/referral-service/src/api/controllers/internal-referral-chain.con...

254 lines
8.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { Controller, Get, Param, Logger, Inject, NotFoundException } from '@nestjs/common';
import { ApiTags, ApiOperation, ApiParam, ApiResponse } from '@nestjs/swagger';
import {
REFERRAL_RELATIONSHIP_REPOSITORY,
IReferralRelationshipRepository,
TEAM_STATISTICS_REPOSITORY,
ITeamStatisticsRepository,
} from '../../domain';
/**
* 内部推荐链API - 供其他微服务调用
* 无需JWT认证服务间内部通信
*/
@ApiTags('Internal Referral Chain API')
@Controller('internal/referral-chain')
export class InternalReferralChainController {
private readonly logger = new Logger(InternalReferralChainController.name);
constructor(
@Inject(REFERRAL_RELATIONSHIP_REPOSITORY)
private readonly referralRepo: IReferralRelationshipRepository,
@Inject(TEAM_STATISTICS_REPOSITORY)
private readonly teamStatsRepo: ITeamStatisticsRepository,
) {}
/**
* 获取用户的祖先链(从直接推荐人到根节点)
*/
@Get(':accountSequence')
@ApiOperation({ summary: '获取用户推荐链内部API' })
@ApiParam({ name: 'accountSequence', description: '账户序列号' })
@ApiResponse({
status: 200,
description: '推荐链数据',
schema: {
type: 'object',
properties: {
accountSequence: { type: 'string', description: '格式: D + YYMMDD + 5位序号' },
userId: { type: 'string' },
ancestorPath: {
type: 'array',
items: { type: 'string' },
description: '祖先链从直接推荐人到根节点的accountSequence列表',
},
referrerId: { type: 'string', nullable: true },
},
},
})
async getReferralChain(@Param('accountSequence') accountSequence: string) {
this.logger.debug(`[INTERNAL] getReferralChain: accountSequence=${accountSequence}`);
const relationship = await this.referralRepo.findByAccountSequence(accountSequence);
if (!relationship) {
this.logger.debug(`[INTERNAL] No referral found for accountSequence: ${accountSequence}`);
// 返回空的祖先链而不是抛出错误
return {
accountSequence: accountSequence,
userId: null,
ancestorPath: [],
referrerId: null,
};
}
// referralChain 存储的是 userId (bigint),需要转换为 accountSequence
// 因为 authorization-service 使用 accountSequence 来查询授权记录
const ancestorUserIds = relationship.referralChain;
const ancestorPath: string[] = [];
for (const ancestorUserId of ancestorUserIds) {
const ancestorRelationship = await this.referralRepo.findByUserId(ancestorUserId);
if (ancestorRelationship) {
ancestorPath.push(ancestorRelationship.accountSequence);
} else {
this.logger.warn(`[INTERNAL] Ancestor userId ${ancestorUserId} not found`);
}
}
this.logger.debug(`[INTERNAL] getReferralChain result: ${ancestorPath.length} ancestors`);
return {
accountSequence: relationship.accountSequence,
userId: relationship.userId.toString(),
ancestorPath,
referrerId: relationship.referrerId?.toString() ?? null,
};
}
/**
* 批量获取用户的祖先链
*/
@Get('batch/:accountSequences')
@ApiOperation({ summary: '批量获取用户推荐链内部API' })
@ApiParam({ name: 'accountSequences', description: '账户序列号列表,逗号分隔' })
@ApiResponse({
status: 200,
description: '批量推荐链数据',
})
async getBatchReferralChains(@Param('accountSequences') accountSequences: string) {
const sequences = accountSequences.split(',').map((s) => s.trim());
this.logger.debug(`[INTERNAL] getBatchReferralChains: ${sequences.length} accounts`);
const results: Record<string, { userId: string | null; ancestorPath: string[]; referrerId: string | null }> = {};
for (const seq of sequences) {
const relationship = await this.referralRepo.findByAccountSequence(seq);
if (relationship) {
// 转换 userId 为 accountSequence
const ancestorPath: string[] = [];
for (const ancestorUserId of relationship.referralChain) {
const ancestorRelationship = await this.referralRepo.findByUserId(ancestorUserId);
if (ancestorRelationship) {
ancestorPath.push(ancestorRelationship.accountSequence);
}
}
results[seq] = {
userId: relationship.userId.toString(),
ancestorPath,
referrerId: relationship.referrerId?.toString() ?? null,
};
} else {
results[seq] = {
userId: null,
ancestorPath: [],
referrerId: null,
};
}
}
return results;
}
/**
* 获取用户的团队成员下级用户的accountSequence列表
* 用于查找下级社区
*/
@Get(':accountSequence/team-members')
@ApiOperation({ summary: '获取团队成员accountSequence列表内部API' })
@ApiParam({ name: 'accountSequence', description: '账户序列号' })
@ApiResponse({
status: 200,
description: '团队成员列表',
schema: {
type: 'object',
properties: {
accountSequence: { type: 'string', description: '格式: D + YYMMDD + 5位序号' },
teamMembers: {
type: 'array',
items: { type: 'string' },
description: '团队成员accountSequence列表直接和间接下级',
},
},
},
})
async getTeamMembers(@Param('accountSequence') accountSequence: string) {
this.logger.debug(`[INTERNAL] getTeamMembers: accountSequence=${accountSequence}`);
const relationship = await this.referralRepo.findByAccountSequence(accountSequence);
if (!relationship) {
return {
accountSequence: accountSequence,
teamMembers: [],
};
}
// 获取所有直推用户
const directReferrals = await this.referralRepo.findDirectReferrals(relationship.userId);
// 递归获取所有下级成员的accountSequence
const teamMembers: string[] = [];
const queue = [...directReferrals];
while (queue.length > 0) {
const current = queue.shift()!;
teamMembers.push(current.accountSequence);
// 获取当前用户的直推
const subReferrals = await this.referralRepo.findDirectReferrals(current.userId);
queue.push(...subReferrals);
}
return {
accountSequence: accountSequence,
teamMembers,
};
}
/**
* 获取用户的完整团队统计内部API
* 用于用户详情页展示
*/
@Get(':accountSequence/profile-stats')
@ApiOperation({ summary: '获取用户团队统计内部API' })
@ApiParam({ name: 'accountSequence', description: '账户序列号' })
@ApiResponse({
status: 200,
description: '用户团队统计',
schema: {
type: 'object',
properties: {
accountSequence: { type: 'string' },
directReferralCount: { type: 'number', description: '直推人数' },
umbrellaUserCount: { type: 'number', description: '伞下用户数(团队总人数)' },
personalPlantingCount: { type: 'number', description: '个人认种数量' },
teamPlantingCount: { type: 'number', description: '团队认种数量' },
},
},
})
async getProfileStats(@Param('accountSequence') accountSequence: string) {
this.logger.debug(`[INTERNAL] getProfileStats: accountSequence=${accountSequence}`);
const relationship = await this.referralRepo.findByAccountSequence(accountSequence);
if (!relationship) {
return {
accountSequence: accountSequence,
directReferralCount: 0,
umbrellaUserCount: 0,
personalPlantingCount: 0,
teamPlantingCount: 0,
};
}
// 获取直推人数
const directReferrals = await this.referralRepo.findDirectReferrals(relationship.userId);
const directReferralCount = directReferrals.length;
// 获取伞下用户数(递归获取所有下级)
let umbrellaUserCount = 0;
const queue = [...directReferrals];
while (queue.length > 0) {
umbrellaUserCount++;
const current = queue.shift()!;
const subReferrals = await this.referralRepo.findDirectReferrals(current.userId);
queue.push(...subReferrals);
}
// 获取团队统计
const teamStats = await this.teamStatsRepo.findByUserId(relationship.userId);
const personalPlantingCount = teamStats?.personalPlantingCount ?? 0;
const teamPlantingCount = teamStats?.teamPlantingCount ?? 0;
return {
accountSequence: accountSequence,
directReferralCount,
umbrellaUserCount,
personalPlantingCount,
teamPlantingCount,
};
}
}