Files
soul/app/admin/page.tsx
2026-01-09 11:58:08 +08:00

119 lines
4.7 KiB
TypeScript

"use client"
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { useStore } from "@/lib/store"
import { Users, BookOpen, ShoppingBag, TrendingUp } from "lucide-react"
export default function AdminDashboard() {
const { getAllUsers, getAllPurchases } = useStore()
const users = getAllUsers()
const purchases = getAllPurchases()
const totalRevenue = purchases.reduce((sum, p) => sum + p.amount, 0)
const totalUsers = users.length
const totalPurchases = purchases.length
const stats = [
{ title: "总用户数", value: totalUsers, icon: Users, color: "text-blue-400", bg: "bg-blue-500/20" },
{
title: "总收入",
value: `¥${totalRevenue.toFixed(2)}`,
icon: TrendingUp,
color: "text-[#38bdac]",
bg: "bg-[#38bdac]/20",
},
{ title: "订单数", value: totalPurchases, icon: ShoppingBag, color: "text-purple-400", bg: "bg-purple-500/20" },
{
title: "转化率",
value: `${totalUsers > 0 ? ((totalPurchases / totalUsers) * 100).toFixed(1) : 0}%`,
icon: BookOpen,
color: "text-orange-400",
bg: "bg-orange-500/20",
},
]
return (
<div className="p-8 max-w-7xl mx-auto">
<h1 className="text-2xl font-bold mb-8 text-white"></h1>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8">
{stats.map((stat, index) => (
<Card key={index} className="bg-[#0f2137] border-gray-700/50 shadow-xl">
<CardHeader className="flex flex-row items-center justify-between pb-2">
<CardTitle className="text-sm font-medium text-gray-400">{stat.title}</CardTitle>
<div className={`p-2 rounded-lg ${stat.bg}`}>
<stat.icon className={`w-4 h-4 ${stat.color}`} />
</div>
</CardHeader>
<CardContent>
<div className="text-2xl font-bold text-white">{stat.value}</div>
</CardContent>
</Card>
))}
</div>
<div className="grid grid-cols-1 lg:grid-cols-2 gap-8">
<Card className="bg-[#0f2137] border-gray-700/50 shadow-xl">
<CardHeader>
<CardTitle className="text-white"></CardTitle>
</CardHeader>
<CardContent>
<div className="space-y-3">
{purchases
.slice(-5)
.reverse()
.map((p) => (
<div
key={p.id}
className="flex items-center justify-between p-4 bg-[#0a1628] rounded-lg border border-gray-700/30"
>
<div>
<p className="text-sm font-medium text-white">{p.sectionTitle || "整本购买"}</p>
<p className="text-xs text-gray-500">{new Date(p.createdAt).toLocaleString()}</p>
</div>
<div className="text-right">
<p className="text-sm font-bold text-[#38bdac]">+¥{p.amount}</p>
<p className="text-xs text-gray-400">{p.paymentMethod || "微信支付"}</p>
</div>
</div>
))}
{purchases.length === 0 && <p className="text-gray-500 text-center py-8"></p>}
</div>
</CardContent>
</Card>
<Card className="bg-[#0f2137] border-gray-700/50 shadow-xl">
<CardHeader>
<CardTitle className="text-white"></CardTitle>
</CardHeader>
<CardContent>
<div className="space-y-3">
{users
.slice(-5)
.reverse()
.map((u) => (
<div
key={u.id}
className="flex items-center justify-between p-4 bg-[#0a1628] rounded-lg border border-gray-700/30"
>
<div className="flex items-center gap-3">
<div className="w-10 h-10 rounded-full bg-[#38bdac]/20 flex items-center justify-center text-sm font-medium text-[#38bdac]">
{u.nickname.charAt(0)}
</div>
<div>
<p className="text-sm font-medium text-white">{u.nickname}</p>
<p className="text-xs text-gray-500">{u.phone}</p>
</div>
</div>
<p className="text-xs text-gray-400">{new Date(u.createdAt).toLocaleDateString()}</p>
</div>
))}
{users.length === 0 && <p className="text-gray-500 text-center py-8"></p>}
</div>
</CardContent>
</Card>
</div>
</div>
)
}