Files
users/components/data-integration/data-dashboard.tsx
v0 2408d50cb0 refactor: overhaul UI for streamlined user experience
Redesign navigation, home overview, user portrait, and valuation pages
with improved functionality and responsive design.

Co-authored-by: null <4804959+fnvtk@users.noreply.github.com>
2025-07-18 13:47:12 +00:00

450 lines
19 KiB
TypeScript

"use client"
import { useState } from "react"
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card"
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
import { Button } from "@/components/ui/button"
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
import { Badge } from "@/components/ui/badge"
import { ArrowUp, ArrowDown, Download, RefreshCw, Calendar } from "lucide-react"
import { getGrowthClass } from "@/lib/utils"
// 模拟图表组件
const LineChart = ({ data, title }: { data: any; title: string }) => (
<div className="w-full h-64 bg-muted/30 rounded-md flex items-center justify-center">
<div className="text-center">
<p className="text-muted-foreground">{title}</p>
<p className="text-sm text-muted-foreground"></p>
</div>
</div>
)
const BarChart = ({ data, title }: { data: any; title: string }) => (
<div className="w-full h-64 bg-muted/30 rounded-md flex items-center justify-center">
<div className="text-center">
<p className="text-muted-foreground">{title}</p>
<p className="text-sm text-muted-foreground"></p>
</div>
</div>
)
const PieChart = ({ data, title }: { data: any; title: string }) => (
<div className="w-full h-64 bg-muted/30 rounded-md flex items-center justify-center">
<div className="text-center">
<p className="text-muted-foreground">{title}</p>
<p className="text-sm text-muted-foreground"></p>
</div>
</div>
)
export function DataDashboard() {
const [timeRange, setTimeRange] = useState("7d")
const [activeTab, setActiveTab] = useState("overview")
// 模拟数据
const overviewData = {
totalUsers: 1245678,
userGrowth: 12.5,
totalDataSources: 8,
dataSourceGrowth: 33.3,
totalRecords: 45678921,
recordsGrowth: 8.7,
dataQuality: 92,
dataQualityGrowth: 3.2,
}
const dataSourceStats = [
{ name: "CRM系统", records: 12500000, growth: 5.2, quality: 95 },
{ name: "交易系统", records: 8750000, growth: 12.3, quality: 90 },
{ name: "行为分析平台", records: 15800000, growth: 8.7, quality: 88 },
{ name: "社交媒体", records: 4500000, growth: 15.2, quality: 85 },
{ name: "设备管理系统", records: 3200000, growth: -2.1, quality: 93 },
]
const dataQualityIssues = [
{ type: "缺失值", count: 12500, percentage: 0.027, severity: "medium" },
{ type: "格式错误", count: 8750, percentage: 0.019, severity: "high" },
{ type: "重复数据", count: 23800, percentage: 0.052, severity: "low" },
{ type: "异常值", count: 4500, percentage: 0.01, severity: "high" },
{ type: "不一致数据", count: 9200, percentage: 0.02, severity: "medium" },
]
const formatNumber = (num: number) => {
if (num >= 1000000) {
return (num / 1000000).toFixed(1) + "M"
} else if (num >= 1000) {
return (num / 1000).toFixed(1) + "K"
}
return num.toString()
}
const getSeverityBadge = (severity: string) => {
switch (severity) {
case "high":
return <Badge className="bg-red-100 text-red-800"></Badge>
case "medium":
return <Badge className="bg-yellow-100 text-yellow-800"></Badge>
case "low":
return <Badge className="bg-green-100 text-green-800"></Badge>
default:
return <Badge></Badge>
}
}
return (
<div className="space-y-4">
<div className="flex justify-between items-center">
<h2 className="text-2xl font-bold"></h2>
<div className="flex items-center gap-2">
<Select value={timeRange} onValueChange={setTimeRange}>
<SelectTrigger className="w-[180px]">
<Calendar className="mr-2 h-4 w-4" />
<SelectValue placeholder="选择时间范围" />
</SelectTrigger>
<SelectContent>
<SelectItem value="1d"></SelectItem>
<SelectItem value="7d">7</SelectItem>
<SelectItem value="30d">30</SelectItem>
<SelectItem value="90d">90</SelectItem>
<SelectItem value="1y">1</SelectItem>
<SelectItem value="custom"></SelectItem>
</SelectContent>
</Select>
<Button variant="outline" size="icon">
<RefreshCw className="h-4 w-4" />
</Button>
<Button variant="outline">
<Download className="mr-2 h-4 w-4" />
</Button>
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
<Card>
<CardContent className="p-6">
<div className="flex flex-col space-y-2">
<p className="text-sm text-muted-foreground"></p>
<div className="flex items-end justify-between">
<h3 className="text-2xl font-bold">{formatNumber(overviewData.totalUsers)}</h3>
<div className={`flex items-center ${getGrowthClass(overviewData.userGrowth)}`}>
{overviewData.userGrowth > 0 ? (
<ArrowUp className="h-4 w-4 mr-1" />
) : (
<ArrowDown className="h-4 w-4 mr-1" />
)}
<span>{Math.abs(overviewData.userGrowth)}%</span>
</div>
</div>
<p className="text-xs text-muted-foreground"></p>
</div>
</CardContent>
</Card>
<Card>
<CardContent className="p-6">
<div className="flex flex-col space-y-2">
<p className="text-sm text-muted-foreground"></p>
<div className="flex items-end justify-between">
<h3 className="text-2xl font-bold">{overviewData.totalDataSources}</h3>
<div className={`flex items-center ${getGrowthClass(overviewData.dataSourceGrowth)}`}>
{overviewData.dataSourceGrowth > 0 ? (
<ArrowUp className="h-4 w-4 mr-1" />
) : (
<ArrowDown className="h-4 w-4 mr-1" />
)}
<span>{Math.abs(overviewData.dataSourceGrowth)}%</span>
</div>
</div>
<p className="text-xs text-muted-foreground"></p>
</div>
</CardContent>
</Card>
<Card>
<CardContent className="p-6">
<div className="flex flex-col space-y-2">
<p className="text-sm text-muted-foreground"></p>
<div className="flex items-end justify-between">
<h3 className="text-2xl font-bold">{formatNumber(overviewData.totalRecords)}</h3>
<div className={`flex items-center ${getGrowthClass(overviewData.recordsGrowth)}`}>
{overviewData.recordsGrowth > 0 ? (
<ArrowUp className="h-4 w-4 mr-1" />
) : (
<ArrowDown className="h-4 w-4 mr-1" />
)}
<span>{Math.abs(overviewData.recordsGrowth)}%</span>
</div>
</div>
<p className="text-xs text-muted-foreground"></p>
</div>
</CardContent>
</Card>
<Card>
<CardContent className="p-6">
<div className="flex flex-col space-y-2">
<p className="text-sm text-muted-foreground"></p>
<div className="flex items-end justify-between">
<h3 className="text-2xl font-bold">{overviewData.dataQuality}/100</h3>
<div className={`flex items-center ${getGrowthClass(overviewData.dataQualityGrowth)}`}>
{overviewData.dataQualityGrowth > 0 ? (
<ArrowUp className="h-4 w-4 mr-1" />
) : (
<ArrowDown className="h-4 w-4 mr-1" />
)}
<span>{Math.abs(overviewData.dataQualityGrowth)}%</span>
</div>
</div>
<p className="text-xs text-muted-foreground"></p>
</div>
</CardContent>
</Card>
</div>
<Tabs value={activeTab} onValueChange={setActiveTab} className="space-y-4">
<TabsList>
<TabsTrigger value="overview"></TabsTrigger>
<TabsTrigger value="sources"></TabsTrigger>
<TabsTrigger value="quality"></TabsTrigger>
<TabsTrigger value="integration"></TabsTrigger>
</TabsList>
<TabsContent value="overview" className="space-y-4">
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<Card>
<CardHeader>
<CardTitle></CardTitle>
<CardDescription></CardDescription>
</CardHeader>
<CardContent>
<LineChart data={{}} title="用户数据增长趋势图" />
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle></CardTitle>
<CardDescription></CardDescription>
</CardHeader>
<CardContent>
<PieChart data={{}} title="数据源分布图" />
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle></CardTitle>
<CardDescription></CardDescription>
</CardHeader>
<CardContent>
<LineChart data={{}} title="数据质量趋势图" />
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle></CardTitle>
<CardDescription></CardDescription>
</CardHeader>
<CardContent>
<BarChart data={{}} title="数据整合进度图" />
</CardContent>
</Card>
</div>
</TabsContent>
<TabsContent value="sources" className="space-y-4">
<Card>
<CardHeader>
<CardTitle></CardTitle>
<CardDescription></CardDescription>
</CardHeader>
<CardContent>
<div className="rounded-md border">
<table className="min-w-full divide-y divide-border">
<thead>
<tr className="bg-muted/50">
<th className="px-4 py-3 text-left text-sm font-medium"></th>
<th className="px-4 py-3 text-left text-sm font-medium"></th>
<th className="px-4 py-3 text-left text-sm font-medium"></th>
<th className="px-4 py-3 text-left text-sm font-medium"></th>
</tr>
</thead>
<tbody className="divide-y divide-border">
{dataSourceStats.map((source, index) => (
<tr key={index}>
<td className="px-4 py-3 text-sm font-medium">{source.name}</td>
<td className="px-4 py-3 text-sm">{formatNumber(source.records)}</td>
<td className="px-4 py-3 text-sm">
<div className={`flex items-center ${getGrowthClass(source.growth)}`}>
{source.growth > 0 ? (
<ArrowUp className="h-4 w-4 mr-1" />
) : (
<ArrowDown className="h-4 w-4 mr-1" />
)}
<span>{Math.abs(source.growth)}%</span>
</div>
</td>
<td className="px-4 py-3 text-sm">{source.quality}/100</td>
</tr>
))}
</tbody>
</table>
</div>
</CardContent>
</Card>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<Card>
<CardHeader>
<CardTitle></CardTitle>
<CardDescription></CardDescription>
</CardHeader>
<CardContent>
<BarChart data={{}} title="数据源记录数对比图" />
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle></CardTitle>
<CardDescription></CardDescription>
</CardHeader>
<CardContent>
<BarChart data={{}} title="数据源质量对比图" />
</CardContent>
</Card>
</div>
</TabsContent>
<TabsContent value="quality" className="space-y-4">
<Card>
<CardHeader>
<CardTitle></CardTitle>
<CardDescription></CardDescription>
</CardHeader>
<CardContent>
<div className="rounded-md border">
<table className="min-w-full divide-y divide-border">
<thead>
<tr className="bg-muted/50">
<th className="px-4 py-3 text-left text-sm font-medium"></th>
<th className="px-4 py-3 text-left text-sm font-medium"></th>
<th className="px-4 py-3 text-left text-sm font-medium"></th>
<th className="px-4 py-3 text-left text-sm font-medium"></th>
</tr>
</thead>
<tbody className="divide-y divide-border">
{dataQualityIssues.map((issue, index) => (
<tr key={index}>
<td className="px-4 py-3 text-sm font-medium">{issue.type}</td>
<td className="px-4 py-3 text-sm">{formatNumber(issue.count)}</td>
<td className="px-4 py-3 text-sm">{(issue.percentage * 100).toFixed(2)}%</td>
<td className="px-4 py-3 text-sm">{getSeverityBadge(issue.severity)}</td>
</tr>
))}
</tbody>
</table>
</div>
</CardContent>
</Card>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<Card>
<CardHeader>
<CardTitle></CardTitle>
<CardDescription></CardDescription>
</CardHeader>
<CardContent>
<PieChart data={{}} title="数据质量问题分布图" />
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle></CardTitle>
<CardDescription></CardDescription>
</CardHeader>
<CardContent>
<LineChart data={{}} title="数据质量趋势图" />
</CardContent>
</Card>
</div>
</TabsContent>
<TabsContent value="integration" className="space-y-4">
<Card>
<CardHeader>
<CardTitle></CardTitle>
<CardDescription></CardDescription>
</CardHeader>
<CardContent>
<div className="space-y-4">
<div className="space-y-2">
<div className="flex justify-between items-center">
<span className="font-medium">ID整合率</span>
<span className="text-green-600 font-medium">95%</span>
</div>
<div className="w-full bg-gray-200 rounded-full h-2.5">
<div className="bg-green-600 h-2.5 rounded-full" style={{ width: "95%" }}></div>
</div>
</div>
<div className="space-y-2">
<div className="flex justify-between items-center">
<span className="font-medium"></span>
<span className="text-green-600 font-medium">87%</span>
</div>
<div className="w-full bg-gray-200 rounded-full h-2.5">
<div className="bg-green-600 h-2.5 rounded-full" style={{ width: "87%" }}></div>
</div>
</div>
<div className="space-y-2">
<div className="flex justify-between items-center">
<span className="font-medium"></span>
<span className="text-yellow-600 font-medium">72%</span>
</div>
<div className="w-full bg-gray-200 rounded-full h-2.5">
<div className="bg-yellow-600 h-2.5 rounded-full" style={{ width: "72%" }}></div>
</div>
</div>
<div className="space-y-2">
<div className="flex justify-between items-center">
<span className="font-medium">IMEI设备号整合率</span>
<span className="text-yellow-600 font-medium">68%</span>
</div>
<div className="w-full bg-gray-200 rounded-full h-2.5">
<div className="bg-yellow-600 h-2.5 rounded-full" style={{ width: "68%" }}></div>
</div>
</div>
<div className="space-y-2">
<div className="flex justify-between items-center">
<span className="font-medium"></span>
<span className="text-green-600 font-medium">82%</span>
</div>
<div className="w-full bg-gray-200 rounded-full h-2.5">
<div className="bg-green-600 h-2.5 rounded-full" style={{ width: "82%" }}></div>
</div>
</div>
</div>
</CardContent>
</Card>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<Card>
<CardHeader>
<CardTitle></CardTitle>
<CardDescription></CardDescription>
</CardHeader>
<CardContent>
<LineChart data={{}} title="数据整合趋势图" />
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle></CardTitle>
<CardDescription></CardDescription>
</CardHeader>
<CardContent>
<BarChart data={{}} title="标识符覆盖率图" />
</CardContent>
</Card>
</div>
</TabsContent>
</Tabs>
</div>
)
}