/** * 网络请求封装 * - 自动携带 JWT token * - 401 自动跳转登录页 * - 统一错误处理 */ // API 基础地址,按环境切换 // const BASE_URL = 'http://localhost:5099' const BASE_URL = 'http://api.zwz.shhmkjgs.cn' /** * 获取本地存储的 token */ function getToken() { return uni.getStorageSync('token') || '' } /** * 清除本地登录凭证 */ function clearAuth() { uni.removeStorageSync('token') uni.removeStorageSync('userInfo') } /** * 跳转到登录页 */ function redirectToLogin() { clearAuth() uni.reLaunch({ url: '/pages/login/login' }) } /** * 通用请求方法 * @param {Object} options - 请求配置 * @param {string} options.url - 请求路径(不含 BASE_URL) * @param {string} [options.method='GET'] - 请求方法 * @param {Object} [options.data] - 请求数据 * @param {Object} [options.header] - 自定义请求头 * @returns {Promise} 响应数据 */ function request(options) { const { url, method = 'GET', data, header = {} } = options const token = getToken() if (token) { header['Authorization'] = `Bearer ${token}` } const timeout = options.timeout ?? 15000 return new Promise((resolve, reject) => { uni.request({ url: `${BASE_URL}${url}`, method, data, timeout, header: { 'Content-Type': 'application/json', ...header }, success: (res) => { const { statusCode, data: resData } = res if (statusCode === 200 || statusCode === 201) { resolve(resData) return } // 未登录或 token 过期 if (statusCode === 401) { // 清除过期的凭证 clearAuth() // 非静默请求时提示用户重新登录 const pages = getCurrentPages() const currentPage = pages[pages.length - 1] const isTabPage = ['pages/index/index', 'pages/order-hall/order-hall', 'pages/message/message', 'pages/mine/mine'].includes(currentPage?.route) if (!isTabPage) { uni.showToast({ title: '登录已过期,请重新登录', icon: 'none' }) } reject(new Error('未登录或登录已过期')) return } // 权限不足 if (statusCode === 403) { uni.showToast({ title: '权限不足', icon: 'none' }) reject(new Error('权限不足')) return } // 业务错误,展示服务端返回的 message const errMsg = resData?.message || '请求失败' uni.showToast({ title: errMsg, icon: 'none' }) reject(new Error(errMsg)) }, fail: (err) => { uni.showToast({ title: '网络异常,请重试', icon: 'none' }) reject(new Error(err.errMsg || '网络异常')) } }) }) } /** * 上传文件 * @param {string} filePath - 本地文件路径 * @param {string} [url='/api/upload/image'] - 上传接口路径 * @returns {Promise} 响应数据 */ function uploadFile(filePath, url = '/api/upload/image') { const token = getToken() const header = {} if (token) { header['Authorization'] = `Bearer ${token}` } return new Promise((resolve, reject) => { uni.uploadFile({ url: `${BASE_URL}${url}`, filePath, name: 'file', header, success: (res) => { if (res.statusCode === 401) { reject(new Error('未登录或登录已过期')) return } const data = JSON.parse(res.data) resolve(data) }, fail: (err) => { uni.showToast({ title: '上传失败', icon: 'none' }) reject(new Error(err.errMsg || '上传失败')) } }) }) } export { BASE_URL, getToken, clearAuth, redirectToLogin, uploadFile } export default request