// @/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; // 返回实际业务数据 }; /** * 核心请求方法 */ 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;