136 lines
6.1 KiB
TypeScript
136 lines
6.1 KiB
TypeScript
"use client"
|
|
|
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
|
|
import { Badge } from "@/components/ui/badge"
|
|
import { Loader2, Database, CheckCircle2, AlertCircle } from "lucide-react"
|
|
import { Progress } from "@/components/ui/progress"
|
|
import type { DataCheckResponse, DataUpdateResponse, SearchResult } from "@/lib/types"
|
|
import { formatTimestamp } from "@/lib/formatters"
|
|
|
|
interface DataStatusDisplayProps {
|
|
company: SearchResult
|
|
dataSource: string
|
|
status: DataCheckResponse | null
|
|
updateStatus: DataUpdateResponse | null
|
|
loading: boolean
|
|
fetching: boolean
|
|
error: string
|
|
}
|
|
|
|
export function DataStatusDisplay({
|
|
company,
|
|
dataSource,
|
|
status,
|
|
updateStatus,
|
|
loading,
|
|
fetching,
|
|
error
|
|
}: DataStatusDisplayProps) {
|
|
|
|
if (loading) {
|
|
return (
|
|
<Card>
|
|
<CardContent className="pt-6 flex items-center justify-center">
|
|
<Loader2 className="h-6 w-6 animate-spin text-muted-foreground" />
|
|
</CardContent>
|
|
</Card>
|
|
)
|
|
}
|
|
|
|
// Determine if we should show fetching state
|
|
const isUpdating = fetching && updateStatus;
|
|
const progress = updateStatus?.progress_percentage || 0;
|
|
const message = updateStatus?.progress_message || (updateStatus?.status === "in_progress" ? "正在获取数据..." : "准备中...");
|
|
|
|
return (
|
|
<Card>
|
|
<CardHeader className="pb-3">
|
|
<div className="flex items-center justify-between">
|
|
<div className="flex items-center gap-2">
|
|
<Database className="h-5 w-5" />
|
|
<CardTitle>数据状态</CardTitle>
|
|
</div>
|
|
</div>
|
|
</CardHeader>
|
|
<CardContent className="space-y-4">
|
|
{error && (
|
|
<div className="flex items-center gap-2 text-sm text-destructive bg-destructive/10 p-3 rounded-md">
|
|
<AlertCircle className="h-4 w-4" />
|
|
<span>{error}</span>
|
|
</div>
|
|
)}
|
|
|
|
{/* 正在更新状态 */}
|
|
{isUpdating && (
|
|
<div className="space-y-4 p-4 bg-muted/50 rounded-lg border">
|
|
<div className="flex items-center justify-between">
|
|
<div className="flex items-center gap-2">
|
|
<Loader2 className="h-4 w-4 animate-spin text-primary" />
|
|
<span className="font-medium">
|
|
{message}
|
|
</span>
|
|
</div>
|
|
<span className="text-sm text-muted-foreground font-mono">{Math.round(progress)}%</span>
|
|
</div>
|
|
|
|
<Progress value={progress} className="h-2" />
|
|
|
|
{updateStatus?.fetched_tables && updateStatus.fetched_tables.length > 0 && (
|
|
<div className="text-xs text-muted-foreground mt-2">
|
|
已完成: {updateStatus.fetched_tables.map(t => t.replace('tushare_', '').replace('cn_', '')).join(", ")}
|
|
</div>
|
|
)}
|
|
</div>
|
|
)}
|
|
|
|
{/* 静态数据状态 (非更新时显示) */}
|
|
{!isUpdating && status?.has_data && status.last_update && (
|
|
<div className="space-y-2">
|
|
<div className="flex items-center gap-2 text-sm text-green-600 font-medium">
|
|
<CheckCircle2 className="h-4 w-4" />
|
|
<span>数据已就绪</span>
|
|
</div>
|
|
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 mt-2 p-3 bg-muted/30 rounded-md">
|
|
<div>
|
|
<span className="text-muted-foreground text-xs uppercase tracking-wider">最后更新</span>
|
|
<div className="font-mono text-sm mt-0.5">
|
|
{formatTimestamp(status.last_update.date)}
|
|
</div>
|
|
</div>
|
|
|
|
{status.last_update.data_start_date && status.last_update.data_end_date && (
|
|
<div>
|
|
<span className="text-muted-foreground text-xs uppercase tracking-wider">数据范围</span>
|
|
<div className="font-mono text-sm mt-0.5">
|
|
{status.last_update.data_start_date} <span className="text-muted-foreground">至</span> {status.last_update.data_end_date}
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
{status.last_update.table_counts && (
|
|
<div className="text-xs text-muted-foreground pt-2 flex flex-wrap gap-2">
|
|
{Object.entries(status.last_update.table_counts).map(([table, count]) => (
|
|
<Badge key={table} variant="secondary" className="font-normal">
|
|
{table.replace('tushare_', '').replace('cn_', '')}: {count}
|
|
</Badge>
|
|
))}
|
|
</div>
|
|
)}
|
|
</div>
|
|
)}
|
|
|
|
{/* 无数据状态 */}
|
|
{!isUpdating && !status?.has_data && !error && (
|
|
<div className="flex flex-col items-center justify-center py-8 text-center text-muted-foreground space-y-2">
|
|
<Database className="h-8 w-8 opacity-20" />
|
|
<p>暂无该数据源的数据</p>
|
|
<p className="text-xs">请点击右上角的"获取数据"按钮开始同步</p>
|
|
</div>
|
|
)}
|
|
</CardContent>
|
|
</Card>
|
|
)
|
|
}
|