feat(referral): add personal/team planting counts to direct referral list
- Backend: batch query TeamStatistics to get each direct referral's personalPlantingCount and teamPlantingCount - Updated DTO and query interfaces with new fields - Frontend: parse and display "个人/团队" counts in profile page 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
e1017fff46
commit
68182fd0a3
|
|
@ -1,65 +1,30 @@
|
|||
{
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"Bash(__NEW_LINE__ echo \"=== Test /api/v1/referral/me (referral-service) ===\")",
|
||||
"Bash(git -C \"c:\\Users\\dong\\Desktop\\rwadurian\" push)",
|
||||
"Bash(__NEW_LINE__ echo \"=== Test /api/v1/authorizations/my (authorization-service on port 3002) ===\")",
|
||||
"Bash(__NEW_LINE__ echo \"=== Test /api/v1/authorizations/my (authorization-service on port 3009) ===\")",
|
||||
"Bash(backend/api-gateway/kong.yml )",
|
||||
"Bash(frontend/mobile-app/lib/core/constants/api_endpoints.dart )",
|
||||
"Bash(frontend/mobile-app/lib/core/di/injection_container.dart )",
|
||||
"Bash(frontend/mobile-app/lib/core/services/referral_service.dart )",
|
||||
"Bash(frontend/mobile-app/lib/core/services/authorization_service.dart )",
|
||||
"Bash(frontend/mobile-app/lib/features/profile/presentation/pages/profile_page.dart )",
|
||||
"Bash(backend/services/authorization-service/package.json )",
|
||||
"Bash(backend/services/authorization-service/package-lock.json )",
|
||||
"Bash(backend/services/authorization-service/src/shared/strategies/jwt.strategy.ts )",
|
||||
"Bash(backend/services/authorization-service/src/infrastructure/persistence/repositories/system-account.repository.impl.ts)",
|
||||
"Bash(DATABASE_URL=\"postgresql://rwauser:rwapass123@localhost:5432/rwa_authorization\" npx prisma migrate:*)",
|
||||
"Bash(backend/services/authorization-service/.gitignore )",
|
||||
"Bash(backend/services/authorization-service/prisma/migrations/00000000000000_init/migration.sql )",
|
||||
"Bash(git fetch:*)",
|
||||
"Bash(backend/services/blockchain-service/package.json )",
|
||||
"Bash(backend/services/blockchain-service/package-lock.json )",
|
||||
"Bash(backend/services/blockchain-service/src/api/api.module.ts )",
|
||||
"Bash(backend/services/blockchain-service/src/api/controllers/index.ts )",
|
||||
"Bash(backend/services/blockchain-service/src/api/controllers/deposit.controller.ts )",
|
||||
"Bash(backend/services/blockchain-service/src/shared/index.ts )",
|
||||
"Bash(backend/services/blockchain-service/src/shared/decorators/ )",
|
||||
"Bash(backend/services/blockchain-service/src/shared/guards/ )",
|
||||
"Bash(backend/services/blockchain-service/src/shared/strategies/ )",
|
||||
"Bash(backend/services/wallet-service/src/api/api.module.ts )",
|
||||
"Bash(backend/services/wallet-service/src/infrastructure/kafka/ )",
|
||||
"Bash(backend/services/wallet-service/src/application/event-handlers/ )",
|
||||
"Bash(backend/services/docker-compose.yml )",
|
||||
"Bash(frontend/mobile-app/lib/core/services/deposit_service.dart)",
|
||||
"Bash(backend/services/authorization-service/prisma/schema.prisma )",
|
||||
"Bash(backend/services/authorization-service/src/application/services/ )",
|
||||
"Bash(backend/services/authorization-service/src/domain/ )",
|
||||
"Bash(backend/services/authorization-service/src/infrastructure/persistence/repositories/ )",
|
||||
"Bash(backend/services/planting-service/src/application/services/planting-application.service.ts )",
|
||||
"Bash(backend/services/planting-service/src/domain/services/fund-allocation.service.ts )",
|
||||
"Bash(backend/services/planting-service/src/infrastructure/external/ )",
|
||||
"Bash(backend/services/planting-service/src/infrastructure/infrastructure.module.ts )",
|
||||
"Bash(backend/services/planting-service/src/infrastructure/persistence/prisma/prisma.service.ts )",
|
||||
"Bash(backend/services/planting-service/src/infrastructure/persistence/unit-of-work.ts )",
|
||||
"Bash(backend/services/referral-service/src/modules/api.module.ts )",
|
||||
"Bash(backend/services/reward-service/src/infrastructure/external/authorization-service/authorization-service.client.ts )",
|
||||
"Bash(backend/services/wallet-service/package.json )",
|
||||
"Bash(backend/services/wallet-service/prisma/schema.prisma )",
|
||||
"Bash(backend/services/wallet-service/src/)",
|
||||
"Bash(git status:*)",
|
||||
"Bash(git check-ignore:*)",
|
||||
"Bash(docker inspect:*)",
|
||||
"Bash(python -m json.tool:*)",
|
||||
"Bash(docker logs:*)",
|
||||
"Bash(curl:*)",
|
||||
"Bash(git -C \"c:\\Users\\dong\\Desktop\\rwadurian\" add frontend/mobile-app/lib/features/home/presentation/pages/home_shell_page.dart)",
|
||||
"Bash(git -C \"c:\\Users\\dong\\Desktop\\rwadurian\" commit -m \"$(cat <<''EOF''\nfix(mobile): change update check interval from 24h to 30-90s random\n\nAllows faster detection of urgent updates while preventing excessive\nAPI calls with random cooldown period.\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n)\")",
|
||||
"Bash(git -C \"c:\\Users\\dong\\Desktop\\rwadurian\" commit -m \"$(cat <<''EOF''\nfix(mobile): change update check interval to 90-300s random\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n)\")",
|
||||
"Bash(git -C \"c:/Users/dong/Desktop/rwadurian\" status --short backend/services/blockchain-service/)",
|
||||
"Bash(git -C \"c:/Users/dong/Desktop/rwadurian\" log --oneline -5)",
|
||||
"Bash(git -C \"c:/Users/dong/Desktop/rwadurian\" status backend/services/blockchain-service/)",
|
||||
"Bash(git -C \"c:/Users/dong/Desktop/rwadurian\" log --oneline --all -- backend/services/blockchain-service/src/api/controllers/deposit-repair.controller.ts)",
|
||||
"Bash(git -C \"c:/Users/dong/Desktop/rwadurian\" log --oneline origin/main -10)",
|
||||
"Bash(npx tsc:*)",
|
||||
"Bash(flutter analyze:*)",
|
||||
"Bash(git add:*)",
|
||||
"Bash(git commit:*)",
|
||||
"Bash(git push)",
|
||||
"Bash(cat:*)",
|
||||
"Bash(git revert:*)",
|
||||
"Bash(git stash:*)"
|
||||
"Bash(git push:*)",
|
||||
"Bash(echo:*)",
|
||||
"Bash(git -C \"c:\\Users\\dong\\Desktop\\rwadurian\" add frontend/mobile-app/lib/features/profile/presentation/pages/profile_page.dart)",
|
||||
"Bash(git -C \"c:\\Users\\dong\\Desktop\\rwadurian\" commit -m \"$(cat <<''EOF''\nfix(mobile): reduce direct referral list item spacing\n\n- Row gap: 8px → 4px\n- Vertical padding: 12px → 8px\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n)\")",
|
||||
"Bash(git -C \"c:\\Users\\dong\\Desktop\\rwadurian\" push)",
|
||||
"Bash(git checkout:*)",
|
||||
"Bash(find:*)",
|
||||
"Bash(docker exec:*)",
|
||||
"Bash(npx prisma migrate status)",
|
||||
"Bash(DATABASE_URL=\"postgresql://rwa_user:your_secure_password_here@localhost:5432/rwa_referral\" npx prisma migrate status:*)",
|
||||
"Bash(DATABASE_URL=\"postgresql://rwa_user:your_secure_password_here@localhost:5432/rwa_referral\" npx prisma migrate deploy:*)",
|
||||
"Bash(DATABASE_URL=\"postgresql://rwa_user:your_secure_password_here@localhost:5432/rwa_referral\" npx prisma migrate resolve:*)"
|
||||
],
|
||||
"deny": [],
|
||||
"ask": []
|
||||
|
|
|
|||
|
|
@ -90,8 +90,11 @@ export class DirectReferralResponseDto {
|
|||
@ApiProperty({ description: '推荐码' })
|
||||
referralCode: string;
|
||||
|
||||
@ApiProperty({ description: '个人认种量' })
|
||||
personalPlantingCount: number;
|
||||
|
||||
@ApiProperty({ description: '团队认种量' })
|
||||
teamCount: number;
|
||||
teamPlantingCount: number;
|
||||
|
||||
@ApiProperty({ description: '加入时间' })
|
||||
joinedAt: Date;
|
||||
|
|
|
|||
|
|
@ -10,7 +10,8 @@ export interface DirectReferralResult {
|
|||
userId: string;
|
||||
accountSequence: number; // 8位账户序列号,显示用
|
||||
referralCode: string;
|
||||
teamCount: number;
|
||||
personalPlantingCount: number; // 个人认种量
|
||||
teamPlantingCount: number; // 团队认种量
|
||||
joinedAt: Date;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -154,20 +154,36 @@ export class ReferralService {
|
|||
*/
|
||||
async getDirectReferrals(query: GetDirectReferralsQuery): Promise<DirectReferralsResult> {
|
||||
const relationships = await this.referralRepo.findDirectReferrals(query.userId);
|
||||
const teamStats = await this.teamStatsRepo.findByUserId(query.userId);
|
||||
const directStats = teamStats?.getDirectReferralStats() ?? new Map();
|
||||
|
||||
// 分页
|
||||
const total = relationships.length;
|
||||
const paginated = relationships.slice(query.offset, query.offset + query.limit);
|
||||
|
||||
const referrals = paginated.map((r) => ({
|
||||
userId: r.userId.toString(),
|
||||
accountSequence: r.accountSequence, // 8位账户序列号,用于前端显示
|
||||
referralCode: r.referralCode,
|
||||
teamCount: directStats.get(r.userId) ?? 0,
|
||||
joinedAt: r.createdAt,
|
||||
}));
|
||||
// 批量查询直推用户的认种统计
|
||||
const directUserIds = paginated.map((r) => r.userId);
|
||||
const directStatsMap = new Map<string, { personal: number; team: number }>();
|
||||
|
||||
if (directUserIds.length > 0) {
|
||||
const directStats = await this.teamStatsRepo.findByUserIds(directUserIds);
|
||||
for (const stats of directStats) {
|
||||
directStatsMap.set(stats.userId.toString(), {
|
||||
personal: stats.personalPlantingCount,
|
||||
team: stats.teamPlantingCount,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const referrals = paginated.map((r) => {
|
||||
const stats = directStatsMap.get(r.userId.toString());
|
||||
return {
|
||||
userId: r.userId.toString(),
|
||||
accountSequence: r.accountSequence,
|
||||
referralCode: r.referralCode,
|
||||
personalPlantingCount: stats?.personal ?? 0,
|
||||
teamPlantingCount: stats?.team ?? 0,
|
||||
joinedAt: r.createdAt,
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
referrals,
|
||||
|
|
|
|||
|
|
@ -46,7 +46,19 @@ export class TeamStatisticsRepository implements ITeamStatisticsRepository {
|
|||
|
||||
// 更新直推统计明细
|
||||
if (data.directReferrals && data.directReferrals.length > 0) {
|
||||
// 批量查询直推用户的 accountSequence
|
||||
const referralIds = data.directReferrals.map((dr) => dr.referralId);
|
||||
const referralRelations = await tx.referralRelationship.findMany({
|
||||
where: { userId: { in: referralIds } },
|
||||
select: { userId: true, accountSequence: true },
|
||||
});
|
||||
const sequenceMap = new Map<bigint, number>();
|
||||
for (const rel of referralRelations) {
|
||||
sequenceMap.set(rel.userId, rel.accountSequence);
|
||||
}
|
||||
|
||||
for (const dr of data.directReferrals) {
|
||||
const accountSequence = sequenceMap.get(dr.referralId) ?? Number(dr.referralId);
|
||||
await tx.directReferral.upsert({
|
||||
where: {
|
||||
uk_referrer_referral: {
|
||||
|
|
@ -61,7 +73,7 @@ export class TeamStatisticsRepository implements ITeamStatisticsRepository {
|
|||
create: {
|
||||
referrerId: data.userId,
|
||||
referralId: dr.referralId,
|
||||
referralSequence: dr.referralId,
|
||||
referralSequence: BigInt(accountSequence),
|
||||
teamPlantingCount: dr.teamCount,
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -54,14 +54,16 @@ class DirectReferralInfo {
|
|||
final String userId;
|
||||
final int accountSequence; // 8位账户序列号,用于显示
|
||||
final String referralCode;
|
||||
final int teamCount;
|
||||
final int personalPlantingCount; // 个人认种量
|
||||
final int teamPlantingCount; // 团队认种量
|
||||
final DateTime joinedAt;
|
||||
|
||||
DirectReferralInfo({
|
||||
required this.userId,
|
||||
required this.accountSequence,
|
||||
required this.referralCode,
|
||||
required this.teamCount,
|
||||
required this.personalPlantingCount,
|
||||
required this.teamPlantingCount,
|
||||
required this.joinedAt,
|
||||
});
|
||||
|
||||
|
|
@ -70,7 +72,8 @@ class DirectReferralInfo {
|
|||
userId: json['userId']?.toString() ?? '',
|
||||
accountSequence: json['accountSequence'] ?? 0,
|
||||
referralCode: json['referralCode'] ?? '',
|
||||
teamCount: json['teamCount'] ?? 0,
|
||||
personalPlantingCount: json['personalPlantingCount'] ?? 0,
|
||||
teamPlantingCount: json['teamPlantingCount'] ?? 0,
|
||||
joinedAt: json['joinedAt'] != null
|
||||
? DateTime.parse(json['joinedAt'])
|
||||
: DateTime.now(),
|
||||
|
|
|
|||
|
|
@ -268,8 +268,8 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
|
|||
// 转换直推列表格式
|
||||
_referrals = directReferrals.referrals.map((r) => <String, dynamic>{
|
||||
'serial': r.accountSequence, // 使用8位账户序列号显示
|
||||
'personal': 0, // API暂未返回个人认种量
|
||||
'team': r.teamCount,
|
||||
'personal': r.personalPlantingCount, // 个人认种量
|
||||
'team': r.teamPlantingCount, // 团队认种量
|
||||
}).toList();
|
||||
});
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue