import { fetch as tauriFetch } from '@tauri-apps/plugin-http' /** * API响应数据类型 */ export interface ApiResponse { code: number message: string data: T timestamp?: number } /** * 基础URL */ const BASE_URL = import.meta.env.VITE_API_BASE_URL || 'http://localhost:8080/api' /** * 检测是否在 Tauri 环境中 * 通过检查 __TAURI__ 全局变量来判断 */ const isTauriEnvironment = (): boolean => { return typeof window !== 'undefined' && '__TAURI__' in window } /** * 构建带查询参数的 URL */ function buildUrl(url: string, params?: Record): string { if (!params || Object.keys(params).length === 0) { return url } const searchParams = new URLSearchParams() Object.entries(params).forEach(([key, value]) => { if (value !== undefined && value !== null) { searchParams.append(key, String(value)) } }) const queryString = searchParams.toString() return queryString ? `${url}?${queryString}` : url } /** * 获取 fetch 函数 * 在 Tauri 环境中使用 tauriFetch,否则使用原生 fetch */ function getFetch() { return isTauriEnvironment() ? tauriFetch : window.fetch.bind(window) } /** * 创建请求配置 */ function createRequestConfig(options?: RequestInit): RequestInit { const token = localStorage.getItem('token') const headers: HeadersInit = { 'Content-Type': 'application/json', ...options?.headers } if (token) { headers['Authorization'] = `Bearer ${token}` } return { ...options, headers } } /** * 处理响应 */ async function handleResponse(response: Response): Promise { const data = await response.json() if (!response.ok) { throw new Error(data.message || `HTTP ${response.status}`) } // 检查业务状态码 if (data.code !== 200) { throw new Error(data.message || '请求失败') } return data.data } /** * 处理错误 */ function handleError(error: any): never { if (error.message) { console.error('请求错误:', error.message) } // 处理特定错误状态 if (error.message?.includes('401')) { localStorage.removeItem('token') localStorage.removeItem('userRole') localStorage.removeItem('userInfo') window.location.href = '/login' } throw error } /** * HTTP 请求封装 */ export const http = { /** * GET 请求 */ async get(url: string, options?: RequestInit & { params?: Record }): Promise { try { const fetchFn = getFetch() const config = createRequestConfig(options) const fullUrl = buildUrl(url, options?.params) const response = await fetchFn(`${BASE_URL}${fullUrl}`, { ...config, method: 'GET' }) return await handleResponse(response) } catch (error) { return handleError(error) } }, /** * POST 请求 */ async post(url: string, data?: any, options?: RequestInit & { params?: Record }): Promise { try { const fetchFn = getFetch() const config = createRequestConfig(options) const fullUrl = buildUrl(url, options?.params) const response = await fetchFn(`${BASE_URL}${fullUrl}`, { ...config, method: 'POST', body: JSON.stringify(data) }) return await handleResponse(response) } catch (error) { return handleError(error) } }, /** * PUT 请求 */ async put(url: string, data?: any, options?: RequestInit & { params?: Record }): Promise { try { const fetchFn = getFetch() const config = createRequestConfig(options) const fullUrl = buildUrl(url, options?.params) const response = await fetchFn(`${BASE_URL}${fullUrl}`, { ...config, method: 'PUT', body: JSON.stringify(data) }) return await handleResponse(response) } catch (error) { return handleError(error) } }, /** * DELETE 请求 */ async delete(url: string, options?: RequestInit & { params?: Record }): Promise { try { const fetchFn = getFetch() const config = createRequestConfig(options) const fullUrl = buildUrl(url, options?.params) const response = await fetchFn(`${BASE_URL}${fullUrl}`, { ...config, method: 'DELETE' }) return await handleResponse(response) } catch (error) { return handleError(error) } }, /** * PATCH 请求 */ async patch(url: string, data?: any, options?: RequestInit & { params?: Record }): Promise { try { const fetchFn = getFetch() const config = createRequestConfig(options) const fullUrl = buildUrl(url, options?.params) const response = await fetchFn(`${BASE_URL}${fullUrl}`, { ...config, method: 'PATCH', body: JSON.stringify(data) }) return await handleResponse(response) } catch (error) { return handleError(error) } } } export default http