"use client" import { useState, useEffect } from "react" import { useRouter } from "next/navigation" import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" import { Users, BookOpen, ShoppingBag, TrendingUp, RefreshCw, ChevronRight } from "lucide-react" export default function AdminDashboard() { const router = useRouter() const [mounted, setMounted] = useState(false) const [users, setUsers] = useState([]) const [purchases, setPurchases] = useState([]) // 从API获取数据 async function loadData() { try { // 获取用户数据 const usersRes = await fetch('/api/db/users') const usersData = await usersRes.json() if (usersData.success && usersData.users) { setUsers(usersData.users) } // 获取订单数据 const ordersRes = await fetch('/api/orders') const ordersData = await ordersRes.json() if (ordersData.success && ordersData.orders) { setPurchases(ordersData.orders) } } catch (e) { console.log('加载数据失败', e) } } useEffect(() => { setMounted(true) loadData() }, []) // 防止Hydration错误:服务端渲染时显示加载状态 if (!mounted) { return (

数据概览

{[1, 2, 3, 4].map((i) => (
))}
加载中...
) } const totalRevenue = purchases.reduce((sum, p) => sum + Number(p.amount || 0), 0) const totalUsers = users.length const totalPurchases = purchases.length // 格式化订单商品信息(显示书名和章节) const formatOrderProduct = (p: any) => { const type = p.productType || "" const desc = p.description || "" // 优先使用 description,因为它包含完整的商品描述 if (desc) { // 如果是章节购买,提取章节标题 if (type === "section" && desc.includes("章节")) { // description 格式可能是:"章节购买-1-2" 或具体章节标题 if (desc.includes("-")) { const parts = desc.split("-") if (parts.length >= 3) { return { title: `第${parts[1]}章 第${parts[2]}节`, subtitle: "《一场Soul的创业实验》" } } } return { title: desc, subtitle: "章节购买" } } // 如果是整本购买 if (type === "fullbook" || desc.includes("全书")) { return { title: "《一场Soul的创业实验》", subtitle: "全书购买" } } // 如果是找伙伴 if (type === "match" || desc.includes("伙伴")) { return { title: "找伙伴匹配", subtitle: "功能服务" } } // 其他情况直接显示 description return { title: desc, subtitle: type === "section" ? "单章" : type === "fullbook" ? "全书" : "其他" } } // 如果没有 description,fallback 到原逻辑 if (type === "section") return { title: `章节 ${p.productId || ""}`, subtitle: "单章购买" } if (type === "fullbook") return { title: "《一场Soul的创业实验》", subtitle: "全书购买" } if (type === "match") return { title: "找伙伴匹配", subtitle: "功能服务" } return { title: "未知商品", subtitle: type || "其他" } } const stats = [ { title: "总用户数", value: totalUsers, icon: Users, color: "text-blue-400", bg: "bg-blue-500/20", link: "/admin/users" }, { title: "总收入", value: `¥${Number(totalRevenue).toFixed(2)}`, icon: TrendingUp, color: "text-[#38bdac]", bg: "bg-[#38bdac]/20", link: "/admin/orders", }, { title: "订单数", value: totalPurchases, icon: ShoppingBag, color: "text-purple-400", bg: "bg-purple-500/20", link: "/admin/orders" }, { title: "转化率", value: `${totalUsers > 0 ? ((totalPurchases / totalUsers) * 100).toFixed(1) : 0}%`, icon: BookOpen, color: "text-orange-400", bg: "bg-orange-500/20", link: "/admin/distribution", }, ] return (

数据概览

{stats.map((stat, index) => ( stat.link && router.push(stat.link)} > {stat.title}
{stat.value}
))}
最近订单
{purchases .slice(-5) .reverse() .map((p) => { const referrer = p.referrerId && users.find((u: any) => u.id === p.referrerId) const inviteCode = p.referralCode || referrer?.referral_code || referrer?.nickname || p.referrerId?.slice(0, 8) const product = formatOrderProduct(p) const buyer = p.userNickname || users.find((u: any) => u.id === p.userId)?.nickname || "匿名用户" return (
{/* 购买者头像 */} {p.userAvatar ? ( {buyer} { // 头像加载失败时显示首字母 e.currentTarget.style.display = 'none' e.currentTarget.nextElementSibling?.classList.remove('hidden') }} /> ) : null}
{buyer.charAt(0)}
{/* 订单信息 */}
{/* 购买者 + 商品名称 */}
{buyer} · {product.title}
{/* 商品类型 + 时间 */}
{product.subtitle} {new Date(p.createdAt).toLocaleString('zh-CN', { month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit' })}
{/* 邀请码 */} {inviteCode && (

推荐: {inviteCode}

)}
{/* 金额 */}

+¥{Number(p.amount).toFixed(2)}

{p.paymentMethod || "微信"}

) })} {purchases.length === 0 && (

暂无订单数据

)}
新注册用户
{users .slice(-5) .reverse() .map((u) => (
{u.nickname?.charAt(0) || "?"}

{u.nickname || "匿名用户"}

{u.phone || "-"}

{u.createdAt ? new Date(u.createdAt).toLocaleDateString() : "-"}

))} {users.length === 0 &&

暂无用户数据

}
) }