"use client"; import { useCallback, useEffect, useMemo, useState } from "react"; import { fetchAnalyticsSummary, type AnalyticsDailyRow, type AnalyticsSummaryResponse, } from "@/features/agent/services/analyticsApi"; import { Button } from "@/components/ui/button"; import { toast } from "@/hooks/useToast"; function formatPercent(n: number) { if (Number.isNaN(n)) return "—"; return `${n.toFixed(2)}%`; } function StatCard({ title, value, sub, }: { title: string; value: string | number; sub?: string; }) { return (
{title}
{value}
{sub ?
{sub}
: null}
); } function DailyBars({ daily, field, label, color, }: { daily: AnalyticsDailyRow[]; field: keyof Pick< AnalyticsDailyRow, "widget_opens" | "sessions" | "messages" | "ai_replies" >; label: string; color: string; }) { const max = useMemo(() => { let m = 1; for (const row of daily) { const v = Number(row[field]) || 0; if (v > m) m = v; } return m; }, [daily, field]); if (daily.length === 0) { return

暂无数据

; } return (
{label}
{daily.map((row) => { const v = Number(row[field]) || 0; const h = Math.round((v / max) * 100); return (
0 ? 8 : 0)}%`, backgroundColor: color, minHeight: v > 0 ? 4 : 0, }} /> {row.date.slice(5)}
); })}
); } export default function AnalyticsPage(_props: { embedded?: boolean }) { const [from, setFrom] = useState(() => { const d = new Date(); d.setDate(d.getDate() - 6); return d.toISOString().slice(0, 10); }); const [to, setTo] = useState(() => new Date().toISOString().slice(0, 10)); const [data, setData] = useState(null); const [loading, setLoading] = useState(true); const load = useCallback(async () => { setLoading(true); try { const res = await fetchAnalyticsSummary(from, to); setData(res); } catch (e) { toast.error((e as Error).message); setData(null); } finally { setLoading(false); } }, [from, to]); useEffect(() => { void load(); }, [load]); const t = data?.totals; return (

数据报表

访客小窗与 AI 客服统计(按上海时区自然日,不含「知识库测试」内部会话)

{data && (

{data.note}

)} {t && ( <>
)} {!loading && !t && (

暂无数据或加载失败

)}
); }