feat(mining-admin-web): update contribution records display to match backend API
- Update ContributionRecord type to match backend response fields (sourceType, baseContribution, distributionRate, etc.) - Update contribution-records-list component with improved UI showing source type badges, user info, tree count, and expiry status Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
dbe9ab223f
commit
04fd7b946a
|
|
@ -3,22 +3,26 @@
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { useContributionRecords } from '../hooks/use-users';
|
import { useContributionRecords } from '../hooks/use-users';
|
||||||
import { formatDecimal, formatPercent } from '@/lib/utils/format';
|
import { formatDecimal, formatPercent } from '@/lib/utils/format';
|
||||||
import { formatDateTime } from '@/lib/utils/date';
|
import { formatDateTime, formatDate } from '@/lib/utils/date';
|
||||||
import { Card, CardContent } from '@/components/ui/card';
|
import { Card, CardContent } from '@/components/ui/card';
|
||||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table';
|
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { Skeleton } from '@/components/ui/skeleton';
|
import { Skeleton } from '@/components/ui/skeleton';
|
||||||
|
import { Badge } from '@/components/ui/badge';
|
||||||
import { ChevronLeft, ChevronRight } from 'lucide-react';
|
import { ChevronLeft, ChevronRight } from 'lucide-react';
|
||||||
|
|
||||||
const contributionTypeLabels: Record<string, string> = {
|
const sourceTypeLabels: Record<string, string> = {
|
||||||
PERSONAL: '个人',
|
PERSONAL: '个人认种',
|
||||||
SYSTEM_OPERATION: '系统运营',
|
|
||||||
SYSTEM_PROVINCE: '系统省级',
|
|
||||||
SYSTEM_CITY: '系统市级',
|
|
||||||
TEAM_LEVEL: '团队层级',
|
TEAM_LEVEL: '团队层级',
|
||||||
TEAM_BONUS: '团队奖励',
|
TEAM_BONUS: '团队奖励',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const sourceTypeBadgeVariant: Record<string, 'default' | 'secondary' | 'outline'> = {
|
||||||
|
PERSONAL: 'default',
|
||||||
|
TEAM_LEVEL: 'secondary',
|
||||||
|
TEAM_BONUS: 'outline',
|
||||||
|
};
|
||||||
|
|
||||||
interface ContributionRecordsListProps {
|
interface ContributionRecordsListProps {
|
||||||
accountSequence: string;
|
accountSequence: string;
|
||||||
}
|
}
|
||||||
|
|
@ -35,20 +39,22 @@ export function ContributionRecordsList({ accountSequence }: ContributionRecords
|
||||||
<Table>
|
<Table>
|
||||||
<TableHeader>
|
<TableHeader>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableHead>来源账户</TableHead>
|
<TableHead>来源</TableHead>
|
||||||
<TableHead>类型</TableHead>
|
<TableHead>来源用户</TableHead>
|
||||||
<TableHead>分配类型</TableHead>
|
<TableHead className="text-right">棵数</TableHead>
|
||||||
<TableHead className="text-right">比例</TableHead>
|
<TableHead className="text-right">基础算力</TableHead>
|
||||||
<TableHead className="text-right">算力值</TableHead>
|
<TableHead className="text-right">分配比例</TableHead>
|
||||||
|
<TableHead className="text-right">获得算力</TableHead>
|
||||||
<TableHead>层级/等级</TableHead>
|
<TableHead>层级/等级</TableHead>
|
||||||
<TableHead>时间</TableHead>
|
<TableHead>生效日期</TableHead>
|
||||||
|
<TableHead>状态</TableHead>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHeader>
|
</TableHeader>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
[...Array(5)].map((_, i) => (
|
[...Array(5)].map((_, i) => (
|
||||||
<TableRow key={i}>
|
<TableRow key={i}>
|
||||||
{[...Array(7)].map((_, j) => (
|
{[...Array(9)].map((_, j) => (
|
||||||
<TableCell key={j}>
|
<TableCell key={j}>
|
||||||
<Skeleton className="h-4 w-full" />
|
<Skeleton className="h-4 w-full" />
|
||||||
</TableCell>
|
</TableCell>
|
||||||
|
|
@ -57,18 +63,34 @@ export function ContributionRecordsList({ accountSequence }: ContributionRecords
|
||||||
))
|
))
|
||||||
) : data?.items.length === 0 ? (
|
) : data?.items.length === 0 ? (
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell colSpan={7} className="text-center py-8 text-muted-foreground">
|
<TableCell colSpan={9} className="text-center py-8 text-muted-foreground">
|
||||||
暂无记录
|
暂无算力记录
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
) : (
|
) : (
|
||||||
data?.items.map((record) => (
|
data?.items.map((record) => (
|
||||||
<TableRow key={record.id}>
|
<TableRow key={record.id} className={record.isExpired ? 'opacity-50' : ''}>
|
||||||
<TableCell className="font-mono">{record.sourceAccountSequence}</TableCell>
|
<TableCell>
|
||||||
<TableCell>{contributionTypeLabels[record.contributionType] || record.contributionType}</TableCell>
|
<Badge variant={sourceTypeBadgeVariant[record.sourceType] || 'default'}>
|
||||||
<TableCell>{record.distributionType === 'UPSTREAM' ? '上游' : '下游'}</TableCell>
|
{sourceTypeLabels[record.sourceType] || record.sourceType}
|
||||||
<TableCell className="text-right">{formatPercent(record.rate)}</TableCell>
|
</Badge>
|
||||||
<TableCell className="text-right font-mono">{formatDecimal(record.amount, 4)}</TableCell>
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
{record.sourceType === 'PERSONAL' ? (
|
||||||
|
<span className="text-muted-foreground">本人</span>
|
||||||
|
) : record.sourceUserInfo ? (
|
||||||
|
<div className="flex flex-col">
|
||||||
|
<span className="font-medium">{record.sourceUserInfo.nickname || record.sourceUserInfo.phone}</span>
|
||||||
|
<span className="text-xs text-muted-foreground font-mono">{record.sourceAccountSequence}</span>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<span className="font-mono text-sm">{record.sourceAccountSequence}</span>
|
||||||
|
)}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className="text-right">{record.treeCount}</TableCell>
|
||||||
|
<TableCell className="text-right font-mono">{formatDecimal(record.baseContribution, 2)}</TableCell>
|
||||||
|
<TableCell className="text-right">{formatPercent(record.distributionRate)}</TableCell>
|
||||||
|
<TableCell className="text-right font-mono font-medium">{formatDecimal(record.amount, 4)}</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
{record.levelDepth !== null
|
{record.levelDepth !== null
|
||||||
? `L${record.levelDepth}`
|
? `L${record.levelDepth}`
|
||||||
|
|
@ -76,7 +98,14 @@ export function ContributionRecordsList({ accountSequence }: ContributionRecords
|
||||||
? `T${record.bonusTier}`
|
? `T${record.bonusTier}`
|
||||||
: '-'}
|
: '-'}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell className="text-sm">{formatDateTime(record.createdAt)}</TableCell>
|
<TableCell className="text-sm">{formatDate(record.effectiveDate)}</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
{record.isExpired ? (
|
||||||
|
<Badge variant="destructive">已过期</Badge>
|
||||||
|
) : (
|
||||||
|
<Badge variant="secondary">有效</Badge>
|
||||||
|
)}
|
||||||
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
))
|
))
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -65,15 +65,21 @@ export interface ContributionBreakdown {
|
||||||
|
|
||||||
export interface ContributionRecord {
|
export interface ContributionRecord {
|
||||||
id: string;
|
id: string;
|
||||||
accountSequence: number;
|
sourceType: string; // PERSONAL, TEAM_LEVEL, TEAM_BONUS
|
||||||
sourceAccountSequence: number;
|
sourceAccountSequence: string;
|
||||||
adoptionId: string;
|
sourceUserInfo?: {
|
||||||
contributionType: string;
|
nickname: string | null;
|
||||||
distributionType: string;
|
phone: string;
|
||||||
amount: string;
|
} | null;
|
||||||
rate: string;
|
treeCount: number;
|
||||||
|
baseContribution: string;
|
||||||
|
distributionRate: string;
|
||||||
levelDepth: number | null;
|
levelDepth: number | null;
|
||||||
bonusTier: number | null;
|
bonusTier: number | null;
|
||||||
|
amount: string;
|
||||||
|
effectiveDate: string;
|
||||||
|
expireDate: string;
|
||||||
|
isExpired: boolean;
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue