| | |
| | | import { ref, reactive, computed, onMounted, onUnmounted, nextTick, readonly } from 'vue' |
| | | import { useWindowSize } from '@vueuse/core' |
| | | import { hash } from 'ohash' |
| | | import { useTableColumns } from './useTableColumns' |
| | | import { TableCache, CacheInvalidationStrategy } from '../../utils/table/tableCache' |
| | | import { |
| | |
| | | const error = ref(null) |
| | | const data = ref([]) |
| | | let abortController = null |
| | | let inflightRequest = null |
| | | let inflightRequestKey = '' |
| | | let cacheCleanupTimer = null |
| | | const searchParams = reactive( |
| | | Object.assign( |
| | | { |
| | | [pageKey]: 1, |
| | | [sizeKey]: 10 |
| | | [sizeKey]: 20 |
| | | }, |
| | | apiParams || {} |
| | | ) |
| | |
| | | cacheUpdateTrigger.value++ |
| | | } |
| | | const fetchData = async (params, useCache = enableCache) => { |
| | | let requestParams = Object.assign( |
| | | {}, |
| | | searchParams, |
| | | { |
| | | [pageKey]: pagination.current, |
| | | [sizeKey]: pagination.size |
| | | }, |
| | | params || {} |
| | | ) |
| | | if (excludeParams.length > 0) { |
| | | const filteredParams = { ...requestParams } |
| | | excludeParams.forEach((key) => { |
| | | delete filteredParams[key] |
| | | }) |
| | | requestParams = filteredParams |
| | | } |
| | | const requestKey = hash(requestParams) |
| | | if (inflightRequest && inflightRequestKey === requestKey) { |
| | | logger.log('复用进行中的请求') |
| | | return inflightRequest |
| | | } |
| | | if (abortController) { |
| | | abortController.abort() |
| | | } |
| | |
| | | abortController = currentController |
| | | loadingState.value = 'loading' |
| | | error.value = null |
| | | try { |
| | | let requestParams = Object.assign( |
| | | {}, |
| | | searchParams, |
| | | { |
| | | [pageKey]: pagination.current, |
| | | [sizeKey]: pagination.size |
| | | }, |
| | | params || {} |
| | | ) |
| | | if (excludeParams.length > 0) { |
| | | const filteredParams = { ...requestParams } |
| | | excludeParams.forEach((key) => { |
| | | delete filteredParams[key] |
| | | }) |
| | | requestParams = filteredParams |
| | | } |
| | | if (useCache && cache) { |
| | | const cachedItem = cache.get(requestParams) |
| | | if (cachedItem) { |
| | | data.value = cachedItem.data |
| | | updatePaginationFromResponse(pagination, cachedItem.response) |
| | | const paramsRecord2 = searchParams |
| | | if (paramsRecord2[pageKey] !== pagination.current) { |
| | | paramsRecord2[pageKey] = pagination.current |
| | | const currentRequest = (async () => { |
| | | try { |
| | | if (useCache && cache) { |
| | | const cachedItem = cache.get(requestParams) |
| | | if (cachedItem) { |
| | | data.value = cachedItem.data |
| | | updatePaginationFromResponse(pagination, cachedItem.response) |
| | | const paramsRecord2 = searchParams |
| | | if (paramsRecord2[pageKey] !== pagination.current) { |
| | | paramsRecord2[pageKey] = pagination.current |
| | | } |
| | | if (paramsRecord2[sizeKey] !== pagination.size) { |
| | | paramsRecord2[sizeKey] = pagination.size |
| | | } |
| | | loadingState.value = 'success' |
| | | if (onCacheHit) { |
| | | onCacheHit(cachedItem.data, cachedItem.response) |
| | | } |
| | | logger.log(`缓存命中`) |
| | | return cachedItem.response |
| | | } |
| | | if (paramsRecord2[sizeKey] !== pagination.size) { |
| | | paramsRecord2[sizeKey] = pagination.size |
| | | } |
| | | loadingState.value = 'success' |
| | | if (onCacheHit) { |
| | | onCacheHit(cachedItem.data, cachedItem.response) |
| | | } |
| | | logger.log(`缓存命中`) |
| | | return cachedItem.response |
| | | } |
| | | const response = await apiFn(requestParams) |
| | | if (currentController.signal.aborted) { |
| | | throw new Error('请求已取消') |
| | | } |
| | | const standardResponse = responseAdapter(response) |
| | | let tableData = extractTableData(standardResponse) |
| | | if (dataTransformer) { |
| | | tableData = dataTransformer(tableData) |
| | | } |
| | | data.value = tableData |
| | | updatePaginationFromResponse(pagination, standardResponse) |
| | | const paramsRecord = searchParams |
| | | if (paramsRecord[pageKey] !== pagination.current) { |
| | | paramsRecord[pageKey] = pagination.current |
| | | } |
| | | if (paramsRecord[sizeKey] !== pagination.size) { |
| | | paramsRecord[sizeKey] = pagination.size |
| | | } |
| | | if (useCache && cache) { |
| | | cache.set(requestParams, tableData, standardResponse) |
| | | cacheUpdateTrigger.value++ |
| | | logger.log(`数据已缓存`) |
| | | } |
| | | loadingState.value = 'success' |
| | | if (onSuccess) { |
| | | onSuccess(tableData, standardResponse) |
| | | } |
| | | return standardResponse |
| | | } catch (err) { |
| | | if ( |
| | | err instanceof Error && |
| | | (err.message === '请求已取消' || err.code === 'REQUEST_CANCELLED') |
| | | ) { |
| | | loadingState.value = 'idle' |
| | | return { records: [], total: 0, current: 1, size: 10 } |
| | | } |
| | | loadingState.value = 'error' |
| | | data.value = [] |
| | | const tableError = handleError(err, '获取表格数据失败') |
| | | throw tableError |
| | | } finally { |
| | | if (abortController === currentController) { |
| | | abortController = null |
| | | } |
| | | if (inflightRequest === currentRequest) { |
| | | inflightRequest = null |
| | | inflightRequestKey = '' |
| | | } |
| | | } |
| | | const response = await apiFn(requestParams) |
| | | if (currentController.signal.aborted) { |
| | | throw new Error('请求已取消') |
| | | } |
| | | const standardResponse = responseAdapter(response) |
| | | let tableData = extractTableData(standardResponse) |
| | | if (dataTransformer) { |
| | | tableData = dataTransformer(tableData) |
| | | } |
| | | data.value = tableData |
| | | updatePaginationFromResponse(pagination, standardResponse) |
| | | const paramsRecord = searchParams |
| | | if (paramsRecord[pageKey] !== pagination.current) { |
| | | paramsRecord[pageKey] = pagination.current |
| | | } |
| | | if (paramsRecord[sizeKey] !== pagination.size) { |
| | | paramsRecord[sizeKey] = pagination.size |
| | | } |
| | | if (useCache && cache) { |
| | | cache.set(requestParams, tableData, standardResponse) |
| | | cacheUpdateTrigger.value++ |
| | | logger.log(`数据已缓存`) |
| | | } |
| | | loadingState.value = 'success' |
| | | if (onSuccess) { |
| | | onSuccess(tableData, standardResponse) |
| | | } |
| | | return standardResponse |
| | | } catch (err) { |
| | | if ( |
| | | err instanceof Error && |
| | | (err.message === '请求已取消' || err.code === 'REQUEST_CANCELLED') |
| | | ) { |
| | | loadingState.value = 'idle' |
| | | return { records: [], total: 0, current: 1, size: 10 } |
| | | } |
| | | loadingState.value = 'error' |
| | | data.value = [] |
| | | const tableError = handleError(err, '获取表格数据失败') |
| | | throw tableError |
| | | } finally { |
| | | if (abortController === currentController) { |
| | | abortController = null |
| | | } |
| | | } |
| | | })() |
| | | inflightRequest = currentRequest |
| | | inflightRequestKey = requestKey |
| | | return currentRequest |
| | | } |
| | | const getData = async (params) => { |
| | | try { |