Files
glt-taro/src/utils/errorHandler.ts
赵忠林 6d9a6ef7e4 fix(api): 修复 API 导入导致的 TypeScript 编译错误
- 将所有 API 文件中的 import request from '@/utils/request'替换为 import request from '@/utils/request-legacy'
- 创建了 request-legacy.ts 兼容层,保持与现有 API 代码的完全兼容性
- 支持旧的 API 响应格式 {code, message, data}
- 自动处理认证头和错误处理
- 批量更新了 30+ 个 API 文件的导入路径
- 修复了 TypeScript 编译错误,项目现在可以正常编译和运行
2025-08-14 19:22:02 +08:00

303 lines
7.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import Taro from '@tarojs/taro';
// 定义本地的RequestError类避免循环依赖
export class RequestError extends Error {
public type: string;
public code?: number;
public data?: any;
constructor(message: string, type: string, code?: number, data?: any) {
super(message);
this.name = 'RequestError';
this.type = type;
this.code = code;
this.data = data;
}
}
// 错误类型枚举
export enum ErrorType {
NETWORK_ERROR = 'NETWORK_ERROR',
TIMEOUT_ERROR = 'TIMEOUT_ERROR',
BUSINESS_ERROR = 'BUSINESS_ERROR',
AUTH_ERROR = 'AUTH_ERROR',
UNKNOWN_ERROR = 'UNKNOWN_ERROR'
}
// 错误级别枚举
export enum ErrorLevel {
INFO = 'info',
WARNING = 'warning',
ERROR = 'error',
FATAL = 'fatal'
}
// 错误信息接口
export interface ErrorInfo {
message: string;
level: ErrorLevel;
type: string;
stack?: string;
extra?: any;
timestamp: number;
userId?: string;
page?: string;
}
/**
* 全局错误处理器
*/
class GlobalErrorHandler {
private static instance: GlobalErrorHandler;
private errorQueue: ErrorInfo[] = [];
private maxQueueSize = 50;
private constructor() {
this.setupGlobalErrorHandlers();
}
public static getInstance(): GlobalErrorHandler {
if (!GlobalErrorHandler.instance) {
GlobalErrorHandler.instance = new GlobalErrorHandler();
}
return GlobalErrorHandler.instance;
}
/**
* 设置全局错误处理器
*/
private setupGlobalErrorHandlers() {
// 捕获未处理的Promise rejection
if (typeof window !== 'undefined') {
window.addEventListener('unhandledrejection', (event) => {
this.handleError(event.reason, ErrorLevel.ERROR, 'UnhandledPromiseRejection');
event.preventDefault();
});
}
}
/**
* 处理错误
*/
public handleError(
error: any,
level: ErrorLevel = ErrorLevel.ERROR,
type: string = 'Unknown',
extra?: any
) {
const errorInfo = this.createErrorInfo(error, level, type, extra);
// 添加到错误队列
this.addToQueue(errorInfo);
// 根据错误级别决定处理方式
switch (level) {
case ErrorLevel.FATAL:
this.handleFatalError(errorInfo);
break;
case ErrorLevel.ERROR:
this.handleNormalError(errorInfo);
break;
case ErrorLevel.WARNING:
this.handleWarning(errorInfo);
break;
case ErrorLevel.INFO:
this.handleInfo(errorInfo);
break;
}
// 上报错误
this.reportError(errorInfo);
}
/**
* 创建错误信息对象
*/
private createErrorInfo(
error: any,
level: ErrorLevel,
type: string,
extra?: any
): ErrorInfo {
let message = '未知错误';
let stack: string | undefined;
if (error instanceof Error) {
message = error.message;
stack = error.stack;
} else if (error instanceof RequestError) {
message = error.message;
type = error.type;
extra = { ...extra, code: error.code, data: error.data };
} else if (typeof error === 'string') {
message = error;
} else if (error && typeof error === 'object') {
message = error.message || error.errMsg || JSON.stringify(error);
}
return {
message,
level,
type,
stack,
extra,
timestamp: Date.now(),
userId: Taro.getStorageSync('UserId') || undefined,
page: this.getCurrentPage()
};
}
/**
* 获取当前页面路径
*/
private getCurrentPage(): string {
try {
const pages = Taro.getCurrentPages();
const currentPage = pages[pages.length - 1];
return currentPage?.route || 'unknown';
} catch {
return 'unknown';
}
}
/**
* 添加到错误队列
*/
private addToQueue(errorInfo: ErrorInfo) {
this.errorQueue.push(errorInfo);
// 保持队列大小
if (this.errorQueue.length > this.maxQueueSize) {
this.errorQueue.shift();
}
}
/**
* 处理致命错误
*/
private handleFatalError(errorInfo: ErrorInfo) {
console.error('Fatal Error:', errorInfo);
Taro.showModal({
title: '严重错误',
content: '应用遇到严重错误,需要重启',
showCancel: false,
confirmText: '重启应用',
success: () => {
Taro.reLaunch({ url: '/pages/index/index' });
}
});
}
/**
* 处理普通错误
*/
private handleNormalError(errorInfo: ErrorInfo) {
console.error('Error:', errorInfo);
// 根据错误类型显示不同的提示
let title = '操作失败';
if (errorInfo.type === ErrorType.NETWORK_ERROR) {
title = '网络连接失败';
} else if (errorInfo.type === ErrorType.TIMEOUT_ERROR) {
title = '请求超时';
} else if (errorInfo.type === ErrorType.AUTH_ERROR) {
title = '认证失败';
}
Taro.showToast({
title: errorInfo.message || title,
icon: 'error',
duration: 2000
});
}
/**
* 处理警告
*/
private handleWarning(errorInfo: ErrorInfo) {
console.warn('Warning:', errorInfo);
// 警告通常不需要用户交互,只记录日志
}
/**
* 处理信息
*/
private handleInfo(errorInfo: ErrorInfo) {
console.info('Info:', errorInfo);
}
/**
* 上报错误到服务器
*/
private reportError(errorInfo: ErrorInfo) {
try {
// 这里可以实现错误上报逻辑
// 例如发送到后端日志系统、第三方监控服务等
// 示例:发送到后端
// request.post('/api/error/report', errorInfo).catch(() => {
// // 上报失败也不要影响用户体验
// });
// 开发环境下打印详细信息
if (process.env.NODE_ENV === 'development') {
console.group('🚨 Error Report');
console.log('Message:', errorInfo.message);
console.log('Level:', errorInfo.level);
console.log('Type:', errorInfo.type);
console.log('Page:', errorInfo.page);
console.log('UserId:', errorInfo.userId);
console.log('Timestamp:', new Date(errorInfo.timestamp).toLocaleString());
if (errorInfo.stack) {
console.log('Stack:', errorInfo.stack);
}
if (errorInfo.extra) {
console.log('Extra:', errorInfo.extra);
}
console.groupEnd();
}
} catch (reportError) {
console.error('Failed to report error:', reportError);
}
}
/**
* 获取错误队列
*/
public getErrorQueue(): ErrorInfo[] {
return [...this.errorQueue];
}
/**
* 清空错误队列
*/
public clearErrorQueue() {
this.errorQueue = [];
}
}
// 导出单例实例
export const errorHandler = GlobalErrorHandler.getInstance();
// 便捷方法
export const handleError = (error: any, level?: ErrorLevel, type?: string, extra?: any) => {
errorHandler.handleError(error, level, type, extra);
};
export const handleFatalError = (error: any, extra?: any) => {
errorHandler.handleError(error, ErrorLevel.FATAL, 'FatalError', extra);
};
export const handleWarning = (error: any, extra?: any) => {
errorHandler.handleError(error, ErrorLevel.WARNING, 'Warning', extra);
};
export const handleInfo = (message: string, extra?: any) => {
errorHandler.handleError(message, ErrorLevel.INFO, 'Info', extra);
};
export default errorHandler;