import axios, { type AxiosInstance, type InternalAxiosRequestConfig } from "axios"; import { ElMessage } from "element-plus"; import { useUserStore } from "@/stores/user"; const TOKEN_KEY = "daocheng_admin_token"; export function getToken(): string { return localStorage.getItem(TOKEN_KEY) || ""; } export function setToken(t: string): void { localStorage.setItem(TOKEN_KEY, t); } export function clearToken(): void { localStorage.removeItem(TOKEN_KEY); } function baseURL(): string { const v = import.meta.env.VITE_API_BASE; if (typeof v === "string" && v.trim()) { return v.trim().replace(/\/+$/, ""); } return ""; } const service: AxiosInstance = axios.create({ baseURL: baseURL(), timeout: 30000, }); service.interceptors.request.use((config: InternalAxiosRequestConfig) => { const token = getToken(); if (token) { config.headers.Authorization = `Bearer ${token}`; } // multipart 必须由浏览器自动带 boundary;若残留 application/json 会导致 PHP 收不到 file if (config.data instanceof FormData) { const h = config.headers; if (h && typeof (h as { delete?: (key: string) => void }).delete === "function") { (h as { delete: (key: string) => void }).delete("Content-Type"); } else if (h && typeof h === "object") { delete (h as Record)["Content-Type"]; delete (h as Record)["content-type"]; } } return config; }); service.interceptors.response.use( (res) => { const data = res.data; if (data && typeof data.code === "number") { if (data.code === 0) { return data; } if (data.code === 401) { clearToken(); useUserStore().clearProfile(); if (!window.location.pathname.includes("/login")) { window.location.href = "/login"; } } ElMessage.error(data.msg || "请求失败"); return Promise.reject(new Error(data.msg || "请求失败")); } return data; }, (err) => { const msg = err.response?.data?.msg || err.message || "网络错误"; ElMessage.error(msg); return Promise.reject(err); } ); export default service; export type ApiEnvelope = { code: number; msg: string; data: T };