useErrorHandler.js 4.78 KB
/**
 * 错误处理 composable
 * 提供统一的错误处理机制
 *
 * @Date: 2026-01-18
 * @Description: 统一处理各种错误,提供用户友好的错误提示
 */

import { showToast, showFailToast } from 'vant'

/**
 * @function useErrorHandler
 * @description 提供错误处理功能
 * @returns {Object} 包含错误处理方法的对象
 */
export function useErrorHandler() {
  /**
   * 默认错误消息
   */
  const DEFAULT_ERROR_MESSAGE = '操作失败,请稍后重试'

  /**
   * 错误消息映射
   * 将常见的错误码映射为用户友好的提示
   */
  const ERROR_MESSAGES = {
    400: '请求参数错误',
    401: '登录已过期,请重新登录',
    403: '没有权限执行此操作',
    404: '请求的资源不存在',
    500: '服务器错误,请稍后重试',
    502: '网关错误,请稍后重试',
    503: '服务暂不可用,请稍后重试',
    504: '请求超时,请稍后重试'
  }

  /**
   * 处理通用错误
   * @param {Error|Object|string} error - 错误对象或错误消息
   * @param {string} [customMessage] - 自定义错误消息,优先使用
   */
  const handleError = (error, customMessage = null) => {
    console.error('Error:', error)

    // 使用自定义消息
    if (customMessage) {
      showFailToast(customMessage)
      return
    }

    // 从错误对象中提取消息
    let message = DEFAULT_ERROR_MESSAGE

    if (typeof error === 'string') {
      message = error
    } else if (error && error.message) {
      message = error.message
    } else if (error && error.msg) {
      message = error.msg
    } else if (error && error.response) {
      // Axios 错误
      const status = error.response.status
      message = ERROR_MESSAGES[status] || error.response.data?.msg || DEFAULT_ERROR_MESSAGE
    }

    showFailToast(message)
  }

  /**
   * 处理 API 错误(检查 code === 1)
   * @param {Object} response - API 响应对象
   * @param {Function} onSuccess - 成功回调
   * @param {Function} [onFailure] - 失败回调
   * @returns {boolean} 是否成功
   */
  const handleApiResponse = (response, onSuccess, onFailure = null) => {
    const { code, data, msg } = response

    if (code === 1) {
      if (onSuccess) {
        onSuccess(data)
      }
      return true
    } else {
      const errorMessage = msg || DEFAULT_ERROR_MESSAGE
      console.error('API Error:', errorMessage)

      if (onFailure) {
        onFailure(errorMessage)
      } else {
        showFailToast(errorMessage)
      }
      return false
    }
  }

  /**
   * 处理异步操作错误
   * @param {Function} asyncFn - 异步函数
   * @param {Object} options - 配置选项
   * @param {Function} [options.onSuccess] - 成功回调
   * @param {Function} [options.onError] - 错误回调
   * @param {string} [options.successMessage] - 成功提示消息
   * @param {string} [options.errorMessage] - 错误提示消息
   * @returns {Promise<boolean>} 是否成功
   */
  const handleAsyncOperation = async (asyncFn, options = {}) => {
    const {
      onSuccess,
      onError,
      successMessage,
      errorMessage
    } = options

    try {
      const result = await asyncFn()

      // 检查 API 响应
      const { code, data, msg } = result

      if (code === 1) {
        if (successMessage) {
          showToast(successMessage)
        }
        if (onSuccess) {
          onSuccess(data)
        }
        return true
      } else {
        const message = errorMessage || msg || DEFAULT_ERROR_MESSAGE
        showFailToast(message)
        if (onError) {
          onError(message)
        }
        return false
      }
    } catch (err) {
      handleError(err, errorMessage)
      if (onError) {
        onError(err.message || DEFAULT_ERROR_MESSAGE)
      }
      return false
    }
  }

  /**
   * 验证并处理表单错误
   * @param {Object} formData - 表单数据
   * @param {Object} rules - 验证规则
   * @returns {Object} 包含 isValid 和 errors 的对象
   */
  const validateForm = (formData, rules) => {
    const errors = {}

    for (const [field, rule] of Object.entries(rules)) {
      const value = formData[field]

      // 必填检查
      if (rule.required && (value === undefined || value === null || value === '')) {
        errors[field] = rule.message || `${field} 为必填项`
        continue
      }

      // 自定义验证
      if (rule.validator && typeof rule.validator === 'function') {
        const result = rule.validator(value, formData)
        if (result !== true) {
          errors[field] = result || rule.message || `${field} 格式不正确`
        }
      }
    }

    return {
      isValid: Object.keys(errors).length === 0,
      errors
    }
  }

  return {
    handleError,
    handleApiResponse,
    handleAsyncOperation,
    validateForm,
    DEFAULT_ERROR_MESSAGE,
    ERROR_MESSAGES
  }
}