import axios from 'axios' import router from '@/router' const BASE_URL = import.meta.env.VITE_API_BASE_URL let refreshPromise = null async function refreshAccessToken() { if (refreshPromise) return refreshPromise const refreshToken = localStorage.getItem('refresh_token') if (!refreshToken) throw new Error('missing_refresh_token') refreshPromise = axios .post(`${BASE_URL}/auth/refresh`, { refresh_token: refreshToken }) .then((res) => { const nextAccessToken = res.data?.access_token const nextRefreshToken = res.data?.refresh_token || refreshToken if (!nextAccessToken) { throw new Error('missing_access_token') } localStorage.setItem('access_token', nextAccessToken) localStorage.setItem('refresh_token', nextRefreshToken) return nextAccessToken }) .finally(() => { refreshPromise = null }) return refreshPromise } function hardLogoutToLogin() { localStorage.removeItem('access_token') localStorage.removeItem('refresh_token') router.push('/login') } // 使用者 API:帶 Bearer token export const userHttp = axios.create({ baseURL: BASE_URL }) userHttp.interceptors.request.use(config => { const token = localStorage.getItem('access_token') if (token) { config.headers['Authorization'] = `Bearer ${token}` } return config }) userHttp.interceptors.response.use( res => res, async err => { const original = err.config || {} if (err.response?.status === 401 && !original._retriedByRefresh) { original._retriedByRefresh = true try { const nextToken = await refreshAccessToken() original.headers = original.headers || {} original.headers['Authorization'] = `Bearer ${nextToken}` return userHttp.request(original) } catch (_refreshErr) { hardLogoutToLogin() } } return Promise.reject(err) } ) // 管理員 API:只帶 Bearer token(後端再檢查 admin 群組) export const adminHttp = axios.create({ baseURL: BASE_URL }) adminHttp.interceptors.request.use(config => { const token = localStorage.getItem('access_token') if (token) { config.headers['Authorization'] = `Bearer ${token}` } return config }) adminHttp.interceptors.response.use( res => res, async err => { const original = err.config || {} if (err.response?.status === 401 && !original._retriedByRefresh) { original._retriedByRefresh = true try { const nextToken = await refreshAccessToken() original.headers = original.headers || {} original.headers['Authorization'] = `Bearer ${nextToken}` return adminHttp.request(original) } catch (_refreshErr) { hardLogoutToLogin() } } return Promise.reject(err) } )