mirror of
https://github.com/stardrophere/InsightRadar.git
synced 2026-06-06 00:52:50 +08:00
big update
This commit is contained in:
@@ -0,0 +1,107 @@
|
||||
/**
|
||||
* 通用 HTTP 客户端:自动注入 Bearer Token,统一处理错误
|
||||
*/
|
||||
import { useAuthStore } from '@/stores/auth'
|
||||
import { pinia } from '@/stores'
|
||||
|
||||
const API_BASE = (import.meta.env.VITE_API_BASE_URL as string | undefined) ?? '/api/v1'
|
||||
|
||||
// 后端返回的错误消息中英映射
|
||||
const MESSAGE_MAP: Record<string, string> = {
|
||||
'You can only operate your own resources': '只能操作自己的资源',
|
||||
'Preference keyword already exists for this user': '该关键词已订阅',
|
||||
'Keyword cannot be empty': '关键词不能为空',
|
||||
'This delivery time already exists': '该推送时间已存在',
|
||||
'This channel type already exists for the user': '该渠道类型已存在',
|
||||
'Schedule not found': '推送时间不存在',
|
||||
'Push endpoint not found': '推送渠道不存在',
|
||||
'Preference not found': '偏好不存在',
|
||||
'Invalid or expired token': '登录已过期,请重新登录',
|
||||
'Authentication credentials were not provided': '请先登录',
|
||||
}
|
||||
|
||||
function localizeMessage(msg: string): string {
|
||||
return MESSAGE_MAP[msg] ?? msg
|
||||
}
|
||||
|
||||
function getAuthHeaders(): Record<string, string> {
|
||||
const authStore = useAuthStore(pinia)
|
||||
const headers: Record<string, string> = { 'Content-Type': 'application/json' }
|
||||
if (authStore.accessToken) {
|
||||
headers['Authorization'] = `Bearer ${authStore.accessToken}`
|
||||
}
|
||||
return headers
|
||||
}
|
||||
|
||||
async function handleResponse<T>(response: Response): Promise<T> {
|
||||
const raw = await response.text()
|
||||
let data: Record<string, unknown> = {}
|
||||
if (raw) {
|
||||
try {
|
||||
data = JSON.parse(raw) as Record<string, unknown>
|
||||
} catch {
|
||||
data = {}
|
||||
}
|
||||
}
|
||||
|
||||
if (!response.ok) {
|
||||
const detail = data.detail
|
||||
if (typeof detail === 'string') {
|
||||
throw new Error(localizeMessage(detail))
|
||||
}
|
||||
throw new Error(`请求失败 (${response.status})`)
|
||||
}
|
||||
|
||||
return data as T
|
||||
}
|
||||
|
||||
/** GET 请求 */
|
||||
export async function apiGet<T>(path: string, params?: Record<string, string | number>): Promise<T> {
|
||||
let url = `${API_BASE}${path}`
|
||||
if (params) {
|
||||
const searchParams = new URLSearchParams()
|
||||
for (const [key, value] of Object.entries(params)) {
|
||||
searchParams.set(key, String(value))
|
||||
}
|
||||
url += `?${searchParams.toString()}`
|
||||
}
|
||||
const response = await fetch(url, { method: 'GET', headers: getAuthHeaders() })
|
||||
return handleResponse<T>(response)
|
||||
}
|
||||
|
||||
/** POST 请求 */
|
||||
export async function apiPost<T>(path: string, body?: unknown): Promise<T> {
|
||||
const response = await fetch(`${API_BASE}${path}`, {
|
||||
method: 'POST',
|
||||
headers: getAuthHeaders(),
|
||||
body: body !== undefined ? JSON.stringify(body) : undefined,
|
||||
})
|
||||
return handleResponse<T>(response)
|
||||
}
|
||||
|
||||
/** PATCH 请求 */
|
||||
export async function apiPatch<T>(path: string, body: unknown): Promise<T> {
|
||||
const response = await fetch(`${API_BASE}${path}`, {
|
||||
method: 'PATCH',
|
||||
headers: getAuthHeaders(),
|
||||
body: JSON.stringify(body),
|
||||
})
|
||||
return handleResponse<T>(response)
|
||||
}
|
||||
|
||||
/** DELETE 请求 */
|
||||
export async function apiDelete(path: string): Promise<void> {
|
||||
const response = await fetch(`${API_BASE}${path}`, {
|
||||
method: 'DELETE',
|
||||
headers: getAuthHeaders(),
|
||||
})
|
||||
if (!response.ok && response.status !== 204) {
|
||||
const raw = await response.text()
|
||||
let detail = `请求失败 (${response.status})`
|
||||
try {
|
||||
const data = JSON.parse(raw) as Record<string, unknown>
|
||||
if (typeof data.detail === 'string') detail = localizeMessage(data.detail)
|
||||
} catch { /* ignore */ }
|
||||
throw new Error(detail)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user