"use client"; import { useCallback, useEffect, useState } from "react"; import { Card, Spinner } from "@heroui/react"; import { Thunderbolt, PlugConnection, CreditCard, ChartColumn, TagDollar, Person, } from "@gravity-ui/icons"; import { useSession } from "@/lib/auth-client"; import { api, type Stats, type UserStats, type Transaction, type ChargePoint } from "@/lib/api"; // ── Helpers ──────────────────────────────────────────────────────────────── function timeAgo(dateStr: string | null | undefined): string { if (!dateStr) return "—"; const ms = Date.now() - new Date(dateStr).getTime(); if (ms < 60_000) return "刚刚"; if (ms < 3_600_000) return `${Math.floor(ms / 60_000)} 分钟前`; if (ms < 86_400_000) return `${Math.floor(ms / 3_600_000)} 小时前`; return new Date(dateStr).toLocaleDateString("zh-CN", { month: "short", day: "numeric" }); } function cpOnline(cp: ChargePoint): boolean { if (!cp.lastHeartbeatAt) return false; return Date.now() - new Date(cp.lastHeartbeatAt).getTime() < 120_000; } // ── StatCard ─────────────────────────────────────────────────────────────── type CardColor = "accent" | "success" | "warning" | "default"; const colorStyles: Record = { accent: { border: "border-accent", bg: "bg-accent/10", icon: "text-accent" }, success: { border: "border-success", bg: "bg-success/10", icon: "text-success" }, warning: { border: "border-warning", bg: "bg-warning/10", icon: "text-warning" }, default: { border: "border-border", bg: "bg-default", icon: "text-muted" }, }; function StatusDot({ color }: { color: "success" | "warning" | "muted" }) { const cls = color === "success" ? "bg-success" : color === "warning" ? "bg-warning" : "bg-muted/40"; return ; } function StatCard({ title, value, footer, icon: Icon, color = "default", }: { title: string; value: string | number; footer?: React.ReactNode; icon?: React.ComponentType<{ className?: string }>; color?: CardColor; }) { const s = colorStyles[color]; return (

{title}

{Icon && (
)}

{value}

{footer && (
{footer}
)}
); } // ── Panel wrapper ────────────────────────────────────────────────────────── function Panel({ title, children }: { title: string; children: React.ReactNode }) { return (

{title}

{children}
); } // ── RecentTransactions ──────────────────────────────────────────────────── function RecentTransactions({ txns }: { txns: Transaction[] }) { if (txns.length === 0) { return
暂无充电记录
; } return ( ); } // ── ChargePointStatus ───────────────────────────────────────────────────── function ChargePointStatus({ cps }: { cps: ChargePoint[] }) { if (cps.length === 0) { return
暂无充电桩
; } return ( ); } // ── Page ─────────────────────────────────────────────────────────────────── export default function DashboardPage() { const { data: sessionData, isPending } = useSession(); const isAdmin = sessionData?.user?.role === "admin"; const [adminStats, setAdminStats] = useState(null); const [userStats, setUserStats] = useState(null); const [recentTxns, setRecentTxns] = useState([]); const [chargePoints, setChargePoints] = useState([]); const [loading, setLoading] = useState(false); const load = useCallback(async () => { if (isPending) return; setLoading(true); try { const [statsData, txnsData, cpsData] = await Promise.all([ api.stats.get(), api.transactions.list({ limit: 6 }), isAdmin ? api.chargePoints.list() : Promise.resolve(null), ]); if ("totalChargePoints" in statsData) { setAdminStats(statsData as Stats); } else { setUserStats(statsData as UserStats); } setRecentTxns(txnsData.data); if (cpsData) setChargePoints(cpsData); } catch {} finally { setLoading(false); } }, [isPending, isAdmin]); useEffect(() => { void load(); }, [load]); if (isPending || loading) { return (

概览

加载中…

); } // ── Admin view ──────────────────────────────────────────────────────────── if (isAdmin) { const s = adminStats; const todayKwh = s ? (s.todayEnergyWh / 1000).toFixed(1) : "—"; const todayRevenue = s ? `¥${(s.todayRevenue / 100).toFixed(2)}` : "—"; const offlineCount = (s?.totalChargePoints ?? 0) - (s?.onlineChargePoints ?? 0); return (

概览

实时运营状态

{/* Today's live metrics */}
当日 00:00 起累计} /> 当日累计输出电能} /> 已完成订单金额合计} /> {s?.activeTransactions ? "充电进行中" : "当前空闲"} } />
{/* Infrastructure metrics */}
{s?.onlineChargePoints ?? 0} 在线 · {offlineCount} 离线 } /> 已注册卡片总量} /> 系统用户总数} />
{/* Detail panels */}
); } // ── User view ───────────────────────────────────────────────────────────── const s = userStats; const totalYuan = s ? (s.totalBalance / 100).toFixed(2) : "—"; const todayKwh = s ? (s.todayEnergyWh / 1000).toFixed(2) : "—"; return (

概览

{sessionData?.user?.name ?? sessionData?.user?.email} 的账户概览

已绑定的储值卡数量} /> 所有储值卡余额合计} /> {s?.activeTransactions ? "充电中" : "当前空闲"} } /> 今日 {s?.todayTransactions ?? 0} 次} />
); }