feat: OpenAI OAuth账号显示Codex使用量

从响应头提取x-codex-*使用量信息并保存到账号Extra字段,
前端账号列表展示5h/7d窗口的使用进度条。
This commit is contained in:
shaw
2025-12-23 16:26:07 +08:00
parent f6341b7f2b
commit f25ac3aff5
6 changed files with 245 additions and 14 deletions

View File

@@ -68,7 +68,31 @@
<SetupTokenTimeWindow :account="account" />
</template>
<!-- OpenAI accounts: no usage window API, show dash -->
<!-- OpenAI OAuth accounts: show Codex usage from extra field -->
<template v-else-if="account.platform === 'openai' && account.type === 'oauth'">
<div v-if="hasCodexUsage" class="space-y-1">
<!-- 5h Window (Secondary) -->
<UsageProgressBar
v-if="codexSecondaryUsedPercent !== null"
label="5h"
:utilization="codexSecondaryUsedPercent"
:resets-at="codexSecondaryResetAt"
color="indigo"
/>
<!-- Weekly Window (Primary) -->
<UsageProgressBar
v-if="codexPrimaryUsedPercent !== null"
label="7d"
:utilization="codexPrimaryUsedPercent"
:resets-at="codexPrimaryResetAt"
color="emerald"
/>
</div>
<div v-else class="text-xs text-gray-400">-</div>
</template>
<!-- Other accounts: no usage window -->
<template v-else>
<div class="text-xs text-gray-400">-</div>
</template>
@@ -100,9 +124,44 @@ const showUsageWindows = computed(() =>
props.account.type === 'oauth' || props.account.type === 'setup-token'
)
// OpenAI Codex usage computed properties
const hasCodexUsage = computed(() => {
const extra = props.account.extra
return extra && (
extra.codex_primary_used_percent !== undefined ||
extra.codex_secondary_used_percent !== undefined
)
})
const codexPrimaryUsedPercent = computed(() => {
const extra = props.account.extra
if (!extra || extra.codex_primary_used_percent === undefined) return null
return extra.codex_primary_used_percent
})
const codexSecondaryUsedPercent = computed(() => {
const extra = props.account.extra
if (!extra || extra.codex_secondary_used_percent === undefined) return null
return extra.codex_secondary_used_percent
})
const codexPrimaryResetAt = computed(() => {
const extra = props.account.extra
if (!extra || extra.codex_primary_reset_after_seconds === undefined) return null
const resetTime = new Date(Date.now() + extra.codex_primary_reset_after_seconds * 1000)
return resetTime.toISOString()
})
const codexSecondaryResetAt = computed(() => {
const extra = props.account.extra
if (!extra || extra.codex_secondary_reset_after_seconds === undefined) return null
const resetTime = new Date(Date.now() + extra.codex_secondary_reset_after_seconds * 1000)
return resetTime.toISOString()
})
const loadUsage = async () => {
// Only fetch usage for Anthropic OAuth accounts
// OpenAI doesn't have a usage window API - usage is updated from response headers during forwarding
// OpenAI usage comes from account.extra field (updated during forwarding)
if (props.account.platform !== 'anthropic' || props.account.type !== 'oauth') return
loading.value = true