/* WAREHOUSE 2.0 · 審計日誌 — Swiss 版式,真後端 */
(() => {
const W2 = window.W2;
const { t } = window.W2_LANG;
window.W2_LANG.addEN({
  "審計日誌": "Audit Log",
  "全平台操作留痕 · 時間戳 · 操作人 · 權限快照 · 頁面只讀,追查交秘書": "Full-platform operation trail · timestamps · operators · permission snapshots · read-only, investigations via Secretary",
  "審計簡報": "Audit briefing",
  "把最近的審計日誌審一遍:標出異常操作、失敗操作和高危 CLI,給我一份審計簡報": "Review the recent audit log: flag anomalies, failures and high-risk CLI, then give me an audit briefing",
  "刷新": "Refresh",
  "留痕總數": "Total entries",
  "寫庫操作": "DB writes",
  "失敗 / 錯誤": "Failed / errors",
  "高危 CLI 執行": "High-risk CLI",
  "條": "", "次": "", "人": "",
  "最新": "latest",
  "AI 來源 {n} 條": "{n} AI-sourced",
  "全部成功": "All succeeded",
  "去追查 →": "Investigate →",
  "把失敗和報錯的操作列出來,逐條分析原因,告訴我要不要處理": "List the failed and errored operations, analyze each cause, and tell me whether action is needed",
  "{n} 次被拒(越權)": "{n} denied (unauthorized)",
  "無越權": "No violations",
  "把被拒絕(越權)的 CLI 操作全部列出來:誰在什麼時候試圖越權、想做什麼,逐條分析": "List all denied (unauthorized) CLI operations: who attempted what and when, analyzed one by one",
  "全部留痕": "All entries",
  "高危 CLI": "High-risk CLI",
  "搜索操作人 / 動作 / 對象 / 指令": "Search operator / action / entity / command",
  "類型": "Type", "人員": "People",
  "全部類型": "All types",
  "全部人員": "All operators",
  "操作流水": "Operation trail",
  "高危 CLI 流水": "High-risk CLI trail",
  "{n} 條記錄": "{n} entries",
  "讀取中…": "Loading…",
  "解釋": "Explain",
  "完成": "Completed", "已執行": "Executed", "待定": "Pending",
  "失敗": "Failed", "錯誤": "Error", "已拒絕": "Rejected",
  "寫": "W", "讀": "R", "寫庫": "Write",
  "審計詳情": "Entry detail",
  "操作人": "Operator", "角色 / 權限": "Role / level", "對象": "Entity",
  "帳號": "Account", "來源": "Source", "狀態": "Status",
  "建立": "Created", "修改 / 刪除": "Updated / deleted",
  "退出碼": "Exit code", "備份": "Backup", "模式": "Mode", "缺權限": "Missing permission", "已備份": "Backed up",
  "請求": "Request", "操作前": "Before", "操作後": "After", "權限快照": "Permission snapshot",
  "完整指令": "Full command",
  "直接吩咐秘書": "Tell the Secretary",
  "解釋這條": "Explain this",
  "追查此人": "Trace this person",
  "追查": "Trace",
  "操作人分佈": "Operators",
  "按留痕條數 · 前 {n} 人": "by entry count · top {n}",
  "暫無審計留痕": "No audit entries yet",
  "所有寫庫操作、AI 動作與高危 CLI 都會自動記錄在這裡,一條不落。": "Every DB write, AI action and high-risk CLI run is recorded here automatically — nothing is missed.",
  "最近系統裡發生了什麼操作?幫我查審計日誌": "What has happened in the system recently? Check the audit log for me",
  "問秘書": "Ask Secretary",
  "當前篩選下沒有記錄": "No entries under current filters",
  "換個條件,或直接讓秘書查:「幫我查◯◯的操作記錄」。": "Change the filters, or just ask the Secretary: \"look up someone's operations\".",
  "還沒有人操作過系統。": "Nobody has operated the system yet.",
  "僅顯示最近 {n} 條 · 更早的記錄請吩咐秘書調取": "Showing latest {n} entries · ask the Secretary for older records",
  "解釋這條審計日誌:{time},{op}({role})執行了「{act}」,對象 {ent},狀態 {st}。說明它具體做了什麼、有沒有風險。": "Explain this audit entry: {time}, {op} ({role}) performed \"{act}\" on {ent}, status {st}. Tell me what it did and whether it carries any risk.",
  "解釋這條高危 CLI 審計:{time},{op} 通過「{kind}」執行了:{cmd}(狀態 {st})。判斷它做了什麼、是否有風險。": "Explain this high-risk CLI entry: {time}, {op} ran via \"{kind}\": {cmd} (status {st}). Assess what it did and whether it is risky.",
  "追查「{name}」最近的操作:把此人的全部審計留痕按時間列出,標出寫庫、失敗與高危 CLI,評估有無異常。": "Trace \"{name}\"'s recent operations: list this person's full audit trail chronologically, flag DB writes, failures and high-risk CLI, and assess anomalies.",
  "新增入庫": "Create inbound", "新增出庫": "Create outbound", "保存設置": "Save settings",
  "AI Action 調用": "AI action call", "寫入日誌": "Write log", "AI 解析降級": "AI parse fallback",
  "SQL 終端": "SQL terminal", "Python 腳本": "Python script", "CLI 指令": "CLI command",
  "平台終端": "Platform terminal", "被拒絕": "Denied", "只讀查詢": "Read-only query",
  "頁面只讀 · 追查與處置交秘書,全程留痕。": "Read-only page · investigations via Secretary, fully audited.",
});

const { useState: _s, useEffect: _e, useMemo: _mm } = React;
const { Icon: I, Btn: B, Tag: T, Label: LB, Empty: EM, Kpi, Meter, Folio, Band, pad2, num } = W2;
const ask = (p) => W2.openSecretary(p);

/* ── 詞表與小工具 ── */
const ACTION_LABEL = {
  create_inbound_order: "新增入庫",
  create_outbound_order: "新增出庫",
  save_settings: "保存設置",
  invoke_ai_database_hook: "AI Action 調用",
  write_audit_log: "寫入日誌",
  deepseek_fallback: "AI 解析降級",
};
const actLabel = (a) => (ACTION_LABEL[a] ? t(ACTION_LABEL[a]) : (a || "—"));
const S = (v) => (v === null || v === undefined || v === "") ? "—" : String(v);
const fmtVal = (v) => {
  if (v === null || v === undefined || v === "") return "—";
  if (typeof v === "object") { try { return JSON.stringify(v, null, 2); } catch (e) { return String(v); } }
  return String(v);
};
const STATUS_META = {
  completed: ["ok", "完成"], executed: ["ok", "已執行"], pending: ["warn", "待定"],
  failed: ["bad", "失敗"], error: ["bad", "錯誤"], rejected: ["bad", "已拒絕"],
};
const StatusTag = ({ s }) => {
  const key = String(s || "completed").toLowerCase();
  const meta = STATUS_META[key];
  return <T tone={meta ? meta[0] : "plain"} dot>{meta ? t(meta[1]) : key}</T>;
};
const SourceTag = ({ s }) => {
  const v = String(s || "system").toLowerCase();
  return v === "ai" ? <T tone="inv">AI</T> : v === "user" ? <T tone="plain">USER</T> : <T tone="plain">SYS</T>;
};
const WriteTag = ({ w }) => w === true ? <T tone="warn">{t("寫")}</T> : w === false ? <T tone="plain">{t("讀")}</T> : <T tone="plain">—</T>;
const PRE = { fontFamily: "var(--f-mono)", fontSize: 11, lineHeight: 1.55, whiteSpace: "pre-wrap", wordBreak: "break-word", maxHeight: 170, overflow: "auto", background: "var(--paper-2)", border: "1px solid var(--hair-soft)", padding: 10, margin: 0 };

const explainPrompt = (r) => r.tab === "cli"
  ? t("解釋這條高危 CLI 審計:{time},{op} 通過「{kind}」執行了:{cmd}(狀態 {st})。判斷它做了什麼、是否有風險。",
      { time: r.when, op: r.opName, kind: r.kind, cmd: (r.command || "—").slice(0, 300), st: r.status })
  : t("解釋這條審計日誌:{time},{op}({role})執行了「{act}」,對象 {ent},狀態 {st}。說明它具體做了什麼、有沒有風險。",
      { time: r.when, op: r.opName, role: S(r.role), act: actLabel(r.actKey), ent: S(r.entity) + " " + S(r.entityId), st: r.status });
const tracePrompt = (name) => t("追查「{name}」最近的操作:把此人的全部審計留痕按時間列出,標出寫庫、失敗與高危 CLI,評估有無異常。", { name });

/* ── 詳情抽屜 ── */
const AuditDrawer = ({ r, onClose }) => {
  const raw = r.raw || {};
  const meta = r.tab === "cli"
    ? [
        [t("操作人"), r.opName],
        [t("角色 / 權限"), S(r.role) + " · L" + S(r.level)],
        [t("來源"), S(r.source)],
        [t("寫庫"), r.write === true ? t("寫") : r.write === false ? t("讀") : "—"],
        [t("退出碼"), S(r.detail.exit_code)],
        [t("備份"), S(r.detail.backup)],
      ]
    : [
        [t("操作人"), r.opName],
        [t("角色 / 權限"), S(r.role) + " · L" + S(r.level)],
        [t("對象"), S(r.entity) + (r.entityId ? " · " + r.entityId : "")],
        [t("帳號"), S(raw.actor)],
        [t("建立"), S(raw.created_at)],
        [t("修改 / 刪除"), S(raw.updated_at) + " / " + S(raw.deleted_at)],
      ];
  const blocks = r.tab === "cli"
    ? [[t("完整指令"), r.command || "—"]]
    : [
        [t("請求"), fmtVal(raw.request !== undefined ? raw.request : raw.request_json)],
        [t("操作前"), fmtVal(raw.before !== undefined ? raw.before : raw.before_json)],
        [t("操作後"), fmtVal(raw.after !== undefined ? raw.after : raw.after_json)],
        [t("權限快照"), fmtVal(raw.permission_snapshot)],
      ];
  return (
    <div className="drawer">
      <div style={{ padding: "16px 18px", borderBottom: "2px solid var(--rule)" }}>
        <div className="row spread" style={{ marginBottom: 10 }}>
          <div className="row g6">
            {r.tab === "cli" ? <T tone={r.status === "rejected" ? "bad" : "inv"}>{t(r.kind)}</T> : <SourceTag s={r.source}/>}
            <StatusTag s={r.status}/>
          </div>
          <button className="btn ghost sm" style={{ padding: "0 7px" }} onClick={onClose} title="Esc"><I name="x" size={13}/></button>
        </div>
        <div style={{ fontSize: 18, fontWeight: 750, letterSpacing: "-.02em", lineHeight: 1.3 }}>
          {r.tab === "cli" ? t("高危 CLI") : actLabel(r.actKey)}
        </div>
        <div className="num muted" style={{ fontSize: 11.5, marginTop: 5 }}>{r.when}</div>
      </div>
      <div style={{ padding: 18, maxHeight: "calc(100vh - 300px)", overflowY: "auto" }}>
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 14, marginBottom: 18 }}>
          {meta.map(([k, v]) => (
            <div key={k} className="col g4" style={{ borderTop: "1px solid var(--hair)", paddingTop: 8, minWidth: 0 }}>
              <LB dim style={{ fontSize: 8.5 }}>{k}</LB>
              <span className="num" style={{ fontSize: 12.5, fontWeight: 650, wordBreak: "break-word" }}>{v}</span>
            </div>
          ))}
        </div>
        {r.tab === "cli" && (
          <div className="row g6 wrap" style={{ marginBottom: 14 }}>
            {r.detail.missing_permission && <T tone="bad">{t("缺權限")} {r.detail.missing_permission}</T>}
            {r.detail.backup && <T tone="plain">{t("已備份")}</T>}
            {r.detail.api && <T tone="plain">{r.detail.api}</T>}
            {r.detail.mode && <T tone="plain">{t("模式")} {r.detail.mode}</T>}
          </div>
        )}
        {blocks.map(([k, v]) => (
          <div key={k} style={{ marginBottom: 14 }}>
            <LB dim style={{ fontSize: 8.5, marginBottom: 6 }}>{k}</LB>
            <pre style={PRE}>{v}</pre>
          </div>
        ))}
        <LB dim style={{ fontSize: 8.5, marginBottom: 8 }}>{t("直接吩咐秘書")}</LB>
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 8 }}>
          <button className="btn" style={{ height: 40, justifyContent: "flex-start", fontSize: 12.5 }} onClick={() => ask(explainPrompt(r))}>
            <I name="sparkle" size={14}/>{t("解釋這條")}
          </button>
          <button className="btn" style={{ height: 40, justifyContent: "flex-start", fontSize: 12.5 }} onClick={() => ask(tracePrompt(r.opName))}>
            <I name="eye" size={14}/>{t("追查此人")}
          </button>
        </div>
        <div className="muted" style={{ fontSize: 10.5, marginTop: 12, lineHeight: 1.6 }}>{t("頁面只讀 · 追查與處置交秘書,全程留痕。")}</div>
      </div>
    </div>
  );
};

/* ── 頁面 ── */
const Page = () => {
  const [logs, setLogs] = _s(null);   // /api/audit/logs → {rows, summary}
  const [cli, setCli] = _s(null);     // /api/audit/cli  → {rows, summary}
  const [tick, setTick] = _s(0);
  const [tab, setTab] = _s("all");
  const [q, setQ] = _s("");
  const [act, setAct] = _s("all");
  const [op, setOp] = _s("all");
  const [sel, setSel] = _s(null);

  _e(() => {
    W2.json("/api/audit/logs?limit=500").then(d => setLogs(d && typeof d === "object" ? d : {})).catch(() => setLogs({}));
    W2.json("/api/audit/cli?limit=500").then(d => setCli(d && typeof d === "object" ? d : {})).catch(() => setCli({}));
  }, [tick]);
  _e(() => {
    const h = (e) => { if (e.key === "Escape") setSel(null); };
    window.addEventListener("keydown", h);
    return () => window.removeEventListener("keydown", h);
  }, []);

  const busy = logs === null || cli === null;
  const lsum = (logs && logs.summary) || {};
  const csum = (cli && cli.summary) || {};

  const logRows = _mm(() => (logs && Array.isArray(logs.rows) ? logs.rows : []).map((r, i) => ({
    key: "a" + (r && r.id != null ? r.id : "i" + i), tab: "all",
    when: S(r.occurred_at || r.created_at),
    opName: S(r.operator_name || r.actor),
    role: r.operator_role, level: r.permission_level,
    actKey: r.action || "", entity: r.entity_type, entityId: r.entity_id,
    source: r.source || "system", status: r.operation_status || "completed",
    command: "", kind: "", detail: {}, raw: r || {},
  })), [logs]);
  const cliRows = _mm(() => (cli && Array.isArray(cli.rows) ? cli.rows : []).map((r, i) => ({
    key: "c" + (r && r.id != null ? r.id : "i" + i), tab: "cli",
    when: S(r.when), opName: S(r.operator), role: r.role, level: r.level,
    kind: S(r.kind), command: r.command || "",
    write: r.write, status: r.status || "completed", source: r.source || "system",
    actKey: r.kind_key || "", entity: "", entityId: "",
    detail: (r.detail && typeof r.detail === "object") ? r.detail : {}, raw: r || {},
  })), [cli]);

  const rows = tab === "all" ? logRows : cliRows;
  const actKeyOf = (r) => tab === "all" ? (r.actKey || "—") : (r.kind || "—");
  const actChips = _mm(() => {
    const m = {};
    rows.forEach(r => { const k = actKeyOf(r); m[k] = (m[k] || 0) + 1; });
    return Object.entries(m).sort((a, b) => b[1] - a[1]).slice(0, 7);
  }, [rows, tab]);
  const opChips = _mm(() => {
    const m = {};
    rows.forEach(r => { if (r.opName && r.opName !== "—") m[r.opName] = (m[r.opName] || 0) + 1; });
    return Object.entries(m).sort((a, b) => b[1] - a[1]).slice(0, 6);
  }, [rows, tab]);

  const shown = _mm(() => {
    let arr = rows;
    if (act !== "all") arr = arr.filter(r => actKeyOf(r) === act);
    if (op !== "all") arr = arr.filter(r => r.opName === op);
    const s = q.trim().toLowerCase();
    if (s) arr = arr.filter(r =>
      [r.opName, r.actKey, r.kind, r.entity, r.entityId, r.command, r.when, r.source, r.status]
        .map(x => String(x || "")).join(" ").toLowerCase().includes(s));
    return arr;
  }, [rows, act, op, q, tab]);
  const CAP = 150;
  const visible = shown.slice(0, CAP);

  const switchTab = (k) => { setTab(k); setAct("all"); setOp("all"); setSel(null); };

  const aiCnt = logRows.filter(r => String(r.source).toLowerCase() === "ai").length;
  const total = num(lsum.total) || logRows.length;
  const writes = num(lsum.writes);
  const failed = num(lsum.failed) + num(csum.failed);
  const cliTotal = num(csum.total) || cliRows.length;
  const denied = num(csum.denied);

  const opsAll = _mm(() => {
    const m = {};
    logRows.concat(cliRows).forEach(r => { if (r.opName && r.opName !== "—") m[r.opName] = (m[r.opName] || 0) + 1; });
    return Object.entries(m).sort((a, b) => b[1] - a[1]).slice(0, 6);
  }, [logRows, cliRows]);
  const opsTotal = logRows.length + cliRows.length;

  return (<>
    <Folio no="14" en="AUDIT" title={t("審計日誌")}
      sub={t("全平台操作留痕 · 時間戳 · 操作人 · 權限快照 · 頁面只讀,追查交秘書")}
      right={<>
        <B icon="refresh" onClick={() => setTick(v => v + 1)}>{t("刷新")}</B>
        <B kind="primary" icon="sparkle" onClick={() => ask(t("把最近的審計日誌審一遍:標出異常操作、失敗操作和高危 CLI,給我一份審計簡報"))}>{t("審計簡報")}</B>
      </>}/>

    <div className="kpi-band">
      <Kpi label={t("留痕總數")} value={total} unit={t("條")} delay={0}
        foot={<span className="muted num" style={{ fontSize: 11.5 }}>{t("最新")} {S(lsum.latest)}</span>}/>
      <Kpi label={t("寫庫操作")} value={writes} unit={t("次")} delay={.05}
        foot={<span className="muted" style={{ fontSize: 11.5 }}>{t("AI 來源 {n} 條", { n: aiCnt })}</span>}/>
      <Kpi label={t("失敗 / 錯誤")} value={failed} unit={t("次")} red={failed > 0} delay={.1}
        foot={failed > 0
          ? <button className="tag bad" style={{ cursor: "pointer" }} onClick={() => ask(t("把失敗和報錯的操作列出來,逐條分析原因,告訴我要不要處理"))}>{t("去追查 →")}</button>
          : <T tone="ok" dot>{t("全部成功")}</T>}/>
      <Kpi label={t("高危 CLI 執行")} value={cliTotal} unit={t("次")} red={denied > 0} delay={.15}
        foot={denied > 0
          ? <button className="tag redinv" style={{ cursor: "pointer" }} onClick={() => ask(t("把被拒絕(越權)的 CLI 操作全部列出來:誰在什麼時候試圖越權、想做什麼,逐條分析"))}>{t("{n} 次被拒(越權)", { n: denied })}</button>
          : <T tone="ok" dot>{t("無越權")}</T>}/>
    </div>

    <div className="row g14 wrap rise" style={{ padding: "18px 0 14px", borderBottom: "1px solid var(--hair)", animationDelay: ".05s" }}>
      <div className="seg">
        {[["all", "全部留痕", "clipboard"], ["cli", "高危 CLI", "shield"]].map(([k, label, icon]) => (
          <button key={k} className={tab === k ? "on" : ""} onClick={() => switchTab(k)}>
            <span className="row g6"><I name={icon} size={12}/>{t(label)}</span>
          </button>
        ))}
      </div>
      <div style={{ position: "relative", flex: 1, minWidth: 240 }}>
        <I name="search" size={15} color="var(--ink-4)" style={{ position: "absolute", left: 0, top: "50%", transform: "translateY(-50%)" }}/>
        <input className="field" style={{ paddingLeft: 26, height: 38 }} value={q} onChange={e => setQ(e.target.value)} placeholder={t("搜索操作人 / 動作 / 對象 / 指令")}/>
      </div>
    </div>

    {!!rows.length && (
      <div className="row g10 wrap rise" style={{ padding: "12px 0 14px", borderBottom: "1px solid var(--hair)", animationDelay: ".08s" }}>
        <LB dim>{t("類型")}</LB>
        <button className={"chip" + (act === "all" ? " on" : "")} onClick={() => setAct("all")}>{t("全部類型")}</button>
        {actChips.map(([k, c]) => (
          <button key={k} className={"chip" + (act === k ? " on" : "")} onClick={() => setAct(act === k ? "all" : k)}>
            {tab === "all" ? actLabel(k) : t(k)}<span className="num muted" style={{ fontSize: 10.5 }}>{c}</span>
          </button>
        ))}
        <span style={{ width: 1, height: 20, background: "var(--hair)", margin: "0 4px" }}/>
        <LB dim>{t("人員")}</LB>
        <button className={"chip" + (op === "all" ? " on" : "")} onClick={() => setOp("all")}>{t("全部人員")}</button>
        {opChips.map(([k, c]) => (
          <button key={k} className={"chip" + (op === k ? " on" : "")} onClick={() => setOp(op === k ? "all" : k)}>
            {k}<span className="num muted" style={{ fontSize: 10.5 }}>{c}</span>
          </button>
        ))}
      </div>
    )}

    <Band no="A" title={tab === "all" ? t("操作流水") : t("高危 CLI 流水")}
      sub={t("{n} 條記錄", { n: shown.length }) + (csum.latest || lsum.latest ? " · " + t("最新") + " " + S(tab === "all" ? lsum.latest : csum.latest) : "")}
      delay={.1}>
      <div style={{ display: "flex", gap: 24, alignItems: "flex-start" }}>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ borderTop: "2px solid var(--rule)" }}>
            {visible.map((r, i) => (
              <div key={r.key} className="ledger-row" style={{ cursor: "pointer", ...(sel && sel.key === r.key ? { background: "var(--white)", borderLeft: "2px solid var(--red)", paddingLeft: 2 } : null) }}
                onClick={() => setSel(sel && sel.key === r.key ? null : r)}>
                <span className="lr-idx">{pad2(i + 1)}</span>
                <span className="num muted" style={{ width: 138, fontSize: 11.5, flexShrink: 0 }}>{r.when}</span>
                {tab === "all" ? (
                  <div className="col g4" style={{ flex: 1.2, minWidth: 0 }}>
                    <span style={{ fontWeight: 650, fontSize: 13.5 }}>{actLabel(r.actKey)}</span>
                    <span className="num muted" style={{ fontSize: 11 }}>{S(r.entity)}{r.entityId ? " · " + r.entityId : ""}</span>
                  </div>
                ) : (
                  <div className="col g4" style={{ flex: 1.2, minWidth: 0 }}>
                    <span className="num" style={{ fontSize: 12, fontWeight: 600, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{r.command || "—"}</span>
                    <span className="muted" style={{ fontSize: 11 }}>{t(r.kind)}</span>
                  </div>
                )}
                <div className="col g4" style={{ flex: .8, minWidth: 0 }}>
                  <span style={{ fontWeight: 600, fontSize: 12.5 }}>{r.opName}</span>
                  <span className="num muted" style={{ fontSize: 11 }}>{S(r.role)} · L{S(r.level)}</span>
                </div>
                {tab === "all" ? <SourceTag s={r.source}/> : <WriteTag w={r.write}/>}
                <StatusTag s={r.status}/>
                <B size="sm" icon="sparkle" onClick={(e) => { e.stopPropagation(); ask(explainPrompt(r)); }}>{t("解釋")}</B>
              </div>
            ))}
          </div>
          {!visible.length && (busy
            ? <div className="muted num" style={{ padding: "34px 0", textAlign: "center", fontSize: 12 }}>{t("讀取中…")}</div>
            : rows.length
              ? <EM icon="search" title={t("當前篩選下沒有記錄")} sub={t("換個條件,或直接讓秘書查:「幫我查◯◯的操作記錄」。")}/>
              : <EM icon="shield" title={t("暫無審計留痕")} sub={t("所有寫庫操作、AI 動作與高危 CLI 都會自動記錄在這裡,一條不落。")}
                  action={<B size="sm" icon="sparkle" onClick={() => ask(t("最近系統裡發生了什麼操作?幫我查審計日誌"))}>{t("問秘書")}</B>}/>)}
          {shown.length > CAP && (
            <div className="muted mono" style={{ fontSize: 10.5, letterSpacing: ".08em", padding: "12px 4px" }}>
              {t("僅顯示最近 {n} 條 · 更早的記錄請吩咐秘書調取", { n: CAP })}
            </div>
          )}
        </div>
        {sel && <AuditDrawer r={sel} onClose={() => setSel(null)}/>}
      </div>
    </Band>

    <Band no="B" title={t("操作人分佈")} sub={opsAll.length ? t("按留痕條數 · 前 {n} 人", { n: opsAll.length }) : ""} delay={.15}>
      {opsAll.length ? (
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: "14px 40px" }}>
          {opsAll.map(([name, cnt]) => (
            <div key={name} className="row g12">
              <div style={{ flex: 1, minWidth: 0 }}>
                <Meter label={name} count={cnt} total={opsTotal} color="var(--ink)"/>
              </div>
              <B size="sm" icon="eye" onClick={() => ask(tracePrompt(name))}>{t("追查")}</B>
            </div>
          ))}
        </div>
      ) : <EM icon="user" title={busy ? t("讀取中…") : t("還沒有人操作過系統。")} sub={busy ? "" : t("所有寫庫操作、AI 動作與高危 CLI 都會自動記錄在這裡,一條不落。")}/>}
    </Band>
  </>);
};

window.W2.PAGES["logs"] = Page;
})();
