feat:重构UI
This commit is contained in:
67
apps/web/lib/admin-api.ts
Normal file
67
apps/web/lib/admin-api.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
export const API_BASE = process.env.NEXT_PUBLIC_API_BASE_URL || 'http://localhost:8000'
|
||||
|
||||
export const ADMIN_UNAUTHORIZED_EVENT = 'admin:unauthorized'
|
||||
|
||||
export class AdminUnauthorizedError extends Error {
|
||||
constructor(message = '未登录或登录已过期') {
|
||||
super(message)
|
||||
this.name = 'AdminUnauthorizedError'
|
||||
}
|
||||
}
|
||||
|
||||
export function getAdminToken(): string {
|
||||
if (typeof window === 'undefined') return ''
|
||||
return localStorage.getItem('admin_token') || ''
|
||||
}
|
||||
|
||||
export function clearAdminToken() {
|
||||
if (typeof window === 'undefined') return
|
||||
localStorage.removeItem('admin_token')
|
||||
}
|
||||
|
||||
function notifyUnauthorized(message?: string) {
|
||||
if (typeof window === 'undefined') return
|
||||
window.dispatchEvent(new CustomEvent(ADMIN_UNAUTHORIZED_EVENT, { detail: { message } }))
|
||||
}
|
||||
|
||||
async function safeReadErrorMessage(res: Response): Promise<string | null> {
|
||||
try {
|
||||
const data = await res.json()
|
||||
const detail = typeof data?.detail === 'string' ? data.detail : null
|
||||
if (detail) return detail
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
export async function adminFetch(path: string, init: RequestInit = {}): Promise<Response> {
|
||||
const token = getAdminToken()
|
||||
const headers = new Headers(init.headers)
|
||||
|
||||
if (!token) {
|
||||
notifyUnauthorized()
|
||||
throw new AdminUnauthorizedError()
|
||||
}
|
||||
|
||||
if (token) headers.set('Authorization', `Bearer ${token}`)
|
||||
if (!headers.has('Content-Type') && init.body) headers.set('Content-Type', 'application/json')
|
||||
|
||||
const res = await fetch(`${API_BASE}${path}`, { ...init, headers })
|
||||
if (res.status === 401) {
|
||||
const message = (await safeReadErrorMessage(res)) || undefined
|
||||
clearAdminToken()
|
||||
notifyUnauthorized(message)
|
||||
throw new AdminUnauthorizedError(message)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
export async function adminFetchJson<T>(path: string, init: RequestInit = {}): Promise<T> {
|
||||
const res = await adminFetch(path, init)
|
||||
if (!res.ok) {
|
||||
const message = (await safeReadErrorMessage(res)) || `请求失败 (${res.status})`
|
||||
throw new Error(message)
|
||||
}
|
||||
return res.json() as Promise<T>
|
||||
}
|
||||
Reference in New Issue
Block a user