Files
codex-proxy-rs/frontend/src/composables/usePagedQuery.ts
T
2026-08-14 01:07:12 +08:00

90 lines
2.1 KiB
TypeScript

import { clamp } from 'es-toolkit'
import { onScopeDispose, shallowRef } from 'vue'
import { errorMessage } from '@/utils/async'
interface PageResult {
items: unknown[]
page: {
page: number
pageSize: number
total: number
totalPages: number
}
}
export function usePagedQuery<Result extends PageResult>(options: {
initialPageSize: number
load: (pagination: { page: number, pageSize: number }) => Promise<Result>
onSuccess?: (result: Result) => void
onError?: (error: unknown) => void
}) {
const page = shallowRef(1)
const pageSize = shallowRef(options.initialPageSize)
const total = shallowRef(0)
const items = shallowRef<Result['items'][number][]>([])
const loading = shallowRef(false)
const error = shallowRef('')
let requestSequence = 0
async function execute(execution: { silent?: boolean } = {}) {
const requestId = ++requestSequence
if (!execution.silent) {
loading.value = true
error.value = ''
}
try {
const result = await options.load({
page: page.value,
pageSize: pageSize.value,
})
if (requestId !== requestSequence)
return false
if (result.items.length === 0 && result.page.total > 0 && result.page.page > 1) {
page.value = clamp(result.page.totalPages, 1, Number.POSITIVE_INFINITY)
return execute(execution)
}
items.value = result.items
page.value = result.page.page
pageSize.value = result.page.pageSize
total.value = result.page.total
options.onSuccess?.(result)
return true
}
catch (cause: unknown) {
if (requestId !== requestSequence)
return false
if (!execution.silent) {
error.value = errorMessage(cause, '加载失败')
options.onError?.(cause)
}
return false
}
finally {
if (requestId === requestSequence)
loading.value = false
}
}
function invalidate() {
requestSequence += 1
loading.value = false
}
onScopeDispose(invalidate)
return {
page,
pageSize,
total,
items,
loading,
error,
execute,
invalidate,
}
}