feat(mining-admin): add totalTrees, separate level/bonus pending display
- Add totalTrees field from syncedAdoption aggregate - Rename fields: networkLevelPending, networkBonusPending - Stats card: show level pending and bonus pending separately - Add new stats card for total trees count - Price overview: 2-row layout showing all contribution metrics Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
b310fde426
commit
12f8fa67fc
|
|
@ -30,10 +30,11 @@ export class DashboardController {
|
||||||
return {
|
return {
|
||||||
totalUsers: raw.users?.total || 0,
|
totalUsers: raw.users?.total || 0,
|
||||||
adoptedUsers: raw.users?.adopted || 0,
|
adoptedUsers: raw.users?.adopted || 0,
|
||||||
|
totalTrees: raw.contribution?.totalTrees || 0,
|
||||||
networkEffectiveContribution: raw.contribution?.effectiveContribution || '0',
|
networkEffectiveContribution: raw.contribution?.effectiveContribution || '0',
|
||||||
networkTotalContribution: raw.contribution?.totalContribution || '0',
|
networkTotalContribution: raw.contribution?.totalContribution || '0',
|
||||||
networkPendingContribution: raw.contribution?.teamLevelContribution || '0',
|
networkLevelPending: raw.contribution?.teamLevelContribution || '0',
|
||||||
networkBonusPendingContribution: raw.contribution?.teamBonusContribution || '0',
|
networkBonusPending: raw.contribution?.teamBonusContribution || '0',
|
||||||
totalDistributed: raw.mining?.totalMined || '0',
|
totalDistributed: raw.mining?.totalMined || '0',
|
||||||
totalBurned: raw.mining?.latestDailyStat?.totalBurned || '0',
|
totalBurned: raw.mining?.latestDailyStat?.totalBurned || '0',
|
||||||
circulationPool: raw.trading?.circulationPool?.totalShares || '0',
|
circulationPool: raw.trading?.circulationPool?.totalShares || '0',
|
||||||
|
|
|
||||||
|
|
@ -112,22 +112,26 @@ export class DashboardService {
|
||||||
* 获取算力统计
|
* 获取算力统计
|
||||||
*/
|
*/
|
||||||
private async getContributionStats() {
|
private async getContributionStats() {
|
||||||
const accounts = await this.prisma.syncedContributionAccount.aggregate({
|
const [accounts, systemContributions, adoptionStats] = await Promise.all([
|
||||||
_sum: {
|
this.prisma.syncedContributionAccount.aggregate({
|
||||||
totalContribution: true,
|
_sum: {
|
||||||
effectiveContribution: true,
|
totalContribution: true,
|
||||||
personalContribution: true,
|
effectiveContribution: true,
|
||||||
teamLevelContribution: true,
|
personalContribution: true,
|
||||||
teamBonusContribution: true,
|
teamLevelContribution: true,
|
||||||
},
|
teamBonusContribution: true,
|
||||||
_count: true,
|
},
|
||||||
});
|
_count: true,
|
||||||
|
}),
|
||||||
const systemContributions =
|
this.prisma.syncedSystemContribution.aggregate({
|
||||||
await this.prisma.syncedSystemContribution.aggregate({
|
|
||||||
_sum: { contributionBalance: true },
|
_sum: { contributionBalance: true },
|
||||||
_count: true,
|
_count: true,
|
||||||
});
|
}),
|
||||||
|
this.prisma.syncedAdoption.aggregate({
|
||||||
|
_sum: { treeCount: true },
|
||||||
|
_count: true,
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
totalAccounts: accounts._count,
|
totalAccounts: accounts._count,
|
||||||
|
|
@ -143,6 +147,8 @@ export class DashboardService {
|
||||||
systemAccounts: systemContributions._count,
|
systemAccounts: systemContributions._count,
|
||||||
systemContribution:
|
systemContribution:
|
||||||
systemContributions._sum.contributionBalance?.toString() || '0',
|
systemContributions._sum.contributionBalance?.toString() || '0',
|
||||||
|
totalAdoptions: adoptionStats._count,
|
||||||
|
totalTrees: adoptionStats._sum.treeCount || 0,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -44,30 +44,33 @@ export function PriceOverview() {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="mt-6 pt-6 border-t">
|
<div className="mt-6 pt-6 border-t">
|
||||||
<div className="grid grid-cols-4 gap-4 text-center">
|
<div className="grid grid-cols-3 gap-4 text-center">
|
||||||
<div>
|
|
||||||
<p className="text-xs text-muted-foreground">流通池</p>
|
|
||||||
<p className="text-sm font-medium">{formatCompactNumber(stats?.circulationPool)}</p>
|
|
||||||
</div>
|
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs text-muted-foreground">有效算力</p>
|
<p className="text-xs text-muted-foreground">有效算力</p>
|
||||||
<p className="text-sm font-medium">{formatCompactNumber(stats?.networkEffectiveContribution)}</p>
|
<p className="text-sm font-medium">{formatCompactNumber(stats?.networkEffectiveContribution)}</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs text-muted-foreground">待解锁</p>
|
<p className="text-xs text-muted-foreground">层级待解锁</p>
|
||||||
<p className="text-sm font-medium">
|
<p className="text-sm font-medium">{formatCompactNumber(stats?.networkLevelPending)}</p>
|
||||||
{formatCompactNumber(
|
</div>
|
||||||
String(
|
<div>
|
||||||
Number(stats?.networkPendingContribution || 0) +
|
<p className="text-xs text-muted-foreground">团队待解锁</p>
|
||||||
Number(stats?.networkBonusPendingContribution || 0)
|
<p className="text-sm font-medium">{formatCompactNumber(stats?.networkBonusPending)}</p>
|
||||||
)
|
</div>
|
||||||
)}
|
</div>
|
||||||
</p>
|
<div className="grid grid-cols-3 gap-4 text-center mt-4">
|
||||||
|
<div>
|
||||||
|
<p className="text-xs text-muted-foreground">认种树总数</p>
|
||||||
|
<p className="text-sm font-medium">{stats?.totalTrees?.toLocaleString() ?? '-'}</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs text-muted-foreground">认种用户</p>
|
<p className="text-xs text-muted-foreground">认种用户</p>
|
||||||
<p className="text-sm font-medium">{stats?.adoptedUsers?.toLocaleString() ?? '-'}</p>
|
<p className="text-sm font-medium">{stats?.adoptedUsers?.toLocaleString() ?? '-'}</p>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<p className="text-xs text-muted-foreground">流通池</p>
|
||||||
|
<p className="text-sm font-medium">{formatCompactNumber(stats?.circulationPool)}</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
|
|
|
||||||
|
|
@ -48,15 +48,16 @@ export function StatsCards() {
|
||||||
{
|
{
|
||||||
title: '全网算力',
|
title: '全网算力',
|
||||||
value: formatCompactNumber(stats?.networkEffectiveContribution),
|
value: formatCompactNumber(stats?.networkEffectiveContribution),
|
||||||
subValue: `待解锁: ${formatCompactNumber(
|
subValue: `层级待解锁: ${formatCompactNumber(stats?.networkLevelPending)} | 团队待解锁: ${formatCompactNumber(stats?.networkBonusPending)}`,
|
||||||
String(
|
|
||||||
Number(stats?.networkPendingContribution || 0) +
|
|
||||||
Number(stats?.networkBonusPendingContribution || 0)
|
|
||||||
)
|
|
||||||
)}`,
|
|
||||||
icon: Activity,
|
icon: Activity,
|
||||||
iconColor: 'text-blue-500',
|
iconColor: 'text-blue-500',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: '认种树总数',
|
||||||
|
value: formatNumber(stats?.totalTrees),
|
||||||
|
icon: Activity,
|
||||||
|
iconColor: 'text-emerald-500',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: '已分配积分股',
|
title: '已分配积分股',
|
||||||
value: formatCompactNumber(stats?.totalDistributed),
|
value: formatCompactNumber(stats?.totalDistributed),
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
export interface DashboardStats {
|
export interface DashboardStats {
|
||||||
totalUsers: number;
|
totalUsers: number;
|
||||||
adoptedUsers: number;
|
adoptedUsers: number;
|
||||||
|
totalTrees: number;
|
||||||
networkEffectiveContribution: string;
|
networkEffectiveContribution: string;
|
||||||
networkTotalContribution: string;
|
networkTotalContribution: string;
|
||||||
networkPendingContribution: string;
|
networkLevelPending: string;
|
||||||
networkBonusPendingContribution: string;
|
networkBonusPending: string;
|
||||||
totalDistributed: string;
|
totalDistributed: string;
|
||||||
totalBurned: string;
|
totalBurned: string;
|
||||||
circulationPool: string;
|
circulationPool: string;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue