干燥机配套车间生产管理系统/云平台服务端
baoshiwei
2024-05-27 fa3ac93010bea3805438ee3ab0a182bfbf7423da
src/utils/http/axios/index.ts
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,288 @@
// axios配置  å¯è‡ªè¡Œæ ¹æ®é¡¹ç›®è¿›è¡Œæ›´æ”¹ï¼Œåªéœ€æ›´æ”¹è¯¥æ–‡ä»¶å³å¯ï¼Œå…¶ä»–文件可以不动
// The axios configuration can be changed according to the project, just change the file, other files can be left unchanged
import type { AxiosResponse } from 'axios'
import { VAxios } from './Axios'
import type { AxiosTransform, CreateAxiosOptions } from './axiosTransform'
import { checkStatus } from './checkStatus'
import { formatRequestDate, joinTimestamp } from './helper'
import type { RequestOptions, Result } from '/#/axios'
import { ConfigEnum, ContentTypeEnum, RequestEnum, ResultEnum } from '/@/enums/httpEnum'
import { useGlobSetting } from '/@/hooks/setting'
import { useI18n } from '/@/hooks/web/useI18n'
import { useMessage } from '/@/hooks/web/useMessage'
import { router } from '/@/router'
import { useErrorLogStoreWithOut } from '/@/store/modules/errorLog'
import { useUserStoreWithOut } from '/@/store/modules/user'
import { deepMerge, setObjToUrlParams } from '/@/utils'
import { getTenantId, getToken } from '/@/utils/auth'
import signMd5Utils from '/@/utils/encryption/signMd5Utils'
import { isString } from '/@/utils/is'
const globSetting = useGlobSetting()
const urlPrefix = globSetting.urlPrefix
const { createMessage, createErrorModal } = useMessage()
/**
 * @description: æ•°æ®å¤„理,方便区分多种处理方式
 */
const transform: AxiosTransform = {
   /**
    * @description: å¤„理请求数据。如果数据不是预期格式,可直接抛出错误
    */
   transformRequestHook: (res: AxiosResponse<Result>, options: RequestOptions) => {
      //console.log(`output->res`, res)
      //console.log(`output->options`, options)
      const { t } = useI18n()
      const { isTransformResponse, isReturnNativeResponse } = options
      // æ˜¯å¦è¿”回原生响应头 æ¯”如:需要获取响应头时使用该属性
      if (isReturnNativeResponse) {
         return res
      }
      // ä¸è¿›è¡Œä»»ä½•处理,直接返回
      // ç”¨äºŽé¡µé¢ä»£ç å¯èƒ½éœ€è¦ç›´æŽ¥èŽ·å–code,data,message这些信息时开启
      if (!isTransformResponse) {
         return res.data
      }
      // é”™è¯¯çš„æ—¶å€™è¿”回
      const { data } = res
      if (!data) {
         // return '[HTTP] Request has no return value';
         throw new Error(t('sys.api.apiRequestFailed'))
      }
      //  è¿™é‡Œ code,result,message为 åŽå°ç»Ÿä¸€çš„字段,需要在 types.ts内修改为项目自己的接口返回格式
      const { code, result, message, success } = data
      // è¿™é‡Œé€»è¾‘可以根据项目进行修改
      const hasSuccess = data && Reflect.has(data, 'code') && (code === ResultEnum.SUCCESS || code === 200)
      if (hasSuccess) {
         if (success && message && options.successMessageMode === 'success') {
            //信息成功提示
            createMessage.success(message)
         }
         return result
      }
      // åœ¨æ­¤å¤„根据自己项目的实际情况对不同的code执行不同的操作
      // å¦‚果不希望中断当前请求,请return数据,否则直接抛出异常即可
      let timeoutMsg = ''
      switch (code) {
         case ResultEnum.TIMEOUT:
            timeoutMsg = t('sys.api.timeoutMessage')
            const userStore = useUserStoreWithOut()
            userStore.setToken(undefined)
            userStore.logout(true)
            break
         default:
            if (message) {
               timeoutMsg = message
            }
      }
      // errorMessageMode=‘modal’的时候会显示modal错误弹窗,而不是消息提示,用于一些比较重要的错误
      // errorMessageMode='none' ä¸€èˆ¬æ˜¯è°ƒç”¨æ—¶æ˜Žç¡®è¡¨ç¤ºä¸å¸Œæœ›è‡ªåŠ¨å¼¹å‡ºé”™è¯¯æç¤º
      if (options.errorMessageMode === 'modal') {
         createErrorModal({ title: t('sys.api.errorTip'), content: timeoutMsg })
      } else if (options.errorMessageMode === 'message') {
         createMessage.error(timeoutMsg)
      }
      throw new Error(timeoutMsg || t('sys.api.apiRequestFailed'))
   },
   // è¯·æ±‚之前处理config
   beforeRequestHook: (config, options) => {
      const { apiUrl, joinPrefix, joinParamsToUrl, formatDate, joinTime = true, urlPrefix } = options
      if (joinPrefix) {
         config.url = `${urlPrefix}${config.url}`
      }
      if (apiUrl && isString(apiUrl)) {
         config.url = `${apiUrl}${config.url}`
      }
      const params = config.params || {}
      const data = config.data || false
      formatDate && data && !isString(data) && formatRequestDate(data)
      if (config.method?.toUpperCase() === RequestEnum.GET) {
         if (!isString(params)) {
            // ç»™ get è¯·æ±‚加上时间戳参数,避免从缓存中拿数据。
            config.params = Object.assign(params || {}, joinTimestamp(joinTime, false))
         } else {
            // å…¼å®¹restful风格
            config.url = config.url + params + `${joinTimestamp(joinTime, true)}`
            config.params = undefined
         }
      } else {
         if (!isString(params)) {
            formatDate && formatRequestDate(params)
            if (Reflect.has(config, 'data') && config.data && Object.keys(config.data).length > 0) {
               config.data = data
               config.params = params
            } else {
               // éžGET请求如果没有提供data,则将params视为data
               config.data = params
               config.params = undefined
            }
            if (joinParamsToUrl) {
               config.url = setObjToUrlParams(config.url as string, Object.assign({}, config.params, config.data))
            }
         } else {
            // å…¼å®¹restful风格
            config.url = config.url + params
            config.params = undefined
         }
      }
      return config
   },
   /**
    * @description: è¯·æ±‚拦截器处理
    */
   requestInterceptors: (config: Recordable, options) => {
      // console.log(`output->config`, config);
      // è¯·æ±‚之前处理config
      const token = getToken()
      let tenantid = getTenantId()
      //--update-begin--author:liusq---date:20220325---for: å¢žåŠ vue3标记
      config.headers[ConfigEnum.VERSION] = 'v3'
      //--update-end--author:liusq---date:20220325---for:增加vue3标记
      if (token && (config as Recordable)?.requestOptions?.withToken !== false) {
         // jwt token
         config.headers.Authorization = options.authenticationScheme ? `${options.authenticationScheme} ${token}` : token
         config.headers[ConfigEnum.TOKEN] = token
         //--update-begin--author:liusq---date:20210831---for:将签名和时间戳,添加在请求接口 Header
         // update-begin--author:taoyan---date:20220421--for: VUEN-410【签名改造】 X-TIMESTAMP牵扯
         config.headers[ConfigEnum.TIMESTAMP] = signMd5Utils.getTimestamp()
         // update-end--author:taoyan---date:20220421--for: VUEN-410【签名改造】 X-TIMESTAMP牵扯
         config.headers[ConfigEnum.Sign] = signMd5Utils.getSign(config.url, config.params)
         //--update-end--author:liusq---date:20210831---for:将签名和时间戳,添加在请求接口 Header
         //--update-begin--author:liusq---date:20211105---for: for:将多租户id,添加在请求接口 Header
         if (!tenantid) {
            tenantid = '0'
         }
         config.headers[ConfigEnum.TENANT_ID] = tenantid
         //--update-end--author:liusq---date:20211105---for:将多租户id,添加在请求接口 Header
         // ========================================================================================
         // update-begin--author:sunjianlei---date:20220624--for: æ·»åŠ ä½Žä»£ç åº”ç”¨ID
         const routeParams = router.currentRoute.value.params
         if (routeParams.appId) {
            config.headers[ConfigEnum.X_LOW_APP_ID] = routeParams.appId
            // lowApp自定义筛选条件
            if (routeParams.lowAppFilter) {
               config.params = { ...config.params, ...JSON.parse(routeParams.lowAppFilter as string) }
               delete routeParams.lowAppFilter
            }
         }
         // update-end--author:sunjianlei---date:20220624--for: æ·»åŠ ä½Žä»£ç åº”ç”¨ID
         // ========================================================================================
      }
      return config
   },
   /**
    * @description: å“åº”拦截器处理
    */
   responseInterceptors: (res: AxiosResponse<any>) => {
      return res
   },
   /**
    * @description: å“åº”错误处理
    */
   responseInterceptorsCatch: (error: any) => {
      const { t } = useI18n()
      const errorLogStore = useErrorLogStoreWithOut()
      errorLogStore.addAjaxErrorInfo(error)
      const { response, code, message, config } = error || {}
      const errorMessageMode = config?.requestOptions?.errorMessageMode || 'none'
      //scott 20211022 token失效提示信息
      //const msg: string = response?.data?.error?.message ?? '';
      const msg: string = response?.data?.message ?? ''
      const err: string = error?.toString?.() ?? ''
      let errMessage = ''
      try {
         if (code === 'ECONNABORTED' && message.indexOf('timeout') !== -1) {
            errMessage = t('sys.api.apiTimeoutMessage')
         }
         if (err?.includes('Network Error')) {
            errMessage = t('sys.api.networkExceptionMsg')
         }
         if (errMessage) {
            if (errorMessageMode === 'modal') {
               createErrorModal({ title: t('sys.api.errorTip'), content: errMessage })
            } else if (errorMessageMode === 'message') {
               createMessage.error(errMessage)
            }
            return Promise.reject(error)
         }
      } catch (error) {
         throw new Error(error)
      }
      checkStatus(error?.response?.status, msg, errorMessageMode)
      return Promise.reject(error)
   },
}
function createAxios(opt?: Partial<CreateAxiosOptions>) {
   return new VAxios(
      deepMerge(
         {
            // See https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication#authentication_schemes
            // authentication schemes,e.g: Bearer
            // authenticationScheme: 'Bearer',
            authenticationScheme: '',
            timeout: 10 * 1000,
            // åŸºç¡€æŽ¥å£åœ°å€
            // baseURL: globSetting.apiUrl,
            headers: { 'Content-Type': ContentTypeEnum.JSON },
            // å¦‚果是form-data格式
            // headers: { 'Content-Type': ContentTypeEnum.FORM_URLENCODED },
            // æ•°æ®å¤„理方式
            transform,
            // é…ç½®é¡¹ï¼Œä¸‹é¢çš„选项都可以在独立的接口请求中覆盖
            requestOptions: {
               // é»˜è®¤å°†prefix æ·»åŠ åˆ°url
               joinPrefix: true,
               // æ˜¯å¦è¿”回原生响应头 æ¯”如:需要获取响应头时使用该属性
               isReturnNativeResponse: false,
               // éœ€è¦å¯¹è¿”回数据进行处理
               isTransformResponse: true,
               // post请求的时候添加参数到url
               joinParamsToUrl: false,
               // æ ¼å¼åŒ–提交参数时间
               formatDate: true,
               // å¼‚常消息提示类型
               errorMessageMode: 'message',
               // æˆåŠŸæ¶ˆæ¯æç¤ºç±»åž‹
               successMessageMode: 'success',
               // æŽ¥å£åœ°å€
               apiUrl: globSetting.apiUrl,
               // æŽ¥å£æ‹¼æŽ¥åœ°å€
               urlPrefix: urlPrefix,
               //  æ˜¯å¦åŠ å…¥æ—¶é—´æˆ³
               joinTime: true,
               // å¿½ç•¥é‡å¤è¯·æ±‚
               ignoreCancelToken: true,
               // æ˜¯å¦æºå¸¦token
               withToken: true,
            },
         },
         opt || {}
      )
   )
}
export const defHttp = createAxios()
// other api url
// export const otherHttp = createAxios({
//   requestOptions: {
//     apiUrl: 'xxx',
//   },
// });