Files
ks-app-employment-service/hook/usePagination.js
2025-08-20 13:38:47 +08:00

173 lines
4.4 KiB
JavaScript

import {
ref,
reactive,
watch,
isRef,
nextTick
} from 'vue'
export function usePagination(
requestFn,
transformFn,
options = {}
) {
const list = ref([])
const loading = ref(false)
const error = ref(false)
const finished = ref(false)
const firstLoading = ref(true)
const empty = ref(false)
const {
pageSize = 10,
search = {},
autoWatchSearch = false,
debounceTime = 300,
autoFetch = false,
// 字段映射
dataKey = 'rows',
totalKey = 'total',
// 分页字段名映射
pageField = 'current',
sizeField = 'pageSize',
onBeforeRequest,
onAfterRequest
} = options
const pageState = reactive({
page: 1,
pageSize: isRef(pageSize) ? pageSize.value : pageSize,
total: 0,
maxPage: 1,
search: isRef(search) ? search.value : search
})
let debounceTimer = null
const fetchData = async (type = 'refresh') => {
if (loading.value) return Promise.resolve()
console.log(type)
loading.value = true
error.value = false
if (typeof onBeforeRequest === 'function') {
try {
onBeforeRequest(type, pageState)
} catch (err) {
console.warn('onBeforeRequest 执行异常:', err)
}
}
if (type === 'refresh') {
pageState.page = 1
finished.value = false
if (list.value.length === 0) {
firstLoading.value = true
}
} else if (type === 'loadMore') {
if (pageState.page >= pageState.maxPage) {
loading.value = false
finished.value = true
return Promise.resolve('no more')
}
pageState.page += 1
}
const params = {
...pageState.search,
[pageField]: pageState.page,
[sizeField]: pageState.pageSize,
}
try {
const res = await requestFn(params)
const rawData = res[dataKey]
const total = res[totalKey] || 99999999
console.log(total, rawData)
const data = typeof transformFn === 'function' ? transformFn(rawData) : rawData
if (type === 'refresh') {
list.value = data
} else {
list.value.push(...data)
}
pageState.total = total
pageState.maxPage = Math.ceil(total / pageState.pageSize)
finished.value = list.value.length >= total
empty.value = list.value.length === 0
} catch (err) {
console.error('分页请求失败:', err)
error.value = true
} finally {
loading.value = false
firstLoading.value = false
if (typeof onAfterRequest === 'function') {
try {
onAfterRequest(type, pageState, {
error: error.value
})
} catch (err) {
console.warn('onAfterRequest 执行异常:', err)
}
}
}
}
const refresh = () => fetchData('refresh')
const loadMore = () => fetchData('loadMore')
const resetPagination = () => {
list.value = []
pageState.page = 1
pageState.total = 0
pageState.maxPage = 1
finished.value = false
error.value = false
firstLoading.value = true
empty.value = false
}
if (autoWatchSearch && isRef(search)) {
watch(search, (newVal) => {
pageState.search = newVal
clearTimeout(debounceTimer)
debounceTimer = setTimeout(() => {
refresh()
}, debounceTime)
}, {
deep: true
})
}
watch(pageSize, (newVal) => {
pageState.pageSize = newVal
}, {
deep: true
})
if (autoFetch) {
nextTick(() => {
refresh()
})
}
return {
list,
loading,
error,
finished,
firstLoading,
empty,
pageState,
refresh,
loadMore,
resetPagination
}
}