Files
lab/frontend/src/api/request.ts
2026-09-21 12:51:08 +08:00

137 lines
3.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import axios, { type AxiosInstance, type AxiosRequestConfig } from 'axios'
import { ElMessage } from 'element-plus'
/** 令牌在 localStorage 中的键名 */
const TOKEN_KEY = 'lab-token'
/**
* 读取本地令牌。
*
* @returns JWT 字符串或空串
*/
export function getToken(): string {
return localStorage.getItem(TOKEN_KEY) ?? ''
}
/**
* 写入本地令牌。
*
* @param token JWT 字符串
*/
export function setToken(token: string): void {
localStorage.setItem(TOKEN_KEY, token)
}
/** 清除本地令牌 */
export function clearToken(): void {
localStorage.removeItem(TOKEN_KEY)
}
/** axios 实例,统一以 /api 为前缀(开发环境由 Vite 代理) */
const request: AxiosInstance = axios.create({
baseURL: '/api',
timeout: 15000
})
/**
* 请求拦截器:附加 Bearer 令牌。
*/
request.interceptors.request.use((config) => {
const token = getToken()
if (token) {
config.headers.Authorization = `Bearer ${token}`
}
return config
})
/**
* 响应拦截器:统一解包业务码,401 时跳转登录页。
*/
request.interceptors.response.use(
(response) => {
const body = response.data
if (body && typeof body.code === 'number' && body.code !== 0) {
ElMessage.error(body.message || '请求失败')
return Promise.reject(new Error(body.message))
}
return response
},
(error) => {
const status = error?.response?.status
if (status === 401) {
clearToken()
ElMessage.error('登录已失效,请重新登录')
if (window.location.pathname !== '/login') {
window.location.href = '/login'
}
} else if (status === 403) {
ElMessage.error('无权限执行该操作')
} else {
ElMessage.error(error?.response?.data?.message || error.message || '网络异常')
}
return Promise.reject(error)
}
)
/**
* 发起 GET 请求。
*
* @param url 接口路径
* @param params 查询参数
* @returns 业务数据
*/
export async function get<T>(url: string, params?: Record<string, unknown>): Promise<T> {
const { data } = await request.get(url, { params })
return data.data as T
}
/**
* 发起 POST 请求。
*
* @param url 接口路径
* @param body 请求体
* @param config 额外配置
* @returns 业务数据
*/
export async function post<T>(url: string, body?: unknown, config?: AxiosRequestConfig): Promise<T> {
const { data } = await request.post(url, body, config)
return data.data as T
}
/**
* 发起 PUT 请求。
*
* @param url 接口路径
* @param body 请求体
* @returns 业务数据
*/
export async function put<T>(url: string, body?: unknown): Promise<T> {
const { data } = await request.put(url, body)
return data.data as T
}
/**
* 发起 PATCH 请求。
*
* @param url 接口路径
* @param body 请求体
* @returns 业务数据
*/
export async function patch<T>(url: string, body?: unknown): Promise<T> {
const { data } = await request.patch(url, body)
return data.data as T
}
/**
* 发起 DELETE 请求。
*
* @param url 接口路径
* @returns 业务数据
*/
export async function del<T>(url: string): Promise<T> {
const { data } = await request.delete(url)
return data.data as T
}
export default request