rwadurian/backend/services/contribution-service/src/api/controllers/contribution.controller.ts

153 lines
6.6 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, Query, NotFoundException } from '@nestjs/common';
import { ApiTags, ApiOperation, ApiResponse, ApiParam, ApiQuery } from '@nestjs/swagger';
import { GetContributionAccountQuery } from '../../application/queries/get-contribution-account.query';
import { GetContributionStatsQuery } from '../../application/queries/get-contribution-stats.query';
import { GetContributionRankingQuery } from '../../application/queries/get-contribution-ranking.query';
import { GetPlantingLedgerQuery, PlantingLedgerDto } from '../../application/queries/get-planting-ledger.query';
import { GetTeamTreeQuery, DirectReferralsResponseDto, MyTeamInfoDto } from '../../application/queries/get-team-tree.query';
import {
ContributionAccountResponse,
ContributionRecordsResponse,
ActiveContributionResponse,
} from '../dto/response/contribution-account.response';
import { ContributionStatsResponse } from '../dto/response/contribution-stats.response';
import { ContributionRankingResponse, UserRankResponse } from '../dto/response/contribution-ranking.response';
import { GetContributionRecordsRequest } from '../dto/request/get-records.request';
import { Public } from '../../shared/guards/jwt-auth.guard';
@ApiTags('Contribution')
@Controller('contribution')
export class ContributionController {
constructor(
private readonly getAccountQuery: GetContributionAccountQuery,
private readonly getStatsQuery: GetContributionStatsQuery,
private readonly getRankingQuery: GetContributionRankingQuery,
private readonly getPlantingLedgerQuery: GetPlantingLedgerQuery,
private readonly getTeamTreeQuery: GetTeamTreeQuery,
) {}
@Get('stats')
@Public()
@ApiOperation({ summary: '获取算力统计数据' })
@ApiResponse({ status: 200, type: ContributionStatsResponse })
async getStats(): Promise<ContributionStatsResponse> {
return this.getStatsQuery.execute();
}
@Get('ranking')
@ApiOperation({ summary: '获取算力排行榜' })
@ApiResponse({ status: 200, type: ContributionRankingResponse })
async getRanking(@Query('limit') limit?: number): Promise<ContributionRankingResponse> {
const data = await this.getRankingQuery.execute(limit ?? 100);
return { data };
}
@Get('accounts/:accountSequence')
@ApiOperation({ summary: '获取账户算力信息' })
@ApiParam({ name: 'accountSequence', description: '账户序号' })
@ApiResponse({ status: 200, type: ContributionAccountResponse })
async getAccount(@Param('accountSequence') accountSequence: string): Promise<ContributionAccountResponse> {
// 始终返回 200通过 status 字段区分账户状态:
// - ACTIVE: 账户正常,有算力数据
// - INACTIVE: 用户存在但暂无认种记录
// - USER_NOT_FOUND: 账户不存在
return this.getAccountQuery.execute(accountSequence);
}
@Get('accounts/:accountSequence/records')
@ApiOperation({ summary: '获取账户算力明细记录' })
@ApiParam({ name: 'accountSequence', description: '账户序号' })
@ApiResponse({ status: 200, type: ContributionRecordsResponse })
async getRecords(
@Param('accountSequence') accountSequence: string,
@Query() query: GetContributionRecordsRequest,
): Promise<ContributionRecordsResponse> {
const result = await this.getAccountQuery.getRecords(accountSequence, {
sourceType: query.sourceType,
includeExpired: query.includeExpired,
page: query.page,
pageSize: query.pageSize,
});
return {
...result,
page: query.page ?? 1,
pageSize: query.pageSize ?? 50,
};
}
@Get('accounts/:accountSequence/active')
@ApiOperation({ summary: '获取账户活跃算力统计' })
@ApiParam({ name: 'accountSequence', description: '账户序号' })
@ApiResponse({ status: 200, type: ActiveContributionResponse })
@ApiResponse({ status: 404, description: '账户不存在' })
async getActiveContribution(@Param('accountSequence') accountSequence: string): Promise<ActiveContributionResponse> {
const result = await this.getAccountQuery.getActiveContribution(accountSequence);
if (!result) {
throw new NotFoundException(`Account ${accountSequence} not found`);
}
return result;
}
@Get('accounts/:accountSequence/rank')
@ApiOperation({ summary: '获取账户排名' })
@ApiParam({ name: 'accountSequence', description: '账户序号' })
@ApiResponse({ status: 200, type: UserRankResponse })
@ApiResponse({ status: 404, description: '账户不存在' })
async getUserRank(@Param('accountSequence') accountSequence: string): Promise<UserRankResponse> {
const result = await this.getRankingQuery.getUserRank(accountSequence);
if (!result) {
throw new NotFoundException(`Account ${accountSequence} not found`);
}
return result;
}
@Get('accounts/:accountSequence/planting-ledger')
@ApiOperation({ summary: '获取账户认种分类账' })
@ApiParam({ name: 'accountSequence', description: '账户序号' })
@ApiQuery({ name: 'page', required: false, type: Number, description: '页码' })
@ApiQuery({ name: 'pageSize', required: false, type: Number, description: '每页数量' })
@ApiResponse({ status: 200, description: '认种分类账' })
async getPlantingLedger(
@Param('accountSequence') accountSequence: string,
@Query('page') page?: number,
@Query('pageSize') pageSize?: number,
): Promise<PlantingLedgerDto> {
return this.getPlantingLedgerQuery.execute(
accountSequence,
page ?? 1,
pageSize ?? 20,
);
}
// ========== 团队树 API ==========
@Get('accounts/:accountSequence/team')
@ApiOperation({ summary: '获取账户团队信息' })
@ApiParam({ name: 'accountSequence', description: '账户序号' })
@ApiResponse({ status: 200, description: '团队信息' })
async getMyTeamInfo(
@Param('accountSequence') accountSequence: string,
): Promise<MyTeamInfoDto> {
return this.getTeamTreeQuery.getMyTeamInfo(accountSequence);
}
@Get('accounts/:accountSequence/team/direct-referrals')
@ApiOperation({ summary: '获取账户直推列表(用于伞下树懒加载)' })
@ApiParam({ name: 'accountSequence', description: '账户序号' })
@ApiQuery({ name: 'limit', required: false, type: Number, description: '每页数量' })
@ApiQuery({ name: 'offset', required: false, type: Number, description: '偏移量' })
@ApiResponse({ status: 200, description: '直推列表' })
async getDirectReferrals(
@Param('accountSequence') accountSequence: string,
@Query('limit') limit?: number,
@Query('offset') offset?: number,
): Promise<DirectReferralsResponseDto> {
return this.getTeamTreeQuery.getDirectReferrals(
accountSequence,
limit ?? 100,
offset ?? 0,
);
}
}