import { tableConfig } from './tableConfig'
|
function extractRecords(obj, fields) {
|
for (const field of fields) {
|
if (field in obj && Array.isArray(obj[field])) {
|
return obj[field]
|
}
|
}
|
return []
|
}
|
function extractTotal(obj, records, fields) {
|
for (const field of fields) {
|
if (field in obj && typeof obj[field] === 'number') {
|
return obj[field]
|
}
|
}
|
return records.length
|
}
|
function extractPagination(obj, data) {
|
const result = {}
|
const sources = [obj, data ?? {}]
|
const currentFields = tableConfig.currentFields
|
for (const src of sources) {
|
for (const field of currentFields) {
|
if (field in src && typeof src[field] === 'number') {
|
result.current = src[field]
|
break
|
}
|
}
|
if (result.current !== void 0) break
|
}
|
const sizeFields = tableConfig.sizeFields
|
for (const src of sources) {
|
for (const field of sizeFields) {
|
if (field in src && typeof src[field] === 'number') {
|
result.size = src[field]
|
break
|
}
|
}
|
if (result.size !== void 0) break
|
}
|
if (result.current === void 0 && result.size === void 0) return void 0
|
return result
|
}
|
const defaultResponseAdapter = (response) => {
|
const recordFields = tableConfig.recordFields
|
if (!response) {
|
return { records: [], total: 0 }
|
}
|
if (Array.isArray(response)) {
|
return { records: response, total: response.length }
|
}
|
if (typeof response !== 'object') {
|
console.warn(
|
'[tableUtils] 无法识别的响应格式,支持的格式包括: 数组、包含' +
|
recordFields.join('/') +
|
'字段的对象、嵌套data对象。当前格式:',
|
response
|
)
|
return { records: [], total: 0 }
|
}
|
const res = response
|
let records = []
|
let total = 0
|
let pagination
|
records = extractRecords(res, recordFields)
|
total = extractTotal(res, records, tableConfig.totalFields)
|
pagination = extractPagination(res)
|
if (records.length === 0 && 'data' in res && typeof res.data === 'object') {
|
const data = res.data
|
records = extractRecords(data, ['list', 'records', 'items'])
|
total = extractTotal(data, records, tableConfig.totalFields)
|
pagination = extractPagination(res, data)
|
if (Array.isArray(res.data)) {
|
records = res.data
|
total = records.length
|
}
|
}
|
if (!recordFields.some((field) => field in res) && records.length === 0) {
|
console.warn('[tableUtils] 无法识别的响应格式')
|
console.warn('支持的字段包括: ' + recordFields.join('、'), response)
|
console.warn('扩展字段请到 utils/table/tableConfig 文件配置')
|
}
|
const result = { records, total }
|
if (pagination) {
|
Object.assign(result, pagination)
|
}
|
return result
|
}
|
const extractTableData = (response) => {
|
const data = response.records || response.data || []
|
return Array.isArray(data) ? data : []
|
}
|
const updatePaginationFromResponse = (pagination, response) => {
|
pagination.total = response.total ?? pagination.total ?? 0
|
if (response.current !== void 0) {
|
pagination.current = response.current
|
}
|
const maxPage = Math.max(1, Math.ceil(pagination.total / (pagination.size || 1)))
|
if (pagination.current > maxPage) {
|
pagination.current = maxPage
|
}
|
}
|
const createSmartDebounce = (fn, delay) => {
|
let timeoutId = null
|
let lastArgs = null
|
let lastResolve = null
|
let lastReject = null
|
const debouncedFn = (...args) => {
|
return new Promise((resolve, reject) => {
|
if (timeoutId) clearTimeout(timeoutId)
|
lastArgs = args
|
lastResolve = resolve
|
lastReject = reject
|
timeoutId = setTimeout(async () => {
|
try {
|
const result = await fn(...args)
|
resolve(result)
|
} catch (error) {
|
reject(error)
|
} finally {
|
timeoutId = null
|
lastArgs = null
|
lastResolve = null
|
lastReject = null
|
}
|
}, delay)
|
})
|
}
|
debouncedFn.cancel = () => {
|
if (timeoutId) clearTimeout(timeoutId)
|
timeoutId = null
|
lastArgs = null
|
lastResolve = null
|
lastReject = null
|
}
|
debouncedFn.flush = async () => {
|
if (timeoutId && lastArgs && lastResolve && lastReject) {
|
clearTimeout(timeoutId)
|
timeoutId = null
|
const args = lastArgs
|
const resolve = lastResolve
|
const reject = lastReject
|
lastArgs = null
|
lastResolve = null
|
lastReject = null
|
try {
|
const result = await fn(...args)
|
resolve(result)
|
return result
|
} catch (error) {
|
reject(error)
|
throw error
|
}
|
}
|
return Promise.resolve()
|
}
|
return debouncedFn
|
}
|
const createErrorHandler = (onError, enableLog = false) => {
|
const logger = {
|
error: (message, ...args) => {
|
if (enableLog) console.error(`[useTable] ${message}`, ...args)
|
}
|
}
|
return (err, context) => {
|
const tableError = {
|
code: 'UNKNOWN_ERROR',
|
message: '未知错误',
|
details: err
|
}
|
if (err instanceof Error) {
|
tableError.message = err.message
|
tableError.code = err.name
|
} else if (typeof err === 'string') {
|
tableError.message = err
|
}
|
logger.error(`${context}:`, err)
|
onError?.(tableError)
|
return tableError
|
}
|
}
|
export {
|
createErrorHandler,
|
createSmartDebounce,
|
defaultResponseAdapter,
|
extractTableData,
|
updatePaginationFromResponse
|
}
|