| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203 |
- /**
- * 微信小程序统一请求封装
- * 参考 ruoyi-admin/src/utils/request.ts 结构
- */
- // -------------------- 配置 --------------------
- const BASE_URL = 'http://localhost:8080'
- const TIMEOUT = 30000
- const TOKEN_KEY = 'token'
- // 防止 401 弹窗重复弹出
- let isReloginPending = false
- // -------------------- 工具 --------------------
- function getToken() {
- return uni.getStorageSync(TOKEN_KEY) || ''
- }
- /**
- * 将对象序列化为 query string
- */
- function toQueryString(params) {
- return Object.entries(params)
- .filter(([, v]) => v !== undefined && v !== null)
- .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`)
- .join('&')
- }
- // -------------------- 响应处理 --------------------
- /**
- * 处理业务响应码,统一返回 { data, total, rows }(按实际字段存在)
- */
- function handleResponse(responseData) {
- return new Promise((resolve, reject) => {
- const code = responseData.code
- const msg = responseData.msg || '系统异常'
- if (code === 200) {
- const result = {}
- if (responseData.data !== undefined) result.data = responseData.data
- if (responseData.total !== undefined) result.total = responseData.total
- if (responseData.rows !== undefined) result.rows = responseData.rows
- resolve(result)
- } else if (code === 401) {
- if (!isReloginPending) {
- isReloginPending = true
- uni.removeStorageSync(TOKEN_KEY)
- uni.showModal({
- title: '登录已过期',
- content: '登录状态已过期,请重新登录',
- showCancel: false,
- confirmText: '重新登录',
- confirmColor: '#C1001C',
- success: () => {
- isReloginPending = false
- const pages = getCurrentPages()
- const currentRoute = pages.length ? '/' + pages[pages.length - 1].route : ''
- uni.reLaunch({
- url: '/pages/login/index' + (currentRoute
- ? '?redirect=' + encodeURIComponent(currentRoute)
- : '')
- })
- }
- })
- }
- reject(new Error('无效的会话,或者会话已过期,请重新登录。'))
- } else if (code === 500) {
- uni.showToast({ title: msg, icon: 'none', duration: 2500 })
- reject(new Error(msg))
- } else {
- uni.showToast({ title: msg, icon: 'none', duration: 2500 })
- reject(new Error(msg))
- }
- })
- }
- // -------------------- 核心请求 --------------------
- /**
- * 统一请求方法
- * @param {object} options
- * @param {string} options.url 接口路径,如 '/system/user/list'
- * @param {string} [options.method] 请求方法,默认 'GET'
- * @param {object} [options.data] 请求体(POST / PUT)
- * @param {object} [options.params] URL 查询参数(GET 也可用此字段)
- * @param {object} [options.header] 额外请求头
- * @param {boolean} [options.isToken] 是否携带 Token,默认 true
- * @returns {Promise<{data?, total?, rows?}>}
- */
- function request({ url, method = 'GET', data = {}, params = {}, header = {}, isToken = true } = {}) {
- return new Promise((resolve, reject) => {
- const upperMethod = method.toUpperCase()
- // 拼接 query string
- let finalUrl = BASE_URL + url
- if (Object.keys(params).length) {
- finalUrl += '?' + toQueryString(params)
- }
- // 组装请求头
- const requestHeader = {
- 'Content-Type': 'application/json',
- ...header
- }
- if (isToken) {
- const token = getToken()
- if (token) {
- requestHeader['Authorization'] = 'Bearer ' + token
- }
- }
- uni.request({
- url: finalUrl,
- method: upperMethod,
- data: upperMethod === 'GET' ? undefined : data,
- header: requestHeader,
- timeout: TIMEOUT,
- success: (res) => {
- const { statusCode, data: responseData } = res
- // HTTP 层异常
- if (statusCode !== 200) {
- const httpMsg = `系统接口 ${statusCode} 异常`
- uni.showToast({ title: httpMsg, icon: 'none' })
- return reject(new Error(httpMsg))
- }
- // 业务层处理
- handleResponse(responseData).then(resolve).catch(reject)
- },
- fail: (err) => {
- let message = '请求失败,请检查网络'
- if (err.errMsg) {
- if (err.errMsg.includes('timeout')) {
- message = '系统接口请求超时'
- } else if (err.errMsg.toLowerCase().includes('network') || err.errMsg.includes('连接')) {
- message = '后端接口连接异常'
- }
- }
- uni.showToast({ title: message, icon: 'none' })
- reject(new Error(message))
- }
- })
- })
- }
- // -------------------- 下载文件 --------------------
- /**
- * 下载文件并自动打开
- * @param {string} url 接口路径
- * @param {object} [params] URL 查询参数
- * @param {string} [fileName] 保存文件名(仅做备注,小程序由系统决定)
- * @returns {Promise<string>} 临时文件路径
- */
- function download(url, params = {}, fileName = '') {
- return new Promise((resolve, reject) => {
- let finalUrl = BASE_URL + url
- if (Object.keys(params).length) {
- finalUrl += '?' + toQueryString(params)
- }
- const header = {}
- const token = getToken()
- if (token) {
- header['Authorization'] = 'Bearer ' + token
- }
- uni.showLoading({ title: '正在下载...', mask: true })
- uni.downloadFile({
- url: finalUrl,
- header,
- success: (res) => {
- uni.hideLoading()
- if (res.statusCode === 200) {
- uni.openDocument({
- filePath: res.tempFilePath,
- showMenu: true,
- success: () => {
- resolve(res.tempFilePath)
- },
- fail: () => {
- uni.showToast({ title: '文件打开失败', icon: 'none' })
- reject(new Error('文件打开失败'))
- }
- })
- } else {
- uni.showToast({ title: '下载失败', icon: 'none' })
- reject(new Error('下载失败'))
- }
- },
- fail: () => {
- uni.hideLoading()
- uni.showToast({ title: '下载文件出现错误,请联系管理员', icon: 'none' })
- reject(new Error('下载文件出现错误,请联系管理员'))
- }
- })
- })
- }
- // -------------------- 导出 --------------------
- export { request, download }
- export default request
|