import { useAsyncData } from "../../lib/useAsyncData"; import { adminListChannels, adminListIoT, adminListMemories, adminListPersonas, adminListPlugins, adminListSessions, } from "../../lib/api"; import { useAppStore } from "../../store/useAppStore"; import { navigateAdmin, type AdminSectionId } from "../router"; import { CardGrid, StatCard } from "../components"; import { Surface, Tag } from "../../components/primitives"; import { Icon, type IconName } from "../../components/Icon"; import { useAutoReload } from "../hooks"; interface DashCard { id: AdminSectionId; label: string; icon: IconName; value: number | string; sub?: string; tone: "ok" | "warn" | "accent" | "neutral" | "err"; } export function DashboardModule(): React.ReactNode { const personas = useAsyncData(adminListPersonas, []); const sessions = useAsyncData(adminListSessions, []); const memories = useAsyncData(adminListMemories, []); const plugins = useAsyncData(adminListPlugins, []); const channels = useAsyncData(adminListChannels, []); const iot = useAsyncData(adminListIoT, []); useAutoReload(personas.reload, 10000); useAutoReload(sessions.reload, 10000); useAutoReload(memories.reload, 20000); useAutoReload(plugins.reload, 15000); useAutoReload(channels.reload, 10000); useAutoReload(iot.reload, 8000); // WS-backed live signals (design/10 §3): subagents + backthink. const agents = useAppStore((s) => s.agents); const backthink = useAppStore((s) => s.backthink); const wsStatus = useAppStore((s) => s.wsStatus); const nPersonas = personas.data?.length ?? 0; const nSessions = sessions.data?.length ?? 0; const nMemories = memories.data?.length ?? 0; const nPlugins = plugins.data?.length ?? 0; const nChannels = channels.data?.length ?? 0; const nDevices = iot.data?.length ?? 0; const offlineChannels = (channels.data ?? []).filter((c) => !c.connected).length; const onlineDevices = (iot.data ?? []).filter((d) => d.online).length; const runningAgents = agents.filter((a) => a.status === "running").length; const cards: DashCard[] = [ { id: "personas", label: "人格", icon: "dna", value: nPersonas, sub: "启停/默认/路由", tone: "accent" }, { id: "sessions", label: "活跃会话", icon: "chat", value: nSessions, sub: "渠道 × actor", tone: "ok" }, { id: "memories", label: "记忆", icon: "memory", value: nMemories, sub: "三类作用域隔离", tone: "accent" }, { id: "plugins", label: "插件与能力", icon: "plugin", value: nPlugins, sub: "含 MCP/渠道", tone: "neutral" }, { id: "channels", label: "渠道", icon: "channel", value: `${nChannels - offlineChannels}/${nChannels}`, sub: offlineChannels > 0 ? `${offlineChannels} 离线` : "全部在线", tone: offlineChannels > 0 ? "warn" : "ok" }, { id: "iot", label: "IoT 设备", icon: "device", value: `${onlineDevices}/${nDevices}`, sub: onlineDevices === nDevices && nDevices > 0 ? "全部在线" : "设备状态", tone: nDevices > 0 && onlineDevices === nDevices ? "ok" : "neutral" }, { id: "agents", label: "Agent 运行", icon: "agent", value: runningAgents, sub: `${agents.length} 个已登记`, tone: runningAgents > 0 ? "accent" : "neutral" }, { id: "backthink", label: "后台思考活跃度", icon: "night", value: backthink.length, sub: "实时 (WS)", tone: backthink.length > 0 ? "warn" : "neutral" }, ]; return (

仪表盘

多而全的概览 · 最详细信息在各独立页面

实时通道 · {wsStatus}
{cards.map((c) => ( ))}

资源 / LLM / 业务概览

占位(后端 M10+ 提供)
卡片即入口,点击上溯卡片下钻到对应模块。
); } function MiniMetric({ label, value, hint }: { label: string; value: string; hint: string }): React.ReactNode { return (
{label}
{value}
{hint}
); }