newRequest.js 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. /**
  2. * Copyright [2022] [https://www.xiaonuo.vip]
  3. * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
  4. * 1.请不要删除和修改根目录下的LICENSE文件。
  5. * 2.请不要删除和修改Snowy源码头部的版权声明。
  6. * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
  7. * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
  8. * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
  9. * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
  10. */
  11. // 统一的请求发送
  12. import axios from 'axios'
  13. import qs from 'qs'
  14. import { Modal, message, notification } from 'ant-design-vue'
  15. import sysConfig from '@/config/index'
  16. import tool from '@/utils/tool'
  17. // 以下这些code需要重新登录
  18. const reloadCodes = [401, 1011007, 1011008]
  19. const errorCodeMap = {
  20. 400: '发出的请求有错误,服务器没有进行新建或修改数据的操作。',
  21. 401: '用户没有权限(令牌、用户名、密码错误)。',
  22. 403: '用户得到授权,但是访问是被禁止的。',
  23. 404: '发出的请求针对的是不存在的记录,服务器没有进行操作。',
  24. 406: '请求的格式不可得。',
  25. 410: '请求的资源被永久删除,且不会再得到的。',
  26. 422: '当创建一个对象时,发生一个验证错误。',
  27. 500: '服务器发生错误,请检查服务器。',
  28. 502: '网关错误。',
  29. 503: '服务不可用,服务器暂时过载或维护。',
  30. 504: '网关超时。'
  31. }
  32. // 定义一个重新登录弹出窗的变量
  33. const loginBack = ref(false)
  34. // 创建 axios 实例
  35. const service = axios.create({
  36. baseURL: '/api', // api base_url
  37. timeout: sysConfig.TIMEOUT // 请求超时时间
  38. })
  39. // HTTP request 拦截器
  40. service.interceptors.request.use(
  41. (config) => {
  42. const token = tool.data.get('TOKEN')
  43. if (token) {
  44. config.headers[sysConfig.TOKEN_NAME] = sysConfig.TOKEN_PREFIX + token
  45. }
  46. if (!sysConfig.REQUEST_CACHE && config.method === 'get') {
  47. config.params = config.params || {}
  48. config.params._ = new Date().getTime()
  49. }
  50. Object.assign(config.headers, sysConfig.HEADERS)
  51. return config
  52. },
  53. (error) => {
  54. return Promise.reject(error)
  55. }
  56. )
  57. // 保持重新登录Modal的唯一性
  58. const error = () => {
  59. loginBack.value = true
  60. Modal.error({
  61. title: '提示:',
  62. okText: '重新登录',
  63. content: '登录已失效, 请重新登录',
  64. onOk: () => {
  65. loginBack.value = false
  66. tool.data.remove('TOKEN')
  67. tool.data.remove('USER_INFO')
  68. tool.data.remove('MENU')
  69. tool.data.remove('PERMISSIONS')
  70. window.location.reload()
  71. }
  72. })
  73. }
  74. // HTTP response 拦截器
  75. service.interceptors.response.use(
  76. (response) => {
  77. console.log(response, '文件')
  78. // 配置了blob,不处理直接返回文件流
  79. if (response.config.responseType === 'blob') {
  80. if (response.status === 200) {
  81. return response
  82. } else {
  83. message.warning('文件下载失败或此文件不存在')
  84. return
  85. }
  86. }
  87. const data = response.data
  88. const code = data.code
  89. if (reloadCodes.includes(code)) {
  90. if (!loginBack.value) {
  91. error()
  92. }
  93. return
  94. }
  95. if (code !== 200) {
  96. const customErrorMessage = response.config.customErrorMessage
  97. message.error(customErrorMessage || data.msg)
  98. return Promise.reject(data)
  99. // 自定义错误提示,覆盖后端返回的message
  100. // 使用示例:
  101. // export function customerList (data) {
  102. // return request('list', data, 'get', {
  103. // customErrorMessage: '自定义错误消息提示'
  104. // });
  105. // }
  106. } else {
  107. // 统一成功提示
  108. const responseUrl = response.config.url
  109. const apiNameArray = [
  110. 'add',
  111. 'edit',
  112. 'delete',
  113. 'update',
  114. 'grant',
  115. 'reset',
  116. 'stop',
  117. 'pass',
  118. 'disable',
  119. 'enable',
  120. 'revoke',
  121. 'suspend',
  122. 'active',
  123. 'turn',
  124. 'adjust',
  125. 'reject',
  126. 'saveDraft'
  127. ]
  128. apiNameArray.forEach((apiName) => {
  129. if (responseUrl.includes(apiName)) {
  130. message.success(data.msg)
  131. }
  132. })
  133. }
  134. return Promise.resolve(data)
  135. },
  136. (error) => {
  137. if (error) {
  138. const status = 503
  139. const description = errorCodeMap[status]
  140. notification.error({
  141. message: '请求错误',
  142. description
  143. })
  144. return Promise.reject(status)
  145. }
  146. }
  147. )
  148. // 适配器, 用于适配不同的请求方式
  149. export const baseRequest = (url, value = {}, method = 'post', options = {}) => {
  150. url = sysConfig.API_URL + url
  151. if (method === 'post') {
  152. return service.post(url, value, options)
  153. } else if (method === 'get') {
  154. return service.get(url, { params: value, ...options })
  155. } else if (method === 'formdata') {
  156. // form-data表单提交的方式
  157. return service.post(url, qs.stringify(value), {
  158. headers: {
  159. 'Content-Type': 'multipart/form-data'
  160. },
  161. ...options
  162. })
  163. } else {
  164. // 其他请求方式,例如:put、delete
  165. return service({
  166. method: method,
  167. url: url,
  168. data: value,
  169. ...options
  170. })
  171. }
  172. }
  173. // 模块内的请求, 会自动加上模块的前缀
  174. export const moduleRequest =
  175. (moduleUrl) =>
  176. (url, ...arg) => {
  177. return baseRequest(moduleUrl + url, ...arg)
  178. }
  179. export default service