"use client"; import { useEffect, useState } from "react"; import { RefreshCcw } from "lucide-react"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { opsApi } from "@/lib/ops-api"; import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, Cell, } from "recharts"; type FunnelStep = { label: string; count: number; pct_of_prev?: number }; export function AnalyticsPageClient() { const [loading, setLoading] = useState(true); const [funnel, setFunnel] = useState([]); const [rates, setRates] = useState | null>(null); const [days, setDays] = useState(30); const load = async () => { setLoading(true); try { const data = await opsApi.funnel(days); setFunnel(data.steps); setRates(data.rates ?? null); } catch { /* */ } setLoading(false); }; useEffect(() => { void load(); }, [days]); const chartData = [...funnel].reverse().map((s) => ({ name: s.label, count: s.count, pct: s.pct_of_prev, })); const maxCount = Math.max(...funnel.map((s) => s.count), 1); if (loading) return
加载中...
; return (

转化分析

{[7, 14, 30].map((d) => ( ))}
{/* Summary cards */} {funnel.length > 0 && (
总注册
{funnel[0]?.count ?? 0}
点击付费
{funnel[2]?.count ?? 0}
发起支付
{funnel[4]?.count ?? 0}
支付成功
{funnel[5]?.count ?? 0}
总体转化 {maxCount > 0 ? `${((funnel[5]?.count ?? 0) / maxCount * 100).toFixed(1)}%` : "—"}
)} {/* Funnel chart */} 转化漏斗 (Recharts) {chartData.length === 0 ? (

暂无数据

) : ( [`${value} 人`, "数量"]} /> {chartData.map((_, i) => { const colors = ["#06b6d4", "#0ea5e9", "#6366f1", "#f59e0b", "#22c55e", "#10b981"]; return ; })} )}
{/* Drop-off table */} 各阶段详情
{funnel.map((step, i) => { const pct = step.pct_of_prev; const dropPct = pct != null ? 100 - pct : 0; return ( ); })}
阶段 人数 转化率 流失率
{step.label} {step.count} {pct != null ? `${pct}%` : "—"} {i > 0 ? `${dropPct}%` : "—"}
); }