/* ZY console — top-level app: login gate → boss cockpit → detail drawers. */
const DSA = window.ZYDesignSystem_d746df;

function KitLogin({ onLogin }) {
  const { Button } = DSA;
  // 真实登录：与 V1 (/sales/) 同一套账号密码，走 /console/api/login 会话闸。
  // internal key 永不进浏览器——登录后拿 Bearer 会话 token，数据请求经服务端闸注入密钥。
  const [u, setU] = React.useState("");
  const [p, setP] = React.useState("");
  const [err, setErr] = React.useState("");
  const [busy, setBusy] = React.useState(false);
  const submit = async (e) => {
    e.preventDefault();
    if (busy) return;
    setBusy(true); setErr("");
    try {
      const res = await fetch((window.ZY_API_BASE || "") + "/console/api/login", {
        method: "POST", headers: { "content-type": "application/json" },
        credentials: "same-origin", body: JSON.stringify({ user: u.trim(), pass: p }),
      });
      const body = await res.json().catch(() => ({}));
      if (!res.ok || !body.token) { setErr(body.message || ("登录失败（HTTP " + res.status + "）")); return; }
      try { sessionStorage.setItem("zy_console_token", body.token); } catch (_) { /* 私密模式等存储不可用时仅本次会话内存持有 */ }
      window.ZY_SESSION_TOKEN = body.token;
      onLogin(body.token);
    } catch (e2) {
      setErr("无法连接服务器，请稍后重试");
    } finally {
      setBusy(false);
    }
  };
  return (
    <div className="loginGate" data-screen-label="登录">
      <div className="loginGate__panel">
        <div className="loginGate__brand">
          <img src="assets/lieeflat-icon.png" alt="LIEEFLAT" />
          <div>
            <div className="loginGate__title">祝余 ZY 运营中台</div>
            <div className="loginGate__sub">经营驾驶舱 · 二代</div>
          </div>
        </div>
        <form className="loginGate__form" onSubmit={submit}>
          <input className="loginGate__input" value={u} onChange={e => setU(e.target.value)} placeholder="账号" autoComplete="username" />
          <input className="loginGate__input" value={p} type="password" onChange={e => setP(e.target.value)} placeholder="密码" autoComplete="current-password" />
          <Button variant="solid" type="submit" disabled={busy}>{busy ? "登录中…" : "登录进入运营中台"}</Button>
        </form>
        {err ? <div className="loginGate__note" style={{ color: "var(--negative)" }}>{err}</div> : <div className="loginGate__note">与一代中台同一套账号密码。</div>}
      </div>
    </div>
  );
}

function OrderDrawer({ order, onClose }) {
  const { Drawer, DSection, DField, Button, Icon, Pill } = DSA;
  if (!order) return null;
  // 双口径：员工口径不承担运费支出，用于提成核算；老板口径为全成本口径。
  // 成本缺失单（cost/profit=null，真数据 cost_missing 异常）无法核算——显「—」，绝不把 null 当 0 算出误导数字。
  const costKnown = order.cost != null && order.profit != null;
  const empCost = costKnown ? order.cost - (order.freightOut || 0) : null;
  const empProfit = costKnown ? order.profit + (order.freightOut || 0) : null;
  const empMargin = costKnown && order.amount ? Math.round((empProfit / order.amount) * 100) : null;
  const dash = (v, fmt) => (v == null ? "—" : fmt(v));
  const platFee = order.plat === "线下客户" ? 0 : Math.round(order.amount * 0.04);
  return (
    <Drawer open={!!order} onClose={onClose}
      title={"订单 " + order.id} tag={order.abn ? order.abnType : "正常"} tagTone={order.abn ? "danger" : "good"}
      sub={order.plat + " · " + order.rep + " · " + order.store}
      footer={<>
        <span className="drawer__footnote"><Icon name="ShieldCheck" size={14} />只读观察 · 不写业务系统</span>
        <Button variant="solid">标记已处理</Button>
      </>}>
      <DSection title="订单" icon="Package">
        <DField k="下单时间" v={order.at} />
        <DField k="买家" v={order.buyer} />
        <DField k="业务员" v={order.rep} />
        <DField k="店铺" v={order.store} />
        <DField k="平台单号" v={order.pno} mono />
        <DField k="内部单号" v={order.ino} mono />
        <DField k="SKU" v={order.sku} full />
        <DField k="快递 / 物流号" v={order.express + " · " + order.lno} full />
        <DField k="数量" v={order.qty} mono />
        <DField k="发货状态" v={order.ship} />
        <DField k="备注" v={order.note} full />
      </DSection>
      <div className="dsection">
        <div className="dsection__t"><Icon name="Wallet" size={14} />利润 · 双口径计算</div>
        <div className="calibox">
          <div className="calibox__col calibox__col--emp">
            <div className="calibox__cap"><Icon name="User" size={13} />员工视角</div>
            <div className="calibox__r"><span>销售额</span><b>{window.yuan(order.amount)}</b></div>
            <div className="calibox__r"><span>成本（不含运费）</span><b>{dash(empCost, window.yuan)}</b></div>
            <div className="calibox__r"><span>员工利润</span><b className={empProfit == null ? "calibox__big" : empProfit >= 0 ? "pos calibox__big" : "neg calibox__big"}>{dash(empProfit, window.yuan)}</b></div>
            <div className="calibox__r"><span>毛利率</span><b>{empMargin == null ? "—（成本缺失）" : empMargin + "%"}</b></div>
          </div>
          <div className="calibox__col calibox__col--boss">
            <div className="calibox__cap"><Icon name="Crown" size={13} />老板视角</div>
            <div className="calibox__r"><span>销售额</span><b>{window.yuan(order.amount)}</b></div>
            <div className="calibox__r"><span>成本（全口径）</span><b>{dash(order.cost, window.yuan)}</b></div>
            <div className="calibox__r"><span>老板利润</span><b className={order.profit == null ? "calibox__big" : order.profit >= 0 ? "pos calibox__big" : "neg calibox__big"}>{dash(order.profit, window.yuan)}</b></div>
            <div className="calibox__r"><span>毛利率</span><b>{order.margin == null ? "—（成本缺失）" : order.margin + "%"}</b></div>
          </div>
        </div>
        <div style={{ display: "flex", gap: 7, marginTop: 10, fontSize: 11.5, color: "var(--fg-3)", lineHeight: 1.55 }}>
          <Icon name="Info" size={13} style={{ flexShrink: 0, marginTop: 1 }} />
          <span>员工口径不承担运费 / 平台扣费，用于核算提成；老板口径为全成本口径。两者<b style={{ color: "var(--fg-2)" }}>不可混入同一个数字</b>。</span>
        </div>
      </div>
      <DSection title="费用明细" icon="Receipt">
        <DField k="运费收入" v={window.yuan(order.freightIn)} mono />
        <DField k="运费支出" v={window.yuan(order.freightOut)} mono />
        <DField k="平台支出" v={window.yuan(platFee)} mono />
        <DField k="提成" v={window.yuan(order.commission)} mono />
        <DField k="利润差异（老板−员工）" v={window.yuan(order.profit - empProfit)} mono full />
      </DSection>
      <DSection title="审计边界" icon="ShieldCheck" audit>
        <DField k="是否写业务系统" v="否" />
        <DField k="是否发消息" v="否" />
        <DField k="回滚" v="不适用（只读观察）" full />
      </DSection>
    </Drawer>
  );
}

function PlatformDrawer({ platform, onOrder, onClose }) {
  const { Drawer, DSection, DField, Icon } = DSA;
  const K = window.KIT;
  if (!platform) return null;
  const orders = K.orders.filter(o => o.plat === platform.name);
  const list = orders.length ? orders : K.orders;
  return (
    <Drawer open={!!platform} onClose={onClose}
      title={platform.name} tag="平台经营" tagTone="accent"
      sub={"运营 COO " + platform.coo + " · " + platform.group}>
      <DSection title="今日经营" icon="Store">
        <DField k="GMV" v={window.yuan(platform.gmv)} mono />
        <DField k="同比" v={(platform.delta >= 0 ? "+" : "") + platform.delta + "%"} mono />
        <DField k="运营 COO" v={platform.coo} />
        <DField k="平台分组" v={platform.group} />
      </DSection>
      <div className="dsection">
        <div className="dsection__t"><Icon name="Wallet" size={14} />利润 · 双口径计算</div>
        <div className="calibox">
          <div className="calibox__col calibox__col--emp">
            <div className="calibox__cap"><Icon name="User" size={13} />员工视角</div>
            <div className="calibox__r"><span>平台利润</span><b className="pos calibox__big">{window.yuan(platform.profitEmp)}</b></div>
            <div className="calibox__r"><span>口径</span><b style={{ fontFamily: "var(--font-sans)", fontWeight: 600 }}>不含运费</b></div>
          </div>
          <div className="calibox__col calibox__col--boss">
            <div className="calibox__cap"><Icon name="Crown" size={13} />老板视角</div>
            <div className="calibox__r"><span>平台利润</span><b className="pos calibox__big">{window.yuan(platform.profitBoss)}</b></div>
            <div className="calibox__r"><span>毛利率</span><b>{platform.margin}%</b></div>
          </div>
        </div>
      </div>
      <div className="dsection">
        <div className="dsection__t"><Icon name="ClipboardList" size={14} />近期订单（点击查看明细）</div>
        <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
          {list.map(o => (
            <button key={o.id} onClick={() => onOrder(o)} style={{
              display: "flex", justifyContent: "space-between", alignItems: "center", gap: 10,
              padding: "10px 12px", border: "1px solid var(--border)", borderRadius: 11,
              background: "var(--surface)", textAlign: "left", cursor: "pointer" }}>
              <span style={{ minWidth: 0 }}>
                <span style={{ fontSize: 13, fontWeight: 600 }} className="num">{o.id}</span>
                <span style={{ fontSize: 11.5, color: "var(--fg-3)", marginLeft: 8 }}>{o.buyer} · {o.rep}</span>
              </span>
              <span className="num" style={{ fontSize: 13, fontWeight: 700 }}>{window.yuan(o.amount)}</span>
            </button>
          ))}
        </div>
      </div>
    </Drawer>
  );
}

function ExceptionDrawer({ exc, onAct, onClose }) {
  const { Drawer, DSection, DField, Button, Icon, Pill } = DSA;
  const TONE = { "待处理": "warn", "处理中": "accent", "已修正": "good", "已关闭": "neutral" };
  const [accepted, setAccepted] = React.useState(false);
  if (!exc) return null;
  const open = exc.status === "待处理" || exc.status === "处理中";
  const openFix = () => onAct({
    title: "提交订单修正（受控写 · 需审批）", subject: exc.sku + " · " + exc.id,
    phrase: "确认修正", submitLabel: "提交修正",
    preview: [
      { k: "店铺", v: exc.store }, { k: "业务员", v: exc.rep },
      { k: "异常类型", v: exc.type }, { k: "涉及金额", v: window.yuan(exc.amount) },
    ],
    rollbackNote: "修正可在重算前撤销", danger: false,
  });
  return (
    <Drawer open={!!exc} onClose={onClose}
      title={exc.sku} sub={"异常单 " + exc.id + " · " + exc.type + " · " + exc.store}
      tag={exc.status} tagTone={TONE[exc.status]}
      footer={<>
        <span className="drawer__footnote"><Icon name="ShieldCheck" size={13} />业务动作 · 提交后留痕 · 不自动退款</span>
        {open && <span className="drawer__btns">
          {exc.status === "待处理" && (accepted
            ? <span className="drawer__ack"><Icon name="Check" size={13} />已受理</span>
            : <Button variant="ghost" size="sm" onClick={() => setAccepted(true)}>受理</Button>)}
          <Button variant="ghost" size="sm" onClick={onClose}>关闭</Button>
          <Button variant="solid" size="sm" onClick={openFix}>提交订单修正</Button>
        </span>}
      </>}>
      <DSection title="异常 · 研判" icon="TriangleAlert">
        <DField k="异常类型" v={exc.type} />
        <DField k="严重程度" v={exc.sev} />
        <DField k="处理状态" v={exc.status} />
        <DField k="来源时间" v={exc.at} />
        <DField k="异常详情" v={exc.detail} full />
        <DField k="处理建议" v={exc.suggestion} full />
      </DSection>
      <DSection title="关联订单" icon="ScrollText">
        <DField k="店铺" v={exc.store} />
        <DField k="业务员" v={exc.rep} />
        <DField k="平台订单号" v={exc.pno} mono />
        <DField k="内部单号" v={exc.ino} mono />
        <DField k="SKU" v={exc.sku} full />
        <DField k="涉及金额" v={window.yuan(exc.amount)} mono />
      </DSection>
      <DSection title="审计边界" icon="ShieldCheck" audit>
        <DField k="是否自动退款" v="否" />
        <DField k="是否写业务系统" v="修正提交后写入并留痕" full />
        <DField k="回滚" v="修正可在重算前撤销" full />
      </DSection>
    </Drawer>
  );
}

function ApprovalDrawer({ approval, onAct, onClose }) {
  const { Drawer, DSection, DField, Button, Icon } = DSA;
  const [rejected, setRejected] = React.useState(false);
  if (!approval) return null;
  const openApprove = () => onAct({
    title: approval.title, subject: approval.type + " · " + approval.from,
    phrase: "确认核发", submitLabel: "确认拍板并执行",
    preview: [
      { k: "上报方", v: approval.from }, { k: "时间", v: approval.time },
      ...(approval.amount ? [{ k: "涉及金额", v: window.yuan(approval.amount) }] : []),
    ],
    rollbackNote: "可在 24h 内撤销该核发", danger: false,
  });
  return (
    <Drawer open={!!approval} onClose={onClose}
      title={approval.type} tag={rejected ? "已驳回" : "待老板拍板"} tagTone={rejected ? "neutral" : "warn"} sub={approval.from + " · " + approval.time}
      footer={<>
        <span className="drawer__footnote"><Icon name="ShieldCheck" size={14} />只读查看 · 拍板前不会写入</span>
        {!rejected && <span style={{ display: "flex", gap: 8 }}>
          <Button variant="ghost" onClick={() => setRejected(true)}>驳回</Button>
          <Button variant="solid" onClick={openApprove}>确认拍板</Button>
        </span>}
      </>}>
      <DSection title="事项" icon="Inbox">
        <DField k="标题" v={approval.title} full />
        <DField k="上报方" v={approval.from} />
        <DField k="时间" v={approval.time} />
        {approval.amount ? <DField k="涉及金额" v={window.yuan(approval.amount)} mono /> : null}
      </DSection>
      <DSection title="受控动作边界" icon="ShieldCheck" audit>
        <DField k="是否需要预检" v="是" />
        <DField k="确认短语" v="确认核发" />
        <DField k="回滚说明" v="可在 24h 内撤销该核发" full />
      </DSection>
    </Drawer>
  );
}

function HermesDrawer({ focus, onClose, onNav }) {
  const { Drawer, Icon } = DSA;
  const K = window.KIT;
  const ICON = { warn: "TriangleAlert", danger: "OctagonAlert", info: "Info", good: "CircleCheck" };
  const seed = focus
    ? [{ who: "coo", text: <span>关于「<b>{focus.title}</b>」：{focus.body} 来源 {focus.tag}。需要我带你前往对应证据吗？</span> }]
    : [{ who: "coo", text: <span>早安，老板。今日已接入真实只读数据：<b>{K.approvals.length} 件</b>需拍板、<b>{K.insights.length} 项</b>经营风险、<b>{K.todos.length} 项</b>可交给 COO / 员工。想先看哪一块？</span> }];
  const [msgs, setMsgs] = React.useState(seed);
  const [val, setVal] = React.useState("");
  const gotoEvidence = (ins) => { if (ins && ins.view && onNav) { onNav(ins.view); onClose && onClose(); } };
  const bodyRef = React.useRef(null);
  React.useEffect(() => { const b = document.querySelector(".drawer__body"); if (b) b.scrollTop = b.scrollHeight; }, [msgs]);

  // 罐头回复不携带任何具体数字（写死数字=示例数据冒充真实,利润数字更违财务铁律）——只给口径与入口指引
  const reply = (q) => {    if (/利润|口径|毛利/.test(q)) return "利润按双口径算：员工口径不含运费 / 平台支出，用于核算提成；老板口径为全成本口径。财务只监督证据、不发布利润数字——证据门控状态在 财务 COO › 双轨利润口径监督。";
    if (/异常|缺货|退款|改址/.test(q)) return "异常订单的真实清单与优先级在 订单中心 › 异常处理，本页顶部「本月异常订单」卡是真实计数。建议从高优先级开始受理。";
    if (/提成|审核/.test(q)) return "提成核发是逐单受控动作：待审核明细在 财务 COO › 提成核发，超阈值单会进「待你拍板」队列。";
    if (/投流|京喜|roi/i.test(q)) return "投流健康度看 投流 COO 工作台（消耗 / 询盘成本 / 止损）；负毛利风险项会进本页「经营洞察」。";
    return "我已读取今日只读数据。你可以问我利润口径、异常订单、提成审核或投流 ROI，我会指给你对应工作台与证据入口。";
  };
  const send = (q) => {
    const text = (q || val).trim();
    if (!text) return;
    setMsgs(m => [...m, { who: "me", text }, { who: "coo", text: reply(text) }]);
    setVal("");
  };

  return (
    <Drawer open onClose={onClose}
      title={<span style={{ display: "inline-flex", alignItems: "center", gap: 9 }}><span className="hmsg__orb"><Icon name="Sparkles" size={15} /></span>Hermes</span>}
      tag="今日早报" tagTone="accent" sub="AI 副手 · 复盘与建议 · 只读观察"
      footer={<div className="hinput">
        <input value={val} placeholder="问问 Hermes…（利润口径 / 异常 / 提成 / 投流）"
          onChange={e => setVal(e.target.value)} onKeyDown={e => { if (e.key === "Enter") send(); }} />
        <button className="btn btn--solid" onClick={() => send()}><Icon name="Send" size={15} /></button>
      </div>}>
      <div className="hbrief">
        <div className="hbrief__c hbrief__c--decide"><div className="hbrief__n">{K.approvals.length}</div><div className="hbrief__l">需拍板</div></div>
        <div className="hbrief__c hbrief__c--risk"><div className="hbrief__n">{K.insights.length}</div><div className="hbrief__l">经营风险</div></div>
        <div className="hbrief__c hbrief__c--deleg"><div className="hbrief__n">{K.todos.length}</div><div className="hbrief__l">可委派</div></div>
      </div>

      <div ref={bodyRef} style={{ flexShrink: 0, margin: "2px 0" }}>
        <div className="hchat">
          {msgs.map((m, i) => (
            <div className={"hmsg hmsg--" + (m.who === "me" ? "me" : "coo")} key={i}>
              {m.who === "coo" && <span className="hmsg__orb"><Icon name="Sparkles" size={14} /></span>}
              <div className="hmsg__b">{m.text}</div>
            </div>
          ))}
        </div>
        {focus && focus.view && (
          <button className="hgoto" onClick={() => gotoEvidence(focus)}>
            <span className="hgoto__ic"><Icon name="MapPin" size={14} /></span>
            <span className="hgoto__txt">前往证据 · <b>{focus.evidence || "对应工作台"}</b></span>
            <Icon name="ArrowRight" size={15} stroke={2} />
          </button>
        )}
      </div>

      <div>
        <div className="hsec">今日洞察 · 点击展开</div>
        <div className="insightlist">
          {K.insights.map(ins => (
            <div className={"insight insight--" + ins.level} key={ins.id}
              onClick={() => send("说说「" + ins.title + "」")} role="button" tabIndex={0} style={{ cursor: "pointer" }}>
              <span className="insight__ic"><Icon name={ICON[ins.level]} size={16} /></span>
              <span className="insight__body">
                <span className="insight__title">{ins.title}</span>
                <span className="insight__text">{ins.body}</span>
                <span className="insight__foot"><span className="insight__tag">{ins.tag}</span>
                  {ins.view
                    ? <button className="insight__goto" onClick={e => { e.stopPropagation(); gotoEvidence(ins); }}><Icon name="MapPin" size={12} />前往 {ins.evidence} <Icon name="ArrowRight" size={12} stroke={2} /></button>
                    : <span className="insight__act">{ins.action} <Icon name="ArrowRight" size={13} stroke={2} /></span>}</span>
              </span>
            </div>
          ))}
        </div>
      </div>

      <div>
        <div className="hsec">建议问我</div>
        <div className="hsugs">
          {["今天为什么要拍板？", "解释一下双口径利润", "异常订单怎么处理", "京喜为什么负毛利"].map(s => (
            <button className="hsug" key={s} onClick={() => send(s)}>{s}</button>
          ))}
        </div>
      </div>
    </Drawer>
  );
}

function StubView({ wb, tab }) {
  const { Icon, EmptyBox } = DSA;
  return (
    <div className="view viewfade">
      <div className="card card--pad ovstrip">
        <div className="ovstrip__head">
          <span className="ovstrip__orb"><Icon name={wb.icon} size={20} /></span>
          <div className="ovstrip__id">
            <div className="ovstrip__title">{tab.label}<span className="ovstrip__mode"><span className="ovstrip__dot" />{wb.role}</span></div>
            <div className="ovstrip__judge">{wb.label} · 二级功能页 · 只读观察，写入走预检 / 审批 / 回执闸门</div>
          </div>
          <div className="ovstrip__src">
            <span className="ovstrip__srclabel">数据源</span>
            <span className="ovstrip__srcval">{tab.src || "—"}</span>
          </div>
        </div>
      </div>
      <EmptyBox title={tab.label + " · 待接入真实只读数据"}
        reason={"数据源：" + (tab.src || "—") + "。该功能页在本 UI Kit 中尚未做高保真复刻；按系统规则，缺源时显示空状态，不使用演示数据补位。已完成高保真：老板总控 · 订单中心 · 平台经营 · Hermes 副手。"} />
    </div>
  );
}

function App() {
  // 已有有效会话 token（本 tab 内登录过）则直接进入；数据注水在登录后进行。
  const [logged, setLogged] = React.useState(() => {
    try {
      const t = window.sessionStorage && sessionStorage.getItem("zy_console_token");
      if (t) { window.ZY_SESSION_TOKEN = t; return true; }
    } catch (_) { /* 存储不可用则要求重新登录 */ }
    return false;
  });
  const [, setHydrated] = React.useState(0); // live 注水完成后 bump 触发重渲染（视图读 window.KIT）
  React.useEffect(() => {
    if (!logged) return;
    (async () => {
      try { if (typeof window.ZY_hydrate === "function") await window.ZY_hydrate(window.KIT); }
      catch (e) { console.warn("[ZY_SOURCES] hydrate 异常，保留 mock：", e && e.message); }
      setHydrated(h => h + 1);
    })();
  }, [logged]);
  const [tabId, setTabId] = React.useState("boss.cockpit");
  const [drawer, setDrawer] = React.useState(null); // {type, data}
  const [gate, setGate] = React.useState(null); // controlled-action

  if (!logged) return <KitLogin onLogin={() => setLogged(true)} />;

  const WB = window.KIT.workbenches;
  const wb = WB.find(w => w.tabs.some(t => t.id === tabId)) || WB[0];
  const tab = wb.tabs.find(t => t.id === tabId) || wb.tabs[0];
  const view = tab.view;
  const title = wb.id === "boss" ? "经营驾驶舱" : wb.label;
  const sub = wb.tabs.length > 1 ? tab.label : wb.role;
  // 顶栏「数据更新于」随当前视图的 read-model freshness 走（有 digest 的视图），其余回退全局 today
  const viewFresh = { shopify: window.KIT.shopifyDigest.freshness.captured_at, tiktok: window.KIT.tiktokDigest.captured_at }[view];
  const td = viewFresh
    ? (() => { const [d, t] = viewFresh.split(" "); const wd = ["周日", "周一", "周二", "周三", "周四", "周五", "周六"][new Date(d + "T00:00:00").getDay()]; return { date: d + " " + wd, updated: t }; })()
    : window.KIT.today;
  const goTab = (id) => { setTabId(id); setGate(null); setDrawer(null); };

  return (
    <div className="app" data-screen-label={wb.label}>
      <window.KitSidebar tabId={tabId} onTab={goTab} />
      <div className="main">
        <window.KitTopbar title={title} sub={sub} date={td.date} updated={td.updated} approvals={window.KIT.approvals.length} onHermes={() => setDrawer({ type: "hermes", data: null })} />
        <div className="scroll">
          {view === "overview" && <window.KitOverview
            onHermes={ins => setDrawer({ type: "hermes", data: ins || null })}
            onApproval={a => setDrawer({ type: "approval", data: a })}
            onPlatform={p => setDrawer({ type: "platform", data: p })}
            onNav={goTab}
          />}
          {view === "orders" && <window.KitOrders
            onOrder={o => setDrawer({ type: "order", data: o })}
            onException={e => setDrawer({ type: "exception", data: e })}
          />}
          {view === "mzreview" && (typeof window.KitMzReview === "function" ? <window.KitMzReview onAct={a => setGate(a)} /> : <StubView wb={wb} tab={tab} />)}
          {view === "platforms" && <window.KitPlatforms
            focus={tab.focus}
            onPlatform={p => setDrawer({ type: "platform", data: p })}
          />}
          {view === "store1688" && (typeof window.KitStore1688 === "function" ? <window.KitStore1688 onAct={a => setGate(a)} /> : <StubView wb={wb} tab={tab} />)}
          {view === "shopee" && (typeof window.KitShopeeCoo === "function" ? <window.KitShopeeCoo onAct={a => setGate(a)} /> : <StubView wb={wb} tab={tab} />)}
          {view === "supply" && <window.KitProcurement onAct={a => setGate(a)} />}
          {view === "flow" && <window.KitFlow />}
          {view === "cost" && <window.KitCost onAct={a => setGate(a)} />}
          {view === "ads" && <window.KitAds focus={tab.focus} />}
          {view === "ads1688" && (typeof window.KitAds1688 === "function" ? <window.KitAds1688 /> : <StubView wb={wb} tab={tab} />)}
          {view === "tiktok" && <window.KitTiktok />}
          {view === "shopify" && <window.KitShopify />}
          {view === "crm" && <window.KitCrm onAct={a => setGate(a)} />}
          {view === "funnel" && <window.KitFunnel />}
          {view === "materialfactory" && (typeof window.KitMaterialFactory === "function" ? <window.KitMaterialFactory /> : <StubView wb={wb} tab={tab} />)}
          {view === "warehouse" && <window.KitWarehouse />}
          {view === "freight" && <window.KitFreight onAct={a => setGate(a)} />}
          {view === "finance" && <window.KitFinance onNav={goTab} onAct={a => setGate(a)} />}
          {view === "commission" && <window.KitCommission onAct={a => setGate(a)} />}
          {view === "manual" && <window.KitManual onAct={a => setGate(a)} />}
          {view === "monthly" && <window.KitMonthly />}
          {view === "todo" && <window.KitTodo onNav={goTab} />}
          {view === "audit" && <window.KitAudit />}
          {view === "workers" && <window.KitWorkers />}
          {view === "accounts" && <window.KitAccounts />}
          {view === "llm" && <window.KitLlm />}
          {view === "cmd" && <window.KitCmd onAct={a => setGate(a)} />}
          {view === "stub" && <StubView wb={wb} tab={tab} />}
        </div>
      </div>
      {drawer && drawer.type === "order" && <OrderDrawer order={drawer.data} onClose={() => setDrawer(null)} />}
      {drawer && drawer.type === "platform" && <PlatformDrawer platform={drawer.data}
        onOrder={o => setDrawer({ type: "order", data: o })} onClose={() => setDrawer(null)} />}
      {drawer && drawer.type === "hermes" && <HermesDrawer focus={drawer.data} onNav={goTab} onClose={() => setDrawer(null)} />}
      {drawer && drawer.type === "exception" && <ExceptionDrawer exc={drawer.data} onAct={a => setGate(a)} onClose={() => setDrawer(null)} />}
      {drawer && drawer.type === "approval" && <ApprovalDrawer approval={drawer.data} onAct={a => setGate(a)} onClose={() => setDrawer(null)} />}
      {gate && <window.KitControlledAction action={gate} onClose={() => setGate(null)} />}
    </div>
  );
}

// 直接挂载：登录前显示登录页；live 数据注水在登录成功后由 App 内 effect 执行
// （需要 Bearer 会话 token 走 /console/api 闸，所以不能在登录前拉）。
ReactDOM.createRoot(document.getElementById("root")).render(<App />);
