// @/utils/request.js
|
|
/**
|
* 显示Toast提示(兼容uview-plus)
|
* @param {string} message 提示内容
|
*/
|
const showToast = (message) => {
|
if (uni.$u?.toast) {
|
uni.$u.toast(message)
|
} else {
|
uni.showToast({
|
title: message,
|
icon: 'none'
|
})
|
}
|
}
|
|
// 基础配置 - 从环境变量中获取baseURL
|
const config = {
|
baseURL: '/api', // 使用环境变量中的配置
|
timeout: 60000,
|
header: {
|
'Content-Type': 'application/json',
|
'X-Business-System': 'medical-system',
|
|
},
|
// 新增配置项
|
loginPage: '/pages/login/Login', // 登录页路径
|
tokenExpiredCode: 401, // 后端返回的Token过期状态码
|
noPermissionCode: 403, // 无权限状态码
|
// 添加白名单配置(不需要校验token的接口)
|
whiteList: [
|
'/login', // 登录接口
|
// '/dingtalk/auth/login', // 钉钉授权登录接口
|
// '/dingtalk/auth/bind' // 钉钉授权登录绑定接口
|
]
|
}
|
|
/**
|
* 检查请求是否在白名单中
|
* @param {string} url 请求URL
|
*/
|
const isInWhiteList = (url) => {
|
// 提取相对路径(移除baseURL)并忽略查询参数
|
const relativeUrl = url.replace(config.baseURL, '').split('?')[0];
|
return config.whiteList.some(path => {
|
// 处理通配符情况
|
if (path.endsWith('/')) {
|
return relativeUrl.startsWith(path)
|
}
|
// 精确匹配路径
|
return relativeUrl === path
|
})
|
}
|
|
/**
|
* 跳转到登录页
|
*/
|
const navigateToLogin = () => {
|
uni.redirectTo({
|
url: config.loginPage + '?redirect=' + encodeURIComponent(getCurrentPagePath())
|
})
|
}
|
|
/**
|
* 获取当前页面路径(用于登录后跳回)
|
*/
|
const getCurrentPagePath = () => {
|
const pages = getCurrentPages()
|
return pages[pages.length - 1]?.route || ''
|
}
|
|
/**
|
* 检查Token是否过期
|
* @param {number} statusCode HTTP状态码
|
*/
|
const checkTokenExpired = (statusCode) => {
|
if (statusCode === config.tokenExpiredCode) {
|
showToast('登录已过期,请重新登录')
|
navigateToLogin()
|
return true
|
}
|
return false
|
}
|
|
/**
|
* 请求拦截器
|
*/
|
const requestInterceptor = (options) => {
|
const token = uni.getStorageSync('token')
|
|
// 如果请求在白名单中,直接放行
|
if (isInWhiteList(options.url)) {
|
return options
|
}
|
|
// 如果未登录且不是白名单接口,跳转登录
|
// console.log(token,'token');
|
|
if (!token) {
|
navigateToLogin()
|
throw new Error('未登录')
|
}
|
|
// 添加Token到Header
|
options.header = {
|
...options.header,
|
'Authorization': `Bearer ${token}`
|
}
|
|
return options
|
}
|
|
/**
|
* 响应拦截器
|
*/
|
const responseInterceptor = (response) => {
|
const { statusCode, data } = response
|
|
// Token过期处理
|
if (checkTokenExpired(statusCode)) {
|
return Promise.reject(data)
|
}
|
|
// 无权限处理
|
if (statusCode === config.noPermissionCode) {
|
showToast('无权限访问')
|
return Promise.reject(data)
|
}
|
|
// 其他错误状态码
|
if (statusCode !== 200) {
|
showToast(`请求失败: ${statusCode}`)
|
return Promise.reject(data)
|
}
|
|
// 接口自定义错误码处理(假设data.code为0表示成功)
|
if (data?.code !== 200) {
|
showToast(data?.msg || '操作失败')
|
return Promise.reject(data)
|
}
|
|
return data.data || data // 返回实际业务数据
|
}
|
|
/**
|
* 核心请求方法
|
*/
|
const request = async (options) => {
|
try {
|
// 合并配置
|
options = {
|
...config,
|
...options,
|
url: config.baseURL + options.url,
|
header: { ...config.header, ...options.header }
|
}
|
|
// 请求拦截
|
options = await requestInterceptor(options)
|
|
// 发起请求
|
return new Promise((resolve, reject) => {
|
uni.request({
|
...options,
|
success: (res) => {
|
resolve(responseInterceptor(res))
|
},
|
fail: (err) => {
|
showToast('网络错误,请重试')
|
reject(err)
|
}
|
})
|
})
|
} catch (err) {
|
return Promise.reject(err)
|
}
|
}
|
|
// 快捷方法封装
|
const http = {
|
get(url, data = {}, options = {}) {
|
return request({ url, data, method: 'GET', ...options })
|
},
|
post(url, data = {}, options = {}) {
|
return request({ url, data, method: 'POST', ...options })
|
},
|
put(url, data = {}, options = {}) {
|
return request({ url, data, method: 'PUT', ...options })
|
},
|
delete(url, data = {}, options = {}) {
|
return request({ url, data, method: 'DELETE', ...options })
|
},
|
// 新增:上传文件方法
|
upload(url, filePath, name = 'file', formData = {}) {
|
return request({
|
url,
|
method: 'POST',
|
filePath,
|
name,
|
formData,
|
header: { 'Content-Type': 'multipart/form-data' }
|
})
|
}
|
}
|
|
// 挂载到全局
|
uni.$uapi = http
|
|
export default http
|