import { useEffect, useState } from 'react' import { Users, PawPrint, MessageSquare, Activity, TrendingUp, CalendarDays, UserPlus, Repeat } from 'lucide-react' import { ResponsiveContainer, AreaChart, Area, BarChart, Bar, LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Cell, } from 'recharts' import { api } from '@/lib/api' import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' const ORANGE = '#F5A93E' const GREEN = '#3FB984' const BLUE = '#5B9BD5' type Pt = { date: string; count: number } type Ret = { day: number; rate: number; base: number } type Analytics = { summary: { total_users: number; new_today: number; new_month: number dau: number; wau: number; mau: number total_pets: number; total_posts: number; total_records: number } new_trend: Pt[]; active_trend: Pt[]; mau_trend: Pt[]; retention: Ret[] } const RANGES = [ { label: '近 7 天', days: 7 }, { label: '近 30 天', days: 30 }, { label: '近 90 天', days: 90 }, ] export default function Dashboard() { const [days, setDays] = useState(30) const [a, setA] = useState(null) const [loading, setLoading] = useState(true) useEffect(() => { setLoading(true) api.analytics(days).then((d) => { setA(d); setLoading(false) }).catch(() => setLoading(false)) }, [days]) const s = a?.summary const kpis = [ { label: '真实用户', value: s?.total_users, icon: Users, tint: ORANGE }, { label: '日活 DAU', value: s?.dau, icon: Activity, tint: GREEN }, { label: '周活 WAU', value: s?.wau, icon: CalendarDays, tint: BLUE }, { label: '月活 MAU', value: s?.mau, icon: TrendingUp, tint: ORANGE }, { label: '今日新增', value: s?.new_today, icon: UserPlus, tint: GREEN }, { label: '本月新增', value: s?.new_month, icon: UserPlus, tint: BLUE }, ] const mini = [ { label: '宠物', value: s?.total_pets, icon: PawPrint }, { label: '帖子', value: s?.total_posts, icon: MessageSquare }, { label: '健康记录', value: s?.total_records, icon: Activity }, ] const retData = (a?.retention || []).map((r) => ({ ...r, pct: Math.round(r.rate * 1000) / 10 })) return (

概览

{RANGES.map((r) => ( ))}
{/* KPI 卡 */}
{kpis.map((c) => ( {c.label}
{c.value ?? '—'}
))}
{/* 图表区 */}
`D${d}`} /> [`${v}%(分母 ${p.payload.base})`, '留存率']} labelFormatter={(d) => `注册后第 ${d} 天`} /> {retData.map((_, i) => )}
{/* 底部小计数 */}
{mini.map((c) => ( {c.label}
{c.value ?? '—'}
))}
{loading &&
加载中…
}
) } const tipProps = { contentStyle: { borderRadius: 10, border: '1px solid #eee', fontSize: 12 }, cursor: { fill: 'rgba(245,169,62,.08)' }, } function ChartCard({ title, hint, children }: { title: string; hint?: string; children: React.ReactNode }) { return ( {title} {hint &&

{hint}

}
{children}
) }