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.
This commit is contained in:
Ethan0x0000
2026-03-17 13:19:20 +08:00
parent 045cba78b4
commit 2005fc97a8
3 changed files with 84 additions and 1 deletions

View File

@@ -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"
/>
<UsageProgressBar
@@ -90,6 +91,7 @@
:utilization="usageInfo.seven_day.utilization"
:resets-at="usageInfo.seven_day.resets_at"
:window-stats="usageInfo.seven_day.window_stats"
:show-now-when-idle="true"
color="emerald"
/>
</div>

View File

@@ -48,7 +48,7 @@
</span>
<!-- Reset time -->
<span v-if="resetsAt" class="shrink-0 text-[10px] text-gray-400">
<span v-if="shouldShowResetTime" class="shrink-0 text-[10px] text-gray-400">
{{ formatResetTime }}
</span>
</div>
@@ -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()

View File

@@ -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<typeof import('vue-i18n')>('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('现在')
})
})