jiachenlong/frontend/src.bak/utils/errorCodes.js

166 lines
7.4 KiB
JavaScript
Raw Normal View History

// 错误码定义
// 格式E + 模块 (2 位) + 序号 (3 位)
export const ErrorCodes = {
// ============ 通用错误 (00-09) ============
E00000: { code: 'E00000', message: '未知错误', httpStatus: 0 },
E00001: { code: 'E00001', message: '网络连接失败,请检查网络', httpStatus: 0 },
E00002: { code: 'E00002', message: '服务器响应超时', httpStatus: 0 },
E00003: { code: 'E00003', message: '服务器内部错误', httpStatus: 500 },
// ============ 认证错误 (10-19) ============
E00010: { code: 'E00010', message: '未登录或登录已过期', httpStatus: 401 },
E00011: { code: 'E00011', message: '用户名或密码错误', httpStatus: 401 },
E00012: { code: 'E00012', message: '验证码错误', httpStatus: 400 },
E00013: { code: 'E00013', message: '账号已被禁用', httpStatus: 403 },
E00014: { code: 'E00014', message: '无权访问此资源', httpStatus: 403 },
E00015: { code: 'E00015', message: '令牌无效或已过期', httpStatus: 401 },
// ============ 登录注册 (20-29) ============
E00020: { code: 'E00020', message: '请输入用户名和密码', httpStatus: 400 },
E00021: { code: 'E00021', message: '用户名至少 3 个字符', httpStatus: 400 },
E00022: { code: 'E00022', message: '密码至少 6 个字符', httpStatus: 400 },
E00023: { code: 'E00023', message: '用户名已存在', httpStatus: 400 },
E00024: { code: 'E00024', message: '邮箱已被注册', httpStatus: 400 },
E00025: { code: 'E00025', message: '邮箱格式不正确', httpStatus: 400 },
E00026: { code: 'E00026', message: '手机号格式不正确', httpStatus: 400 },
// ============ 藏品管理 (30-39) ============
E00030: { code: 'E00030', message: '藏品名称不能为空', httpStatus: 400 },
E00031: { code: 'E00031', message: '藏品名称至少 2 个字符', httpStatus: 400 },
E00032: { code: 'E00032', message: '藏品分类不能为空', httpStatus: 400 },
E00033: { code: 'E00033', message: '藏品不存在', httpStatus: 404 },
E00034: { code: 'E00034', message: '禁止重复:此冠字号已存在', httpStatus: 400 },
E00035: { code: 'E00035', message: '成本价格必须>=0', httpStatus: 400 },
E00036: { code: 'E00036', message: '目标价格必须>=0', httpStatus: 400 },
E00037: { code: 'E00037', message: '发行年份必须是 4 位数字', httpStatus: 400 },
E00038: { code: 'E00038', message: '图片格式不正确', httpStatus: 400 },
E00039: { code: 'E00039', message: '图片大小不能超过 10MB', httpStatus: 400 },
// ============ OCR 识别 (40-49) ============
E00040: { code: 'E00040', message: '请选择图片文件', httpStatus: 400 },
E00041: { code: 'E00041', message: '图片尺寸太小,无法识别', httpStatus: 400 },
E00042: { code: 'E00042', message: 'OCR 识别失败,请重试', httpStatus: 500 },
E00043: { code: 'E00043', message: 'OCR 服务暂时不可用', httpStatus: 503 },
E00044: { code: 'E00044', message: '无法识别图片内容', httpStatus: 400 },
// ============ 用户管理 (50-59) ============
E00050: { code: 'E00050', message: '仅管理员可访问', httpStatus: 403 },
E00051: { code: 'E00051', message: '用户不存在', httpStatus: 404 },
E00052: { code: 'E00052', message: '不能删除自己', httpStatus: 400 },
E00053: { code: 'E00053', message: '不能修改自己的角色', httpStatus: 403 },
// ============ 文件上传 (60-69) ============
E00060: { code: 'E00060', message: '文件太大', httpStatus: 400 },
E00061: { code: 'E00061', message: '不支持的文件格式', httpStatus: 400 },
E00062: { code: 'E00062', message: '上传失败', httpStatus: 500 },
}
// 根据 HTTP 状态码和错误信息匹配错误码
export function matchErrorCode(status, errorMessage = '') {
// 首先尝试精确匹配错误信息
for (const code in ErrorCodes) {
const error = ErrorCodes[code]
if (error.httpStatus === status) {
// 检查错误信息是否包含关键词
const msg = errorMessage.toLowerCase()
if (status === 401) {
if (msg.includes('password') || msg.includes('密码')) return ErrorCodes.E00011
if (msg.includes('token') || msg.includes('令牌')) return ErrorCodes.E00015
return ErrorCodes.E00010
}
if (status === 403) {
if (msg.includes('admin') || msg.includes('管理员')) return ErrorCodes.E00050
return ErrorCodes.E00014
}
if (status === 404) {
if (msg.includes('user')) return ErrorCodes.E00051
if (msg.includes('collection') || msg.includes('藏品')) return ErrorCodes.E00033
}
if (status === 400) {
if (msg.includes('captcha') || msg.includes('验证码')) return ErrorCodes.E00012
if (msg.includes('username') || msg.includes('用户名')) return ErrorCodes.E00023
if (msg.includes('email') || msg.includes('邮箱')) return ErrorCodes.E00024
if (msg.includes('重复') || msg.includes('duplicate')) return ErrorCodes.E00034
if (msg.includes('价格') || msg.includes('price')) {
if (msg.includes('greater') || msg.includes('>=')) return ErrorCodes.E00035
}
if (msg.includes('year') || msg.includes('年份')) return ErrorCodes.E00037
if (msg.includes('image') || msg.includes('图片')) return ErrorCodes.E00038
}
if (status === 422) {
// 验证错误
if (msg.includes('cost_price') || msg.includes('成本')) return ErrorCodes.E00035
if (msg.includes('target_price') || msg.includes('目标价格')) return ErrorCodes.E00036
if (msg.includes('issue_year') || msg.includes('年份')) return ErrorCodes.E00037
if (msg.includes('name') || msg.includes('名称')) return ErrorCodes.E00031
if (msg.includes('category') || msg.includes('分类')) return ErrorCodes.E00032
}
if (status === 500) {
if (msg.includes('ocr') || msg.includes('识别')) return ErrorCodes.E00042
}
}
}
// 默认错误码
if (status === 0) return ErrorCodes.E00001
if (status >= 500) return ErrorCodes.E00003
return ErrorCodes.E00000
}
// 格式化错误信息
export function formatError(error) {
if (error.code && typeof error.code === 'string' && error.code.startsWith('E')) {
// 已经是错误码格式
const errorCode = ErrorCodes[error.code]
if (errorCode) {
return `${errorCode.code}: ${errorCode.message}`
}
}
// 匹配错误码
const status = error.status || error.httpStatus || 0
const message = error.message || error.detail || error.error || ''
const errorCode = matchErrorCode(status, message)
return `${errorCode.code}: ${errorCode.message}`
}
// 显示错误 Toast
export function showErrorToast(error, duration = 3000) {
const errorMessage = formatError(error)
// 创建 Toast 元素
const toast = document.createElement('div')
toast.style.cssText = `
position: fixed;
top: 20px;
left: 50%;
transform: translateX(-50%);
background: rgba(239, 68, 68, 0.95);
color: white;
padding: 12px 24px;
border-radius: 8px;
font-size: 14px;
z-index: 9999;
box-shadow: 0 4px 12px rgba(0,0,0,0.3);
animation: slideDown 0.3s ease;
`
toast.textContent = errorMessage
document.body.appendChild(toast)
// 3 秒后移除
setTimeout(() => {
toast.style.animation = 'slideUp 0.3s ease'
setTimeout(() => toast.remove(), 300)
}, duration)
}
export default { ErrorCodes, matchErrorCode, formatError, showErrorToast }