From bfd2b328e8decf9968029a4f69ea9d36eefc56b7 Mon Sep 17 00:00:00 2001 From: root Date: Fri, 17 Jul 2026 02:28:33 +0200 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=AF=B9=E9=BD=90=20API=20USD=20?= =?UTF-8?q?=E5=B0=8F=E6=95=B0=E5=B1=95=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- static/app.js | 18 +++++++++++++++--- static/ranking.html | 2 +- static/scores.html | 2 +- static/styles.css | 8 ++++++++ 4 files changed, 25 insertions(+), 5 deletions(-) diff --git a/static/app.js b/static/app.js index 8c5d65f..2d215a3 100644 --- a/static/app.js +++ b/static/app.js @@ -12,6 +12,18 @@ function number(value, digits = 0) { return Number(value).toLocaleString('zh-CN', { maximumFractionDigits: digits, minimumFractionDigits: digits }) } +function usd(value, digits = 3) { + const numeric = Number(value) + if (value === null || value === undefined || !Number.isFinite(numeric)) return '' + const formatter = new Intl.NumberFormat('zh-CN', { maximumFractionDigits: digits, minimumFractionDigits: digits }) + const parts = formatter.formatToParts(numeric) + const whole = parts.filter(({ type }) => ['minusSign', 'plusSign', 'integer', 'group'].includes(type)).map(({ value: part }) => part).join('') + const point = parts.find(({ type }) => type === 'decimal')?.value ?? '.' + const fraction = parts.find(({ type }) => type === 'fraction')?.value ?? ''.padEnd(digits, '0') + const label = `$${formatter.format(numeric)}` + return `` +} + function compact(value) { if (value === null || value === undefined) return '—' return new Intl.NumberFormat('zh-CN', { notation: 'compact', maximumFractionDigits: 2 }).format(Number(value)) @@ -134,7 +146,7 @@ function renderScoreRows() { ${row.ttftP95Ms == null ? '—' : `${number(row.ttftP95Ms)} ms`} ${compact(usage.requestCount)} ${compact(usage.tokenCount)} - ${usage.apiAmountUsd == null ? '—' : `$${number(usage.apiAmountUsd, 3)}`} + ${usd(usage.apiAmountUsd)} ${number(row.failoverRecovered)} / ${number(row.failoverRequests)} ${row.currentlyAvailable ? '可用' : '不可用'} ` @@ -180,10 +192,10 @@ async function rankingPage() { const data = await requestJson('/api/ranking') const ranking = data.ranking $('#ranking-range').textContent = `${ranking.startDate} 至 ${ranking.endDate}` - $('#ranking-cost').textContent = `$${number(ranking.totals.actualCost, 3)}` + $('#ranking-cost').innerHTML = usd(ranking.totals.actualCost) $('#ranking-requests').textContent = compact(ranking.totals.requests) $('#ranking-tokens').textContent = compact(ranking.totals.tokens) - $('#ranking-body').innerHTML = ranking.rows.length ? ranking.rows.map((row) => `${String(row.rank).padStart(2, '0')}${escapeHtml(row.displayName)}$${number(row.actualCost, 3)}${compact(row.requests)}${compact(row.tokens)}`).join('') : '当前窗口暂无用量' + $('#ranking-body').innerHTML = ranking.rows.length ? ranking.rows.map((row) => `${String(row.rank).padStart(2, '0')}${escapeHtml(row.displayName)}${usd(row.actualCost)}${compact(row.requests)}${compact(row.tokens)}`).join('') : '当前窗口暂无用量' } function creditLabel(status) { diff --git a/static/ranking.html b/static/ranking.html index e8b8b15..85316cf 100644 --- a/static/ranking.html +++ b/static/ranking.html @@ -13,7 +13,7 @@

USER FLOW / DAILY

用户用量

读取中
标准 API 用量
请求
Token
-
名次用户API USD请求Token
正在读取用量...
+
名次用户API USD请求Token
正在读取用量...
diff --git a/static/scores.html b/static/scores.html index 54a44c0..dc6164b 100644 --- a/static/scores.html +++ b/static/scores.html @@ -36,7 +36,7 @@
- +
账号分组优先级评分等级置信度尝试失败率TTFT P95请求TokenAPI USD切号恢复可用
账号分组优先级评分等级置信度尝试失败率TTFT P95请求TokenAPI USD切号恢复可用
正在读取评分快照...
diff --git a/static/styles.css b/static/styles.css index e974a87..0ee9f15 100644 --- a/static/styles.css +++ b/static/styles.css @@ -67,6 +67,14 @@ button:disabled { cursor: wait; opacity: .48; } .data-table th { height: 40px; padding: 0 12px; position: sticky; top: 0; z-index: 1; text-align: left; white-space: nowrap; background: var(--surface-raised); color: var(--muted); font: 10px/1 var(--mono); border-bottom: 1px solid var(--line); } .data-table td { height: 52px; padding: 8px 12px; border-bottom: 1px solid var(--line); white-space: nowrap; } .data-table tbody tr:hover { background: rgba(185,228,71,.045); } +.usd-cell { text-align: right !important; } +.usd-value { display: inline-grid; grid-template-columns: 1ch 9ch .65ch 3ch; justify-content: end; align-items: baseline; font-family: var(--mono); font-variant-numeric: tabular-nums; white-space: nowrap; } +.usd-symbol { color: var(--muted); text-align: left; } +.usd-whole { color: var(--paper); text-align: right; font-weight: 650; } +.usd-point, .usd-fraction { color: var(--info); } +.usd-point { text-align: center; } +.usd-fraction { text-align: left; font-weight: 550; } +.usd-value.is-empty { display: inline-block; width: 13.65ch; color: var(--muted); text-align: right; } .account-cell { min-width: 230px; } .account-cell b { display: block; max-width: 360px; overflow: hidden; text-overflow: ellipsis; } .account-cell small { display: block; color: var(--muted); margin-top: 4px; font: 10px/1 var(--mono); }