WXL
18 小时以前 05c363fdd7ab04e3bd9a753e2c5d5bfff04d681c
utils/request.js
@@ -1,109 +1,87 @@
import getConfig from "./config.js";
const { baseURL } = getConfig();
// @/utils/request.js
// 添加全局标记
let isRedirectingToLogin = false;
/**
 * 显示Toast提示(兼容uview-plus)
 * @param {string} message 提示内容
 */
// 全局 SSO 处理标记(挂载到 uni 上,便于跨模块共享)
uni.__isSSOHandling = false;
const showToast = (message) => {
  if (uni.$u?.toast) {
    uni.$u.toast(message);
  } else {
    uni.showToast({
      title: message,
      icon: "none",
    });
    uni.showToast({ title: message, icon: "none" });
  }
};
console.log(baseURL,'baseURL');
// 基础配置 - 从环境变量中获取baseURL
const config = {
  baseURL: "/api", // 使用环境变量中的配置
  baseURL: baseURL,
  timeout: 60000,
  header: {
    "Content-Type": "application/json",
    "X-Business-System": "medical-system",
  },
  // 新增配置项
  loginPage: "/pages/login/Login", // 登录页路径
  tokenExpiredCode: 401, // 后端返回的Token过期状态码
  noPermissionCode: 403, // 无权限状态码
  // 添加白名单配置(不需要校验token的接口)
  whiteList: [
    "/login", // 登录接口
    "/getToken",
    // '/dingtalk/auth/login', // 钉钉授权登录接口
    // '/dingtalk/auth/bind' // 钉钉授权登录绑定接口
  ],
  loginPage: "/pages/login/Login",
  tokenExpiredCode: 401,
  noPermissionCode: 403,
  whiteList: ["/login", "/getToken", "/GiLink/getCode"],
};
/**
 * 检查请求是否在白名单中
 * @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);
    }
    // 精确匹配路径
    if (path.endsWith("/")) return relativeUrl.startsWith(path);
    return relativeUrl === path;
  });
};
/**
 * 跳转到登录页
 */
const navigateToLogin = () => {
  if (isRedirectingToLogin) {
    console.log('正在跳转登录页中,跳过');
  // SSO 处理中,不重复跳转
  if (isRedirectingToLogin || uni.__isSSOHandling) {
    console.log("正在跳转登录页或SSO处理中,跳过");
    return;
  }
  isRedirectingToLogin = true;
  const pages = getCurrentPages();
  const currentPage = pages[pages.length - 1];
  const isLoginPage = currentPage && currentPage.route &&
                     currentPage.route.includes('login/Login');
  const isLoginPage =
    currentPage &&
    currentPage.route &&
    currentPage.route.includes("login/Login");
  if (isLoginPage) {
    console.log('当前已在登录页,不跳转');
    console.log("当前已在登录页,不跳转");
    isRedirectingToLogin = false;
    return;
  }
  console.log('跳转到登录页');
  console.log("跳转到登录页");
  setTimeout(() => {
    uni.redirectTo({
      url: config.loginPage + "?redirect=" + encodeURIComponent(getCurrentPagePath()),
      url:
        config.loginPage +
        "?redirect=" +
        encodeURIComponent(getCurrentPagePath()),
      success: () => {
        console.log('跳转登录页成功');
        console.log("跳转登录页成功");
        isRedirectingToLogin = false;
      },
      fail: () => {
        console.log('跳转登录页失败');
        console.log("跳转登录页失败");
        isRedirectingToLogin = false;
      }
      },
    });
  }, 100);
};
/**
 * 获取当前页面路径(用于登录后跳回)
 */
const getCurrentPagePath = () => {
  const pages = getCurrentPages();
  return pages[pages.length - 1]?.route || "";
};
/**
 * 检查Token是否过期
 * @param {number} statusCode HTTP状态码
 */
const checkTokenExpired = (statusCode) => {
  if (statusCode === config.tokenExpiredCode) {
    showToast("登录已过期,请重新登录");
@@ -113,101 +91,71 @@
  return false;
};
/**
 * 请求拦截器
 */
const requestInterceptor = (options) => {
  const token = uni.getStorageSync("token");
  // 如果请求在白名单中,直接放行
  if (isInWhiteList(options.url)) {
    console.log('白名单接口,跳过token校验:', options.url);
    console.log("白名单接口,跳过token校验:", options.url);
    return options;
  }
  // ✅ 关键修改:在登录页时不进行跳转
  if (!token) {
    const pages = getCurrentPages();
    const currentPage = pages[pages.length - 1];
    const isLoginPage = currentPage && currentPage.route &&
                       (currentPage.route.includes('login/Login') ||
                        currentPage.route.includes('login/DingTalkLogin'));
    const isLoginPage =
      currentPage &&
      currentPage.route &&
      (currentPage.route.includes("login/Login") ||
        currentPage.route.includes("login/DingTalkLogin"));
    if (isLoginPage) {
      console.log('当前是登录页,允许无token请求');
      console.log("当前是登录页,允许无token请求");
      return options;
    }
    // 不在登录页,才跳转
    console.log('未登录且不在登录页,跳转到登录页');
    console.log("未登录且不在登录页,跳转到登录页");
    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 (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; // 返回实际业务数据
  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));
        },
        success: (res) => resolve(responseInterceptor(res)),
        fail: (err) => {
          showToast("网络错误,请重试");
          reject(err);
@@ -219,7 +167,6 @@
  }
};
// 快捷方法封装
const http = {
  get(url, data = {}, options = {}) {
    return request({ url, data, method: "GET", ...options });
@@ -233,7 +180,6 @@
  delete(url, data = {}, options = {}) {
    return request({ url, data, method: "DELETE", ...options });
  },
  // 新增:上传文件方法
  upload(url, filePath, name = "file", formData = {}) {
    return request({
      url,
@@ -246,7 +192,5 @@
  },
};
// 挂载到全局
uni.$uapi = http;
export default http;