errorHandler.js 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. // 全局错误处理插件
  2. import { message, notification } from 'ant-design-vue';
  3. import { h } from 'vue';
  4. import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
  5. // 错误类型枚举
  6. const ErrorType = {
  7. NETWORK: 'network',
  8. API: 'api',
  9. RUNTIME: 'runtime',
  10. VALIDATION: 'validation'
  11. };
  12. // 错误处理配置
  13. const errorConfig = {
  14. // 是否在控制台输出错误
  15. logError: true,
  16. // 是否向用户显示错误
  17. showError: true,
  18. // 是否收集错误信息(可用于后续接入错误监控系统)
  19. collectError: false
  20. };
  21. /**
  22. * 处理网络错误
  23. * @param {Error} error 错误对象
  24. */
  25. function handleNetworkError(error) {
  26. if (!navigator.onLine) {
  27. message.error('网络连接已断开,请检查您的网络');
  28. return;
  29. }
  30. const statusText = error.response?.statusText || '未知网络错误';
  31. const status = error.response?.status;
  32. if (status === 404) {
  33. notification.error({
  34. message: '请求的资源不存在',
  35. description: `${error.config?.url || ''}`,
  36. duration: 3
  37. });
  38. } else if (status >= 500) {
  39. notification.error({
  40. message: '服务器错误',
  41. description: `服务器暂时无法响应请求,请稍后再试 (${status}: ${statusText})`,
  42. duration: 4
  43. });
  44. } else {
  45. notification.error({
  46. message: '网络请求失败',
  47. description: statusText,
  48. duration: 3
  49. });
  50. }
  51. }
  52. /**
  53. * 处理API错误(业务逻辑错误)
  54. * @param {Object} response API响应对象
  55. */
  56. function handleApiError(response) {
  57. const { code, msg } = response;
  58. // 根据不同的错误码显示不同的提示
  59. if (code === 401) {
  60. notification.warning({
  61. message: '登录已过期',
  62. description: '您的登录状态已失效,请重新登录',
  63. duration: 3
  64. });
  65. // 可以在这里添加重定向到登录页的逻辑
  66. } else if (code === 403) {
  67. notification.warning({
  68. message: '权限不足',
  69. description: '您没有权限执行此操作',
  70. duration: 3
  71. });
  72. } else {
  73. message.error(msg || '操作失败');
  74. }
  75. }
  76. /**
  77. * 处理运行时错误
  78. * @param {Error} error 错误对象
  79. * @param {Object} vm Vue实例
  80. * @param {String} info 错误信息
  81. */
  82. function handleRuntimeError(error, vm, info) {
  83. console.error('运行时错误:', error);
  84. console.error('错误组件:', vm);
  85. console.error('错误信息:', info);
  86. notification.error({
  87. message: '应用发生错误',
  88. description: '应用运行过程中发生错误,请刷新页面或联系管理员',
  89. duration: 4,
  90. icon: () => h(ExclamationCircleOutlined, { style: 'color: #ff4d4f' })
  91. });
  92. // 如果配置了错误收集,可以在这里发送错误信息到服务器
  93. if (errorConfig.collectError) {
  94. // 实现错误收集逻辑
  95. }
  96. }
  97. /**
  98. * 处理表单验证错误
  99. * @param {Object} errors 验证错误对象
  100. */
  101. function handleValidationError(errors) {
  102. const errorMsg = Object.values(errors)
  103. .map(err => err.message || err)
  104. .filter(Boolean)
  105. .join('、');
  106. message.error(errorMsg || '表单验证失败,请检查输入');
  107. }
  108. /**
  109. * 全局错误处理函数
  110. * @param {Error|Object} error 错误对象
  111. * @param {String} type 错误类型
  112. * @param {Object} context 上下文信息
  113. */
  114. function errorHandler(error, type = ErrorType.RUNTIME, context = {}) {
  115. // 如果配置了在控制台输出错误
  116. if (errorConfig.logError) {
  117. console.group('应用错误');
  118. console.error('错误类型:', type);
  119. console.error('错误详情:', error);
  120. if (Object.keys(context).length > 0) {
  121. console.error('上下文信息:', context);
  122. }
  123. console.groupEnd();
  124. }
  125. // 如果配置了向用户显示错误
  126. if (errorConfig.showError) {
  127. switch (type) {
  128. case ErrorType.NETWORK:
  129. handleNetworkError(error);
  130. break;
  131. case ErrorType.API:
  132. handleApiError(error);
  133. break;
  134. case ErrorType.VALIDATION:
  135. handleValidationError(error);
  136. break;
  137. case ErrorType.RUNTIME:
  138. default:
  139. handleRuntimeError(error, context.vm, context.info);
  140. break;
  141. }
  142. }
  143. return Promise.reject(error);
  144. }
  145. // 导出错误处理器和类型
  146. export { errorHandler, ErrorType };
  147. // Vue插件
  148. export default {
  149. install(app) {
  150. // 设置全局错误处理
  151. app.config.errorHandler = (error, vm, info) => {
  152. errorHandler(error, ErrorType.RUNTIME, { vm, info });
  153. };
  154. // 添加到全局属性中,方便在组件中使用
  155. app.config.globalProperties.$errorHandler = errorHandler;
  156. app.config.globalProperties.$errorType = ErrorType;
  157. // 捕获未处理的Promise错误
  158. window.addEventListener('unhandledrejection', event => {
  159. // 避免重复处理已经被errorHandler处理过的错误
  160. if (event.reason && event.reason._handled) {
  161. return;
  162. }
  163. // 标记错误已被处理
  164. if (event.reason) {
  165. event.reason._handled = true;
  166. }
  167. // 处理错误
  168. const error = event.reason;
  169. const errorType = error?.response ? ErrorType.NETWORK : ErrorType.RUNTIME;
  170. errorHandler(error, errorType, { unhandled: true });
  171. });
  172. }
  173. };