153 lines
6.6 KiB
TypeScript
153 lines
6.6 KiB
TypeScript
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,
|
||
);
|
||
}
|
||
}
|