diff --git a/web/admin-spa/src/views/AccountsView.vue b/web/admin-spa/src/views/AccountsView.vue index f3c76a09..ddfd4a95 100644 --- a/web/admin-spa/src/views/AccountsView.vue +++ b/web/admin-spa/src/views/AccountsView.vue @@ -195,26 +195,72 @@ 会话窗口 - - 会话窗口进度表示5小时窗口的时间进度 - - - - 正常:请求正常处理 + + + + Claude 系列 - - - 警告:接近限制 + + 会话窗口进度表示 5 小时窗口的时间推移,颜色提示当前调度状态。 - - - 拒绝:达到速率限制 + + + + 正常:请求正常处理 + + + + 警告:接近限制 + + + + 拒绝:达到速率限制 + + + + + + + OpenAI + + + 进度条分别展示 5h 与周限窗口的额度使用比例,颜色含义与上方保持一致。 + + + + + 5h 窗口:5小时使用量进度,到达重置时间后会自动归零。 + + + + 周限窗口:7天使用量进度,重置时同样回到 0%。 + + + + 当“重置剩余”为 0 时,进度条与百分比会同步清零。 + @@ -669,17 +715,17 @@ - {{ formatCodexUsagePercent(account.codexUsage.primary.usedPercent) }} + {{ formatCodexUsagePercent(account.codexUsage.primary) }} @@ -701,21 +747,17 @@ - {{ - formatCodexUsagePercent(account.codexUsage.secondary.usedPercent) - }} + {{ formatCodexUsagePercent(account.codexUsage.secondary) }} @@ -988,17 +1030,17 @@ - {{ formatCodexUsagePercent(account.codexUsage.primary.usedPercent) }} + {{ formatCodexUsagePercent(account.codexUsage.primary) }} @@ -1020,17 +1062,17 @@ - {{ formatCodexUsagePercent(account.codexUsage.secondary.usedPercent) }} + {{ formatCodexUsagePercent(account.codexUsage.secondary) }} @@ -2195,9 +2237,47 @@ const getSessionProgressBarClass = (status, account = null) => { } } +// 归一化 OpenAI 会话窗口使用率 +const normalizeCodexUsagePercent = (usageItem) => { + if (!usageItem) { + return null + } + + const basePercent = + typeof usageItem.usedPercent === 'number' && !Number.isNaN(usageItem.usedPercent) + ? usageItem.usedPercent + : null + + const resetAfterSeconds = + typeof usageItem.resetAfterSeconds === 'number' && !Number.isNaN(usageItem.resetAfterSeconds) + ? usageItem.resetAfterSeconds + : null + + const remainingSeconds = + typeof usageItem.remainingSeconds === 'number' ? usageItem.remainingSeconds : null + + const resetAtMs = usageItem.resetAt ? Date.parse(usageItem.resetAt) : null + + const resetElapsed = + resetAfterSeconds !== null && + ((remainingSeconds !== null && remainingSeconds <= 0) || + (resetAtMs !== null && !Number.isNaN(resetAtMs) && Date.now() >= resetAtMs)) + + if (resetElapsed) { + return 0 + } + + if (basePercent === null) { + return null + } + + return Math.max(0, Math.min(100, basePercent)) +} + // OpenAI 限额进度条颜色 -const getCodexUsageBarClass = (percent) => { - if (percent === null || percent === undefined || Number.isNaN(percent)) { +const getCodexUsageBarClass = (usageItem) => { + const percent = normalizeCodexUsagePercent(usageItem) + if (percent === null) { return 'bg-gradient-to-r from-gray-300 to-gray-400' } if (percent >= 90) { @@ -2210,20 +2290,21 @@ const getCodexUsageBarClass = (percent) => { } // 百分比显示 -const formatCodexUsagePercent = (percent) => { - if (percent === null || percent === undefined || Number.isNaN(percent)) { +const formatCodexUsagePercent = (usageItem) => { + const percent = normalizeCodexUsagePercent(usageItem) + if (percent === null) { return '--' } return `${percent.toFixed(1)}%` } // 进度条宽度 -const getCodexUsageWidth = (percent) => { - if (percent === null || percent === undefined || Number.isNaN(percent)) { +const getCodexUsageWidth = (usageItem) => { + const percent = normalizeCodexUsagePercent(usageItem) + if (percent === null) { return '0%' } - const clamped = Math.max(0, Math.min(100, percent)) - return `${clamped}%` + return `${percent}%` } // 时间窗口标签