Reorganize navigation and module structure based on new requirements. Co-authored-by: null <4804959+fnvtk@users.noreply.github.com>
300 lines
13 KiB
TypeScript
300 lines
13 KiB
TypeScript
"use client"
|
|
|
|
import { useState, useEffect } from "react"
|
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
|
|
import { Button } from "@/components/ui/button"
|
|
import { Badge } from "@/components/ui/badge"
|
|
import {
|
|
TrendingUp,
|
|
ArrowLeft,
|
|
Users,
|
|
Target,
|
|
DollarSign,
|
|
Activity,
|
|
RefreshCw,
|
|
ArrowUpRight,
|
|
ArrowDownRight,
|
|
} from "lucide-react"
|
|
import Link from "next/link"
|
|
import {
|
|
LineChart,
|
|
Line,
|
|
XAxis,
|
|
YAxis,
|
|
CartesianGrid,
|
|
Tooltip,
|
|
ResponsiveContainer,
|
|
PieChart,
|
|
Pie,
|
|
Cell,
|
|
} from "recharts"
|
|
|
|
const kpiData = [
|
|
{ name: "数据接入成功率", value: 99.2, target: 99, unit: "%", trend: "up", change: 0.3 },
|
|
{ name: "标签覆盖率", value: 87.5, target: 85, unit: "%", trend: "up", change: 2.1 },
|
|
{ name: "价值预测准确率", value: 91.8, target: 90, unit: "%", trend: "up", change: 1.2 },
|
|
{ name: "API调用增长", value: 15.2, target: 10, unit: "%", trend: "up", change: 3.5 },
|
|
]
|
|
|
|
const userTrend = [
|
|
{ date: "12-06", total: 4020000, active: 1250000, new: 12500 },
|
|
{ date: "12-07", total: 4025000, active: 1280000, new: 13200 },
|
|
{ date: "12-08", total: 4030000, active: 1260000, new: 11800 },
|
|
{ date: "12-09", total: 4038000, active: 1320000, new: 14500 },
|
|
{ date: "12-10", total: 4045000, active: 1350000, new: 15200 },
|
|
{ date: "12-11", total: 4052000, active: 1380000, new: 16800 },
|
|
{ date: "12-12", total: 4062000, active: 1420000, new: 18500 },
|
|
]
|
|
|
|
const valueDistribution = [
|
|
{ name: "S级", value: 328000, percent: 8.1, color: "#f59e0b" },
|
|
{ name: "A级", value: 650000, percent: 16.0, color: "#3b82f6" },
|
|
{ name: "B级", value: 1220000, percent: 30.0, color: "#10b981" },
|
|
{ name: "C级", value: 1180000, percent: 29.1, color: "#8b5cf6" },
|
|
{ name: "D级", value: 684000, percent: 16.8, color: "#6b7280" },
|
|
]
|
|
|
|
const projectRanking = [
|
|
{ rank: 1, name: "美妆护肤项目", users: 580000, value: 28.5, growth: 12.3 },
|
|
{ rank: 2, name: "母婴亲子项目", users: 420000, value: 22.1, growth: 8.5 },
|
|
{ rank: 3, name: "运动健康项目", users: 380000, value: 18.6, growth: 15.2 },
|
|
{ rank: 4, name: "家居生活项目", users: 320000, value: 15.2, growth: 6.8 },
|
|
{ rank: 5, name: "数码科技项目", users: 280000, value: 12.8, growth: 10.5 },
|
|
]
|
|
|
|
export default function BusinessPage() {
|
|
const [totalValue, setTotalValue] = useState(125.8)
|
|
|
|
useEffect(() => {
|
|
const interval = setInterval(() => {
|
|
setTotalValue((prev) => prev + Math.random() * 0.01)
|
|
}, 5000)
|
|
return () => clearInterval(interval)
|
|
}, [])
|
|
|
|
return (
|
|
<div className="min-h-screen bg-gradient-to-br from-slate-50 via-white to-blue-50/30 p-6">
|
|
<div className="max-w-7xl mx-auto space-y-6">
|
|
{/* 页面标题 */}
|
|
<div className="flex items-center justify-between">
|
|
<div className="flex items-center gap-4">
|
|
<Link href="/monitoring">
|
|
<Button variant="ghost" size="icon" className="rounded-full">
|
|
<ArrowLeft className="w-5 h-5" />
|
|
</Button>
|
|
</Link>
|
|
<div>
|
|
<h1 className="text-2xl font-bold text-slate-800">业务指标看板</h1>
|
|
<p className="text-slate-500 mt-1">核心业务KPI监控与分析</p>
|
|
</div>
|
|
</div>
|
|
<Button variant="outline">
|
|
<RefreshCw className="w-4 h-4 mr-2" />
|
|
刷新数据
|
|
</Button>
|
|
</div>
|
|
|
|
{/* 核心KPI */}
|
|
<div className="grid grid-cols-1 md:grid-cols-4 gap-4">
|
|
{kpiData.map((kpi, i) => (
|
|
<Card key={i} className="bg-white/70 backdrop-blur border-slate-200/60">
|
|
<CardContent className="p-4">
|
|
<div className="flex items-center justify-between mb-2">
|
|
<p className="text-sm text-slate-500">{kpi.name}</p>
|
|
<Badge
|
|
className={
|
|
kpi.value >= kpi.target ? "bg-emerald-100 text-emerald-700" : "bg-amber-100 text-amber-700"
|
|
}
|
|
>
|
|
目标: {kpi.target}
|
|
{kpi.unit}
|
|
</Badge>
|
|
</div>
|
|
<div className="flex items-end justify-between">
|
|
<p className="text-3xl font-bold text-slate-800">
|
|
{kpi.value}
|
|
<span className="text-lg text-slate-500">{kpi.unit}</span>
|
|
</p>
|
|
<div
|
|
className={`flex items-center gap-1 ${kpi.trend === "up" ? "text-emerald-600" : "text-red-600"}`}
|
|
>
|
|
{kpi.trend === "up" ? <ArrowUpRight className="w-4 h-4" /> : <ArrowDownRight className="w-4 h-4" />}
|
|
<span className="text-sm font-medium">{kpi.change}%</span>
|
|
</div>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
))}
|
|
</div>
|
|
|
|
{/* 资产总价值 */}
|
|
<Card className="bg-gradient-to-r from-blue-500 to-indigo-600 border-0">
|
|
<CardContent className="p-6">
|
|
<div className="flex items-center justify-between">
|
|
<div className="text-white">
|
|
<p className="text-sm opacity-80">数据资产总价值</p>
|
|
<p className="text-5xl font-bold mt-2">{totalValue.toFixed(2)} 亿</p>
|
|
<div className="flex items-center gap-4 mt-4">
|
|
<div>
|
|
<p className="text-xs opacity-60">总用户数</p>
|
|
<p className="text-lg font-semibold">40.62 亿</p>
|
|
</div>
|
|
<div className="w-px h-10 bg-white/20" />
|
|
<div>
|
|
<p className="text-xs opacity-60">覆盖项目</p>
|
|
<p className="text-lg font-semibold">156 个</p>
|
|
</div>
|
|
<div className="w-px h-10 bg-white/20" />
|
|
<div>
|
|
<p className="text-xs opacity-60">合作企业</p>
|
|
<p className="text-lg font-semibold">89 家</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div className="w-32 h-32 rounded-full bg-white/20 flex items-center justify-center">
|
|
<DollarSign className="w-16 h-16 text-white" />
|
|
</div>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
|
{/* 用户增长趋势 */}
|
|
<Card className="bg-white/70 backdrop-blur border-slate-200/60">
|
|
<CardHeader className="pb-2">
|
|
<CardTitle className="text-base flex items-center gap-2">
|
|
<Users className="w-4 h-4 text-slate-500" />
|
|
用户增长趋势 (近7天)
|
|
</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="h-64">
|
|
<ResponsiveContainer width="100%" height="100%">
|
|
<LineChart data={userTrend}>
|
|
<CartesianGrid strokeDasharray="3 3" stroke="#e2e8f0" />
|
|
<XAxis dataKey="date" tick={{ fontSize: 12 }} stroke="#94a3b8" />
|
|
<YAxis
|
|
tick={{ fontSize: 12 }}
|
|
stroke="#94a3b8"
|
|
tickFormatter={(v) => `${(v / 10000).toFixed(0)}万`}
|
|
/>
|
|
<Tooltip
|
|
contentStyle={{
|
|
backgroundColor: "white",
|
|
border: "1px solid #e2e8f0",
|
|
borderRadius: "8px",
|
|
}}
|
|
formatter={(value: number) => [`${(value / 10000).toFixed(1)}万`]}
|
|
/>
|
|
<Line type="monotone" dataKey="active" stroke="#3b82f6" strokeWidth={2} name="活跃用户" />
|
|
<Line type="monotone" dataKey="new" stroke="#10b981" strokeWidth={2} name="新增用户" />
|
|
</LineChart>
|
|
</ResponsiveContainer>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
{/* 价值等级分布 */}
|
|
<Card className="bg-white/70 backdrop-blur border-slate-200/60">
|
|
<CardHeader className="pb-2">
|
|
<CardTitle className="text-base flex items-center gap-2">
|
|
<Target className="w-4 h-4 text-slate-500" />
|
|
用户价值分布
|
|
</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="flex items-center justify-between">
|
|
<div className="h-64 flex-1">
|
|
<ResponsiveContainer width="100%" height="100%">
|
|
<PieChart>
|
|
<Pie
|
|
data={valueDistribution}
|
|
cx="50%"
|
|
cy="50%"
|
|
innerRadius={60}
|
|
outerRadius={90}
|
|
dataKey="value"
|
|
label={({ name, percent }) => `${name} ${percent}%`}
|
|
>
|
|
{valueDistribution.map((entry, index) => (
|
|
<Cell key={`cell-${index}`} fill={entry.color} />
|
|
))}
|
|
</Pie>
|
|
<Tooltip formatter={(value: number) => [`${(value / 10000).toFixed(1)}万`, "用户数"]} />
|
|
</PieChart>
|
|
</ResponsiveContainer>
|
|
</div>
|
|
<div className="space-y-2">
|
|
{valueDistribution.map((item, i) => (
|
|
<div key={i} className="flex items-center gap-2">
|
|
<div className="w-3 h-3 rounded-full" style={{ backgroundColor: item.color }} />
|
|
<span className="text-sm text-slate-600">
|
|
{item.name}: {(item.value / 10000).toFixed(1)}万
|
|
</span>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
|
|
{/* 项目价值排名 */}
|
|
<Card className="bg-white/70 backdrop-blur border-slate-200/60">
|
|
<CardHeader className="pb-3">
|
|
<CardTitle className="text-base flex items-center gap-2">
|
|
<Activity className="w-4 h-4 text-slate-500" />
|
|
项目价值排名 Top 5
|
|
</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="overflow-x-auto">
|
|
<table className="w-full">
|
|
<thead>
|
|
<tr className="border-b border-slate-200">
|
|
<th className="text-left py-3 px-4 text-xs font-medium text-slate-500">排名</th>
|
|
<th className="text-left py-3 px-4 text-xs font-medium text-slate-500">项目名称</th>
|
|
<th className="text-left py-3 px-4 text-xs font-medium text-slate-500">用户数</th>
|
|
<th className="text-left py-3 px-4 text-xs font-medium text-slate-500">资产价值</th>
|
|
<th className="text-left py-3 px-4 text-xs font-medium text-slate-500">环比增长</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{projectRanking.map((project) => (
|
|
<tr key={project.rank} className="border-b border-slate-100 hover:bg-slate-50/50">
|
|
<td className="py-3 px-4">
|
|
<div
|
|
className={`w-6 h-6 rounded-full flex items-center justify-center text-xs font-bold ${
|
|
project.rank === 1
|
|
? "bg-amber-100 text-amber-700"
|
|
: project.rank === 2
|
|
? "bg-slate-200 text-slate-700"
|
|
: project.rank === 3
|
|
? "bg-orange-100 text-orange-700"
|
|
: "bg-slate-100 text-slate-600"
|
|
}`}
|
|
>
|
|
{project.rank}
|
|
</div>
|
|
</td>
|
|
<td className="py-3 px-4 text-sm font-medium text-slate-800">{project.name}</td>
|
|
<td className="py-3 px-4 text-sm text-slate-600">{(project.users / 10000).toFixed(1)}万</td>
|
|
<td className="py-3 px-4 text-sm font-medium text-slate-800">{project.value}亿</td>
|
|
<td className="py-3 px-4">
|
|
<div className="flex items-center gap-1 text-emerald-600">
|
|
<TrendingUp className="w-4 h-4" />
|
|
<span className="text-sm font-medium">{project.growth}%</span>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
))}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|