"use client"; import type { ComponentProps } from "react"; import { Area, AreaChart, Bar, BarChart, CartesianGrid, Cell, Legend, Line, LineChart, Pie, PieChart, ResponsiveContainer, Tooltip, XAxis, YAxis, } from "recharts"; const TOOLTIP_STYLE = { background: "var(--panel)", border: "1px solid var(--line)", borderRadius: 12, fontSize: 12, color: "var(--ink)", }; const LEGEND_STYLE = { fontSize: 12, overflow: "hidden" as const }; const LEGEND_STYLE_SM = { fontSize: 11, overflow: "hidden" as const }; /** 统一 Tooltip:关闭默认 cursor 灰框,避免选中/悬停黑边 */ function ChartTooltip(props: Omit, "contentStyle" | "cursor">) { return ; } function shortDate(d: string) { if (!d || d.length < 10) return d; return d.slice(5); } export function AdminChartCard({ title, hint, children, actions, }: { title: string; hint?: string; children: React.ReactNode; actions?: React.ReactNode; }) { return (

{title}

{hint ? (

{hint}

) : null}
{actions}
{/* 捕获阶段拦截 mousedown:冒泡阶段太晚,浏览器已开始 SVG 多柱选区黑框 */}
e.preventDefault()} > {children}
); } export function VisitTrendChart({ data, }: { data: { date: string; pv: number; uv: number }[]; }) { const rows = data.map((d) => ({ ...d, label: shortDate(d.date) })); return ( ); } export function DualLineChart({ data, aKey, bKey, aName, bName, aColor = "var(--accent)", bColor = "var(--gold)", }: { data: { date: string; [k: string]: string | number }[]; aKey: string; bKey: string; aName: string; bName: string; aColor?: string; bColor?: string; }) { const rows = data.map((d) => ({ ...d, label: shortDate(String(d.date)) })); return ( ); } export function SingleAreaChart({ data, dataKey, name, color = "var(--accent)", }: { data: { date: string; [k: string]: string | number }[]; dataKey: string; name: string; color?: string; }) { const rows = data.map((d) => ({ ...d, label: shortDate(String(d.date)) })); return ( ); } const PIE_COLORS = [ "var(--accent)", "var(--ok)", "var(--gold)", "var(--clay)", "var(--danger)", "#8b5cf6", "#06b6d4", "#84cc16", ]; export function NamedBarChart({ data, layout = "vertical", }: { data: { label: string; count: number }[]; layout?: "vertical" | "horizontal"; }) { if (layout === "horizontal") { return ( ); } return ( ); } export function NamedPieChart({ data }: { data: { label: string; count: number }[] }) { const total = data.reduce((s, d) => s + d.count, 0) || 1; return ( {data.map((_, i) => ( ))} { const n = typeof value === "number" ? value : Number(value) || 0; return [`${n}(${Math.round((n / total) * 100)}%)`, String(name ?? "")]; }} /> ); } export function DeltaBarChart({ data, }: { data: { date: string; granted: number; spent: number }[]; }) { const rows = data.map((d) => ({ ...d, label: shortDate(d.date) })); return ( ); }