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('现在')
+ })
+})