fix(mining): move progress endpoint to MiningController for correct Kong routing
- Add /api/v2/mining/progress endpoint in MiningController - Update frontend API to call /progress instead of /admin/mining/status - Kong routes /api/v2/mining/* with strip_path=false, so endpoint must be under /mining controller path Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
1aaf32cbb3
commit
1e33ab178d
|
|
@ -3,6 +3,7 @@ import { ApiTags, ApiOperation, ApiResponse, ApiParam, ApiQuery } from '@nestjs/
|
||||||
import { GetMiningAccountQuery } from '../../application/queries/get-mining-account.query';
|
import { GetMiningAccountQuery } from '../../application/queries/get-mining-account.query';
|
||||||
import { GetMiningStatsQuery } from '../../application/queries/get-mining-stats.query';
|
import { GetMiningStatsQuery } from '../../application/queries/get-mining-stats.query';
|
||||||
import { Public } from '../../shared/guards/jwt-auth.guard';
|
import { Public } from '../../shared/guards/jwt-auth.guard';
|
||||||
|
import { PrismaService } from '../../infrastructure/persistence/prisma/prisma.service';
|
||||||
|
|
||||||
@ApiTags('Mining')
|
@ApiTags('Mining')
|
||||||
@Controller('mining')
|
@Controller('mining')
|
||||||
|
|
@ -11,6 +12,7 @@ export class MiningController {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly getAccountQuery: GetMiningAccountQuery,
|
private readonly getAccountQuery: GetMiningAccountQuery,
|
||||||
private readonly getStatsQuery: GetMiningStatsQuery,
|
private readonly getStatsQuery: GetMiningStatsQuery,
|
||||||
|
private readonly prisma: PrismaService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@Get('stats')
|
@Get('stats')
|
||||||
|
|
@ -20,6 +22,72 @@ export class MiningController {
|
||||||
return this.getStatsQuery.execute();
|
return this.getStatsQuery.execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Get('progress')
|
||||||
|
@ApiOperation({ summary: '获取挖矿进度状态(类似销毁进度)' })
|
||||||
|
@ApiResponse({ status: 200, description: '挖矿进度状态' })
|
||||||
|
async getMiningProgress() {
|
||||||
|
const config = await this.prisma.miningConfig.findFirst();
|
||||||
|
if (!config) {
|
||||||
|
return {
|
||||||
|
totalDistributed: '0',
|
||||||
|
distributionPool: '0',
|
||||||
|
remainingDistribution: '0',
|
||||||
|
miningProgress: '0',
|
||||||
|
minuteDistribution: '0',
|
||||||
|
remainingMinutes: 0,
|
||||||
|
lastMiningMinute: null,
|
||||||
|
isActive: false,
|
||||||
|
currentEra: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询用户挖矿账户的总已挖数量
|
||||||
|
const userMiningStats = await this.prisma.miningAccount.aggregate({
|
||||||
|
_sum: { totalMined: true },
|
||||||
|
});
|
||||||
|
|
||||||
|
// 查询系统账户的总已挖数量
|
||||||
|
const systemMiningStats = await this.prisma.systemMiningAccount.aggregate({
|
||||||
|
_sum: { totalMined: true },
|
||||||
|
});
|
||||||
|
|
||||||
|
// 总已分配 = 用户已挖 + 系统已挖
|
||||||
|
const totalDistributedDecimal =
|
||||||
|
Number(userMiningStats._sum.totalMined || 0) +
|
||||||
|
Number(systemMiningStats._sum.totalMined || 0);
|
||||||
|
|
||||||
|
// 查询最后分配时间
|
||||||
|
const lastMinuteStat = await this.prisma.minuteMiningStat.findFirst({
|
||||||
|
orderBy: { minute: 'desc' },
|
||||||
|
select: { minute: true },
|
||||||
|
});
|
||||||
|
|
||||||
|
// 计算每分钟分配量(每秒 × 60)
|
||||||
|
const secondDistribution = Number(config.secondDistribution || 0);
|
||||||
|
const minuteDistribution = secondDistribution * 60;
|
||||||
|
|
||||||
|
// 计算挖矿进度
|
||||||
|
const distributionPool = Number(config.distributionPool || 0);
|
||||||
|
const remainingDistribution = Number(config.remainingDistribution || 0);
|
||||||
|
const distributed = distributionPool - remainingDistribution;
|
||||||
|
const miningProgress = distributionPool > 0 ? (distributed / distributionPool) * 100 : 0;
|
||||||
|
|
||||||
|
// 计算剩余分钟数
|
||||||
|
const remainingMinutes = minuteDistribution > 0 ? Math.ceil(remainingDistribution / minuteDistribution) : 0;
|
||||||
|
|
||||||
|
return {
|
||||||
|
totalDistributed: totalDistributedDecimal.toFixed(8),
|
||||||
|
distributionPool: distributionPool.toFixed(8),
|
||||||
|
remainingDistribution: remainingDistribution.toFixed(8),
|
||||||
|
miningProgress: miningProgress.toFixed(4),
|
||||||
|
minuteDistribution: minuteDistribution.toFixed(8),
|
||||||
|
remainingMinutes,
|
||||||
|
lastMiningMinute: lastMinuteStat?.minute || null,
|
||||||
|
isActive: config.isActive,
|
||||||
|
currentEra: config.currentEra,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
@Get('ranking')
|
@Get('ranking')
|
||||||
@ApiOperation({ summary: '获取挖矿排行榜' })
|
@ApiOperation({ summary: '获取挖矿排行榜' })
|
||||||
@ApiQuery({ name: 'limit', required: false, description: '返回数量限制', type: Number })
|
@ApiQuery({ name: 'limit', required: false, description: '返回数量限制', type: Number })
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
|
||||||
// Mining API 需要独立的 baseURL,因为它走不同的路由
|
// Mining Service API 客户端
|
||||||
// 生产环境: 通过 Next.js rewrite /api/mining/* -> Kong -> mining-service
|
// 生产环境: /api/mining/* -> Kong /api/v2/mining/* -> mining-service /api/v2/*
|
||||||
// 开发环境: 通过 Next.js rewrite /api/mining/* -> mining-service
|
// 开发环境: /api/mining/* -> mining-service /api/v2/*
|
||||||
|
// 注意: Kong 的路由是 /api/v2/mining/* 映射到 mining-service 的 /api/v2/*
|
||||||
|
// 所以前端调用 /api/mining/admin/mining/status 会被转发到 mining-service 的 /api/v2/admin/mining/status
|
||||||
const miningBaseURL = '/api/mining';
|
const miningBaseURL = '/api/mining';
|
||||||
|
|
||||||
const miningClient = axios.create({
|
const miningClient = axios.create({
|
||||||
|
|
@ -52,7 +54,7 @@ export interface MiningStatus {
|
||||||
export const miningApi = {
|
export const miningApi = {
|
||||||
// 获取挖矿进度状态
|
// 获取挖矿进度状态
|
||||||
getMiningStatus: async (): Promise<MiningStatus> => {
|
getMiningStatus: async (): Promise<MiningStatus> => {
|
||||||
const response = await miningClient.get('/admin/mining/status');
|
const response = await miningClient.get('/progress');
|
||||||
// 后端返回 { success, data, timestamp }
|
// 后端返回 { success, data, timestamp }
|
||||||
return response.data.data || response.data;
|
return response.data.data || response.data;
|
||||||
},
|
},
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue