fix: 合并图库吸顶区域并关闭自动刷新

This commit is contained in:
GouJ
2026-09-04 11:38:30 +08:00
parent acc0a1e9ad
commit bd66f7e719
16 changed files with 359 additions and 197 deletions
+41
View File
@@ -5,6 +5,47 @@ import { usePolling } from './usePolling'
afterEach(() => vi.useRealTimers())
describe('异步轮询生命周期', () => {
it('关闭定时刷新后仍支持首次读取、手动刷新及查询目标切换', async () => {
vi.useFakeTimers()
const key = ref('first')
const loader = vi.fn<(id: string) => Promise<string>>(async id => id)
const scope = effectScope()
const query = scope.run(() => usePolling(key, loader, false))!
await Promise.resolve()
expect(query.data.value).toBe('first')
await vi.advanceTimersByTimeAsync(30_000)
expect(loader).toHaveBeenCalledTimes(1)
await query.refresh()
expect(loader).toHaveBeenCalledTimes(2)
key.value = 'second'
await nextTick()
await Promise.resolve()
expect(query.data.value).toBe('second')
await vi.advanceTimersByTimeAsync(30_000)
expect(loader).toHaveBeenCalledTimes(3)
scope.stop()
})
it('响应式暂停清除旧定时器,恢复只创建一个轮询链', async () => {
vi.useFakeTimers()
const interval = ref<number | false>(1000)
const loader = vi.fn<() => Promise<string>>(async () => '数据')
const scope = effectScope()
scope.run(() => usePolling(ref('p'), loader, interval))
await Promise.resolve()
interval.value = false
await nextTick()
await vi.advanceTimersByTimeAsync(5000)
expect(loader).toHaveBeenCalledTimes(1)
interval.value = 1000
await nextTick()
await vi.advanceTimersByTimeAsync(2000)
expect(loader).toHaveBeenCalledTimes(3)
scope.stop()
await vi.advanceTimersByTimeAsync(5000)
expect(loader).toHaveBeenCalledTimes(3)
})
it('切换项目忽略旧响应,卸载时不再排队请求', async () => {
vi.useFakeTimers()
const key = ref('first')
+14 -3
View File
@@ -1,11 +1,11 @@
import { onScopeDispose, ref, watch, type Ref } from 'vue'
import { onScopeDispose, ref, toValue, watch, type MaybeRefOrGetter, type Ref } from 'vue'
import { errorMessage } from '../lib/http'
/** 串行轮询:请求完成后才计时;切换项目立即取消,过期响应不会覆盖新项目。 */
export function usePolling<T>(
key: Ref<string>,
loader: (key: string, signal: AbortSignal) => Promise<T>,
interval = 6000
interval: MaybeRefOrGetter<number | false> = 6000
) {
const data = ref<T | null>(null) as Ref<T | null>
const loading = ref(false)
@@ -18,10 +18,13 @@ export function usePolling<T>(
/** 隐藏页面只安排下一次检查,不继续拉取完整 checkpoint。 */
function schedule() {
const delay = toValue(interval)
if (disposed || delay === false) return
timer = setTimeout(() => {
if (toValue(interval) === false) return
if (document.visibilityState === 'hidden') schedule()
else void refresh()
}, interval)
}, delay)
}
/** 手动刷新也取消上一次查询,避免同时存在多个轮询链。 */
@@ -49,6 +52,14 @@ export function usePolling<T>(
}
}
// 页面可关闭定时刷新;首次读取、切换查询目标和手动刷新仍然有效。
watch(
() => toValue(interval),
() => {
clearTimeout(timer)
if (!loading.value) schedule()
}
)
watch(
key,
() => {