import axios, { AxiosError, type AxiosInstance, type AxiosRequestConfig } from 'axios' import { Device, Language, type ApiRequest, type ApiResponse, type ErrorResponse } from '@/types/api' import { useAuthStore } from '@/stores/auth' // 根据环境选择基础地址 // Docker 开发环境:Vite proxy 会将 /api 转发到后端 // 生产环境:Nginx 代理 /api 到后端网关 const baseURL = import.meta.env.DEV ? '/' : '/api' const client: AxiosInstance = axios.create({ baseURL, timeout: 30000, headers: { 'Content-Type': 'application/json', }, }) // 请求拦截器:注入 JWT client.interceptors.request.use((config) => { const token = useAuthStore.getState().token if (token && config.headers) { config.headers.Authorization = `Bearer ${token}` } return config }) // 响应拦截器:统一错误处理 client.interceptors.response.use( (response) => response, (error: AxiosError) => { const status = error.response?.status const message = error.response?.data?.message || error.message || '请求失败' if (status === 401) { useAuthStore.getState().logout() window.location.href = '/login' } return Promise.reject(new Error(message)) } ) /** 包装业务请求(注册/业务类接口) */ export async function apiPost( url: string, data: TReq, config?: AxiosRequestConfig ): Promise { const body: ApiRequest = { device: Device.Web, language: Language.SimplifiedChinese, data, } const response = await client.post>(url, body, config) const result = response.data if (!result.success) { throw new Error(result.message) } if (result.data === null) { throw new Error('接口返回数据为空') } return result.data } /** 原始 POST(登录/认证类接口,不包装) */ export async function rawPost( url: string, data: TReq, config?: AxiosRequestConfig ): Promise { const response = await client.post(url, data, config) return response.data } /** 通用 GET */ export async function apiGet(url: string, config?: AxiosRequestConfig): Promise { const response = await client.get>(url, config) const result = response.data if (!result.success) { throw new Error(result.message) } if (result.data === null) { throw new Error('接口返回数据为空') } return result.data } export default client