/** * 请求封装(基于 uni.request,支持 token、错误统一处理) */ import config from '@/config.js' // 存储 token 的 key const TOKEN_KEY = 'cj_student_token' export function getToken() { return uni.getStorageSync(TOKEN_KEY) } export function setToken(t) { uni.setStorageSync(TOKEN_KEY, t) } export function clearToken() { uni.removeStorageSync(TOKEN_KEY) } function request(method, url, data = {}, options = {}) { return new Promise((resolve, reject) => { const token = getToken() uni.request({ url: config.baseUrl + url, method, data, header: { 'Content-Type': 'application/json', ...(token ? { Authorization: 'Bearer ' + token } : {}), ...(options.header || {}), }, success: (res) => { if (res.statusCode === 401) { clearToken() uni.showToast({ title: '请重新登录', icon: 'none' }) uni.reLaunch({ url: '/pages/login/login' }) reject(res.data) return } if (res.data && res.data.code === 200) { resolve(res.data) } else { // 后端以 HTTP 200 + body.code 401 表达登录失效:同步清 token,跳登录页 if (res.data && res.data.code === 401) { clearToken() uni.showToast({ title: '登录已失效,请重新登录', icon: 'none' }) uni.reLaunch({ url: '/pages/login/login' }) } else { uni.showToast({ title: (res.data && res.data.msg) || '请求失败', icon: 'none' }) } reject(res.data) } }, fail: (err) => { uni.showToast({ title: '网络异常,请检查后端连接', icon: 'none' }) reject(err) }, }) }) } /** * 上传单个文件到 /miniapp/upload。 * H5 可传 file(input[type=file] 选中的 File 对象);小程序/App 传 filePath(临时路径)。 * 后端响应为 { code, msg, data: { fileName, originalName } }; * 成功时 resolve 内层 data({ fileName, originalName }),兼容个别旧结构的顶层 fileName。 */ export function uploadFile({ filePath, file }) { return new Promise((resolve, reject) => { const token = getToken() // uni-h5 的 uploadFile 缺 filePath 会先 reject("file error")(但 XHR 仍会发出,导致 // 「后端传成功、前端报失败」);H5 传 File 对象时补一个 blob URL 兜底。 let fp = filePath if (!fp && file) { try { fp = URL.createObjectURL(file) } catch (e) { /* 非浏览器环境忽略 */ } } uni.uploadFile({ url: config.baseUrl + '/miniapp/upload', filePath: fp, file, name: 'file', header: token ? { Authorization: 'Bearer ' + token } : {}, success: (res) => { let d = res.data try { d = JSON.parse(res.data) } catch (e) { /* 保留原始文本 */ } if (res.statusCode === 401) { clearToken() uni.showToast({ title: '请重新登录', icon: 'none' }) uni.reLaunch({ url: '/pages/login/login' }) reject(d) return } if (d && d.code === 200) { // 真正有用的是 data 内层;旧代码直接 resolve 整个响应体导致 res.fileName 恒为 undefined resolve(d.data || d) } else { uni.showToast({ title: (d && d.msg) || '上传失败', icon: 'none' }) reject(d) } }, fail: (err) => { uni.showToast({ title: '上传失败,请检查网络', icon: 'none' }) reject(err) }, }) }) } export default { get: (url, data, opts) => request('GET', url, data, opts), post: (url, data, opts) => request('POST', url, data, opts), put: (url, data, opts) => request('PUT', url, data, opts), delete: (url, data, opts) => request('DELETE', url, data, opts), upload: uploadFile, }