From d1da40e49337b95a2028d62d258d23374ece1770 Mon Sep 17 00:00:00 2001 From: JianFeeeee Date: Fri, 2 Oct 2026 12:16:40 +0800 Subject: [PATCH] =?UTF-8?q?fix(billing):=20=E9=A1=B5=E9=9D=A2=E6=96=87?= =?UTF-8?q?=E5=AD=97=E6=BA=A2=E5=87=BA=E5=8D=A1=E7=89=87=20+=20=E6=95=B0?= =?UTF-8?q?=E5=AD=97=E5=8D=83=E5=88=86=E4=BD=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 用户报 billing 页"文字超出展示框"。真因是三处叠加,都不是文案问题: 1. KPI 卡是 CSS grid,grid item 默认 min-width:auto。2e8 级的 prompt tokens(实测 270,149,209)无法收缩,于是把 grid 轨道撑出容器 → 整页横向 溢出。修法是 min-width:0 + overflow:hidden(不给 min-width:0 的话, grid 子项永远不肯收缩,这是 grid 最常见的溢出坑)。 2. 表格写死 min-width:560px,窄视口下必然溢出。改 width:100% + table-layout:fixed,列宽由布局分配而不是由内容撑开。 3. 长名称(deepseek-v4.1-flash 这类模型 id)撑宽单元格。名称列改 ellipsis + title 悬停看全名;数字列 word-break:break-all 在列宽内换行。 顺手:所有 token/请求数走 toLocaleString 千分位。原始 9 位数字读起来要数 零位数,分组后 270,149,209 一眼可读,也顺带缩短了字符串宽度。 CDP 实测(820px 窄视口,逼出溢出条件): main/body 横向溢出 = no table=338 < card=366(修复前 min-width:560 必然 > 366) KPI 输入 tokens = 270,149,209 billing 页无控制台错误 残留(不影响布局):表头 TH 在固定布局下 48>42 轻微超出自身格,因为 word-break 不拆单个长词;表格整体仍在容器内,未产生页面滚动。 全量测试全绿(8 包)。 --- internal/lua/plugins/billing.lua | 42 ++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/internal/lua/plugins/billing.lua b/internal/lua/plugins/billing.lua index 39978e2..72e4a2b 100644 --- a/internal/lua/plugins/billing.lua +++ b/internal/lua/plugins/billing.lua @@ -547,21 +547,30 @@ plugin.ui = { if (!b.cache_reported_reqs) return "n/r"; return ((hit / prompt) * 100).toFixed(1) + "%"; } + // fmtInt 千分位分组:2e8 级 token 总数可读、也更短,降低撑宽风险。 + function fmtInt(n) { + return (Number(n) || 0).toLocaleString("en-US"); + } function row(name, b, cur) { var fresh = (b.cache_fresh_tokens === undefined) ? (b.prompt_tokens || 0) : b.cache_fresh_tokens; - return "" + esc(name) + "" + money(b.cost, cur) + - "" + (b.requests || 0) + "" + (b.prompt_tokens || 0) + - "" + fresh + - "" + (b.cache_hit_tokens || 0) + - "" + esc(cacheRate(b)) + - "" + (b.completion_tokens || 0) + ""; + // 名称列 ellipsis(title 悬停看全名);数字列 break-all 在列宽内换行而不是 + // 把表格撑出卡片。单元格结构与列数不变,列数判据不受影响。 + return "" + esc(name) + "" + + "" + money(b.cost, cur) + "" + + "" + fmtInt(b.requests || 0) + "" + + "" + fmtInt(b.prompt_tokens || 0) + "" + + "" + fmtInt(fresh) + "" + + "" + fmtInt(b.cache_hit_tokens || 0) + "" + + "" + esc(cacheRate(b)) + "" + + "" + fmtInt(b.completion_tokens || 0) + ""; } function tableFor(el, obj, cur, empty) { var keys = Object.keys(obj || {}); if (!keys.length) { el.innerHTML = '
' + empty + "
"; return; } keys.sort(function (a, b) { return (obj[b].cost || 0) - (obj[a].cost || 0); }); var TH = L(); - var h = "" + + var h = "
" + "
" + TH.thName + "" + TH.thCost + "" + TH.thReqs + "" + TH.thPrompt + "" + TH.thFresh + "" + TH.thCache + "" + TH.thCachePct + @@ -589,20 +598,23 @@ plugin.ui = { var t = st.total || {}; document.getElementById("billing-kpis").innerHTML = [ [T.total, money(t.cost, cur)], - [T.requests, t.requests || 0], - [T.degraded, st.degraded_reqs || 0], - [T.unpriced, st.unpriced_reqs || 0], - [T.prompt, t.prompt_tokens || 0], - [T.completion, t.completion_tokens || 0], + [T.requests, fmtInt(t.requests || 0)], + [T.degraded, fmtInt(st.degraded_reqs || 0)], + [T.unpriced, fmtInt(st.unpriced_reqs || 0)], + [T.prompt, fmtInt(t.prompt_tokens || 0)], + [T.completion, fmtInt(t.completion_tokens || 0)], [T.failures, t.failures || 0], // Cache KPIs: last session added the table columns but the KPI cards // were left out — the edit's assert failed and the retry only re-did the // tables. The numbers existed in state and nowhere in the UI. [T.cacheRate, cacheRate(t)], - [T.cacheTokens, t.cache_hit_tokens || 0] + [T.cacheTokens, fmtInt(t.cache_hit_tokens || 0)] ].map(function (kv) { - return "
" + - kv[0] + "
" + + // min-width:0:grid item 默认 min-width:auto,2e8 级长数字会把轨道撑出 + // 容器造成横向溢出。标签 nowrap 截断,数值 break-all 换行。 + return "
" + + "
" + + esc(kv[0]) + "
" + esc(kv[1]) + "
"; }).join(""); var TD = L();