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>
450 lines
19 KiB
TypeScript
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>
|
|
)
|
|
}
|