import { i18n } from '@/plugins/i18n' /** 请求基础 URL,默认 https://api.xtrader.vip,可通过环境变量 VITE_API_BASE_URL 覆盖 */ export const BASE_URL = (import.meta as { env?: { VITE_API_BASE_URL?: string } }).env?.VITE_API_BASE_URL ?? 'https://api.xtrader.vip' const FALLBACK_BASE = typeof window !== 'undefined' ? window.location.origin : 'https://api.xtrader.vip' /** 生成 WebSocket URL,与 REST API 同源 */ function getWsUrl(path: string): string { const base = BASE_URL || FALLBACK_BASE const url = new URL(base) const protocol = url.protocol === 'https:' ? 'wss:' : 'ws:' return `${protocol}//${url.host}${path.startsWith('/') ? path : `/${path}`}` } /** CLOB WebSocket URL */ export function getClobWsUrl(): string { return getWsUrl('/clob/ws') } /** User WebSocket URL(订单/持仓/余额推送) */ export function getUserWsUrl(): string { return getWsUrl('/clob/ws/user') } /** * 过滤空值后构建 query 对象,供 GET 请求使用 * - undefined/null 跳过 * - 空字符串 '' 跳过 * - 空数组 [] 跳过 * - NaN 跳过 */ export function buildQuery( params: Record, ): Record { const result: Record = {} for (const [k, v] of Object.entries(params)) { if (v === undefined || v === null) continue if (typeof v === 'string' && v === '') continue if (Array.isArray(v) && v.length === 0) continue if (typeof v === 'number' && !Number.isFinite(v)) continue result[k] = v } return result } export interface RequestConfig { /** 请求头,如 { 'x-token': token, 'x-user-id': userId } */ headers?: Record } /** * 带 x-token 等自定义头的 GET 请求 */ export async function get( path: string, params?: Record, config?: RequestConfig, ): Promise { const url = new URL(path, BASE_URL || window.location.origin) if (params) { Object.entries(params).forEach(([key, value]) => { if (value === undefined) return if (Array.isArray(value)) { value.forEach((v) => url.searchParams.append(key, String(v))) } else { url.searchParams.set(key, String(value)) } }) } const headers: Record = { 'Content-Type': 'application/json', 'Accept-Language': i18n.global.locale.value as string, ...config?.headers, } const res = await fetch(url.toString(), { method: 'GET', headers }) if (!res.ok) { throw new Error(`HTTP ${res.status}: ${res.statusText}`) } return res.json() as Promise } /** * 带 x-token 等自定义头的 POST 请求 */ export async function post( path: string, body?: unknown, config?: RequestConfig, ): Promise { const url = new URL(path, BASE_URL || window.location.origin) const headers: Record = { 'Content-Type': 'application/json', 'Accept-Language': i18n.global.locale.value as string, ...config?.headers, } const res = await fetch(url.toString(), { method: 'POST', headers, body: body !== undefined ? JSON.stringify(body) : undefined, }) if (!res.ok) { throw new Error(`HTTP ${res.status}: ${res.statusText}`) } return res.json() as Promise }