mirror of
https://github.com/fawney19/Aether.git
synced 2026-10-04 16:37:46 +08:00
feat(claude-code): 支持通过 /api/oauth/usage 查询账号 5H/周额度并在号池展示
This commit is contained in:
@@ -1,4 +1,10 @@
|
||||
export const legacyAdminEnglishMessages: Record<string, string> = {
|
||||
'响应中未包含配额信息': 'The response contains no quota information',
|
||||
'响应中未包含额度窗口': 'The response contains no quota windows',
|
||||
'oauth/usage 请求执行失败': 'oauth/usage request failed',
|
||||
'oauth/usage 返回 401,Token 可能已失效,请刷新 Token': 'oauth/usage returned 401. The token may have expired; please refresh it',
|
||||
'oauth/usage 返回 403,该账号缺少 user:profile 权限(如 Setup Token),无法查询额度': 'oauth/usage returned 403. This account lacks the user:profile scope (e.g. a Setup Token), so quota cannot be queried',
|
||||
'oauth/usage 被限流,请稍后重试': 'oauth/usage was rate limited; please retry later',
|
||||
'配置额度、流量限制、会员权益和组合套餐': 'Configure credit, usage limits, membership benefits, and bundled plans',
|
||||
'新建套餐': 'Create plan',
|
||||
'套餐列表': 'Plans',
|
||||
|
||||
@@ -6,6 +6,11 @@ import { legacyGuideEnglishMessages } from './legacy-guide-messages'
|
||||
export const messages = {
|
||||
'zh-CN': {
|
||||
'common.loading': '加载中...',
|
||||
'poolQuota.claudeCode.window5h': '5H',
|
||||
'poolQuota.claudeCode.weekly': '周',
|
||||
'poolQuota.claudeCode.weeklySonnet': '周 Sonnet',
|
||||
'poolQuota.claudeCode.weeklyFable': '周 Fable',
|
||||
'poolQuota.claudeCode.unknownWindow': '额度',
|
||||
'common.confirmRead': '确认已读',
|
||||
'common.confirming': '确认中...',
|
||||
'common.copy': '复制',
|
||||
@@ -491,6 +496,11 @@ export const messages = {
|
||||
},
|
||||
'en-US': {
|
||||
'common.loading': 'Loading...',
|
||||
'poolQuota.claudeCode.window5h': '5H',
|
||||
'poolQuota.claudeCode.weekly': 'Weekly',
|
||||
'poolQuota.claudeCode.weeklySonnet': 'Weekly Sonnet',
|
||||
'poolQuota.claudeCode.weeklyFable': 'Weekly Fable',
|
||||
'poolQuota.claudeCode.unknownWindow': 'Quota',
|
||||
'common.confirmRead': 'Confirm read',
|
||||
'common.confirming': 'Confirming...',
|
||||
'common.copy': 'Copy',
|
||||
@@ -3066,6 +3076,7 @@ const legacyDynamicPatterns: Array<[RegExp, (match: RegExpMatchArray) => string]
|
||||
[/^(1[0-2]|[1-9])月$/u, match => new Intl.DateTimeFormat('en-US', { month: 'short', timeZone: 'UTC' }).format(new Date(Date.UTC(2020, Number(match[1]) - 1, 1)))],
|
||||
[/^总可用:(.+)$/u, match => `Total available: ${match[1]}`],
|
||||
[/^余额:(.+)$/u, match => `Balance: ${match[1]}`],
|
||||
[/^oauth\/usage 返回状态码 (\d+)$/u, match => `oauth/usage returned status ${match[1]}`],
|
||||
[/^(.+) 秒$/u, match => `${translateLegacyText(match[1], 'en-US')}s`],
|
||||
[/^(.+) 分钟$/u, match => `${translateLegacyText(match[1], 'en-US')} min`],
|
||||
[/^(.+) 小时$/u, match => `${translateLegacyText(match[1], 'en-US')} h`],
|
||||
|
||||
@@ -1071,6 +1071,7 @@ import { useConfirm } from '@/composables/useConfirm'
|
||||
import { useRouteQuery } from '@/composables/useRouteQuery'
|
||||
import { useBatchSelection } from '@/composables/useBatchSelection'
|
||||
import { useI18n } from '@/i18n'
|
||||
import type { MessageKey } from '@/i18n/messages'
|
||||
import { parseApiError } from '@/utils/errorParser'
|
||||
import {
|
||||
getPoolOverview,
|
||||
@@ -1696,6 +1697,7 @@ watch(showAdaptiveHotPoolMetricsButton, (enabled) => {
|
||||
|
||||
const showAccountQuotaColumn = computed(() => {
|
||||
return selectedProviderType.value === 'codex'
|
||||
|| selectedProviderType.value === 'claude_code'
|
||||
|| selectedProviderType.value === 'gemini_cli'
|
||||
|| selectedProviderType.value === 'kiro'
|
||||
|| selectedProviderType.value === 'windsurf'
|
||||
@@ -2146,6 +2148,7 @@ function getPoolKeyAccountStatsMetrics(key: PoolKeyDetail): PoolStatsMetric[] {
|
||||
|
||||
const quotaRefreshSupported = computed(() => {
|
||||
return selectedProviderType.value === 'codex'
|
||||
|| selectedProviderType.value === 'claude_code'
|
||||
|| selectedProviderType.value === 'kiro'
|
||||
|| selectedProviderType.value === 'gemini_cli'
|
||||
|| selectedProviderType.value === 'windsurf'
|
||||
@@ -3902,6 +3905,33 @@ function buildQuotaProgressItemsFromSnapshot(key: PoolKeyDetail): QuotaProgressI
|
||||
.filter((item): item is QuotaProgressItem => item != null)
|
||||
}
|
||||
|
||||
if (providerType === 'claude_code') {
|
||||
const quotaResetAtSeconds = getQuotaSnapshotResetAtSeconds(quota)
|
||||
const quotaResetSeconds = getQuotaSnapshotResetSeconds(quota)
|
||||
const windowPresentations: Record<string, { labelKey: MessageKey, sortOrder: number }> = {
|
||||
'5h': { labelKey: 'poolQuota.claudeCode.window5h', sortOrder: 0 },
|
||||
weekly: { labelKey: 'poolQuota.claudeCode.weekly', sortOrder: 1 },
|
||||
weekly_sonnet: { labelKey: 'poolQuota.claudeCode.weeklySonnet', sortOrder: 2 },
|
||||
weekly_fable: { labelKey: 'poolQuota.claudeCode.weeklyFable', sortOrder: 3 },
|
||||
}
|
||||
return (quota.windows ?? [])
|
||||
.map((window): QuotaProgressItem | null => {
|
||||
const remainingPercent = getQuotaWindowRemainingPercent(window)
|
||||
if (remainingPercent == null) return null
|
||||
const presentation = windowPresentations[String(window.code || '')]
|
||||
return {
|
||||
label: t(presentation?.labelKey ?? 'poolQuota.claudeCode.unknownWindow'),
|
||||
sortOrder: presentation?.sortOrder ?? 9,
|
||||
remainingPercent,
|
||||
resetAtSeconds: normalizeUnixSeconds(window.reset_at ?? quotaResetAtSeconds ?? null),
|
||||
resetSeconds: normalizeRemainingSeconds(window.reset_seconds ?? quotaResetSeconds ?? null),
|
||||
updatedAtSeconds: getQuotaSnapshotUpdatedAtSeconds(quota),
|
||||
allowDynamicReset: true,
|
||||
}
|
||||
})
|
||||
.filter((item): item is QuotaProgressItem => item != null)
|
||||
}
|
||||
|
||||
if (providerType === 'gemini_cli') {
|
||||
const windows = getQuotaSnapshotWindowsByScope(quota, 'model')
|
||||
if (windows.length === 0) return []
|
||||
|
||||
Reference in New Issue
Block a user