63 lines
1.5 KiB
TypeScript
63 lines
1.5 KiB
TypeScript
import { ref } from 'vue'
|
|
|
|
import type { ApiEnvelope } from '@/lib/http'
|
|
import type { AdminPagination } from '@/types/admin'
|
|
|
|
export interface AdminListPageData<TItem> {
|
|
items: TItem[]
|
|
pagination: AdminPagination
|
|
}
|
|
|
|
export interface UseAdminListPageOptions<TItem> {
|
|
defaultErrorMessage: string
|
|
pageSize?: number
|
|
fetchPage: (page: number, pageSize: number) => Promise<ApiEnvelope<AdminListPageData<TItem>>>
|
|
}
|
|
|
|
export function useAdminListPage<TItem>(options: UseAdminListPageOptions<TItem>) {
|
|
const loading = ref(true)
|
|
const errorMessage = ref('')
|
|
const items = ref<TItem[]>([])
|
|
const pagination = ref<AdminPagination>({
|
|
page: 1,
|
|
pageSize: options.pageSize ?? 20,
|
|
total: 0,
|
|
})
|
|
let latestRequestId = 0
|
|
|
|
async function loadPage(page = pagination.value.page) {
|
|
const requestId = ++latestRequestId
|
|
loading.value = true
|
|
errorMessage.value = ''
|
|
|
|
try {
|
|
const response = await options.fetchPage(page, pagination.value.pageSize)
|
|
|
|
if (requestId !== latestRequestId) {
|
|
return
|
|
}
|
|
|
|
items.value = response.data.items
|
|
pagination.value = response.data.pagination
|
|
} catch (error) {
|
|
if (requestId !== latestRequestId) {
|
|
return
|
|
}
|
|
|
|
errorMessage.value = error instanceof Error ? error.message : options.defaultErrorMessage
|
|
} finally {
|
|
if (requestId === latestRequestId) {
|
|
loading.value = false
|
|
}
|
|
}
|
|
}
|
|
|
|
return {
|
|
loading,
|
|
errorMessage,
|
|
items,
|
|
pagination,
|
|
loadPage,
|
|
}
|
|
}
|