import axios, { AxiosError, AxiosInstance, AxiosRequestConfig, AxiosResponse } from "axios"; import { ElMessage } from "element-plus"; import router from "../router"; import { getToken } from "../utils/auth"; import { useAuthStore } from "../store/auth"; import type { ApiError } from "../types/api"; import { useStudyStore } from "../store/study"; import { TEXT } from "../locales"; let unauthorizedNotified = false; const instance: AxiosInstance = axios.create({ baseURL: "/", timeout: 15000, }); instance.interceptors.request.use((config: AxiosRequestConfig) => { const token = getToken(); if (token) { config.headers = config.headers || {}; config.headers.Authorization = `Bearer ${token}`; } return config; }); instance.interceptors.response.use( (response: AxiosResponse) => response, async (error: AxiosError) => { const status = error.response?.status; const data = error.response?.data; const reqUrl = error.config?.url || ""; const isAuthEndpoint = reqUrl.includes("/api/v1/auth/login") || reqUrl.includes("/api/v1/auth/register"); if (isAuthEndpoint) { // 认证相关的错误由具体页面自行处理,避免重复提示 return Promise.reject(error); } // 401 统一处理:同步清理本地 token,并防止重复弹窗 const handleUnauthorized = () => { const auth = useAuthStore(); auth.logout(); if (!unauthorizedNotified) { unauthorizedNotified = true; ElMessage.error(data?.message || TEXT.common.messages.sessionExpired); setTimeout(() => { unauthorizedNotified = false; }, 1000); } router.push("/login"); }; // 如果当前项目不存在或已失效,清理项目并跳到工作台 if (status === 404 && typeof data?.message === "string" && data.message.toLowerCase().includes("study")) { try { const studyStore = useStudyStore(); studyStore.clearCurrentStudy(); } catch { /* ignore */ } router.push("/workbench"); } if (status === 401) { handleUnauthorized(); } else if (data?.message) { ElMessage.error(data.message); } else { ElMessage.error(TEXT.common.messages.requestFailed); } return Promise.reject(error); } ); export const apiGet = (url: string, config?: AxiosRequestConfig) => instance.get(url, config); export const apiPost = (url: string, data?: unknown, config?: AxiosRequestConfig) => instance.post(url, data, config); export const apiPatch = (url: string, data?: unknown, config?: AxiosRequestConfig) => instance.patch(url, data, config); export const apiDelete = (url: string, config?: AxiosRequestConfig) => instance.delete(url, config); export default instance;