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

231 lines
5.7 KiB
JavaScript
Raw Normal View History

// 统一的 API 客户端
const API_BASE = '' // 生产环境由 Nginx 代理
import { ErrorCodes, matchErrorCode } from './errorCodes.js'
// 错误处理
class ApiError extends Error {
constructor(message, status, data, code = null) {
super(message)
this.name = 'ApiError'
this.status = status
this.data = data
this.code = code || matchErrorCode(status, message).code
}
// 获取格式化的错误信息
get formattedMessage() {
return `${this.code}: ${this.message}`
}
}
// 获取 Token
const getToken = () => localStorage.getItem('token')
// 统一请求方法
async function request(endpoint, options = {}) {
const token = getToken()
const defaultHeaders = {
'Content-Type': 'application/json',
}
if (token) {
defaultHeaders['Authorization'] = `Bearer ${token}`
}
const config = {
...options,
headers: {
...defaultHeaders,
...(options.headers || {})
}
}
try {
const response = await fetch(`${API_BASE}${endpoint}`, config)
const data = await response.json()
if (!response.ok) {
// 处理 401 未授权
if (response.status === 401) {
localStorage.removeItem('token')
localStorage.removeItem('user')
window.location.hash = '#/login'
throw new ApiError(
data.detail || data.message || '登录已过期,请重新登录',
401,
data,
'E00010'
)
}
// 处理 422 验证错误
if (response.status === 422 && data.detail) {
const detail = Array.isArray(data.detail) ? data.detail[0] : data.detail
const field = detail.loc ? detail.loc.join('.') : ''
const msg = detail.msg || detail.message || data.message
throw new ApiError(
`${field}: ${msg}`,
422,
data
)
}
// 其他错误
throw new ApiError(
data.detail || data.message || data.error || '请求失败',
response.status,
data
)
}
return data
} catch (error) {
// 网络错误
if (error.name === 'TypeError' && error.message.includes('fetch')) {
throw new ApiError('网络连接失败,请检查网络', 0, null, 'E00001')
}
throw error
}
}
// API 模块
export const api = {
// 认证
auth: {
login: async (username, password) => {
// 登录时不使用 token
const params = new URLSearchParams()
params.append('username', username)
params.append('password', password)
const response = await fetch(`${API_BASE}/api/auth/login`, {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: params.toString()
})
const data = await response.json()
if (!response.ok) {
// 优先使用 error.code 和 error.message后端标准格式
const errorCode = data.error?.code || data.code
const errorMsg = data.error?.message || data.detail || data.message || '登录失败'
const error = new ApiError(errorMsg, response.status, data)
if (errorCode) error.code = errorCode
throw error
}
return data
},
register: (data) => request('/api/auth/register', {
method: 'POST',
body: JSON.stringify(data)
})
},
// 当前用户
user: {
me: async () => {
const token = getToken()
if (!token) throw new ApiError('未登录', 401, null, 'E00010')
const response = await fetch(`${API_BASE}/api/users/me`, {
headers: { 'Authorization': `Bearer ${token}` }
})
const data = await response.json()
if (!response.ok) {
throw new ApiError(
data.detail || data.message || '获取用户信息失败',
response.status,
data
)
}
return data
},
update: (data) => request('/api/users/me', {
method: 'PUT',
body: JSON.stringify(data)
})
},
// 藏品
collections: {
// 列表
list: (params = {}) => {
const query = new URLSearchParams(params).toString()
return request(`/api/collections${query ? '?' + query : ''}`)
},
// 详情
get: (id) => request(`/api/collections/${id}`),
// 创建
create: (data) => request('/api/collections', {
method: 'POST',
body: JSON.stringify(data)
}),
// 更新
update: (id, data) => request(`/api/collections/${id}`, {
method: 'PUT',
body: JSON.stringify(data)
}),
// 删除
delete: (id) => request(`/api/collections/${id}`, {
method: 'DELETE'
}),
// 下一个编号
nextCode: () => request('/api/collections/next-code'),
// 统计
stats: (params = {}) => {
const query = new URLSearchParams(params).toString()
return request(`/api/collections/stats${query ? '?' + query : ''}`)
},
// 导出
export: (params) => request(`/api/collections/export?${new URLSearchParams(params)}`)
},
// OCR
ocr: {
recognize: (file) => {
const formData = new FormData()
formData.append('image', file)
return request('/api/ocr/recognize', {
method: 'POST',
body: formData
})
}
},
// 用户管理(仅管理员)
admin: {
users: {
list: (page = 1, limit = 20) => request(`/api/admin/users?page=${page}&limit=${limit}`),
get: (userId) => request(`/api/admin/users/${userId}`),
collections: (userId) => request(`/api/admin/users/${userId}/collections`),
count: (userId) => request(`/api/admin/users/${userId}/count`)
}
}
}
// 导出错误类
export { ApiError }
// 默认导出
export default api