"use client"; import { useEffect, useState } from "react"; import { Users, UserPlus, Repeat, LogIn } from "lucide-react"; import { AdminStatCard } from "@/components/admin"; import { AdminChartCard, NamedBarChart, NamedPieChart } from "@/components/admin/charts"; import { apiStatsVisitors, type VisitVisitors } from "@/lib/api"; import { RangeSegmented, StatsState, TableEmpty, formatInt } from "../ui"; export default function VisitorsPage() { const [range, setRange] = useState<"7d" | "30d">("7d"); const [data, setData] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(""); useEffect(() => { let alive = true; setLoading(true); apiStatsVisitors(range) .then((d) => { if (alive) { setData(d); setError(""); } }) .catch(() => alive && setError("加载失败,请稍后重试")) .finally(() => alive && setLoading(false)); return () => { alive = false; }; }, [range]); if (!data) return ; const devices = data.devices.map((d) => ({ label: d.label || "未知", count: d.count })); const oses = data.oses.map((d) => ({ label: d.label || "未知", count: d.count })); const browsers = data.browsers.map((d) => ({ label: d.label || "未知", count: d.count })); const hourly = data.hourly.map((h) => ({ label: `${h.key}时`, count: h.count })); const totalPv = data.logged_in_pv + data.guest_pv; const totalVisitors = data.new_visitors + data.returning; return (

基于匿名访客标识(仅存哈希)与登录用户统计。

{error ? : null}
} /> } color="var(--ok)" soft="var(--ok-soft, var(--panel-2))" /> 0 ? `${Math.round((data.new_visitors / totalVisitors) * 100)}%` : undefined} hint="统计期内首次出现" icon={} color="var(--gold)" soft="var(--gold-soft)" /> 0 ? `${Math.round((data.returning / totalVisitors) * 100)}%` : undefined} icon={} color="var(--ink-2)" soft="var(--panel-2)" />
{totalPv > 0 ? ( ) : null}
{devices.length ? : } {oses.length ? : } {browsers.length ? : }
{hourly.length ? ( ) : ( )}
); }