import axios from 'axios' import { ElMessage } from 'element-plus' let lastToastKey = '' let lastToastAt = 0 function toastErrorOnce(key, message, minIntervalMs = 1500) { const now = Date.now() if (key === lastToastKey && now - lastToastAt < minIntervalMs) return lastToastKey = key lastToastAt = now ElMessage.error(message) } function getCookie(name) { const escaped = String(name || '').replace(/([.*+?^${}()|[\]\\])/g, '\\$1') const match = document.cookie.match(new RegExp(`(?:^|; )${escaped}=([^;]*)`)) return match ? decodeURIComponent(match[1]) : '' } export const publicApi = axios.create({ baseURL: '/api', timeout: 30_000, withCredentials: true, }) publicApi.interceptors.request.use((config) => { const method = String(config?.method || 'GET').toUpperCase() if (!['GET', 'HEAD', 'OPTIONS'].includes(method)) { const token = getCookie('csrf_token') if (token) { config.headers = config.headers || {} config.headers['X-CSRF-Token'] = token } } return config }) publicApi.interceptors.response.use( (response) => response, (error) => { const status = error?.response?.status const payload = error?.response?.data const message = payload?.error || payload?.message || error?.message || '请求失败' if (status === 401) { const pathname = window.location?.pathname || '' // 登录页面不弹通知,让 LoginPage.vue 自己处理错误显示 if (!pathname.startsWith('/login')) { toastErrorOnce('401', message || '登录已过期,请重新登录', 3000) window.location.href = '/login' } } else if (status === 403) { toastErrorOnce('403', message || '无权限', 5000) } else if (error?.code === 'ECONNABORTED') { toastErrorOnce('timeout', '请求超时', 3000) } else if (!status) { toastErrorOnce(`net:${message}`, message, 3000) } return Promise.reject(error) }, )