import axios from 'axios' import { isForbidden, isKicked, isLoginLocation, isUnauthorized, loginRedirectTarget, shouldRedirectUnauthorized, } from './envelope' export { unwrap } from './envelope' export const http = axios.create({ baseURL: '/', withCredentials: true, timeout: 30_000, }) function redirectToLogin(requestUrl?: string): void { if (typeof window === 'undefined') return // 已在登录页或失败请求即登录端点时不再跳转,避免登录页循环与吞掉登录失败反馈。 if (!shouldRedirectUnauthorized(window.location.pathname, requestUrl)) return const target = loginRedirectTarget(window.location) window.location.assign('/admin-vue/login?redirect=' + target) } /** 单设备登录:被新设备顶下线,整页回登录页(整页 reload 顺带重置会话 store,避免守卫弹回)。 */ function redirectToLoginKicked(): void { if (typeof window === 'undefined') return if (isLoginLocation(window.location.pathname)) return window.location.assign('/admin-vue/login?kicked=1') } http.interceptors.response.use( (response) => { // Java 未登录以 HTTP 200 + body.code=401 返回,需统一按未登录处理; // 403(已登录但无后台权限,如用工具前端账号 token 访问后台)与 401 同样跳登录页。 // 4011(账号已在其他设备登录)单独提示,不按普通 401 处理。 if (isKicked(response.data)) { redirectToLoginKicked() } else if (isUnauthorized(response.data) || isForbidden(response.data)) { redirectToLogin(response.config?.url) } return response }, (error) => { if (isKicked(error?.response?.data)) { redirectToLoginKicked() } else if ( error?.response?.status === 401 || error?.response?.status === 403 || isUnauthorized(error?.response?.data) || isForbidden(error?.response?.data) ) { redirectToLogin(error?.config?.url) } return Promise.reject(error) }, )