import { Controller, Get, Post, HttpException, HttpStatus } from '@nestjs/common'; import { ApiTags, ApiOperation } from '@nestjs/swagger'; import { ConfigService } from '@nestjs/config'; import { PrismaService } from '../../infrastructure/persistence/prisma/prisma.service'; import { NetworkSyncService } from '../../application/services/network-sync.service'; import { Public } from '../../shared/guards/jwt-auth.guard'; @ApiTags('Admin') @Controller('admin') export class AdminController { constructor( private readonly prisma: PrismaService, private readonly networkSyncService: NetworkSyncService, private readonly configService: ConfigService, ) {} @Get('accounts/sync') @Public() @ApiOperation({ summary: '获取所有挖矿账户用于同步' }) async getAllAccountsForSync() { const accounts = await this.prisma.miningAccount.findMany({ select: { accountSequence: true, totalMined: true, availableBalance: true, frozenBalance: true, totalContribution: true, createdAt: true, updatedAt: true, }, }); return { accounts: accounts.map((acc) => ({ accountSequence: acc.accountSequence, totalMined: acc.totalMined.toString(), availableBalance: acc.availableBalance.toString(), frozenBalance: acc.frozenBalance.toString(), totalContribution: acc.totalContribution.toString(), createdAt: acc.createdAt, updatedAt: acc.updatedAt, })), total: accounts.length, }; } @Get('status') @Public() @ApiOperation({ summary: '获取挖矿系统状态' }) async getStatus() { const config = await this.prisma.miningConfig.findFirst(); const accountCount = await this.prisma.miningAccount.count(); // 用户有效算力 const userContribution = await this.prisma.miningAccount.aggregate({ _sum: { totalContribution: true }, }); // 系统账户算力 const systemContribution = await this.prisma.systemMiningAccount.aggregate({ _sum: { totalContribution: true }, }); // 待解锁算力 const pendingContribution = await this.prisma.pendingContributionMining.aggregate({ _sum: { amount: true }, where: { isExpired: false }, }); return { initialized: !!config, isActive: config?.isActive || false, activatedAt: config?.activatedAt, currentEra: config?.currentEra || 0, remainingDistribution: config?.remainingDistribution?.toString() || '0', secondDistribution: config?.secondDistribution?.toString() || '0', accountCount, // 用户有效算力 totalContribution: userContribution._sum.totalContribution?.toString() || '0', // 全网理论算力(从 contribution-service 同步) networkTotalContribution: config?.networkTotalContribution?.toString() || '0', totalTreeCount: config?.totalTreeCount || 0, contributionPerTree: config?.contributionPerTree?.toString() || '22617', networkLastSyncedAt: config?.networkLastSyncedAt, // 系统账户算力 systemContribution: systemContribution._sum.totalContribution?.toString() || '0', // 待解锁算力 pendingContribution: pendingContribution._sum.amount?.toString() || '0', }; } @Post('activate') @Public() @ApiOperation({ summary: '激活挖矿系统' }) async activate() { const config = await this.prisma.miningConfig.findFirst(); if (!config) { throw new HttpException('挖矿系统未初始化,请先运行 seed 脚本', HttpStatus.BAD_REQUEST); } if (config.isActive) { return { success: true, message: '挖矿系统已经处于激活状态' }; } await this.prisma.miningConfig.update({ where: { id: config.id }, data: { isActive: true, activatedAt: new Date(), }, }); return { success: true, message: '挖矿系统已激活' }; } @Post('deactivate') @Public() @ApiOperation({ summary: '停用挖矿系统' }) async deactivate() { const config = await this.prisma.miningConfig.findFirst(); if (!config) { throw new HttpException('挖矿系统未初始化', HttpStatus.BAD_REQUEST); } if (!config.isActive) { return { success: true, message: '挖矿系统已经处于停用状态' }; } await this.prisma.miningConfig.update({ where: { id: config.id }, data: { isActive: false, }, }); return { success: true, message: '挖矿系统已停用' }; } @Post('sync-network') @Public() @ApiOperation({ summary: '从 contribution-service 同步全网数据(系统账户、全网进度)' }) async syncNetwork() { const contributionServiceUrl = this.configService.get( 'CONTRIBUTION_SERVICE_URL', 'http://localhost:3020', ); return this.networkSyncService.syncFromContributionService(contributionServiceUrl); } @Get('system-accounts') @Public() @ApiOperation({ summary: '获取系统账户挖矿状态' }) async getSystemAccounts() { const accounts = await this.prisma.systemMiningAccount.findMany({ orderBy: { accountType: 'asc' }, }); return { accounts: accounts.map((acc) => ({ accountType: acc.accountType, name: acc.name, totalMined: acc.totalMined.toString(), availableBalance: acc.availableBalance.toString(), totalContribution: acc.totalContribution.toString(), lastSyncedAt: acc.lastSyncedAt, })), total: accounts.length, }; } }