You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

177 lines
5.6 KiB

5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
  1. import { getToken, setToken } from '@/store/system.ts'
  2. import { IApiResult } from '@/global'
  3. import { Record } from '@icon-park/react'
  4. import { message } from 'antd'
  5. import axios, {
  6. AxiosRequestConfig,
  7. AxiosInstance, AxiosResponse,
  8. } from 'axios'
  9. export type { AxiosRequestConfig }
  10. type FetchMethod = <T = any, D = any>(url: string, data?: D, config?: AxiosRequestConfig<D>) => Promise<IApiResult<T>>
  11. interface RequestMethods extends Pick<AxiosInstance, 'get' | 'post' | 'put' | 'delete' | 'request' | 'postForm' | 'patch' | 'patchForm' | 'putForm' | 'options'> {
  12. download: (url: string, data?: any) => Promise<BlobPart>
  13. }
  14. const axiosInstance = axios.create({
  15. baseURL: '/api/v1',
  16. // timeout: 1000,
  17. headers: {
  18. 'Content-Type': 'application/json',
  19. },
  20. validateStatus: status => {
  21. return status >= 200 && status < 300
  22. }
  23. })
  24. //拦截request,添加token
  25. axiosInstance.interceptors.request.use((config) => {
  26. const token = getToken()
  27. if (token) {
  28. config.headers.Authorization = `Bearer ${token}`
  29. }
  30. return config
  31. }, (error) => {
  32. console.log('error', error)
  33. return Promise.reject(error)
  34. })
  35. //拦截response,返回data
  36. axiosInstance.interceptors.response.use(
  37. (response) => {
  38. // console.log('response', response.data)
  39. message.destroy()
  40. const result = response.data as IApiResult
  41. switch (result.code) {
  42. case 0:
  43. case 200:
  44. //login
  45. if (response.config.url?.includes('/sys/login')) {
  46. setToken(result.data.token)
  47. const search = new URLSearchParams(window.location.search)
  48. // eslint-disable-next-line no-case-declarations
  49. const redirect = search.get('redirect')
  50. if (redirect) {
  51. window.location.href = redirect
  52. }
  53. }
  54. return response
  55. case 401:
  56. setToken('')
  57. if (window.location.pathname === '/login') {
  58. return Promise.reject(new Error('to login'))
  59. }
  60. // 401: 未登录
  61. message.error('登录失败,跳转重新登录')
  62. // eslint-disable-next-line no-case-declarations
  63. const search = new URLSearchParams(window.location.search)
  64. // eslint-disable-next-line no-case-declarations
  65. let redirect = window.location.pathname
  66. if (search.toString() !== '') {
  67. redirect = window.location.pathname + '?=' + search.toString()
  68. }
  69. window.location.href = `/login?redirect=${encodeURIComponent(redirect)}`
  70. return Promise.reject(new Error('to login'))
  71. default:
  72. message.error(result.message ?? '请求失败')
  73. return Promise.reject(response)
  74. }
  75. }, (error) => {
  76. // console.log('error', error)
  77. message.destroy()
  78. const { response } = error
  79. if (response) {
  80. switch (response.status) {
  81. case 401:
  82. if (window.location.pathname === '/login') {
  83. return
  84. }
  85. setToken('')
  86. // 401: 未登录
  87. message.error('登录失败,跳转重新登录')
  88. // eslint-disable-next-line no-case-declarations
  89. const search = new URLSearchParams(window.location.search)
  90. // eslint-disable-next-line no-case-declarations
  91. let redirect = window.location.pathname
  92. if (search.toString() !== '') {
  93. redirect = window.location.pathname + '?=' + search.toString()
  94. }
  95. window.location.href = `/login?redirect=${encodeURIComponent(redirect)}`
  96. return
  97. case 403:
  98. message.error('没有权限')
  99. break
  100. case 404:
  101. message.error('请求的资源不存在')
  102. break
  103. default:
  104. message.error(response.data.message ?? response.data ?? error.message ?? '请求失败')
  105. return Promise.reject(response)
  106. }
  107. }
  108. return Promise.reject(error)
  109. })
  110. //扩展download方法
  111. // @ts-ignore fix download
  112. axiosInstance.download = (url: string, data?: any) => {
  113. const formData = new FormData()
  114. for (const key in data) {
  115. formData.append(key, data[key])
  116. }
  117. const config = {
  118. method: 'post',
  119. url,
  120. data: formData,
  121. responseType: 'blob',
  122. timeout: 40 * 1000,
  123. } as AxiosRequestConfig
  124. return axiosInstance.request(config)
  125. }
  126. //创建返回IApiResult类型的request
  127. export const createFetchMethods = () => {
  128. const methods = {}
  129. for (const method of Object.keys(axiosInstance)) {
  130. methods[method] = async <T = any, D = any>(url: string, data?: D, config?: AxiosRequestConfig<D>) => {
  131. config = config ?? {}
  132. config.url = url
  133. config.method = method
  134. const isGet = method === 'get'
  135. if (isGet) {
  136. config.params = data
  137. } else {
  138. config.data = data
  139. }
  140. return axiosInstance(config)
  141. .then((response: AxiosResponse<IApiResult<T>>) => {
  142. if (response.data.code !== 200 && response.data.code !== 0) {
  143. throw new Error(response.data.message)
  144. }
  145. return response.data as IApiResult<T>
  146. })
  147. .catch((err) => {
  148. throw err
  149. })
  150. }
  151. }
  152. return methods as Record<keyof RequestMethods, FetchMethod>
  153. }
  154. export const request = createFetchMethods()
  155. export default request