import { NavLink, Outlet } from "react-router-dom"; import { useEffect, useState } from "react"; import { api } from "../api/client"; import { useAuth } from "../auth/AuthContext"; const NAV = [ { to: "/labeling", icon: "◎", label: "送标工作台", badge: "pending" as const, perm: "read:pending" }, { to: "/catalog", icon: "▤", label: "数据目录", perm: "read:catalog" }, { to: "/audit", icon: "✓", label: "审核管理", badge: "audit" as const, perm: "read:audit" }, { to: "/jobs", icon: "◷", label: "任务监控", perm: "read:jobs" }, { to: "/training", icon: "▶", label: "模型训练", perm: "write:approval_submit" }, { to: "/logs", icon: "☰", label: "审计日志", perm: "read:audit" }, ]; export function Layout() { const { user, logout, hasPermission } = useAuth(); const [apiOk, setApiOk] = useState(null); const [pendingN, setPendingN] = useState(0); const [auditN, setAuditN] = useState(0); const refreshMeta = async () => { try { await api.health(); setApiOk(true); if (hasPermission("read:pending")) { const pending = await api.pending(); const actionable = (pending.batches || []).filter((b) => ["returned", "raw_pool", "out_for_labeling"].includes(b.stage) ); setPendingN(actionable.length); } if (hasPermission("read:audit")) { const aud = await api.listApprovals("pending"); setAuditN(aud.items?.length || 0); } } catch { setApiOk(false); } }; useEffect(() => { refreshMeta(); const t = setInterval(refreshMeta, 30000); return () => clearInterval(t); }, [user]); const path = location.pathname.replace(/^\//, "").split("/")[0] || "labeling"; const title = NAV.find((n) => n.to.slice(1) === path)?.label || "送标工作台"; const roleLabel = user?.roles?.map((r) => r.name).join(" · ") || ""; return (

{title}

); }