/* WAREHOUSE 2.0 · 財務 — Swiss 版式,真後端
   複式總賬駕駛艙(只讀):利潤表 / 資產負債表 / 現金流量表 / AP·AR 賬齡 / 記賬憑證
   一切動賬 = 交給財務秘書;借貸平衡由後端 GL 引擎保證 */
(() => {
const W2 = window.W2;
const { t } = window.W2_LANG;
window.W2_LANG.addEN({
  "財務": "Finance", "問秘書": "Ask Secretary", "交給秘書": "Secretary",
  "2.0 約定:頁面只讀,改動經秘書確認執行,全程留痕。": "2.0 contract: pages are read-only; changes run through the Secretary with full audit.",
  "複式總賬即時推算 · 頁面只讀,動賬交秘書,借貸平衡由後端保證": "Computed live from the double-entry ledger · read-only page, postings via Secretary, balance guaranteed by the backend",
  "本期財務怎麼樣?利潤、現金、應收應付撿重點講,有風險直接說。": "How are the finances this period? Hit the highlights — profit, cash, AR/AP — and flag any risk directly.",
  "月末結賬": "Close period",
  "幫我做 {p} 的期末結賬結轉損益(用 fin close);結賬會鎖定期間,執行前先跟我確認。": "Run the {p} period close and transfer P&L (fin close); closing locks the period, confirm with me before executing.",
  "本月": "Month", "本季": "Quarter", "本年": "Year",
  "動賬交秘書": "Post via Secretary",
  "補錄流水": "Backfill entry",
  "幫我補錄一筆賬:先問我是收款、付款還是開銷,再追問對方、金額、日期,複述確認後入賬。": "Backfill an entry for me: first ask whether it is a receipt, a payment or an expense, then ask for the party, amount and date; repeat it back for my confirmation before posting.",
  "收客戶款": "Record receipt",
  "幫我記一筆收款:收到客戶 ___ ¥___(用 fin receive),請追問客戶和金額後執行。": "Record a receipt: customer ___ paid ¥___ (fin receive); ask me for the customer and amount, then execute.",
  "付供應商款": "Record payment",
  "幫我記一筆付款:付給供應商 ___ ¥___(用 fin pay),請追問供應商和金額後執行。": "Record a payment: pay supplier ___ ¥___ (fin pay); ask me for the supplier and amount, then execute.",
  "記 AA 開銷": "AA expense",
  "幫我記一筆 AA 共享開銷:墊付人、金額、項目、怎麼分攤,逐項追問我(用 fin expense)。": "Record a shared AA expense: ask me one by one for the payer, amount, item and how to split it (fin expense).",
  "本期利潤": "Profit · period", "現金及銀行": "Cash & bank", "應收未收": "AR outstanding", "應付未付": "AP outstanding",
  "元": "CNY", "萬元": "×10⁴ CNY", "億元": "×10⁸ CNY",
  "收入 {v}": "Revenue {v}",
  "本期淨流 {v}": "Net cash {v}",
  "{n} 個客戶": "{n} customers", "{n} 個供應商": "{n} suppliers",
  "讓秘書催收 →": "Chase via Secretary →",
  "把應收賬款按賬齡列出來,幫我催收拖得最久的那幾筆,起草催款話術。": "List receivables by age and help me chase the oldest ones — draft the reminder message.",
  "總賬還是空的——這正常,不是沒同步。": "The ledger is still empty — that is normal, not a sync problem.",
  "總賬是事件驅動的:只在新發生的採購、銷售、收付款時自動記賬,不會倒灌歷史庫存。做一次期初建賬,財務就和現有家底對上;物資要有單價才有價值。": "The ledger is event-driven: it posts automatically only on new purchases, sales and payments — it never back-fills historical stock. Run an opening-balance setup once and the books will match what you own; items need a unit price to carry value.",
  "讓秘書期初建賬": "Opening balances via Secretary",
  "幫我做期初建賬,把現有庫存價值計入總賬(用 fin init-balances);期初現金和銀行金額你來追問我。": "Set up opening balances and post current inventory value to the ledger (fin init-balances); ask me for the opening cash and bank amounts.",
  "三大報表": "Financial statements",
  "口徑:{p} · 即時從總賬推算": "Basis: {p} · computed live from the ledger",
  "讓秘書解讀": "Explain via Secretary",
  "把本期利潤表、資產負債表、現金流量表用大白話講一遍,指出異常和風險。": "Walk me through this period's P&L, balance sheet and cash flow in plain words, and point out anomalies and risks.",
  "利潤表": "Profit & loss", "資產負債表": "Balance sheet", "現金流量表": "Cash flow",
  "營業收入": "Revenue", "營業成本": "Cost of sales", "費用": "Expenses", "淨利潤": "Net profit",
  "資產合計": "Total assets", "負債合計": "Total liabilities", "本年利潤": "Current-year profit", "權益合計": "Total equity",
  "現金流入": "Cash in", "現金流出": "Cash out", "淨增加": "Net change",
  "平衡": "Balanced", "不平衡": "Unbalanced",
  "截至 {d}": "As of {d}",
  "往來對賬": "Receivables & payables",
  "賬齡分桶 0-30 / 31-60 / 61-90 / >90 天": "Aging buckets 0-30 / 31-60 / 61-90 / >90 days",
  "讓秘書對賬": "Reconcile via Secretary",
  "把應收應付逐個往來方對一遍賬,列出賬齡最久的幾筆,給出催收和付款建議。": "Reconcile AR and AP party by party, list the oldest open items, and recommend chasing and payment actions.",
  "應收賬款 · 客戶欠我": "AR · owed by customers",
  "應付賬款 · 我欠供應商": "AP · owed to suppliers",
  "天": "d",
  "暫無未結往來": "No open items",
  "讓秘書催收": "Chase payment", "安排付款": "Schedule payment",
  "客戶「{p}」還欠 {amt}:幫我催收,起草催款話術並登記跟進;若款已到就記收款核銷(fin receive)。": "Customer \"{p}\" still owes {amt}: help me chase it — draft a reminder and log the follow-up; if the money arrived, record the receipt and settle it (fin receive).",
  "還欠供應商「{p}」{amt}:幫我安排付款計劃並記賬核銷(fin pay),付款前和我確認金額。": "We still owe supplier \"{p}\" {amt}: plan the payment and post it with settlement (fin pay); confirm the amount with me before paying.",
  "記賬憑證": "Vouchers",
  "最近 {n} 張 · 業務發生自動生成,每張借貸平衡": "Latest {n} · auto-generated from business events, each one balanced",
  "憑證號": "Voucher no.", "日期": "Date", "摘要": "Summary", "分錄": "Entries", "金額": "Amount",
  "借": "DR", "貸": "CR",
  "暫無憑證": "No vouchers yet",
  "出入庫、採購、銷售、收付款發生後會自動生成憑證;歷史賬讓秘書補錄即可。": "Vouchers are generated automatically after stock moves, purchases, sales and payments; ask the Secretary to backfill history.",
  "補錄一筆": "Backfill one",
  "解釋憑證 {no}({s}):這筆賬怎麼來的?借貸分錄逐條講給我聽。": "Explain voucher {no} ({s}): where did this posting come from? Walk me through each debit/credit line.",
  "問這張": "Explain",
});

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

/* 金額:全額(表格)與巨數縮寫(KPI 帶) */
const money = (v) => {
  const n = Number(v);
  return "¥" + (Number.isFinite(n) ? n : 0).toLocaleString("zh-CN", { minimumFractionDigits: 2, maximumFractionDigits: 2 });
};
const kAmt = (v) => {
  const n = Number(v) || 0, a = Math.abs(n);
  if (a >= 1e8) return [(n / 1e8).toFixed(2), t("億元")];
  if (a >= 1e5) return [(n / 1e4).toFixed(1), t("萬元")];
  return [n.toLocaleString("zh-CN", { maximumFractionDigits: 0 }), t("元")];
};
const periodsOf = () => {
  const d = new Date(), y = d.getFullYear(), m = d.getMonth() + 1, q = Math.floor((m - 1) / 3) + 1;
  return [
    { id: y + "-" + pad2(m), label: "本月" },
    { id: y + "-Q" + q, label: "本季" },
    { id: String(y), label: "本年" },
  ];
};

/* 報表行:年報式髮絲行,合計行加粗頂線 */
const SRow = ({ k, v, strong, tone, dim }) => (
  <div className="row spread" style={{ padding: "9px 2px", gap: 12, borderTop: strong ? "2px solid var(--rule)" : "1px solid var(--hair-soft)" }}>
    <span style={{ fontSize: 12.5, minWidth: 0, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap",
      fontWeight: strong ? 700 : 500, color: dim ? "var(--ink-3)" : strong ? "var(--ink)" : "var(--ink-2)", paddingLeft: dim ? 12 : 0 }}>{k}</span>
    <span className="num" style={{ flexShrink: 0, fontSize: strong ? 15 : 12.5, fontWeight: strong ? 700 : 550,
      color: tone || (dim ? "var(--ink-3)" : "var(--ink)") }}>{v}</span>
  </div>
);
const Stmt = ({ title, meta, tag, rows }) => (
  <div className="col" style={{ minWidth: 0 }}>
    <div className="row spread" style={{ paddingBottom: 10, borderBottom: "2px solid var(--rule)", gap: 10 }}>
      <LB>{title}</LB>
      <span className="row g8">{tag}{meta && <span className="mono muted" style={{ fontSize: 9.5, letterSpacing: ".08em" }}>{meta}</span>}</span>
    </div>
    <div className="col">{rows.map((r, i) => <SRow key={i} {...r}/>)}</div>
  </div>
);

/* 往來方塊:合計 + 賬齡桶 + 各往來方(每行交秘書追賬) */
const PartyBlock = ({ title, data, isAR }) => {
  const d = data || {};
  const parties = Array.isArray(d.by_party) ? d.by_party : [];
  const aging = d.aging || {};
  return (
    <div className="col g12" style={{ minWidth: 0 }}>
      <div className="row spread" style={{ paddingBottom: 10, borderBottom: "2px solid var(--rule)", gap: 10 }}>
        <LB>{title}</LB>
        <span className="num" style={{ fontSize: 16, fontWeight: 700, color: num(d.total_outstanding) > 0 ? "var(--ink)" : "var(--ink-3)" }}>{money(d.total_outstanding)}</span>
      </div>
      <div className="row g6 wrap">
        {["0-30", "31-60", "61-90", ">90"].map(k => (
          <span key={k} className="chip" style={{ cursor: "default", color: num(aging[k]) > 0 ? "var(--ink)" : "var(--ink-4)" }}>
            <span className="mono" style={{ fontSize: 10, letterSpacing: ".06em" }}>{k}{t("天")}</span>
            <b className="num" style={{ fontSize: 11.5 }}>{money(aging[k])}</b>
          </span>
        ))}
      </div>
      {parties.length ? (
        <div style={{ borderTop: "1px solid var(--hair)" }}>
          {parties.slice(0, 6).map((p, i) => (
            <div key={(p.party || "p") + i} className="ledger-row" style={{ gap: 12 }}>
              <span className="lr-idx">{pad2(i + 1)}</span>
              <span style={{ flex: 1, minWidth: 0, fontWeight: 650, fontSize: 13, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{p.party || "—"}</span>
              <span className="num" style={{ fontWeight: 700, fontSize: 14 }}>{money(p.outstanding)}</span>
              <B size="sm" icon="sparkle" onClick={() => ask(isAR
                ? t("客戶「{p}」還欠 {amt}:幫我催收,起草催款話術並登記跟進;若款已到就記收款核銷(fin receive)。", { p: p.party || "—", amt: money(p.outstanding) })
                : t("還欠供應商「{p}」{amt}:幫我安排付款計劃並記賬核銷(fin pay),付款前和我確認金額。", { p: p.party || "—", amt: money(p.outstanding) }))}>
                {isAR ? t("讓秘書催收") : t("安排付款")}
              </B>
            </div>
          ))}
        </div>
      ) : <div className="muted" style={{ fontSize: 12.5, padding: "16px 2px", borderTop: "1px solid var(--hair)" }}>{t("暫無未結往來")}</div>}
    </div>
  );
};

const Page = ({ boot }) => {
  const periods = _mm(() => periodsOf(), []);
  const [period, setPeriod] = _s(periods[0].id);
  const [incD, setIncD] = _s(null);
  const [cfD, setCfD] = _s(null);
  const [bsD, setBsD] = _s(null);
  const [apD, setApD] = _s(null);
  const [arD, setArD] = _s(null);
  const [vs, setVs] = _s(null);

  _e(() => {
    let on = true;
    W2.json("/api/erp/gl/income?period=" + encodeURIComponent(period)).then(d => on && setIncD(d || {})).catch(() => on && setIncD({}));
    W2.json("/api/erp/gl/cashflow?period=" + encodeURIComponent(period)).then(d => on && setCfD(d || {})).catch(() => on && setCfD({}));
    return () => { on = false; };
  }, [period]);
  _e(() => {
    W2.json("/api/erp/gl/balance-sheet").then(d => setBsD(d || {})).catch(() => setBsD({}));
    W2.json("/api/erp/gl/ap").then(d => setApD(d || {})).catch(() => setApD({}));
    W2.json("/api/erp/gl/ar").then(d => setArD(d || {})).catch(() => setArD({}));
    W2.json("/api/erp/gl/vouchers?limit=30").then(d => setVs(Array.isArray(d && d.vouchers) ? d.vouchers : [])).catch(() => setVs([]));
  }, []);

  const inc = incD || {}, cf = cfD || {}, bs = bsD || {}, ap = apD || {}, ar = arD || {};
  const vouchers = Array.isArray(vs) ? vs : [];
  const pLabel = t((periods.find(x => x.id === period) || periods[0]).label);
  const cashTotal = (Array.isArray(bs.asset_lines) ? bs.asset_lines : [])
    .filter(l => l && (l.code === "1001" || l.code === "1002"))
    .reduce((a, l) => a + num(l.amount), 0);
  const arTotal = num(ar.total_outstanding), apTotal = num(ap.total_outstanding);
  const [profitV, profitU] = kAmt(inc.profit);
  const [cashV, cashU] = kAmt(cashTotal);
  const [arV, arU] = kAmt(arTotal);
  const [apV, apU] = kAmt(apTotal);
  const ledgerEmpty = vs !== null && vouchers.length === 0;

  const backfillPrompt = () => ask(t("幫我補錄一筆賬:先問我是收款、付款還是開銷,再追問對方、金額、日期,複述確認後入賬。"));
  const quick = [
    ["補錄流水", "幫我補錄一筆賬:先問我是收款、付款還是開銷,再追問對方、金額、日期,複述確認後入賬。"],
    ["收客戶款", "幫我記一筆收款:收到客戶 ___ ¥___(用 fin receive),請追問客戶和金額後執行。"],
    ["付供應商款", "幫我記一筆付款:付給供應商 ___ ¥___(用 fin pay),請追問供應商和金額後執行。"],
    ["記 AA 開銷", "幫我記一筆 AA 共享開銷:墊付人、金額、項目、怎麼分攤,逐項追問我(用 fin expense)。"],
  ];

  /* 三大報表行(全部字段防禦性取值) */
  const plRows = [
    { k: t("營業收入"), v: money(inc.revenue) },
    { k: t("營業成本"), v: "− " + money(inc.cost) },
    { k: t("費用"), v: "− " + money(inc.expense) },
    ...(Array.isArray(inc.lines) ? inc.lines.slice(0, 4).map(l => ({ k: ((l && l.code) ? l.code + " " : "") + ((l && l.name) || "—"), v: money(l && l.amount), dim: true })) : []),
    { k: t("淨利潤"), v: money(inc.profit), strong: true, tone: num(inc.profit) < 0 ? "var(--red)" : "var(--ink)" },
  ];
  const bsRows = [
    { k: t("資產合計"), v: money(bs.assets) },
    ...(Array.isArray(bs.asset_lines) ? bs.asset_lines.slice(0, 3).map(l => ({ k: ((l && l.code) ? l.code + " " : "") + ((l && l.name) || "—"), v: money(l && l.amount), dim: true })) : []),
    { k: t("負債合計"), v: money(bs.liabilities) },
    { k: t("本年利潤"), v: money(bs.current_profit), dim: true },
    { k: t("權益合計"), v: money(bs.total_equity), strong: true },
  ];
  const cfRows = [
    { k: t("現金流入"), v: money(cf.inflow), tone: num(cf.inflow) > 0 ? "var(--ok)" : undefined },
    { k: t("現金流出"), v: "− " + money(cf.outflow), tone: num(cf.outflow) > 0 ? "var(--red)" : undefined },
    ...(Array.isArray(cf.accounts) ? cf.accounts.slice(0, 3).map(a => ({ k: ((a && a.code) ? a.code + " " : "") + ((a && a.name) || "—"), v: money(a && a.net), dim: true })) : []),
    { k: t("淨增加"), v: money(cf.net_change), strong: true, tone: num(cf.net_change) < 0 ? "var(--red)" : "var(--ink)" },
  ];
  const shown = vouchers.slice(0, 12);

  return (<>
    <Folio no="08" en="FINANCE" title={t("財務")}
      sub={t("複式總賬即時推算 · 頁面只讀,動賬交秘書,借貸平衡由後端保證")}
      right={<>
        <B icon="check" onClick={() => ask(t("幫我做 {p} 的期末結賬結轉損益(用 fin close);結賬會鎖定期間,執行前先跟我確認。", { p: period }))}>{t("月末結賬")}</B>
        <B kind="primary" icon="sparkle" onClick={() => ask(t("本期財務怎麼樣?利潤、現金、應收應付撿重點講,有風險直接說。"))}>{t("問秘書")}</B>
      </>}/>

    {/* 期間 + 動賬快捷指令(全部交秘書) */}
    <div className="row g14 wrap rise" style={{ padding: "18px 0 16px", borderBottom: "1px solid var(--hair)", animationDelay: ".05s" }}>
      <div className="seg">
        {periods.map(p => <button key={p.id} className={period === p.id ? "on" : ""} onClick={() => setPeriod(p.id)}>{t(p.label)}</button>)}
      </div>
      <span style={{ width: 1, height: 22, background: "var(--hair)" }}/>
      <LB dim>{t("動賬交秘書")}</LB>
      <div className="row g6 wrap">
        {quick.map(([label, prompt]) => (
          <button key={label} className="chip" onClick={() => ask(t(prompt))}><I name="sparkle" size={11}/>{t(label)}</button>
        ))}
      </div>
    </div>

    {/* KPI 帶:巨型數字 */}
    <div className="kpi-band">
      <Kpi label={t("本期利潤")} value={profitV} unit={profitU} red={num(inc.profit) < 0} delay={0}
        foot={<><span className="muted" style={{ fontSize: 11.5 }}>{t("收入 {v}", { v: money(inc.revenue) })}</span><T tone="plain">{pLabel}</T></>}/>
      <Kpi label={t("現金及銀行")} value={cashV} unit={cashU} delay={.05}
        foot={<span className="muted num" style={{ fontSize: 11.5, color: num(cf.net_change) < 0 ? "var(--red)" : undefined }}>{t("本期淨流 {v}", { v: money(cf.net_change) })}</span>}/>
      <Kpi label={t("應收未收")} value={arV} unit={arU} red={arTotal > 0} delay={.1}
        foot={arTotal > 0
          ? <button className="tag redinv" style={{ cursor: "pointer" }} onClick={() => ask(t("把應收賬款按賬齡列出來,幫我催收拖得最久的那幾筆,起草催款話術。"))}>{t("讓秘書催收 →")}</button>
          : <span className="muted" style={{ fontSize: 11.5 }}>{t("{n} 個客戶", { n: (Array.isArray(ar.by_party) ? ar.by_party : []).length })}</span>}/>
      <Kpi label={t("應付未付")} value={apV} unit={apU} delay={.15}
        foot={<span className="muted" style={{ fontSize: 11.5 }}>{t("{n} 個供應商", { n: (Array.isArray(ap.by_party) ? ap.by_party : []).length })}</span>}/>
    </div>

    {/* 空賬引導:總賬事件驅動,先期初建賬 */}
    {ledgerEmpty && (
      <div className="rise" style={{ border: "1px solid var(--ink)", background: "var(--white)", padding: "20px 24px", marginTop: 24,
        display: "flex", flexWrap: "wrap", gap: 18, alignItems: "center", justifyContent: "space-between" }}>
        <div className="col g6" style={{ maxWidth: 720, minWidth: 260 }}>
          <LB red>LEDGER EMPTY</LB>
          <div style={{ fontSize: 15, fontWeight: 700, letterSpacing: "-.02em" }}>{t("總賬還是空的——這正常,不是沒同步。")}</div>
          <div className="muted" style={{ fontSize: 12.5, lineHeight: 1.7 }}>{t("總賬是事件驅動的:只在新發生的採購、銷售、收付款時自動記賬,不會倒灌歷史庫存。做一次期初建賬,財務就和現有家底對上;物資要有單價才有價值。")}</div>
        </div>
        <B kind="primary" icon="sparkle" onClick={() => ask(t("幫我做期初建賬,把現有庫存價值計入總賬(用 fin init-balances);期初現金和銀行金額你來追問我。"))}>{t("讓秘書期初建賬")}</B>
      </div>
    )}

    {/* 01 · 三大報表 */}
    <Band no="01" title={t("三大報表")} sub={t("口徑:{p} · 即時從總賬推算", { p: pLabel })} delay={.1}
      right={<B size="sm" icon="sparkle" onClick={() => ask(t("把本期利潤表、資產負債表、現金流量表用大白話講一遍,指出異常和風險。"))}>{t("讓秘書解讀")}</B>}>
      <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(min(100%, 300px), 1fr))", gap: 28 }}>
        <Stmt title={t("利潤表")} meta={inc.from ? inc.from + " ~ " + (inc.to || "") : pLabel} rows={plRows}/>
        <Stmt title={t("資產負債表")} meta={bs.as_of ? t("截至 {d}", { d: bs.as_of }) : null}
          tag={bs.as_of ? <T tone={bs.balanced ? "ok" : "bad"} dot>{bs.balanced ? t("平衡") : t("不平衡")}</T> : null} rows={bsRows}/>
        <Stmt title={t("現金流量表")} meta={cf.from ? cf.from + " ~ " + (cf.to || "") : pLabel} rows={cfRows}/>
      </div>
    </Band>

    {/* 02 · 往來對賬(AP / AR + 賬齡) */}
    <Band no="02" title={t("往來對賬")} sub={t("賬齡分桶 0-30 / 31-60 / 61-90 / >90 天")} delay={.15}
      right={<B size="sm" icon="sparkle" onClick={() => ask(t("把應收應付逐個往來方對一遍賬,列出賬齡最久的幾筆,給出催收和付款建議。"))}>{t("讓秘書對賬")}</B>}>
      <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(min(100%, 380px), 1fr))", gap: 28 }}>
        <PartyBlock title={t("應收賬款 · 客戶欠我")} data={ar} isAR={true}/>
        <PartyBlock title={t("應付賬款 · 我欠供應商")} data={ap} isAR={false}/>
      </div>
    </Band>

    {/* 03 · 記賬憑證 */}
    <Band no="03" title={t("記賬憑證")} sub={t("最近 {n} 張 · 業務發生自動生成,每張借貸平衡", { n: shown.length })} delay={.2}
      right={<B size="sm" icon="plus" onClick={backfillPrompt}>{t("補錄一筆")}</B>}>
      {shown.length ? (
        <div style={{ overflowX: "auto" }}>
          <table className="tbl2">
            <thead><tr>
              <th style={{ width: 40 }}>#</th><th>{t("憑證號")}</th><th>{t("日期")}</th><th>{t("摘要")}</th><th>{t("分錄")}</th>
              <th style={{ textAlign: "right" }}>{t("金額")}</th><th style={{ width: 90 }}>{t("交給秘書")}</th>
            </tr></thead>
            <tbody>
              {shown.map((v, i) => {
                const lines = Array.isArray(v.lines) ? v.lines : [];
                return (
                  <tr key={v.id || v.voucher_no || i}>
                    <td className="num muted" style={{ fontSize: 11 }}>{pad2(i + 1)}</td>
                    <td><span className="num" style={{ fontWeight: 650 }}>{v.voucher_no || "—"}</span></td>
                    <td><span className="num muted" style={{ fontSize: 12 }}>{v.voucher_date || "—"}</span></td>
                    <td>
                      <div className="col g4" style={{ minWidth: 160 }}>
                        <span style={{ fontWeight: 600, fontSize: 13 }}>{v.summary || "—"}</span>
                        {v.source_type && <span className="mono muted" style={{ fontSize: 9.5, letterSpacing: ".08em" }}>{v.source_type}</span>}
                      </div>
                    </td>
                    <td>
                      <div className="col g4">
                        {lines.slice(0, 4).map((l, j) => (
                          <span key={j} className="num" style={{ fontSize: 11, color: num(l && l.debit) > 0 ? "var(--ink)" : "var(--ink-3)" }}>
                            {num(l && l.debit) > 0 ? t("借") : t("貸")} {(l && l.code) || ""} {(l && l.name) || ""} {money(num(l && l.debit) || num(l && l.credit))}
                          </span>
                        ))}
                        {lines.length > 4 && <span className="muted num" style={{ fontSize: 10.5 }}>+{lines.length - 4}</span>}
                      </div>
                    </td>
                    <td style={{ textAlign: "right" }}><span className="num" style={{ fontWeight: 700, fontSize: 14 }}>{money(v.total_amount)}</span></td>
                    <td>
                      <B size="sm" icon="sparkle" onClick={() => ask(t("解釋憑證 {no}({s}):這筆賬怎麼來的?借貸分錄逐條講給我聽。", { no: v.voucher_no || v.id || "—", s: v.summary || "—" }))}>{t("問這張")}</B>
                    </td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        </div>
      ) : (
        <EM icon="doc" title={t("暫無憑證")}
          sub={t("出入庫、採購、銷售、收付款發生後會自動生成憑證;歷史賬讓秘書補錄即可。")}
          action={<B size="sm" icon="plus" onClick={backfillPrompt}>{t("補錄一筆")}</B>}/>
      )}
    </Band>

    <div className="muted" style={{ fontSize: 10.5, padding: "16px 0 0", lineHeight: 1.6 }}>{t("2.0 約定:頁面只讀,改動經秘書確認執行,全程留痕。")}</div>
  </>);
};

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