feat(mining-admin): 重构算力构成展示,添加解锁状态

- 后端添加 unlockedBonusTiers 字段同步
- 前端算力构成卡片展示层级解锁(L1-15)和团队奖励解锁(3档)状态
- 移除无用的系统运营/省级/市级字段

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
hailin 2026-01-12 04:59:51 -08:00
parent 4ca4fc9135
commit 180e5ad057
8 changed files with 131 additions and 29 deletions

View File

@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "synced_contribution_accounts" ADD COLUMN "unlockedBonusTiers" INTEGER NOT NULL DEFAULT 0;

View File

@ -191,6 +191,7 @@ model SyncedContributionAccount {
hasAdopted Boolean @default(false)
directReferralCount Int @default(0)
unlockedLevelDepth Int @default(0)
unlockedBonusTiers Int @default(0)
syncedAt DateTime @default(now())
updatedAt DateTime @updatedAt

View File

@ -174,6 +174,7 @@ export class InitializationService {
hasAdopted: account.hasAdopted || false,
directReferralCount: account.directReferralAdoptedCount || 0,
unlockedLevelDepth: account.unlockedLevelDepth || 0,
unlockedBonusTiers: account.unlockedBonusTiers || 0,
},
update: {
personalContribution: account.personalContribution,
@ -184,6 +185,7 @@ export class InitializationService {
hasAdopted: account.hasAdopted,
directReferralCount: account.directReferralAdoptedCount,
unlockedLevelDepth: account.unlockedLevelDepth,
unlockedBonusTiers: account.unlockedBonusTiers,
},
});
syncedCount++;

View File

@ -325,6 +325,9 @@ export class UsersService {
totalContribution: '0',
effectiveContribution: '0',
hasAdopted: false,
directReferralCount: 0,
unlockedLevelDepth: 0,
unlockedBonusTiers: 0,
},
records: [],
pagination: { page, pageSize, total: 0, totalPages: 0 },
@ -342,6 +345,7 @@ export class UsersService {
hasAdopted: contribution.hasAdopted,
directReferralCount: contribution.directReferralCount,
unlockedLevelDepth: contribution.unlockedLevelDepth,
unlockedBonusTiers: contribution.unlockedBonusTiers,
},
// 详细流水需要从 contribution-service 获取
records: [],
@ -883,6 +887,7 @@ export class UsersService {
hasAdopted: user.contributionAccount.hasAdopted,
directReferralCount: user.contributionAccount.directReferralCount,
unlockedLevelDepth: user.contributionAccount.unlockedLevelDepth,
unlockedBonusTiers: user.contributionAccount.unlockedBonusTiers,
}
: null,
mining: user.miningAccount

View File

@ -447,6 +447,7 @@ export class CdcSyncService implements OnModuleInit {
hasAdopted: payload.hasAdopted || false,
directReferralCount: payload.directReferralAdoptedCount || 0,
unlockedLevelDepth: payload.unlockedLevelDepth || 0,
unlockedBonusTiers: payload.unlockedBonusTiers || 0,
},
update: {
personalContribution: payload.personalContribution,
@ -457,6 +458,7 @@ export class CdcSyncService implements OnModuleInit {
hasAdopted: payload.hasAdopted,
directReferralCount: payload.directReferralAdoptedCount,
unlockedLevelDepth: payload.unlockedLevelDepth,
unlockedBonusTiers: payload.unlockedBonusTiers,
},
});
@ -496,6 +498,7 @@ export class CdcSyncService implements OnModuleInit {
hasAdopted: true, // 有算力计算说明已认种
directReferralCount: 0,
unlockedLevelDepth: 0,
unlockedBonusTiers: 0,
},
update: {
// 增量更新个人算力

View File

@ -175,35 +175,120 @@ export default function UserDetailPage() {
</CardTitle>
</CardHeader>
<CardContent className="space-y-3">
<div className="flex justify-between">
<span className="text-sm text-muted-foreground"></span>
<span className="font-mono">{formatDecimal(user?.contributions?.personal, 4)}</span>
<CardContent className="space-y-4">
{/* 个人算力 */}
<div className="flex justify-between items-center">
<span className="text-sm text-muted-foreground"> (70%)</span>
<span className="font-mono font-medium">{formatDecimal(user?.contributions?.personal, 4)}</span>
</div>
<div className="flex justify-between">
<span className="text-sm text-muted-foreground"></span>
<span className="font-mono">{formatDecimal(user?.contributions?.systemOperation, 4)}</span>
{/* 层级算力 */}
<div className="space-y-2">
<div className="flex justify-between items-center">
<span className="text-sm text-muted-foreground"> (7.5%)</span>
<span className="font-mono font-medium">{formatDecimal(user?.contributions?.teamLevel, 4)}</span>
</div>
<div className="pl-3 space-y-1 text-xs">
<div className="flex items-center gap-2">
{(user?.contributions?.unlockedLevelDepth ?? 0) >= 5 ? (
<span className="text-green-600"></span>
) : (
<span className="text-muted-foreground"></span>
)}
<span className={`${(user?.contributions?.unlockedLevelDepth ?? 0) >= 5 ? 'text-foreground' : 'text-muted-foreground'}`}>
L1-L5 {(user?.contributions?.unlockedLevelDepth ?? 0) >= 5 ? '已解锁' : '未解锁'}
</span>
<span className="text-muted-foreground">(1)</span>
</div>
<div className="flex items-center gap-2">
{(user?.contributions?.unlockedLevelDepth ?? 0) >= 10 ? (
<span className="text-green-600"></span>
) : (
<span className="text-muted-foreground"></span>
)}
<span className={`${(user?.contributions?.unlockedLevelDepth ?? 0) >= 10 ? 'text-foreground' : 'text-muted-foreground'}`}>
L6-L10 {(user?.contributions?.unlockedLevelDepth ?? 0) >= 10 ? '已解锁' : '未解锁'}
</span>
<span className="text-muted-foreground">(3)</span>
</div>
<div className="flex items-center gap-2">
{(user?.contributions?.unlockedLevelDepth ?? 0) >= 15 ? (
<span className="text-green-600"></span>
) : (
<span className="text-muted-foreground"></span>
)}
<span className={`${(user?.contributions?.unlockedLevelDepth ?? 0) >= 15 ? 'text-foreground' : 'text-muted-foreground'}`}>
L11-L15 {(user?.contributions?.unlockedLevelDepth ?? 0) >= 15 ? '已解锁' : '未解锁'}
</span>
<span className="text-muted-foreground">(5)</span>
</div>
</div>
</div>
<div className="flex justify-between">
<span className="text-sm text-muted-foreground"></span>
<span className="font-mono">{formatDecimal(user?.contributions?.systemProvince, 4)}</span>
</div>
<div className="flex justify-between">
<span className="text-sm text-muted-foreground"></span>
<span className="font-mono">{formatDecimal(user?.contributions?.systemCity, 4)}</span>
</div>
<div className="flex justify-between">
<span className="text-sm text-muted-foreground"></span>
<span className="font-mono">{formatDecimal(user?.contributions?.teamLevel, 4)}</span>
</div>
<div className="flex justify-between">
<span className="text-sm text-muted-foreground"></span>
<span className="font-mono">{formatDecimal(user?.contributions?.teamBonus, 4)}</span>
{/* 团队奖励 */}
<div className="space-y-2">
<div className="flex justify-between items-center">
<span className="text-sm text-muted-foreground"> (7.5%)</span>
<span className="font-mono font-medium">{formatDecimal(user?.contributions?.teamBonus, 4)}</span>
</div>
<div className="pl-3 space-y-1 text-xs">
<div className="flex items-center gap-2">
{(user?.contributions?.unlockedBonusTiers ?? 0) >= 1 ? (
<span className="text-green-600"></span>
) : (
<span className="text-muted-foreground"></span>
)}
<span className={`${(user?.contributions?.unlockedBonusTiers ?? 0) >= 1 ? 'text-foreground' : 'text-muted-foreground'}`}>
1 2.5% {(user?.contributions?.unlockedBonusTiers ?? 0) >= 1 ? '已解锁' : '未解锁'}
</span>
<span className="text-muted-foreground">()</span>
</div>
<div className="flex items-center gap-2">
{(user?.contributions?.unlockedBonusTiers ?? 0) >= 2 ? (
<span className="text-green-600"></span>
) : (
<span className="text-muted-foreground"></span>
)}
<span className={`${(user?.contributions?.unlockedBonusTiers ?? 0) >= 2 ? 'text-foreground' : 'text-muted-foreground'}`}>
2 2.5% {(user?.contributions?.unlockedBonusTiers ?? 0) >= 2 ? '已解锁' : '未解锁'}
</span>
<span className="text-muted-foreground">(2)</span>
</div>
<div className="flex items-center gap-2">
{(user?.contributions?.unlockedBonusTiers ?? 0) >= 3 ? (
<span className="text-green-600"></span>
) : (
<span className="text-muted-foreground"></span>
)}
<span className={`${(user?.contributions?.unlockedBonusTiers ?? 0) >= 3 ? 'text-foreground' : 'text-muted-foreground'}`}>
3 2.5% {(user?.contributions?.unlockedBonusTiers ?? 0) >= 3 ? '已解锁' : '未解锁'}
</span>
<span className="text-muted-foreground">(4)</span>
</div>
</div>
</div>
{/* 有效算力 */}
<div className="flex justify-between pt-3 border-t font-medium">
<span> ()</span>
<span className="font-mono text-primary text-lg">{formatDecimal(user?.effectiveContribution, 4)}</span>
</div>
{/* 解锁状态汇总 */}
<div className="pt-2 border-t text-xs text-muted-foreground">
<div className="flex justify-between">
<span></span>
<span className="font-mono">{user?.contributions?.directReferralCount ?? 0} </span>
</div>
<div className="flex justify-between">
<span></span>
<span className="font-mono">{user?.contributions?.unlockedLevelDepth ?? 0} / 15 </span>
</div>
<div className="flex justify-between">
<span></span>
<span className="font-mono">{user?.contributions?.unlockedBonusTiers ?? 0} / 3 </span>
</div>
</div>
</CardContent>
</Card>
</div>

View File

@ -54,15 +54,17 @@ function transformUserDetail(backendUser: any): UserDetail {
// 认种数据
personalAdoptions: backendUser.adoption?.personalAdoptionCount || 0,
teamAdoptions: backendUser.adoption?.teamAdoptions || 0,
// 算力明细
// 算力明细及解锁状态
contributions: {
personal: backendUser.contribution?.personalContribution || '0',
systemOperation: '0',
systemProvince: '0',
systemCity: '0',
teamLevel: backendUser.contribution?.teamLevelContribution || '0',
teamBonus: backendUser.contribution?.teamBonusContribution || '0',
total: backendUser.contribution?.totalContribution || '0',
// 解锁状态
hasAdopted: backendUser.contribution?.hasAdopted || false,
directReferralCount: backendUser.contribution?.directReferralCount || 0,
unlockedLevelDepth: backendUser.contribution?.unlockedLevelDepth || 0,
unlockedBonusTiers: backendUser.contribution?.unlockedBonusTiers || 0,
},
kycStatus: backendUser.kycStatus,
registeredAt: backendUser.createdAt,

View File

@ -53,12 +53,14 @@ export interface UserDetail extends UserOverview {
export interface ContributionBreakdown {
personal: string;
systemOperation: string;
systemProvince: string;
systemCity: string;
teamLevel: string;
teamBonus: string;
total: string;
// 解锁状态
hasAdopted: boolean;
directReferralCount: number;
unlockedLevelDepth: number; // 0, 5, 10, 15
unlockedBonusTiers: number; // 0, 1, 2, 3
}
export interface ContributionRecord {