173 lines
4.4 KiB
JavaScript
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
|
|
}
|
|
} |