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)
|
|
|
|
|
}
|