refactor: restructure navigation and module layout

Reorganize navigation and module structure based on new requirements.

Co-authored-by: null <4804959+fnvtk@users.noreply.github.com>
This commit is contained in:
v0
2026-01-31 04:32:36 +00:00
parent 22e725887a
commit b17b488f8e
105 changed files with 20530 additions and 3622 deletions

View File

@@ -1,280 +1,396 @@
"use client"
import { useState, useEffect } from "react"
import { Users, Database, Activity, DollarSign, TrendingUp, Search, ArrowUpRight, Zap } from "lucide-react"
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Badge } from "@/components/ui/badge"
import Link from "next/link"
import {
Users,
Database,
RefreshCw,
Activity,
Globe,
Brain,
Tags,
LineChart,
Line,
XAxis,
YAxis,
CartesianGrid,
Tooltip,
ResponsiveContainer,
PieChart,
Pie,
Cell,
} from "recharts"
Package,
ArrowUpRight,
Zap,
Target,
CheckCircle,
} from "lucide-react"
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { Button } from "@/components/ui/button"
import { Badge } from "@/components/ui/badge"
import { Progress } from "@/components/ui/progress"
import { useRouter } from "next/navigation"
import Link from "next/link"
// 模拟数据
const growthData = [
{ month: "1月", users: 3200, value: 420 },
{ month: "2月", users: 3800, value: 480 },
{ month: "3月", users: 4100, value: 520 },
{ month: "4月", users: 4600, value: 580 },
{ month: "5月", users: 5200, value: 650 },
{ month: "6月", users: 5800, value: 720 },
]
interface SystemMetrics {
dataTaskSuccessRate: number
tagCoverageRate: number
valuePredictionAccuracy: number
apiDailyCallGrowth: number
}
const valueDistribution = [
{ name: "S级", value: 5, color: "#8B5CF6" },
{ name: "A级", value: 15, color: "#3B82F6" },
{ name: "B级", value: 35, color: "#10B981" },
{ name: "C级", value: 30, color: "#F59E0B" },
{ name: "D级", value: 15, color: "#EF4444" },
]
interface DataFlowStats {
totalUsers: number
totalProjects: number
totalDataSources: number
totalTags: number
totalModels: number
totalApiCalls: number
}
const recentActivities = [
{ id: 1, user: "张伟", action: "完成首次购买", time: "2分钟前", type: "purchase" },
{ id: 2, user: "李娜", action: "升级为A级用户", time: "5分钟前", type: "upgrade" },
{ id: 3, user: "王芳", action: "触发流失预警", time: "8分钟前", type: "warning" },
{ id: 4, user: "刘洋", action: "完成问卷调查", time: "12分钟前", type: "survey" },
{ id: 5, user: "陈明", action: "加入VIP计划", time: "15分钟前", type: "vip" },
]
export default function HomePage() {
export default function OverviewPage() {
const router = useRouter()
const [searchQuery, setSearchQuery] = useState("")
const [currentTime, setCurrentTime] = useState(new Date())
const [isRefreshing, setIsRefreshing] = useState(false)
const [lastUpdate, setLastUpdate] = useState(new Date())
// 核心OKR指标 (按PRD定义)
const [metrics, setMetrics] = useState<SystemMetrics>({
dataTaskSuccessRate: 99.7,
tagCoverageRate: 82.3,
valuePredictionAccuracy: 87.5,
apiDailyCallGrowth: 32.8,
})
// 数据流统计
const [stats, setStats] = useState<DataFlowStats>({
totalUsers: 4028567890,
totalProjects: 1256,
totalDataSources: 28,
totalTags: 1892,
totalModels: 15,
totalApiCalls: 8956234,
})
// 实时数据流
const [dataFlows, setDataFlows] = useState([
{ source: "存客宝", type: "用户行为", count: 125680, status: "running" },
{ source: "触客宝", type: "互动数据", count: 89234, status: "running" },
{ source: "数智员工", type: "账号数据", count: 45678, status: "running" },
{ source: "外部API", type: "征信数据", count: 12890, status: "waiting" },
])
useEffect(() => {
const timer = setInterval(() => setCurrentTime(new Date()), 1000)
return () => clearInterval(timer)
const interval = setInterval(() => {
// 模拟实时数据更新
setStats((prev) => ({
...prev,
totalUsers: prev.totalUsers + Math.floor(Math.random() * 1000),
totalApiCalls: prev.totalApiCalls + Math.floor(Math.random() * 100),
}))
setDataFlows((prev) =>
prev.map((flow) => ({
...flow,
count: flow.count + Math.floor(Math.random() * 100),
})),
)
}, 3000)
return () => clearInterval(interval)
}, [])
const refreshData = async () => {
setIsRefreshing(true)
await new Promise((r) => setTimeout(r, 1000))
setLastUpdate(new Date())
setIsRefreshing(false)
}
const formatNumber = (num: number): string => {
if (num >= 1000000000) return `${(num / 1000000000).toFixed(2)}B`
if (num >= 1000000) return `${(num / 1000000).toFixed(1)}M`
if (num >= 1000) return `${(num / 1000).toFixed(1)}K`
return num.toString()
}
// 5大功能模块快捷入口按HTML文档重构
const modules = [
{
title: "数据接入",
icon: Database,
color: "text-blue-600",
bg: "bg-blue-100",
href: "/data-ingestion/sources",
desc: "数据源管理、清洗规则、任务调度、数据血缘",
stats: `${stats.totalDataSources}个数据源`,
},
{
title: "标签画像",
icon: Tags,
color: "text-green-600",
bg: "bg-green-100",
href: "/tag-portrait/tags",
desc: "标签体系、用户画像、人群圈选",
stats: `${stats.totalTags}个标签`,
},
{
title: "AI Agent",
icon: Brain,
color: "text-purple-600",
bg: "bg-purple-100",
href: "/ai-agent/chat",
desc: "智能对话、AI打标、AI清洗、自然语言查询",
stats: "5大AI能力",
},
{
title: "数据输出",
icon: Package,
color: "text-orange-600",
bg: "bg-orange-100",
href: "/data-output/packages",
desc: "流量包、API市场、数据订阅",
stats: `${formatNumber(stats.totalApiCalls)}次调用`,
},
{
title: "系统监控",
icon: LineChart,
color: "text-cyan-600",
bg: "bg-cyan-100",
href: "/system/health",
desc: "系统健康、告警中心、操作日志",
stats: "实时监控",
},
]
return (
<div className="flex-1 space-y-6 p-6 md:p-8">
{/* 顶部标题区 */}
<div className="flex flex-col md:flex-row md:items-center md:justify-between gap-4">
<div className="space-y-6 p-6">
{/* Header */}
<div className="flex flex-col md:flex-row md:items-center justify-between gap-4">
<div>
<h1 className="text-2xl md:text-3xl font-bold tracking-tight"></h1>
<p className="text-muted-foreground mt-1">
{currentTime.toLocaleDateString("zh-CN", { weekday: "long", year: "numeric", month: "long", day: "numeric" })}
{" · "}
{currentTime.toLocaleTimeString("zh-CN")}
</p>
<h1 className="text-3xl font-bold text-gray-900"></h1>
<p className="text-gray-500 mt-1"></p>
</div>
<div className="flex items-center gap-3">
<div className="relative w-full md:w-80">
<Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" />
<Input
placeholder="搜索用户、手机号、标签..."
className="pl-9"
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
/>
</div>
<Button>
<Zap className="mr-2 h-4 w-4" />
<Badge variant="outline" className="bg-green-50 text-green-600 border-green-200 px-3 py-1">
<Activity className="w-3 h-3 mr-1" />
</Badge>
<span className="text-xs text-gray-400"> {lastUpdate.toLocaleTimeString()}</span>
<Button variant="outline" size="sm" onClick={refreshData} disabled={isRefreshing} className="bg-white/50">
<RefreshCw className={`w-4 h-4 mr-2 ${isRefreshing ? "animate-spin" : ""}`} />
</Button>
</div>
</div>
{/* 核心指标卡片 */}
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4">
<Card className="bg-gradient-to-br from-violet-500/10 to-purple-500/10 border-violet-200 dark:border-violet-800">
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium"></CardTitle>
<Users className="h-4 w-4 text-violet-600" />
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">40.5亿</div>
<div className="flex items-center text-xs text-muted-foreground mt-1">
<TrendingUp className="h-3 w-3 text-green-500 mr-1" />
<span className="text-green-500">+20.1%</span>
<span className="ml-1"></span>
{/* 核心OKR指标 */}
<div className="grid grid-cols-2 lg:grid-cols-4 gap-4">
<Card className="border-none shadow-sm bg-white/60 backdrop-blur-sm">
<CardContent className="p-4">
<div className="flex items-center justify-between mb-2">
<span className="text-sm text-gray-500"></span>
<Badge className="bg-green-100 text-green-700 text-xs">99.5%</Badge>
</div>
<div className="text-3xl font-bold text-gray-900">{metrics.dataTaskSuccessRate}%</div>
<Progress value={metrics.dataTaskSuccessRate} className="h-2 mt-2" />
</CardContent>
</Card>
<Card className="bg-gradient-to-br from-blue-500/10 to-cyan-500/10 border-blue-200 dark:border-blue-800">
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium"></CardTitle>
<Activity className="h-4 w-4 text-blue-600" />
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">2,350</div>
<div className="flex items-center text-xs text-muted-foreground mt-1">
<TrendingUp className="h-3 w-3 text-green-500 mr-1" />
<span className="text-green-500">+18.2%</span>
<span className="ml-1"></span>
<Card className="border-none shadow-sm bg-white/60 backdrop-blur-sm">
<CardContent className="p-4">
<div className="flex items-center justify-between mb-2">
<span className="text-sm text-gray-500"></span>
<Badge className="bg-blue-100 text-blue-700 text-xs">80%</Badge>
</div>
<div className="text-3xl font-bold text-gray-900">{metrics.tagCoverageRate}%</div>
<Progress value={metrics.tagCoverageRate} className="h-2 mt-2" />
</CardContent>
</Card>
<Card className="bg-gradient-to-br from-emerald-500/10 to-green-500/10 border-emerald-200 dark:border-emerald-800">
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium"></CardTitle>
<Database className="h-4 w-4 text-emerald-600" />
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">125亿</div>
<div className="flex items-center text-xs text-muted-foreground mt-1">
<TrendingUp className="h-3 w-3 text-green-500 mr-1" />
<span className="text-green-500">+32.5%</span>
<span className="ml-1"></span>
<Card className="border-none shadow-sm bg-white/60 backdrop-blur-sm">
<CardContent className="p-4">
<div className="flex items-center justify-between mb-2">
<span className="text-sm text-gray-500"></span>
<Badge className="bg-purple-100 text-purple-700 text-xs">85%</Badge>
</div>
<div className="text-3xl font-bold text-gray-900">{metrics.valuePredictionAccuracy}%</div>
<Progress value={metrics.valuePredictionAccuracy} className="h-2 mt-2" />
</CardContent>
</Card>
<Card className="bg-gradient-to-br from-amber-500/10 to-orange-500/10 border-amber-200 dark:border-amber-800">
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium"></CardTitle>
<DollarSign className="h-4 w-4 text-amber-600" />
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">¥125.8亿</div>
<div className="flex items-center text-xs text-muted-foreground mt-1">
<TrendingUp className="h-3 w-3 text-green-500 mr-1" />
<span className="text-green-500">+45.2%</span>
<span className="ml-1"></span>
<Card className="border-none shadow-sm bg-white/60 backdrop-blur-sm">
<CardContent className="p-4">
<div className="flex items-center justify-between mb-2">
<span className="text-sm text-gray-500">API调用增长</span>
<Badge className="bg-orange-100 text-orange-700 text-xs">30%QoQ</Badge>
</div>
<div className="text-3xl font-bold text-gray-900">+{metrics.apiDailyCallGrowth}%</div>
<Progress value={metrics.apiDailyCallGrowth} className="h-2 mt-2" />
</CardContent>
</Card>
</div>
{/* 图表区域 */}
<div className="grid gap-4 md:grid-cols-7">
<Card className="col-span-4">
<CardHeader>
<CardTitle></CardTitle>
<CardDescription>6</CardDescription>
{/* 用户资产总览 */}
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
<Card className="lg:col-span-2 border-none shadow-lg bg-gradient-to-br from-blue-500 to-indigo-600 text-white overflow-hidden relative">
<div className="absolute top-0 right-0 w-64 h-64 bg-white/10 rounded-full -mr-16 -mt-16 blur-3xl" />
<CardHeader className="pb-2 relative z-10">
<CardTitle className="flex items-center gap-2 text-blue-100">
<Users className="w-5 h-5" />
</CardTitle>
</CardHeader>
<CardContent>
<ResponsiveContainer width="100%" height={300}>
<LineChart data={growthData}>
<CartesianGrid strokeDasharray="3 3" className="stroke-muted" />
<XAxis dataKey="month" className="text-xs" />
<YAxis className="text-xs" />
<Tooltip />
<Line type="monotone" dataKey="users" stroke="#8B5CF6" strokeWidth={2} name="用户(万)" />
<Line type="monotone" dataKey="value" stroke="#3B82F6" strokeWidth={2} name="价值(亿)" />
</LineChart>
</ResponsiveContainer>
</CardContent>
</Card>
<Card className="col-span-3">
<CardHeader>
<CardTitle></CardTitle>
<CardDescription>S/A/B/C/D级用户占比</CardDescription>
</CardHeader>
<CardContent>
<ResponsiveContainer width="100%" height={200}>
<PieChart>
<Pie
data={valueDistribution}
cx="50%"
cy="50%"
innerRadius={50}
outerRadius={80}
dataKey="value"
label={({ name, value }) => `${name}: ${value}%`}
>
{valueDistribution.map((entry, index) => (
<Cell key={`cell-${index}`} fill={entry.color} />
))}
</Pie>
<Tooltip />
</PieChart>
</ResponsiveContainer>
<div className="flex flex-wrap justify-center gap-2 mt-4">
{valueDistribution.map((item) => (
<Badge key={item.name} variant="outline" style={{ borderColor: item.color, color: item.color }}>
{item.name}: {item.value}%
</Badge>
))}
<CardContent className="relative z-10">
<div className="flex items-baseline gap-2 mb-4">
<span className="text-5xl font-bold">{formatNumber(stats.totalUsers)}</span>
<span className="text-blue-100"></span>
</div>
<div className="grid grid-cols-3 gap-4 pt-4 border-t border-white/20">
<div>
<div className="text-2xl font-bold text-green-300">+2.3%</div>
<div className="text-sm text-blue-100"></div>
</div>
<div>
<div className="text-2xl font-bold">{stats.totalProjects.toLocaleString()}</div>
<div className="text-sm text-blue-100"></div>
</div>
<div>
<div className="text-2xl font-bold">125.6B</div>
<div className="text-sm text-blue-100">()</div>
</div>
</div>
</CardContent>
</Card>
</div>
{/* 底部区域 */}
<div className="grid gap-4 md:grid-cols-2">
<Card>
<CardHeader>
<CardTitle></CardTitle>
<CardDescription></CardDescription>
{/* 实时数据流 */}
<Card className="border-none shadow-md bg-white/60 backdrop-blur-md">
<CardHeader className="pb-2">
<CardTitle className="text-gray-700 text-sm font-medium flex items-center gap-2">
<Zap className="w-4 h-4 text-yellow-500" />
</CardTitle>
</CardHeader>
<CardContent>
<div className="space-y-4">
{recentActivities.map((activity) => (
<div key={activity.id} className="flex items-center justify-between">
<div className="flex items-center gap-3">
<div className="h-8 w-8 rounded-full bg-muted flex items-center justify-center text-sm font-medium">
{activity.user.charAt(0)}
</div>
<div>
<p className="text-sm font-medium">{activity.user}</p>
<p className="text-xs text-muted-foreground">{activity.action}</p>
</div>
<CardContent className="space-y-3">
{dataFlows.map((flow, i) => (
<div key={i} className="flex items-center justify-between p-2 rounded-lg bg-gray-50">
<div className="flex items-center gap-2">
<div
className={`w-2 h-2 rounded-full ${flow.status === "running" ? "bg-green-500 animate-pulse" : "bg-yellow-500"}`}
/>
<div>
<div className="text-sm font-medium text-gray-900">{flow.source}</div>
<div className="text-xs text-gray-500">{flow.type}</div>
</div>
<span className="text-xs text-muted-foreground">{activity.time}</span>
</div>
))}
</div>
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle></CardTitle>
<CardDescription>访</CardDescription>
</CardHeader>
<CardContent>
<div className="grid grid-cols-2 gap-3">
<Link href="/data-platform">
<Button variant="outline" className="w-full justify-start h-auto py-4 bg-transparent">
<Database className="mr-2 h-4 w-4" />
<div className="text-left">
<div className="font-medium"></div>
<div className="text-xs text-muted-foreground"></div>
</div>
<ArrowUpRight className="ml-auto h-4 w-4" />
</Button>
</Link>
<Link href="/user-portrait">
<Button variant="outline" className="w-full justify-start h-auto py-4 bg-transparent">
<Users className="mr-2 h-4 w-4" />
<div className="text-left">
<div className="font-medium"></div>
<div className="text-xs text-muted-foreground"></div>
</div>
<ArrowUpRight className="ml-auto h-4 w-4" />
</Button>
</Link>
<Link href="/value-assessment">
<Button variant="outline" className="w-full justify-start h-auto py-4 bg-transparent">
<DollarSign className="mr-2 h-4 w-4" />
<div className="text-left">
<div className="font-medium"></div>
<div className="text-xs text-muted-foreground">RFM模型</div>
</div>
<ArrowUpRight className="ml-auto h-4 w-4" />
</Button>
</Link>
<Link href="/ai-assistant">
<Button variant="outline" className="w-full justify-start h-auto py-4 bg-transparent">
<Zap className="mr-2 h-4 w-4" />
<div className="text-left">
<div className="font-medium">AI助手</div>
<div className="text-xs text-muted-foreground"></div>
</div>
<ArrowUpRight className="ml-auto h-4 w-4" />
</Button>
</Link>
</div>
<div className="text-right">
<div className="text-sm font-semibold text-gray-900">{flow.count.toLocaleString()}</div>
<div className="text-xs text-gray-500">/</div>
</div>
</div>
))}
</CardContent>
</Card>
</div>
{/* 5大功能模块入口 */}
<div>
<h2 className="text-lg font-semibold text-gray-900 mb-4"></h2>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-5 gap-4">
{modules.map((module, index) => (
<Link key={index} href={module.href}>
<Card className="h-full cursor-pointer hover:shadow-lg transition-all duration-300 border-none shadow-sm bg-white/60 backdrop-blur-md group hover:-translate-y-1">
<CardContent className="p-5">
<div
className={`w-12 h-12 rounded-2xl ${module.bg} flex items-center justify-center mb-3 group-hover:scale-110 transition-transform`}
>
<module.icon className={`w-6 h-6 ${module.color}`} />
</div>
<h3 className="font-bold text-gray-900 mb-1">{module.title}</h3>
<p className="text-xs text-gray-500 mb-2 line-clamp-2">{module.desc}</p>
<div className="flex items-center justify-between">
<Badge variant="secondary" className="text-xs">
{module.stats}
</Badge>
<ArrowUpRight className="w-4 h-4 text-gray-400 group-hover:text-blue-500 transition-colors" />
</div>
</CardContent>
</Card>
</Link>
))}
</div>
</div>
{/* 系统关联图说明 */}
<Card className="border-none shadow-md bg-white/60 backdrop-blur-md">
<CardHeader>
<CardTitle className="text-gray-700 text-sm font-medium flex items-center gap-2">
<Globe className="w-4 h-4" />
</CardTitle>
</CardHeader>
<CardContent>
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
{/* 数据流入 */}
<div className="space-y-3">
<h4 className="font-semibold text-gray-900 flex items-center gap-2">
<ArrowUpRight className="w-4 h-4 text-blue-500" />
</h4>
<div className="space-y-2">
{[
{ name: "存客宝", desc: "用户基础信息、交易流水" },
{ name: "触客宝", desc: "互动行为、活动参与" },
{ name: "数智员工", desc: "账号信息、粉丝画像" },
{ name: "外部系统", desc: "征信数据、行业数据" },
].map((item, i) => (
<div key={i} className="flex items-start gap-2 p-2 rounded-lg bg-blue-50">
<CheckCircle className="w-4 h-4 text-blue-500 mt-0.5" />
<div>
<div className="text-sm font-medium text-gray-900">{item.name}</div>
<div className="text-xs text-gray-500">{item.desc}</div>
</div>
</div>
))}
</div>
</div>
{/* 神射手处理 */}
<div className="space-y-3">
<h4 className="font-semibold text-gray-900 flex items-center gap-2">
<Target className="w-4 h-4 text-purple-500" />
</h4>
<div className="space-y-2">
{[
{ name: "数据治理", desc: "清洗、标准化、质量监控" },
{ name: "标签计算", desc: "规则/模型/AI标签生成" },
{ name: "价值评估", desc: "CLV、RFM、流失预测" },
{ name: "AI洞察", desc: "智能分析、报告生成" },
].map((item, i) => (
<div key={i} className="flex items-start gap-2 p-2 rounded-lg bg-purple-50">
<Zap className="w-4 h-4 text-purple-500 mt-0.5" />
<div>
<div className="text-sm font-medium text-gray-900">{item.name}</div>
<div className="text-xs text-gray-500">{item.desc}</div>
</div>
</div>
))}
</div>
</div>
{/* 服务输出 */}
<div className="space-y-3">
<h4 className="font-semibold text-gray-900 flex items-center gap-2">
<Package className="w-4 h-4 text-green-500" />
</h4>
<div className="space-y-2">
{[
{ name: "存客宝/触客宝", desc: "画像API、人群包推送" },
{ name: "数智员工", desc: "账号价值评估API" },
{ name: "聚宝盆", desc: "核心指标聚合接口" },
{ name: "外部客户", desc: "行业报告、趋势分析包" },
].map((item, i) => (
<div key={i} className="flex items-start gap-2 p-2 rounded-lg bg-green-50">
<ArrowUpRight className="w-4 h-4 text-green-500 mt-0.5" />
<div>
<div className="text-sm font-medium text-gray-900">{item.name}</div>
<div className="text-xs text-gray-500">{item.desc}</div>
</div>
</div>
))}
</div>
</div>
</div>
</CardContent>
</Card>
</div>
)
}