// @/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;
|