125 lines
4.5 KiB
TypeScript
125 lines
4.5 KiB
TypeScript
import { Controller, Get, Query } from '@nestjs/common';
|
||
import {
|
||
ApiTags,
|
||
ApiOperation,
|
||
ApiBearerAuth,
|
||
ApiQuery,
|
||
} from '@nestjs/swagger';
|
||
import { DashboardService } from '../../application/services/dashboard.service';
|
||
|
||
@ApiTags('Dashboard')
|
||
@ApiBearerAuth()
|
||
@Controller('dashboard')
|
||
export class DashboardController {
|
||
constructor(private readonly dashboardService: DashboardService) {}
|
||
|
||
@Get()
|
||
@ApiOperation({ summary: '获取仪表盘统计数据' })
|
||
async getStats() {
|
||
const raw = await this.dashboardService.getDashboardStats();
|
||
|
||
// 计算24小时价格变化
|
||
let priceChange24h = 0;
|
||
if (raw.latestPrice) {
|
||
const open = parseFloat(raw.latestPrice.open) || 1;
|
||
const close = parseFloat(raw.latestPrice.close) || 1;
|
||
priceChange24h = (close - open) / open;
|
||
}
|
||
|
||
// 详细算力分解数据
|
||
const dc = raw.detailedContribution || {};
|
||
|
||
// 转换为前端期望的格式
|
||
return {
|
||
// 基础统计
|
||
totalUsers: raw.users?.total || 0,
|
||
adoptedUsers: raw.users?.adopted || 0,
|
||
totalTrees: raw.contribution?.totalTrees || 0,
|
||
networkEffectiveContribution: raw.contribution?.effectiveContribution || '0',
|
||
networkTotalContribution: raw.contribution?.totalContribution || '0',
|
||
networkLevelPending: dc.levelContribution?.pending || '0',
|
||
networkBonusPending: dc.bonusContribution?.pending || '0',
|
||
totalDistributed: raw.mining?.totalMined || '0',
|
||
totalBurned: raw.mining?.latestDailyStat?.totalBurned || '0',
|
||
circulationPool: raw.trading?.circulationPool?.totalShares || '0',
|
||
currentPrice: raw.latestPrice?.close || '1',
|
||
priceChange24h,
|
||
totalOrders: raw.trading?.totalAccounts || 0,
|
||
totalTrades: raw.trading?.totalAccounts || 0,
|
||
|
||
// ========== 详细算力分解 ==========
|
||
detailedContribution: {
|
||
totalTrees: dc.totalTrees || 0,
|
||
// 全网算力(理论值)= 总树数 * 22617
|
||
networkTotalTheory: dc.networkTotalTheory || '0',
|
||
// 个人算力(70%)
|
||
personalTheory: dc.personalTheory || '0',
|
||
personalActual: raw.contribution?.personalContribution || '0',
|
||
// 运营账户(12%)
|
||
operationTheory: dc.operationTheory || '0',
|
||
operationActual: dc.operationActual || '0',
|
||
// 省公司(1%)
|
||
provinceTheory: dc.provinceTheory || '0',
|
||
provinceActual: dc.provinceActual || '0',
|
||
// 市公司(2%)
|
||
cityTheory: dc.cityTheory || '0',
|
||
cityActual: dc.cityActual || '0',
|
||
|
||
// 层级算力(7.5%)
|
||
level: {
|
||
theory: dc.levelTheory || '0',
|
||
unlocked: dc.levelContribution?.unlocked || '0',
|
||
pending: dc.levelContribution?.pending || '0',
|
||
// 分档详情
|
||
tier1: dc.levelContribution?.byTier?.tier1 || { unlocked: '0', pending: '0' },
|
||
tier2: dc.levelContribution?.byTier?.tier2 || { unlocked: '0', pending: '0' },
|
||
tier3: dc.levelContribution?.byTier?.tier3 || { unlocked: '0', pending: '0' },
|
||
},
|
||
|
||
// 团队奖励算力(7.5%)
|
||
bonus: {
|
||
theory: dc.bonusTheory || '0',
|
||
unlocked: dc.bonusContribution?.unlocked || '0',
|
||
pending: dc.bonusContribution?.pending || '0',
|
||
// 分档详情
|
||
tier1: dc.bonusContribution?.byTier?.tier1 || { unlocked: '0', pending: '0' },
|
||
tier2: dc.bonusContribution?.byTier?.tier2 || { unlocked: '0', pending: '0' },
|
||
tier3: dc.bonusContribution?.byTier?.tier3 || { unlocked: '0', pending: '0' },
|
||
},
|
||
},
|
||
};
|
||
}
|
||
|
||
@Get('stats')
|
||
@ApiOperation({ summary: '获取仪表盘统计数据(别名)' })
|
||
async getStatsAlias() {
|
||
return this.getStats();
|
||
}
|
||
|
||
@Get('realtime')
|
||
@ApiOperation({ summary: '获取实时数据' })
|
||
async getRealtimeStats() {
|
||
const raw = await this.dashboardService.getRealtimeStats();
|
||
|
||
// 转换为前端期望的格式
|
||
return {
|
||
currentMinuteDistribution: raw.minuteDistribution || '0',
|
||
currentMinuteBurn: '0', // 暂无实时销毁数据
|
||
activeOrders: 0, // 暂无实时订单数据
|
||
pendingTrades: 0, // 暂无待处理交易数据
|
||
lastPriceUpdateAt: raw.timestamp,
|
||
};
|
||
}
|
||
|
||
@Get('reports')
|
||
@ApiOperation({ summary: '获取每日报表' })
|
||
@ApiQuery({ name: 'page', required: false, type: Number })
|
||
@ApiQuery({ name: 'pageSize', required: false, type: Number })
|
||
async getReports(
|
||
@Query('page') page?: number,
|
||
@Query('pageSize') pageSize?: number,
|
||
) {
|
||
return this.dashboardService.getReports(page ?? 1, pageSize ?? 30);
|
||
}
|
||
}
|