单应用项目,可以创建很多独立工具类页面 ,不用登录 初始化的页面
zhangchen
2025-09-12 4d9be1e572745750541be8be52a3cb30e1a8408f
ID1766-封装axios公共模块
3个文件已修改
1个文件已添加
211 ■■■■ 已修改文件
src/api/user.ts 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/store/bedsideAuxiliaryScreen.ts 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/axios.ts 180 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mobile/bedsideAuxiliaryScreen/components/Login/index.vue 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/user.ts
New file
@@ -0,0 +1,16 @@
import request from "@/utils/axios";
/**
 * 副屏退出登录Api
 * @returns
 */
export function logOutApi(params: string) {
  return request({
    url: "/user/info/logoutForSubScreen",
    method: "post",
    headers: {
      "Content-Type": "application/x-www-form-urlencoded",
    },
    data: params,
  });
}
src/store/bedsideAuxiliaryScreen.ts
@@ -15,7 +15,7 @@
import { ElMessage } from "element-plus/es";
import { Local } from "@/utils/storage";
import type { DeviceLoginRecord } from './type/user.type';
import { logoutForSubScreen } from "@/utils/httpApi";
import { logOutApi } from "@/api/user";
export const useBedsideAuxiliaryScreenStore = defineStore(
  "bedsideAuxiliaryScreen",
@@ -82,8 +82,8 @@
    /** 退出登录 */
    const logout = async (deviceCode: string) => {
      await logoutForSubScreen(deviceCode);
    const logout = async (deviceCodeStr: string) => {
      await logOutApi(deviceCodeStr);
      setUserInfo(null);
    };
src/utils/axios.ts
@@ -1,132 +1,134 @@
import axios, {AxiosError, AxiosResponse} from 'axios'
import {useRouter} from 'vue-router'
import axios, { AxiosError, AxiosResponse, InternalAxiosRequestConfig } from 'axios'
import Qs from 'qs'
import { useBedsideAuxiliaryScreenStore } from '@/store/bedsideAuxiliaryScreen'
import { ElMessage } from 'element-plus/es'
const BASE_URL = import.meta.env.VITE_BASIC_API
// ====== 配置 ======
const BASE_URL = import.meta.env.VITE_API_BASE_URL
const TIME_OUT = 60 * 1 * 1000
const TIME_OUT = 60 * 2 * 1000
// 正在进行中的请求列表
let reqList: any[] = [] // 如果某个api存在这个数组里,说明该api暂时无法再次请求
// 正在进行中的请求列表,避免重复请求
let reqList: string[] = []
  /**
 * 允许某个请求可以继续进行
 * @param {array} reqList 全部请求列表
 * @param {string} url 请求地址
 * 允许某个请求再次发送
 */
const allowRequest = function (reqList: any[], url: any) {
    for (let i = 0; i < reqList.length; i++) {
      if (reqList[i] === url) {
        reqList.splice(i, 1)
        break
const allowRequest = (url?: string) => {
  if (!url) return
  const idx = reqList.indexOf(url)
  if (idx > -1) reqList.splice(idx, 1)
      }
    }
  }
/**
 * 创建axios实例
 */
const instance = axios.create({
    baseURL: BASE_URL,
    timeout: TIME_OUT,
    paramsSerializer: function(params) {//序列化请求参数,避免get请求参数出现&,空格等识别错误的问题
        return Qs.stringify(params, {arrayFormat: 'brackets'})
    },
  paramsSerializer: (params) => Qs.stringify(params, { arrayFormat: 'brackets' }),
})
// ====== 错误处理函数 ======
const errorHandle = (status: number, error:any): void => {
    // HTTP状态码判断
  const msg = error?.msg || error?.message || ''
    switch (status) {
        case 401:
            return alert(`Error Code: ${status}, Message: ${error.msg || '登录失效,请重新登录'}`)
      ElMessage.error(`Error Code: 401, Message: ${msg || '登录失效,请重新登录'}`);
      break
        case 403:
            return alert(`Error Code: ${status}, Message: ${error.msg || '你没有访问权限'}`)
      ElMessage.error(`Error Code: 403, Message: ${msg || '你没有访问权限'}`);
      break
        case 500:
            return alert(`Error Code: ${status}, Message: ${error.msg || '后台错误,请联系管理员'}`)
      ElMessage.error(`Error Code: 500, Message: ${msg || '后台错误,请联系管理员'}`);
      break
        case 502:
            return alert(`Error Code: ${status}, Message: ${error.msg || '平台环境异常'}`)
      alert()
      ElMessage.error(`Error Code: 502, Message: ${msg || '平台环境异常'}`);
      break
        default:
            alert(`Error Code: ${status}, Message: ${error.msg || '未知错误,请刷新重试'}`)
      ElMessage.error(`Error Code: ${status}, Message: ${msg || '未知错误,请刷新重试'}`);
    }
}
// 前置拦截器(发起请求之前的拦截)
// ====== 请求拦截 ======
instance.interceptors.request.use(
    (response:any) =>{
        if (useBedsideAuxiliaryScreenStore().userInfo?.token) {
            response.headers.common['Authorization'] = 'Bearer '+ `${useBedsideAuxiliaryScreenStore().userInfo?.token}`
  (config: InternalAxiosRequestConfig) => {
    const store = useBedsideAuxiliaryScreenStore()
    // 加 token
    if (store.userInfo?.token) {
      config.headers.set('Authorization', `Bearer ${store.userInfo.token}`)
        }
        let cancel
        // 设置cancelToken对象
        response.cancelToken = new axios.CancelToken(function(c) {
            cancel = c
        })
        return response
    // 防止同一接口短时间内重复请求
    if (config.url) {
      if (reqList.includes(config.url)) {
        return Promise.reject(new axios.Cancel(`重复请求:${config.url}`))
      } else {
        reqList.push(config.url)
      }
    }
    return config
    },
    (error) => Promise.reject(error)
  (error) => Promise.reject(error),
)
// 后置拦截器(获取到响应时的拦截)
// ====== 响应拦截 ======
instance.interceptors.response.use(
    (res: AxiosResponse) => {
        // 增加延迟,相同请求不得在短时间内重复发送
        setTimeout(() => {
            allowRequest(reqList, res.config.url)
          }, 1000) // 上一次请求返回后过1s才允许再次请求
        if (String(res.status).indexOf('2') !== 0) {
            return {
                code: res.status,
                message: res.data.message || '请求异常,请刷新重试',
                result: false
            }
        }
        if (res.data.code===200){
            return res.data
        }
        // 返回异常
        else {
            // Toast(res.data.message)
            // 白名单,直接返回不提示
            const whiteList: string[] = ["/patient/hemo/med/record/updateSchemeTool","/patient/hemo/med/monitor/data/prepareAdd"];
            const requestUrl = res.request.responseURL;
            const isInWhiteList = whiteList.some(item => requestUrl.includes(item));
            if(isInWhiteList) return Promise.reject(res.data);
    setTimeout(() => allowRequest(res.config.url), 1000)
    if (String(res.status).charAt(0) !== '2') {
      return Promise.reject({
        code: res.status,
        message: res.data?.message || '请求异常,请刷新重试',
      })
    }
    if (res.data?.code === 200) return res.data
    const whiteList: string[] = []
    const requestUrl: string = res?.config?.url || ''
    const isInWhiteList = whiteList.some((item) => requestUrl.includes(item))
    ElMessage.error(res.data.message);
    if (isInWhiteList) return Promise.reject(res.data)
            return Promise.reject(res.data)
        }
        // return Promise.reject(instance.interceptors.response)
    },
    (error: AxiosError) => {
        if (axios.isCancel(error)) {
            console.log(error.message);
  (err: unknown) => {
    const anyErr = err as any
    const configUrl = anyErr?.config?.url
    // 失败后 1s 允许再次请求
    setTimeout(() => allowRequest(configUrl), 1000)
    // 先判断是否是取消请求
    if (axios.isCancel(err as any)) {
      console.warn('请求被取消:', (err as any)?.message)
      return Promise.reject(err)
        } 
        else {
        setTimeout(() => {
            allowRequest(reqList, error.config.url)
            }, 1000) // 请求失败返回后过1s才允许再次请求
    // 判断是否为 axios 的错误类型(有 response)
    if (axios.isAxiosError(err)) {
      const axErr = err // 现在 TypeScript 知道这是 AxiosError
      if (axErr.response) {
        // 使用你现有的错误处理函数
        errorHandle(axErr.response.status, axErr.response.data)
        if (axErr.response.status === 401) {
            ElMessage.error('请登录');
        }
        if (error && error.response) {
            // 请求已发出,但是不在2xx的范围
            errorHandle(error.response.status, error.response)
            if (error.response.status===401){
                Dialog.confirm({
                    title: '提示',
                    message:
                        '是否需要退出登录?',
                })
                    .then(() => {
                        Session.clear(); // 清除浏览器全部临时缓存
                        window.location.href = '/'; // 去登录页
                    })
                    .catch(() => {
                        Toast('取消操作')
                    })
        return Promise.reject(axErr.response.data || axErr.response)
            }
            return Promise.reject(error.response)
      ElMessage.error('网络请求失败, 请刷新重试');
      return Promise.reject(axErr)
        }
        Toast('网络请求失败, 请刷新重试')
        return Promise.reject(error)
    }
    //(未知错误)
    ElMessage.error('网络请求失败, 请刷新重试');
    return Promise.reject(err)
  },
)
export default instance
src/views/mobile/bedsideAuxiliaryScreen/components/Login/index.vue
@@ -97,19 +97,16 @@
        .then(async() => {
            state.loading = true
            try {
              await bedsideAuxiliaryScreenStore.logout(bedsideAuxiliaryScreenStore.deviceCode);
              await bedsideAuxiliaryScreenStore.logout(`deviceCode=${bedsideAuxiliaryScreenStore.deviceCode}`);
              handleCancel();
              ElMessage.success('退出登录成功')
              handleCancel();
            } catch (error) {
              ElMessage.success('退出登录失败')
              console.error('error: ', error)
              // ElMessage.error('退出登录失败')
            } finally {
              state.loading = false;
            }
          ElMessage({
            type: "success",
            message: "退出成功!",
          });
        })
        .catch(() => {});
    };