// 全局错误处理插件 import { message, notification } from 'ant-design-vue'; import { h } from 'vue'; import { ExclamationCircleOutlined } from '@ant-design/icons-vue'; // 错误类型枚举 const ErrorType = { NETWORK: 'network', API: 'api', RUNTIME: 'runtime', VALIDATION: 'validation' }; // 错误处理配置 const errorConfig = { // 是否在控制台输出错误 logError: true, // 是否向用户显示错误 showError: true, // 是否收集错误信息(可用于后续接入错误监控系统) collectError: false }; /** * 处理网络错误 * @param {Error} error 错误对象 */ function handleNetworkError(error) { if (!navigator.onLine) { message.error('网络连接已断开,请检查您的网络'); return; } const statusText = error.response?.statusText || '未知网络错误'; const status = error.response?.status; if (status === 404) { notification.error({ message: '请求的资源不存在', description: `${error.config?.url || ''}`, duration: 3 }); } else if (status >= 500) { notification.error({ message: '服务器错误', description: `服务器暂时无法响应请求,请稍后再试 (${status}: ${statusText})`, duration: 4 }); } else { notification.error({ message: '网络请求失败', description: statusText, duration: 3 }); } } /** * 处理API错误(业务逻辑错误) * @param {Object} response API响应对象 */ function handleApiError(response) { const { code, msg } = response; // 根据不同的错误码显示不同的提示 if (code === 401) { notification.warning({ message: '登录已过期', description: '您的登录状态已失效,请重新登录', duration: 3 }); // 可以在这里添加重定向到登录页的逻辑 } else if (code === 403) { notification.warning({ message: '权限不足', description: '您没有权限执行此操作', duration: 3 }); } else { message.error(msg || '操作失败'); } } /** * 处理运行时错误 * @param {Error} error 错误对象 * @param {Object} vm Vue实例 * @param {String} info 错误信息 */ function handleRuntimeError(error, vm, info) { console.error('运行时错误:', error); console.error('错误组件:', vm); console.error('错误信息:', info); notification.error({ message: '应用发生错误', description: '应用运行过程中发生错误,请刷新页面或联系管理员', duration: 4, icon: () => h(ExclamationCircleOutlined, { style: 'color: #ff4d4f' }) }); // 如果配置了错误收集,可以在这里发送错误信息到服务器 if (errorConfig.collectError) { // 实现错误收集逻辑 } } /** * 处理表单验证错误 * @param {Object} errors 验证错误对象 */ function handleValidationError(errors) { const errorMsg = Object.values(errors) .map(err => err.message || err) .filter(Boolean) .join('、'); message.error(errorMsg || '表单验证失败,请检查输入'); } /** * 全局错误处理函数 * @param {Error|Object} error 错误对象 * @param {String} type 错误类型 * @param {Object} context 上下文信息 */ function errorHandler(error, type = ErrorType.RUNTIME, context = {}) { // 如果配置了在控制台输出错误 if (errorConfig.logError) { console.group('应用错误'); console.error('错误类型:', type); console.error('错误详情:', error); if (Object.keys(context).length > 0) { console.error('上下文信息:', context); } console.groupEnd(); } // 如果配置了向用户显示错误 if (errorConfig.showError) { switch (type) { case ErrorType.NETWORK: handleNetworkError(error); break; case ErrorType.API: handleApiError(error); break; case ErrorType.VALIDATION: handleValidationError(error); break; case ErrorType.RUNTIME: default: handleRuntimeError(error, context.vm, context.info); break; } } return Promise.reject(error); } // 导出错误处理器和类型 export { errorHandler, ErrorType }; // Vue插件 export default { install(app) { // 设置全局错误处理 app.config.errorHandler = (error, vm, info) => { errorHandler(error, ErrorType.RUNTIME, { vm, info }); }; // 添加到全局属性中,方便在组件中使用 app.config.globalProperties.$errorHandler = errorHandler; app.config.globalProperties.$errorType = ErrorType; // 捕获未处理的Promise错误 window.addEventListener('unhandledrejection', event => { // 避免重复处理已经被errorHandler处理过的错误 if (event.reason && event.reason._handled) { return; } // 标记错误已被处理 if (event.reason) { event.reason._handled = true; } // 处理错误 const error = event.reason; const errorType = error?.response ? ErrorType.NETWORK : ErrorType.RUNTIME; errorHandler(error, errorType, { unhandled: true }); }); } };