/** * 统一的错误处理工具 * 用于解析和显示各种类型的错误 */ import { DownloadErrorCode, parseDownloadError, DownloadErrorMessages } from './download-errors'; /** * API错误响应接口 */ export interface ApiErrorResponse { error?: string; code?: string; details?: string; message?: string; } /** * 通用错误类型 */ export enum ErrorType { // 下载错误 DOWNLOAD = 'DOWNLOAD', // 上传错误 UPLOAD = 'UPLOAD', // 网络错误 NETWORK = 'NETWORK', // 权限错误 PERMISSION = 'PERMISSION', // 验证错误 VALIDATION = 'VALIDATION', // 服务器错误 SERVER = 'SERVER', // 未知错误 UNKNOWN = 'UNKNOWN', } /** * 解析API错误响应 */ export function parseApiError(error: any): { type: ErrorType; message: string; code?: string; details?: string; } { // 如果已经是解析后的格式 if (error?.type && error?.message) { return error; } // 如果是下载错误(有DownloadErrorCode) if (error?.code && Object.values(DownloadErrorCode).includes(error.code as DownloadErrorCode)) { const parsed = parseDownloadError(error); return { type: ErrorType.DOWNLOAD, message: parsed.message, code: parsed.code, details: parsed.details, }; } // 如果是API错误响应格式 if (error?.error || error?.message) { const errorMessage = error.error || error.message || String(error); const errorCode = error.code; // 根据错误代码或消息推断错误类型 if (errorCode === 'UNAUTHORIZED' || errorMessage.includes('未登录') || errorMessage.includes('请先登录')) { return { type: ErrorType.PERMISSION, message: '请先登录', code: errorCode, details: error.details, }; } if (errorCode === 'FORBIDDEN' || errorCode === 'NO_PERMISSION' || errorMessage.includes('权限') || errorMessage.includes('无权限')) { return { type: ErrorType.PERMISSION, message: errorMessage.includes('下载') ? '无权限下载该素材' : '无权限执行此操作', code: errorCode, details: error.details, }; } if (errorMessage.includes('上传') || errorMessage.includes('upload')) { return { type: ErrorType.UPLOAD, message: errorMessage, code: errorCode, details: error.details, }; } if (errorMessage.includes('网络') || errorMessage.includes('network') || errorMessage.includes('连接')) { return { type: ErrorType.NETWORK, message: '网络连接失败,请检查网络后重试', code: errorCode, details: error.details, }; } if (errorMessage.includes('验证') || errorMessage.includes('validation') || errorMessage.includes('格式')) { return { type: ErrorType.VALIDATION, message: errorMessage, code: errorCode, details: error.details, }; } // 默认返回原始错误消息 return { type: ErrorType.UNKNOWN, message: errorMessage, code: errorCode, details: error.details, }; } // 如果是Error对象 if (error instanceof Error) { const message = error.message || '操作失败,请稍后重试'; // 根据错误消息推断类型 if (message.includes('权限') || message.includes('无权限')) { return { type: ErrorType.PERMISSION, message }; } if (message.includes('网络') || message.includes('network') || message.includes('连接')) { return { type: ErrorType.NETWORK, message: '网络连接失败,请检查网络后重试' }; } if (message.includes('上传') || message.includes('upload')) { return { type: ErrorType.UPLOAD, message }; } return { type: ErrorType.UNKNOWN, message }; } // 如果是字符串 if (typeof error === 'string') { return { type: ErrorType.UNKNOWN, message: error || '操作失败,请稍后重试', }; } // 默认未知错误 return { type: ErrorType.UNKNOWN, message: '操作失败,请稍后重试', }; } /** * 从fetch响应中解析错误 */ export async function parseFetchError(response: Response): Promise<{ type: ErrorType; message: string; code?: string; details?: string; }> { try { const errorData = await response.json(); return parseApiError(errorData); } catch { // 如果无法解析JSON,根据状态码返回错误 if (response.status === 401) { return { type: ErrorType.PERMISSION, message: '请先登录' }; } if (response.status === 403) { return { type: ErrorType.PERMISSION, message: '无权限执行此操作' }; } if (response.status === 404) { return { type: ErrorType.UNKNOWN, message: '资源不存在' }; } if (response.status >= 500) { return { type: ErrorType.SERVER, message: '服务器错误,请稍后重试' }; } return { type: ErrorType.UNKNOWN, message: `请求失败 (${response.status})` }; } } /** * 处理错误并显示提示(需要传入showToast函数) */ export function handleError( error: any, showToast?: (message: string, options?: { variant?: 'success' | 'error' }) => void ): { type: ErrorType; message: string; code?: string; details?: string; } { const parsed = parseApiError(error); // 如果提供了showToast,自动显示错误 if (showToast) { showToast(parsed.message, { variant: 'error' }); } return parsed; }