From 31d963e956575916add934667863a9c65507c943 Mon Sep 17 00:00:00 2001 From: skycurtain Date: Fri, 9 Oct 2026 13:42:13 +0800 Subject: [PATCH] =?UTF-8?q?fix(core):=20=E6=98=8E=E7=BB=86=E7=94=A8?= =?UTF-8?q?=E9=87=8F=E7=BE=8E=E5=85=83=E4=BF=9D=E7=95=99=206=20=E4=BD=8D?= =?UTF-8?q?=E5=B0=8F=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/server/src/routes/admin-usage.ts | 6 ++++-- apps/server/src/routes/member-view.ts | 6 ++++-- packages/core/src/money.ts | 9 +++++++++ packages/core/src/usage.ts | 16 ++++++++++++++++ 4 files changed, 33 insertions(+), 4 deletions(-) diff --git a/apps/server/src/routes/admin-usage.ts b/apps/server/src/routes/admin-usage.ts index a3c072f..0c08aef 100644 --- a/apps/server/src/routes/admin-usage.ts +++ b/apps/server/src/routes/admin-usage.ts @@ -4,6 +4,7 @@ import { resolveQpuTimeline, sumUsage, toUnixSec, + usageRowPrecise, type LogItem, } from "@new-api-key-usage/core"; import { @@ -337,8 +338,9 @@ export function adminUsageRoutes() { }); const items: LogItem[] = rows.map((row) => { - const { quota_usd } = sumUsage( - [{ quota: row.quota, created_at: row.created_at }], + const { quota_usd } = usageRowPrecise( + row.quota, + row.created_at, timeline, ); return { diff --git a/apps/server/src/routes/member-view.ts b/apps/server/src/routes/member-view.ts index e9ce286..07ea586 100644 --- a/apps/server/src/routes/member-view.ts +++ b/apps/server/src/routes/member-view.ts @@ -3,6 +3,7 @@ import { ERR, resolveQpuTimeline, sumUsage, + usageRowPrecise, toUnixSec, type LogItem, type PaymentItem, @@ -265,8 +266,9 @@ export function memberViewRoutes() { page_size, }); const items: LogItem[] = rows.map((row) => { - const { quota_usd } = sumUsage( - [{ quota: row.quota, created_at: row.created_at }], + const { quota_usd } = usageRowPrecise( + row.quota, + row.created_at, timeline, ); return { diff --git a/packages/core/src/money.ts b/packages/core/src/money.ts index 7acc7af..393f67a 100644 --- a/packages/core/src/money.ts +++ b/packages/core/src/money.ts @@ -18,6 +18,15 @@ export function microUsdToQuotaUsdStr(micro: number): string { return `${dollars}.${String(rem).padStart(2, "0")}`; } +/** 明细行等小额场景:保留更多小数位(默认 4 位,仍是字符串两位小数契约的展示增强) */ +export function microUsdToQuotaUsdStrPrecise( + micro: number, + fractionDigits = 4, +): string { + const usd = micro / 1_000_000; + return usd.toFixed(fractionDigits); +} + export function quotaToUsdStr(quota: number, qpu: number): string { return microUsdToQuotaUsdStr(quotaToMicroUsd(quota, qpu)); } diff --git a/packages/core/src/usage.ts b/packages/core/src/usage.ts index a7b606a..de45059 100644 --- a/packages/core/src/usage.ts +++ b/packages/core/src/usage.ts @@ -3,6 +3,7 @@ */ import { microSumToUsdStr, + microUsdToQuotaUsdStrPrecise, qpuAt, quotaToMicroUsd, quotaToUsdStr, @@ -54,6 +55,21 @@ export function usageAt( return { count: 1, quota, quota_usd: quotaToUsdStr(quota, qpu) }; } +/** 明细行:按当时 QPU 换算,展示保留 6 位小数(微美元级,小额不被抹成 0) */ +export function usageRowPrecise( + quota: number, + created_at: Date | number, + timeline: readonly QpuPoint[], +): UsageSum { + const qpu = qpuAt(created_at, timeline); + const micro = quotaToMicroUsd(quota, qpu); + return { + count: 1, + quota, + quota_usd: microUsdToQuotaUsdStrPrecise(micro, 6), + }; +} + export function addUsage(a: UsageSum, b: UsageSum): UsageSum { // 合并已成形的两段时,quota_usd 需重算——调用方应尽量走 sumUsage return {