| | |
| | | }, 1500) |
| | | } |
| | | |
| | | // ======================== 文件上传方法 ======================== |
| | | |
| | | /** |
| | | * 统一文件上传方法(基于 uni.uploadFile) |
| | | * 与 request 保持一致的令牌注入、响应解包与登录失效处理,供图片/文件上传使用 |
| | | * @param {String} url 上传接口路径(不含根地址;传完整 http 地址则直接使用) |
| | | * @param {String} filePath 本地文件路径(如 chooseImage 返回的 tempFilePath) |
| | | * @param {Object} [options] 可选配置 |
| | | * @param {String} [options.name] 表单文件字段名,默认 file |
| | | * @param {Object} [options.formData] 附加表单参数 |
| | | * @param {Object} [options.header] 自定义请求头 |
| | | * @param {Boolean} [options.auth] 是否需要携带 token,默认 true |
| | | * @param {Boolean} [options.loading] 是否显示上传中提示,默认 true |
| | | * @param {String} [options.loadingText] 上传提示文案 |
| | | * @returns {Promise<Object>} 解析后的响应体 { code, msg, data } |
| | | */ |
| | | export function uploadFile(url = '', filePath = '', options = {}) { |
| | | const { |
| | | name = 'file', |
| | | formData = {}, |
| | | header = {}, |
| | | auth = true, |
| | | loading = true, |
| | | loadingText = '上传中...' |
| | | } = options |
| | | |
| | | // 拼接完整请求地址 |
| | | const fullUrl = /^https?:\/\//i.test(url) ? url : config.baseUrl + url |
| | | |
| | | // 组装请求头并注入令牌(multipart 边界由底层自动生成,此处不设 Content-Type) |
| | | const finalHeader = { ...header } |
| | | const token = getToken() |
| | | if (auth && token) { |
| | | finalHeader.Authorization = 'Bearer ' + token |
| | | } |
| | | |
| | | if (loading) { |
| | | uni.showLoading({ title: loadingText, mask: true }) |
| | | } |
| | | |
| | | return new Promise((resolve, reject) => { |
| | | uni.uploadFile({ |
| | | url: fullUrl, |
| | | filePath, |
| | | name, |
| | | formData, |
| | | header: finalHeader, |
| | | timeout: config.timeout, |
| | | success: (res) => { |
| | | const { statusCode } = res |
| | | |
| | | // 非 HTTP 200 视为网络异常 |
| | | if (statusCode !== 200) { |
| | | reject(new Error('网络请求异常:' + statusCode)) |
| | | return |
| | | } |
| | | |
| | | // uploadFile 返回的 data 为字符串,需解析为 JSON |
| | | let body |
| | | try { |
| | | body = JSON.parse(res.data) |
| | | } catch (e) { |
| | | reject(new Error('上传响应解析失败')) |
| | | return |
| | | } |
| | | |
| | | // 登录失效:清理登录态并跳转登录页 |
| | | if (body && body.code === config.unauthorizedCode) { |
| | | _handleUnauthorized() |
| | | reject(new Error(body.msg || '登录状态已过期')) |
| | | return |
| | | } |
| | | |
| | | // 业务成功:返回完整响应体,调用方按需取 data |
| | | if (body && body.code === config.successCode) { |
| | | resolve(body) |
| | | return |
| | | } |
| | | |
| | | // 业务失败:统一抛出错误信息 |
| | | reject(new Error((body && body.msg) || '上传失败')) |
| | | }, |
| | | fail: (err) => { |
| | | reject(new Error((err && err.errMsg) || '上传失败')) |
| | | }, |
| | | complete: () => { |
| | | if (loading) { |
| | | uni.hideLoading() |
| | | } |
| | | } |
| | | }) |
| | | }) |
| | | } |
| | | |
| | | // ======================== 快捷方法 ======================== |
| | | |
| | | /** GET 请求 */ |