From 2005fc97a8a7fe18ab3016b53525309d401185e3 Mon Sep 17 00:00:00 2001
From: Ethan0x0000 <3352979663@qq.com>
Date: Tue, 17 Mar 2026 13:19:20 +0800
Subject: [PATCH] fix(ui): show 'now' for idle OpenAI usage windows
Use utilization-based idle detection instead of local request counts so newly imported OAuth accounts keep countdowns when usage is non-zero.
---
.../components/account/AccountUsageCell.vue | 2 +
.../components/account/UsageProgressBar.vue | 14 +++-
.../__tests__/UsageProgressBar.spec.ts | 69 +++++++++++++++++++
3 files changed, 84 insertions(+), 1 deletion(-)
create mode 100644 frontend/src/components/account/__tests__/UsageProgressBar.spec.ts
diff --git a/frontend/src/components/account/AccountUsageCell.vue b/frontend/src/components/account/AccountUsageCell.vue
index e548be8c..131d82b2 100644
--- a/frontend/src/components/account/AccountUsageCell.vue
+++ b/frontend/src/components/account/AccountUsageCell.vue
@@ -82,6 +82,7 @@
:utilization="usageInfo.five_hour.utilization"
:resets-at="usageInfo.five_hour.resets_at"
:window-stats="usageInfo.five_hour.window_stats"
+ :show-now-when-idle="true"
color="indigo"
/>
diff --git a/frontend/src/components/account/UsageProgressBar.vue b/frontend/src/components/account/UsageProgressBar.vue
index 506071fa..52f0ecbb 100644
--- a/frontend/src/components/account/UsageProgressBar.vue
+++ b/frontend/src/components/account/UsageProgressBar.vue
@@ -48,7 +48,7 @@
-
+
{{ formatResetTime }}
@@ -68,6 +68,7 @@ const props = defineProps<{
resetsAt?: string | null
color: 'indigo' | 'emerald' | 'purple' | 'amber'
windowStats?: WindowStats | null
+ showNowWhenIdle?: boolean
}>()
const { t } = useI18n()
@@ -139,9 +140,20 @@ const displayPercent = computed(() => {
return percent > 999 ? '>999%' : `${percent}%`
})
+const shouldShowResetTime = computed(() => {
+ if (props.resetsAt) return true
+ return Boolean(props.showNowWhenIdle && props.utilization <= 0)
+})
+
// Format reset time
const formatResetTime = computed(() => {
+ // For rolling windows, when utilization is 0%, treat as immediately available.
+ if (props.showNowWhenIdle && props.utilization <= 0) {
+ return '现在'
+ }
+
if (!props.resetsAt) return '-'
+
const date = new Date(props.resetsAt)
const diffMs = date.getTime() - now.value.getTime()
diff --git a/frontend/src/components/account/__tests__/UsageProgressBar.spec.ts b/frontend/src/components/account/__tests__/UsageProgressBar.spec.ts
new file mode 100644
index 00000000..9def052c
--- /dev/null
+++ b/frontend/src/components/account/__tests__/UsageProgressBar.spec.ts
@@ -0,0 +1,69 @@
+import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
+import { mount } from '@vue/test-utils'
+import UsageProgressBar from '../UsageProgressBar.vue'
+
+vi.mock('vue-i18n', async () => {
+ const actual = await vi.importActual('vue-i18n')
+ return {
+ ...actual,
+ useI18n: () => ({
+ t: (key: string) => key
+ })
+ }
+})
+
+describe('UsageProgressBar', () => {
+ beforeEach(() => {
+ vi.useFakeTimers()
+ vi.setSystemTime(new Date('2026-03-17T00:00:00Z'))
+ })
+
+ afterEach(() => {
+ vi.useRealTimers()
+ })
+
+ it('showNowWhenIdle=true 且利用率为 0 时显示“现在”', () => {
+ const wrapper = mount(UsageProgressBar, {
+ props: {
+ label: '5h',
+ utilization: 0,
+ resetsAt: '2026-03-17T02:30:00Z',
+ showNowWhenIdle: true,
+ color: 'indigo'
+ }
+ })
+
+ expect(wrapper.text()).toContain('现在')
+ expect(wrapper.text()).not.toContain('2h 30m')
+ })
+
+ it('showNowWhenIdle=true 但利用率大于 0 时显示倒计时', () => {
+ const wrapper = mount(UsageProgressBar, {
+ props: {
+ label: '7d',
+ utilization: 12,
+ resetsAt: '2026-03-17T02:30:00Z',
+ showNowWhenIdle: true,
+ color: 'emerald'
+ }
+ })
+
+ expect(wrapper.text()).toContain('2h 30m')
+ expect(wrapper.text()).not.toContain('现在')
+ })
+
+ it('showNowWhenIdle=false 时保持原有倒计时行为', () => {
+ const wrapper = mount(UsageProgressBar, {
+ props: {
+ label: '1d',
+ utilization: 0,
+ resetsAt: '2026-03-17T02:30:00Z',
+ showNowWhenIdle: false,
+ color: 'indigo'
+ }
+ })
+
+ expect(wrapper.text()).toContain('2h 30m')
+ expect(wrapper.text()).not.toContain('现在')
+ })
+})