Files
Incidents-Data-Portal/frontend/src/utils/request.ts
T

166 lines
4.6 KiB
TypeScript
Raw Normal View History

2026-07-10 18:55:55 +08:00
import type { AxiosError, AxiosInstance, AxiosRequestConfig, AxiosResponse, InternalAxiosRequestConfig } from 'axios'
import axios from 'axios'
import { ContentTypeEnum, RequestEnum } from '~#/http-enum'
import { STORAGE_AUTHORIZE_KEY, useAuthorization } from '~/composables/authorization'
import router from '~/router'
import { AxiosLoading } from './loading'
export interface ResponseBody<T = any> {
code: number
data?: T
msg: string
}
export interface RequestConfigExtra {
token?: boolean
customDev?: boolean
loading?: boolean
}
const instance: AxiosInstance = axios.create({
baseURL: import.meta.env.VITE_APP_BASE_API ?? '/',
timeout: 60000,
headers: { 'Content-Type': ContentTypeEnum.JSON },
})
const axiosLoading = new AxiosLoading()
async function requestHandler(config: InternalAxiosRequestConfig & RequestConfigExtra): Promise<InternalAxiosRequestConfig> {
// 处理请求前的url
if (
import.meta.env.DEV
&& import.meta.env.VITE_APP_BASE_API_DEV
&& import.meta.env.VITE_APP_BASE_URL_DEV
) {
2026-07-10 21:10:17 +08:00
// 开发环境统一使用 /api 前缀(由 vite 代理重写为后端真实前缀)
2026-07-10 18:55:55 +08:00
config.baseURL = import.meta.env.VITE_APP_BASE_API_DEV
}
// console.log('Request URL:', config.baseURL)
const token = useAuthorization()
if (token.value && config.token !== false)
config.headers.set(STORAGE_AUTHORIZE_KEY, token.value)
// 增加多语言的配置
const { locale } = useI18nLocale()
config.headers.set('Accept-Language', locale.value ?? 'zh-CN')
if (config.loading)
axiosLoading.addLoading()
return config
}
function responseHandler(response: any): ResponseBody<any> | AxiosResponse<any> | Promise<any> | any {
return response.data
}
function errorHandler(error: AxiosError): Promise<any> {
const token = useAuthorization()
const notification = useNotification()
if (error.response) {
const { data, status, statusText } = error.response as AxiosResponse<ResponseBody>
if (status === 401) {
notification?.error({
message: '401',
description: data?.msg || statusText,
duration: 3,
})
/**
* 这里处理清空用户信息和token的逻辑,后续扩展
*/
token.value = null
const { fullPath, query: { redirect } } = router.currentRoute.value
router
.push({
path: '/login',
query: {
redirect: redirect || fullPath,
},
})
.then(() => { })
}
else if (status === 403) {
notification?.error({
message: '403',
description: data?.msg || statusText,
duration: 3,
})
}
else if (status === 500) {
notification?.error({
message: '500',
description: data?.msg || statusText,
duration: 3,
})
}
else {
notification?.error({
message: '服务错误',
description: data?.msg || statusText,
duration: 3,
})
}
}
return Promise.reject(error)
}
interface AxiosOptions<T> {
url: string
params?: T
data?: T
}
instance.interceptors.request.use(requestHandler)
instance.interceptors.response.use(responseHandler, errorHandler)
export default instance
function instancePromise<R = any, T = any>(options: AxiosOptions<T> & RequestConfigExtra): Promise<ResponseBody<R>> {
const { loading } = options
return new Promise((resolve, reject) => {
instance.request(options).then((res) => {
resolve(res as any)
}).catch((e: Error | AxiosError) => {
reject(e)
}).finally(() => {
if (loading)
axiosLoading.closeLoading()
})
})
}
export function useGet<R = any, T = any>(url: string, params?: T, config?: AxiosRequestConfig & RequestConfigExtra): Promise<ResponseBody<R>> {
const options = {
url,
params,
method: RequestEnum.GET,
...config,
}
return instancePromise<R, T>(options)
}
export function usePost<R = any, T = any>(url: string, data?: T, config?: AxiosRequestConfig & RequestConfigExtra): Promise<ResponseBody<R>> {
const options = {
url,
data,
method: RequestEnum.POST,
...config,
}
return instancePromise<R, T>(options)
}
export function usePut<R = any, T = any>(url: string, data?: T, config?: AxiosRequestConfig & RequestConfigExtra): Promise<ResponseBody<R>> {
const options = {
url,
data,
method: RequestEnum.PUT,
...config,
}
return instancePromise<R, T>(options)
}
export function useDelete<R = any, T = any>(url: string, data?: T, config?: AxiosRequestConfig & RequestConfigExtra): Promise<ResponseBody<R>> {
const options = {
url,
data,
method: RequestEnum.DELETE,
...config,
}
return instancePromise<R, T>(options)
}