feat(web): admin 近7天用量表加合计行(bump 0.31.1)

renderByDay 在 by_day_7d 表底加 tfoot 合计行,汇总 7 天
cost_cny/tokens_in/tokens_out;无数据时不渲染。后端无改动。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
caoqianming 2026-06-26 14:21:40 +08:00
parent b4808b0370
commit 1352f092a3
4 changed files with 20 additions and 3 deletions

View File

@ -2,7 +2,7 @@
> 配合 `DESIGN.md`。本文件只记 phase 状态、决策偏差、文件量、下一步。每条 1-2 句:做了啥 + 关键判断;细节查 `git log` / `git diff` / `DESIGN §7.9` > 配合 `DESIGN.md`。本文件只记 phase 状态、决策偏差、文件量、下一步。每条 1-2 句:做了啥 + 关键判断;细节查 `git log` / `git diff` / `DESIGN §7.9`
最后更新:2026-06-26(定时任务执行历史列表(分页)+ bump 0.29.0) 最后更新:2026-06-26(admin 近7天用量表加合计行 + bump 0.31.1)
--- ---
@ -21,6 +21,10 @@
## 已完成关键能力 ## 已完成关键能力
### 2026-06-26 / admin 近7天用量表加合计行(bump 0.31.1)
- 纯前端展示:`renderByDay`(`web/static/js/admin.js`)在 `by_day_7d` 表底加 `<tfoot>` 合计行,对 7 天 cost_cny/tokens_in/tokens_out 求和;`tfoot .total-row` 样式(粗体 + 上分隔线)在 `admin.html`。无数据时不渲染合计行。后端数据已有(`_usage_section`),无改动。
### 2026-06-26 / per-account 模型访问控制(档位制,复用 plan 列)(bump 0.31.0) ### 2026-06-26 / per-account 模型访问控制(档位制,复用 plan 列)(bump 0.31.0)
- 需求:管理后台按账户控制可调用哪些模型。deepseek flash/pro + seedream/seedance + 内网 local 对所有人开放,doubao/glm 按账户分配。 - 需求:管理后台按账户控制可调用哪些模型。deepseek flash/pro + seedream/seedance + 内网 local 对所有人开放,doubao/glm 按账户分配。

View File

@ -1,3 +1,3 @@
# zcbot 版本号单一事实源:web/app.py 的 FastAPI version、/healthz 返回、前端展示都引这里。 # zcbot 版本号单一事实源:web/app.py 的 FastAPI version、/healthz 返回、前端展示都引这里。
# 改版本只动这一行。 # 改版本只动这一行。
__version__ = "0.31.0" __version__ = "0.31.1"

View File

@ -98,6 +98,7 @@
td.num { font-family: var(--mono); } td.num { font-family: var(--mono); }
td.email { font-family: var(--mono); max-width: 220px; overflow: hidden; text-overflow: ellipsis; } td.email { font-family: var(--mono); max-width: 220px; overflow: hidden; text-overflow: ellipsis; }
.bar-cell { position: relative; } .bar-cell { position: relative; }
tfoot .total-row td { border-top: 2px solid var(--border); border-bottom: none; font-weight: 700; }
.scroll-x { overflow-x: auto; } .scroll-x { overflow-x: auto; }
.empty { color: var(--muted); padding: 8px; text-align: center; } .empty { color: var(--muted); padding: 8px; text-align: center; }

View File

@ -135,9 +135,21 @@ function renderByDay(rows) {
+ `<td class="num">${fmtTokens(r.tokens_in)}</td>` + `<td class="num">${fmtTokens(r.tokens_in)}</td>`
+ `<td class="num">${fmtTokens(r.tokens_out)}</td>` + `<td class="num">${fmtTokens(r.tokens_out)}</td>`
+ `</tr>`).join("") || `<tr><td colspan="4" class="empty">无数据</td></tr>`; + `</tr>`).join("") || `<tr><td colspan="4" class="empty">无数据</td></tr>`;
const sum = rows.reduce((a, r) => {
a.cost_cny += r.cost_cny || 0;
a.tokens_in += r.tokens_in || 0;
a.tokens_out += r.tokens_out || 0;
return a;
}, { cost_cny: 0, tokens_in: 0, tokens_out: 0 });
const foot = rows.length ? `<tfoot><tr class="total-row">`
+ `<td>合计</td>`
+ `<td class="num">${fmtCNY(sum.cost_cny)}</td>`
+ `<td class="num">${fmtTokens(sum.tokens_in)}</td>`
+ `<td class="num">${fmtTokens(sum.tokens_out)}</td>`
+ `</tr></tfoot>` : "";
return `<div class="card"><h2>近 7 天用量(按天)</h2><div class="scroll-x"><table>` return `<div class="card"><h2>近 7 天用量(按天)</h2><div class="scroll-x"><table>`
+ `<thead><tr><th>日期</th><th>成本</th><th>输入</th><th>输出</th></tr></thead>` + `<thead><tr><th>日期</th><th>成本</th><th>输入</th><th>输出</th></tr></thead>`
+ `<tbody>${body}</tbody></table></div></div>`; + `<tbody>${body}</tbody>${foot}</table></div></div>`;
} }
// 按模型(时间筛选 + 排序)。d = {range, sort, rows} // 按模型(时间筛选 + 排序)。d = {range, sort, rows}