import { GUIDE_LOGIN_KEY } from '../constants/mock' export const API_BASE_URL = (import.meta.env.VITE_API_BASE_URL || 'http://221.182.45.100:8011/api').replace(/\/$/, '') const API_ORIGIN = API_BASE_URL.replace(/\/api$/, '') const LOGIN_PAGE = '/pages/login/index' let authRedirecting = false export function request({ url, method = 'GET', data, authenticated = true, headers = {} }) { const loginState = uni.getStorageSync(GUIDE_LOGIN_KEY) const header = { 'Content-Type': 'application/json', ...headers } if (authenticated && loginState && loginState.token) { header.Authorization = `Bearer ${loginState.token}` } return new Promise((resolve, reject) => { uni.request({ url: `${API_BASE_URL}${url}`, method, data, header, success(response) { const body = response.data || {} if (shouldHandleAuthExpired(response.statusCode, body, authenticated)) { handleAuthExpired() reject(createAuthExpiredError(body.message || body.msg)) return } if (response.statusCode >= 200 && response.statusCode < 300 && body.code === 0) { resolve(body.data) return } reject(createRequestError(body, response.statusCode)) }, fail(error) { reject(new Error(error.errMsg || '网络连接失败')) } }) }) } export function uploadFile({ url, filePath, name = 'file', header = {}, authenticated = true }) { const loginState = uni.getStorageSync(GUIDE_LOGIN_KEY) const requestHeader = { ...header } if (authenticated && loginState && loginState.token) { requestHeader.Authorization = `Bearer ${loginState.token}` } return new Promise((resolve, reject) => { uni.uploadFile({ url: `${API_BASE_URL}${url}`, filePath, name, header: requestHeader, success(response) { let body = response.data try { body = typeof body === 'string' ? JSON.parse(body) : body } catch (error) { reject(new Error('上传响应格式不正确')) return } if (shouldHandleAuthExpired(response.statusCode, body, authenticated)) { handleAuthExpired() reject(createAuthExpiredError(body && (body.message || body.msg))) return } if (response.statusCode >= 200 && response.statusCode < 300 && body && body.code === 0) { resolve(body.data) return } reject(createRequestError(body, response.statusCode, '上传失败')) }, fail(error) { reject(new Error(error.errMsg || '文件上传失败')) } }) }) } function shouldHandleAuthExpired(statusCode, body = {}, authenticated = true) { if (!authenticated) return false if (statusCode === 401) return true return body && (body.code === 401 || body.code === '401') } function createAuthExpiredError(message) { const error = new Error(message || '登录已过期,请重新登录') error.authExpired = true return error } function createRequestError(body = {}, statusCode, fallback = '请求失败') { const responseBody = body || {} const error = new Error(responseBody.message || responseBody.msg || `${fallback}(${statusCode})`) error.code = responseBody.code error.statusCode = statusCode return error } function handleAuthExpired() { try { uni.removeStorageSync(GUIDE_LOGIN_KEY) } catch (error) {} if (authRedirecting || isLoginPage()) return authRedirecting = true uni.showToast({ title: '登录已过期,请重新登录', icon: 'none' }) setTimeout(() => { uni.reLaunch({ url: LOGIN_PAGE, complete() { setTimeout(() => { authRedirecting = false }, 500) } }) }, 300) } function isLoginPage() { const pages = typeof getCurrentPages === 'function' ? getCurrentPages() : [] const current = pages[pages.length - 1] return current && `/${current.route}` === LOGIN_PAGE } export function resolveApiAssetUrl(path) { if (!path) { return '' } if (/^https?:\/\//i.test(path) || path.startsWith('wxfile://') || path.startsWith('blob:')) { return path } return `${API_ORIGIN}${path.startsWith('/') ? path : `/${path}`}` }