mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-03 01:40:21 +08:00
Merge pull request #411 from buniakinazach-dev/feat/codex-spark-quota
新增 Codex Spark 额度展示
This commit is contained in:
@@ -29,10 +29,12 @@ describe('quota selectors', () => {
|
||||
it('detects only depleted weekly segments', () => {
|
||||
expect(hasNoWeeklyLimit('周剩余 0.0%(5天后重置) | 5H剩余 93.0%(2小时后重置)')).toBe(true)
|
||||
expect(hasNoWeeklyLimit('周剩余 45.0%(5天后重置) | 5H剩余 0.0%(2小时后重置)')).toBe(false)
|
||||
expect(hasNoWeeklyLimit('周剩余 45.0% | Spark周剩余 0.0%')).toBe(false)
|
||||
})
|
||||
|
||||
it('detects only depleted 5h segments', () => {
|
||||
expect(hasNoFiveHourLimit('周剩余 45.0%(5天后重置) | 5H剩余 0.0%(2小时后重置)')).toBe(true)
|
||||
expect(hasNoFiveHourLimit('周剩余 0.0%(5天后重置) | 5H剩余 93.0%(2小时后重置)')).toBe(false)
|
||||
expect(hasNoFiveHourLimit('5H剩余 93.0% | Spark5H剩余 0.0%')).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -38,14 +38,20 @@ export function isDepletedQuotaSegment(segment: string): boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
function isSparkQuotaSegment(segment: string): boolean {
|
||||
return /spark/.test(segment)
|
||||
}
|
||||
|
||||
export function hasNoFiveHourLimit(accountQuota: string | null | undefined): boolean {
|
||||
return getQuotaSegments(accountQuota)
|
||||
.filter((segment) => !isSparkQuotaSegment(segment))
|
||||
.filter((segment) => /5h|5小时/.test(segment))
|
||||
.some(isDepletedQuotaSegment)
|
||||
}
|
||||
|
||||
export function hasNoWeeklyLimit(accountQuota: string | null | undefined): boolean {
|
||||
return getQuotaSegments(accountQuota)
|
||||
.filter((segment) => !isSparkQuotaSegment(segment))
|
||||
.filter((segment) => /周|weekly|week/.test(segment))
|
||||
.some(isDepletedQuotaSegment)
|
||||
}
|
||||
|
||||
@@ -576,7 +576,7 @@
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 限额并排显示:Team/Plus/Enterprise 账号 2列, Free 账号 1列 -->
|
||||
<!-- 普通 Codex 限额并排显示:Team/Plus/Enterprise 账号 2列, Free 账号 1列 -->
|
||||
<div
|
||||
class="grid gap-3"
|
||||
:class="isCodexTeamPlan(key) ? 'grid-cols-2' : 'grid-cols-1'"
|
||||
@@ -653,6 +653,89 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Spark 限额独立一行展示,避免与普通 Codex 周/5H 混淆 -->
|
||||
<div
|
||||
v-if="hasCodexSparkQuotaDisplayData(key)"
|
||||
class="mt-3 border-t border-border/60 pt-2"
|
||||
>
|
||||
<div class="mb-1 text-[10px] text-muted-foreground">GPT-5.3 Codex Spark</div>
|
||||
<div class="grid gap-3 grid-cols-2">
|
||||
<div v-if="getCodexQuotaDisplay(key)?.spark_secondary_used_percent !== undefined">
|
||||
<div class="flex items-center justify-between text-[10px] mb-0.5">
|
||||
<span class="text-muted-foreground">Spark 周</span>
|
||||
<span :class="getQuotaRemainingClass(getCodexQuotaDisplay(key)?.spark_secondary_used_percent || 0)">
|
||||
{{ (100 - (getCodexQuotaDisplay(key)?.spark_secondary_used_percent || 0)).toFixed(1) }}%
|
||||
</span>
|
||||
</div>
|
||||
<div class="relative w-full h-1.5 bg-border rounded-full overflow-hidden">
|
||||
<div
|
||||
class="absolute left-0 top-0 h-full transition-all duration-300"
|
||||
:class="getQuotaRemainingBarColor(getCodexQuotaDisplay(key)?.spark_secondary_used_percent || 0)"
|
||||
:style="{ width: `${Math.max(100 - (getCodexQuotaDisplay(key)?.spark_secondary_used_percent || 0), 0)}%` }"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-if="shouldStartCodexResetCountdown(getCodexQuotaDisplay(key)?.spark_secondary_used_percent || 0)"
|
||||
class="text-[9px] mt-0.5 tabular-nums"
|
||||
:class="getResetCountdownClass(
|
||||
getCodexQuotaDisplay(key)?.spark_secondary_reset_at,
|
||||
getCodexQuotaDisplay(key)?.spark_secondary_reset_seconds,
|
||||
getCodexQuotaDisplay(key)?.updated_at,
|
||||
getCodexQuotaDisplay(key)?.spark_secondary_used_percent
|
||||
)"
|
||||
>
|
||||
<template v-if="getCodexQuotaDisplay(key)?.spark_secondary_reset_at || getCodexQuotaDisplay(key)?.spark_secondary_reset_seconds">
|
||||
{{ getResetCountdownText(
|
||||
getCodexQuotaDisplay(key)?.spark_secondary_reset_at,
|
||||
getCodexQuotaDisplay(key)?.spark_secondary_reset_seconds,
|
||||
getCodexQuotaDisplay(key)?.updated_at,
|
||||
getCodexQuotaDisplay(key)?.spark_secondary_used_percent
|
||||
) }}
|
||||
</template>
|
||||
<template v-else>
|
||||
已重置
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="getCodexQuotaDisplay(key)?.spark_primary_used_percent !== undefined">
|
||||
<div class="flex items-center justify-between text-[10px] mb-0.5">
|
||||
<span class="text-muted-foreground">Spark 5H</span>
|
||||
<span :class="getQuotaRemainingClass(getCodexQuotaDisplay(key)?.spark_primary_used_percent || 0)">
|
||||
{{ (100 - (getCodexQuotaDisplay(key)?.spark_primary_used_percent || 0)).toFixed(1) }}%
|
||||
</span>
|
||||
</div>
|
||||
<div class="relative w-full h-1.5 bg-border rounded-full overflow-hidden">
|
||||
<div
|
||||
class="absolute left-0 top-0 h-full transition-all duration-300"
|
||||
:class="getQuotaRemainingBarColor(getCodexQuotaDisplay(key)?.spark_primary_used_percent || 0)"
|
||||
:style="{ width: `${Math.max(100 - (getCodexQuotaDisplay(key)?.spark_primary_used_percent || 0), 0)}%` }"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-if="shouldStartCodexResetCountdown(getCodexQuotaDisplay(key)?.spark_primary_used_percent || 0)"
|
||||
class="text-[9px] mt-0.5 tabular-nums"
|
||||
:class="getResetCountdownClass(
|
||||
getCodexQuotaDisplay(key)?.spark_primary_reset_at,
|
||||
getCodexQuotaDisplay(key)?.spark_primary_reset_seconds,
|
||||
getCodexQuotaDisplay(key)?.updated_at,
|
||||
getCodexQuotaDisplay(key)?.spark_primary_used_percent
|
||||
)"
|
||||
>
|
||||
<template v-if="getCodexQuotaDisplay(key)?.spark_primary_reset_at || getCodexQuotaDisplay(key)?.spark_primary_reset_seconds">
|
||||
{{ getResetCountdownText(
|
||||
getCodexQuotaDisplay(key)?.spark_primary_reset_at,
|
||||
getCodexQuotaDisplay(key)?.spark_primary_reset_seconds,
|
||||
getCodexQuotaDisplay(key)?.updated_at,
|
||||
getCodexQuotaDisplay(key)?.spark_primary_used_percent
|
||||
) }}
|
||||
</template>
|
||||
<template v-else>
|
||||
已重置
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Antigravity 上游额度摘要(按家族分组展示关键配额) -->
|
||||
<div
|
||||
@@ -1997,6 +2080,28 @@ function getCodexQuotaDisplay(key: EndpointAPIKey): CodexUpstreamMetadata | null
|
||||
display.secondary_window_minutes = secondaryWindow.window_minutes
|
||||
}
|
||||
|
||||
const sparkPrimaryWindow = getQuotaWindow(quota, 'spark_5h')
|
||||
const sparkPrimaryUsedPercent = getQuotaWindowUsedPercent(sparkPrimaryWindow)
|
||||
if (sparkPrimaryUsedPercent !== undefined) display.spark_primary_used_percent = sparkPrimaryUsedPercent
|
||||
const sparkPrimaryResetAt = getQuotaWindowResetAt(sparkPrimaryWindow)
|
||||
if (sparkPrimaryResetAt !== undefined) display.spark_primary_reset_at = sparkPrimaryResetAt
|
||||
const sparkPrimaryResetSeconds = getQuotaWindowResetSeconds(sparkPrimaryWindow)
|
||||
if (sparkPrimaryResetSeconds !== undefined) display.spark_primary_reset_seconds = sparkPrimaryResetSeconds
|
||||
if (typeof sparkPrimaryWindow?.window_minutes === 'number') {
|
||||
display.spark_primary_window_minutes = sparkPrimaryWindow.window_minutes
|
||||
}
|
||||
|
||||
const sparkSecondaryWindow = getQuotaWindow(quota, 'spark_weekly')
|
||||
const sparkSecondaryUsedPercent = getQuotaWindowUsedPercent(sparkSecondaryWindow)
|
||||
if (sparkSecondaryUsedPercent !== undefined) display.spark_secondary_used_percent = sparkSecondaryUsedPercent
|
||||
const sparkSecondaryResetAt = getQuotaWindowResetAt(sparkSecondaryWindow)
|
||||
if (sparkSecondaryResetAt !== undefined) display.spark_secondary_reset_at = sparkSecondaryResetAt
|
||||
const sparkSecondaryResetSeconds = getQuotaWindowResetSeconds(sparkSecondaryWindow)
|
||||
if (sparkSecondaryResetSeconds !== undefined) display.spark_secondary_reset_seconds = sparkSecondaryResetSeconds
|
||||
if (typeof sparkSecondaryWindow?.window_minutes === 'number') {
|
||||
display.spark_secondary_window_minutes = sparkSecondaryWindow.window_minutes
|
||||
}
|
||||
|
||||
return Object.keys(display).length > 0 ? display : null
|
||||
}
|
||||
|
||||
@@ -2005,6 +2110,16 @@ function hasCodexQuotaDisplayData(key: EndpointAPIKey): boolean {
|
||||
return !!codex && (
|
||||
codex.primary_used_percent !== undefined
|
||||
|| codex.secondary_used_percent !== undefined
|
||||
|| codex.spark_primary_used_percent !== undefined
|
||||
|| codex.spark_secondary_used_percent !== undefined
|
||||
)
|
||||
}
|
||||
|
||||
function hasCodexSparkQuotaDisplayData(key: EndpointAPIKey): boolean {
|
||||
const codex = getCodexQuotaDisplay(key)
|
||||
return !!codex && (
|
||||
codex.spark_primary_used_percent !== undefined
|
||||
|| codex.spark_secondary_used_percent !== undefined
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user