238 lines
5.0 KiB
JavaScript
238 lines
5.0 KiB
JavaScript
/**
|
||
* 统一错误处理工具
|
||
* 提供统一的错误提示和处理机制
|
||
*/
|
||
|
||
/**
|
||
* 错误类型映射
|
||
*/
|
||
const ERROR_TYPES = {
|
||
NETWORK: 'network',
|
||
AUTH: 'auth',
|
||
BUSINESS: 'business',
|
||
UNKNOWN: 'unknown'
|
||
}
|
||
|
||
/**
|
||
* 错误消息映射
|
||
*/
|
||
const ERROR_MESSAGES = {
|
||
// 网络错误
|
||
'request:fail': '网络连接失败,请检查网络设置',
|
||
'request:fail timeout': '请求超时,请稍后重试',
|
||
'request:fail abort': '请求已取消',
|
||
|
||
// 认证错误
|
||
401: '登录已过期,请重新登录',
|
||
403: '没有权限访问',
|
||
|
||
// 业务错误
|
||
400: '请求参数错误',
|
||
404: '请求的资源不存在',
|
||
500: '服务器错误,请稍后重试',
|
||
|
||
// 默认错误
|
||
default: '操作失败,请稍后重试'
|
||
}
|
||
|
||
/**
|
||
* 判断错误类型
|
||
* @param {object} error - 错误对象
|
||
* @returns {string} 错误类型
|
||
*/
|
||
function getErrorType(error) {
|
||
if (!error) return ERROR_TYPES.UNKNOWN
|
||
|
||
// 网络错误
|
||
if (error.errMsg && error.errMsg.includes('request:fail')) {
|
||
return ERROR_TYPES.NETWORK
|
||
}
|
||
|
||
// 认证错误
|
||
if (error.code === 401 || error.statusCode === 401) {
|
||
return ERROR_TYPES.AUTH
|
||
}
|
||
|
||
// 业务错误
|
||
if (error.code || error.statusCode) {
|
||
return ERROR_TYPES.BUSINESS
|
||
}
|
||
|
||
return ERROR_TYPES.UNKNOWN
|
||
}
|
||
|
||
/**
|
||
* 获取错误消息
|
||
* @param {object} error - 错误对象
|
||
* @returns {string} 错误消息
|
||
*/
|
||
function getErrorMessage(error) {
|
||
if (!error) return ERROR_MESSAGES.default
|
||
|
||
// 优先使用后端返回的错误消息
|
||
if (error.message) return error.message
|
||
if (error.error) return error.error
|
||
if (error.msg) return error.msg
|
||
|
||
// 根据错误码获取消息
|
||
const code = error.code || error.statusCode
|
||
if (code && ERROR_MESSAGES[code]) {
|
||
return ERROR_MESSAGES[code]
|
||
}
|
||
|
||
// 根据错误信息获取消息
|
||
if (error.errMsg && ERROR_MESSAGES[error.errMsg]) {
|
||
return ERROR_MESSAGES[error.errMsg]
|
||
}
|
||
|
||
return ERROR_MESSAGES.default
|
||
}
|
||
|
||
/**
|
||
* 显示错误提示
|
||
* @param {object} error - 错误对象
|
||
* @param {object} options - 选项
|
||
*/
|
||
function showError(error, options = {}) {
|
||
const {
|
||
silent = false, // 是否静默(不显示提示)
|
||
duration = 2000, // 提示持续时间
|
||
icon = 'none', // 图标类型
|
||
mask = false // 是否显示透明蒙层
|
||
} = options
|
||
|
||
if (silent) return
|
||
|
||
const message = getErrorMessage(error)
|
||
const type = getErrorType(error)
|
||
|
||
// 认证错误不显示toast,由auth模块处理
|
||
if (type === ERROR_TYPES.AUTH) {
|
||
return
|
||
}
|
||
|
||
wx.showToast({
|
||
title: message,
|
||
icon,
|
||
duration,
|
||
mask
|
||
})
|
||
}
|
||
|
||
/**
|
||
* 处理API错误
|
||
* @param {object} error - 错误对象
|
||
* @param {object} options - 选项
|
||
* @returns {object} 处理后的错误对象
|
||
*/
|
||
function handleApiError(error, options = {}) {
|
||
const {
|
||
showToast = true, // 是否显示错误提示
|
||
logError = true, // 是否记录错误日志
|
||
customMessage = null // 自定义错误消息
|
||
} = options
|
||
|
||
// 记录错误日志
|
||
if (logError) {
|
||
console.error('[Error Handler]', error)
|
||
}
|
||
|
||
// 显示错误提示
|
||
if (showToast) {
|
||
showError(error, {
|
||
silent: false,
|
||
duration: 2000
|
||
})
|
||
}
|
||
|
||
// 返回标准化的错误对象
|
||
return {
|
||
type: getErrorType(error),
|
||
message: customMessage || getErrorMessage(error),
|
||
code: error.code || error.statusCode || -1,
|
||
originalError: error
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 错误重试机制
|
||
* @param {function} fn - 要重试的函数
|
||
* @param {object} options - 选项
|
||
* @returns {Promise}
|
||
*/
|
||
async function retryOnError(fn, options = {}) {
|
||
const {
|
||
maxRetries = 3, // 最大重试次数
|
||
retryDelay = 1000, // 重试延迟(毫秒)
|
||
onRetry = null // 重试回调
|
||
} = options
|
||
|
||
let lastError = null
|
||
|
||
for (let i = 0; i < maxRetries; i++) {
|
||
try {
|
||
return await fn()
|
||
} catch (error) {
|
||
lastError = error
|
||
|
||
// 认证错误不重试
|
||
if (getErrorType(error) === ERROR_TYPES.AUTH) {
|
||
throw error
|
||
}
|
||
|
||
// 最后一次重试失败,抛出错误
|
||
if (i === maxRetries - 1) {
|
||
throw error
|
||
}
|
||
|
||
// 执行重试回调
|
||
if (onRetry) {
|
||
onRetry(i + 1, maxRetries)
|
||
}
|
||
|
||
// 等待后重试
|
||
await new Promise(resolve => setTimeout(resolve, retryDelay))
|
||
}
|
||
}
|
||
|
||
throw lastError
|
||
}
|
||
|
||
/**
|
||
* 检查网络状态
|
||
* @returns {Promise<boolean>}
|
||
*/
|
||
function checkNetworkStatus() {
|
||
return new Promise((resolve) => {
|
||
wx.getNetworkType({
|
||
success: (res) => {
|
||
const networkType = res.networkType
|
||
if (networkType === 'none') {
|
||
wx.showToast({
|
||
title: '网络未连接',
|
||
icon: 'none',
|
||
duration: 2000
|
||
})
|
||
resolve(false)
|
||
} else {
|
||
resolve(true)
|
||
}
|
||
},
|
||
fail: () => {
|
||
resolve(true) // 获取失败时假设网络正常
|
||
}
|
||
})
|
||
})
|
||
}
|
||
|
||
module.exports = {
|
||
ERROR_TYPES,
|
||
ERROR_MESSAGES,
|
||
getErrorType,
|
||
getErrorMessage,
|
||
showError,
|
||
handleApiError,
|
||
retryOnError,
|
||
checkNetworkStatus
|
||
}
|