// 后端 API 基础地址 - 根据环境自动切换 // 开发环境使用本地服务器,生产环境使用线上地址 const ENV_BASE_URL: Record = { development: 'http://localhost:3000', production: 'https://api.example.com', // 部署时替换为真实域名 } const BASE_URL = ENV_BASE_URL[process.env.NODE_ENV || 'development'] || 'http://localhost:3000' export { BASE_URL } interface RequestOptions { url: string method?: 'GET' | 'POST' | 'PUT' | 'DELETE' data?: Record header?: Record } interface ApiResponse { code: number data: T message: string } /** 将下划线命名转换为驼峰命名 */ function toCamelCase(obj: any): any { if (obj === null || typeof obj !== 'object') return obj if (Array.isArray(obj)) { return obj.map(item => toCamelCase(item)) } const result: any = {} for (const key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { const camelKey = key.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase()) result[camelKey] = toCamelCase(obj[key]) } } return result } function getToken(): string { return uni.getStorageSync('token') || '' } export function request(options: RequestOptions): Promise { const { url, method = 'GET', data, header = {} } = options const token = getToken() return new Promise((resolve, reject) => { uni.request({ url: `${BASE_URL}${url}`, method, data, header: { 'Content-Type': 'application/json', ...(token ? { Authorization: `Bearer ${token}` } : {}), ...header, }, success(res) { const statusCode = res.statusCode if (statusCode === 401) { uni.removeStorageSync('token') uni.showToast({ title: '请重新登录', icon: 'none' }) autoLogin() reject(new Error('未授权')) return } if (statusCode >= 200 && statusCode < 300) { const body = res.data as ApiResponse if (body.code === 0) { // 将下划线命名转换为驼峰命名 const camelData = toCamelCase(body.data) resolve(camelData) } else { uni.showToast({ title: body.message || '请求失败', icon: 'none' }) reject(new Error(body.message)) } } else { uni.showToast({ title: '网络异常,请稍后重试', icon: 'none' }) reject(new Error(`HTTP ${statusCode}`)) } }, fail(err) { uni.showToast({ title: '网络异常,请稍后重试', icon: 'none' }) reject(err) }, }) }) } /** 微信小程序自动登录 */ export function autoLogin(): Promise { return new Promise((resolve, reject) => { uni.login({ provider: 'weixin', success: async (loginRes) => { if (loginRes.code) { try { const data = await request<{ token: string; userId: number }>({ url: '/api/auth/wx-login', method: 'POST', data: { code: loginRes.code }, }) uni.setStorageSync('token', data.token) resolve() } catch (err) { console.error('登录接口调用失败:', err) reject(err) } } else { console.error('微信登录获取 code 失败') reject(new Error('获取微信 code 失败')) } }, fail: (err) => { console.error('uni.login 失败:', err) reject(err) }, }) }) } export const get = (url: string, data?: Record) => request({ url, method: 'GET', data }) export const post = (url: string, data?: Record) => request({ url, method: 'POST', data }) export const put = (url: string, data?: Record) => request({ url, method: 'PUT', data }) export const del = (url: string, data?: Record) => request({ url, method: 'DELETE', data })