巴青农资商城

request.js 5.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. import { joinApiUrl } from '@/config'
  2. import { getToken } from '@/utils/auth'
  3. import errorCode from '@/utils/errorCode'
  4. import { useUserStore } from '@/store/user'
  5. /** 是否正在处理 401 跳转,避免重复提示 */
  6. export const isRelogin = { show: false }
  7. const SESSION_EXPIRED_MSG = '登录过期,即将登录'
  8. import { PAGE_LOGIN } from '@/utils/pageRoute'
  9. const LOGIN_PAGE_URL = PAGE_LOGIN
  10. const LOGIN_REDIRECT_DELAY_MS = 400
  11. /** 与 ruoyi-ui tansParams 一致:null / undefined / 空字符串不参与序列化 */
  12. function isEmptyParam(value) {
  13. return value === null || value === undefined || value === ''
  14. }
  15. /**
  16. * 剔除空值形参(GET 查询用)
  17. */
  18. export function sanitizeParams(params) {
  19. if (params == null || typeof params !== 'object') {
  20. return params
  21. }
  22. if (Array.isArray(params)) {
  23. return params
  24. }
  25. const result = {}
  26. Object.keys(params).forEach((key) => {
  27. const value = params[key]
  28. if (isEmptyParam(value)) {
  29. return
  30. }
  31. if (typeof value === 'object' && !Array.isArray(value)) {
  32. const nested = sanitizeParams(value)
  33. if (nested && Object.keys(nested).length > 0) {
  34. result[key] = nested
  35. }
  36. return
  37. }
  38. result[key] = value
  39. })
  40. return result
  41. }
  42. function appendQuery(url, params) {
  43. const parts = []
  44. const build = (obj, prefix) => {
  45. Object.keys(obj).forEach((key) => {
  46. const value = obj[key]
  47. const name = prefix ? `${prefix}[${key}]` : key
  48. if (value !== null && value !== '' && typeof value !== 'undefined') {
  49. if (typeof value === 'object' && !Array.isArray(value)) {
  50. build(value, name)
  51. } else {
  52. parts.push(`${encodeURIComponent(name)}=${encodeURIComponent(value)}`)
  53. }
  54. }
  55. })
  56. }
  57. build(params, '')
  58. if (!parts.length) {
  59. return url
  60. }
  61. const qs = parts.join('&')
  62. return url + (url.indexOf('?') >= 0 ? '&' : '?') + qs
  63. }
  64. /**
  65. * 封装 uni.request,响应格式与 ruoyi-ui axios 拦截器一致
  66. */
  67. export function request(options = {}) {
  68. const header = { ...(options.header || {}) }
  69. const skipToken = header.isToken === false
  70. delete header.isToken
  71. delete header.repeatSubmit
  72. if (skipToken) {
  73. delete header.Authorization
  74. } else if (getToken()) {
  75. header.Authorization = 'Bearer ' + getToken()
  76. }
  77. const method = (options.method || 'GET').toUpperCase()
  78. let url = (options.url || '').startsWith('http')
  79. ? options.url
  80. : joinApiUrl(options.url)
  81. let requestData = options.data !== undefined ? options.data : options.params
  82. if (method === 'GET' && requestData && typeof requestData === 'object' && !Array.isArray(requestData)) {
  83. const cleaned = sanitizeParams(requestData)
  84. const keys = Object.keys(cleaned || {})
  85. if (keys.length) {
  86. url = appendQuery(url, cleaned)
  87. }
  88. requestData = undefined
  89. }
  90. return new Promise((resolve, reject) => {
  91. uni.request({
  92. url,
  93. method,
  94. data: requestData,
  95. header: {
  96. 'Content-Type': 'application/json;charset=utf-8',
  97. ...header
  98. },
  99. timeout: options.timeout || 10000,
  100. success: (res) => {
  101. const httpStatus = res.statusCode || 200
  102. const data = parseResponseData(res.data)
  103. const bizCode = data.code !== undefined && data.code !== null ? Number(data.code) : null
  104. const code = bizCode !== null && !Number.isNaN(bizCode) ? bizCode : httpStatus >= 200 && httpStatus < 300 ? 200 : httpStatus
  105. const msg = resolveErrorMessage(data, code)
  106. if (code === 401) {
  107. if (skipToken) {
  108. showErrorToast(msg)
  109. reject(new Error(msg))
  110. } else {
  111. handle401SessionExpired()
  112. reject(new Error(SESSION_EXPIRED_MSG))
  113. }
  114. return
  115. }
  116. if (code !== 200) {
  117. if (!options.silent) {
  118. showErrorToast(msg)
  119. }
  120. reject(new Error(msg || 'error'))
  121. return
  122. }
  123. resolve(data)
  124. },
  125. fail: (err) => {
  126. let message = err.errMsg || '网络异常'
  127. if (message.includes('timeout')) {
  128. message = '系统接口请求超时'
  129. } else if (message.includes('fail')) {
  130. message = '后端接口连接异常'
  131. }
  132. if (!options.silent) {
  133. showErrorToast(message)
  134. }
  135. reject(err)
  136. }
  137. })
  138. })
  139. }
  140. function parseResponseData(raw) {
  141. if (raw == null || raw === '') {
  142. return {}
  143. }
  144. if (typeof raw === 'object') {
  145. return raw
  146. }
  147. if (typeof raw === 'string') {
  148. try {
  149. return JSON.parse(raw)
  150. } catch (e) {
  151. return { msg: raw }
  152. }
  153. }
  154. return {}
  155. }
  156. function resolveErrorMessage(data, code) {
  157. const serverMsg = data && data.msg != null ? String(data.msg).trim() : ''
  158. if (serverMsg) {
  159. return serverMsg
  160. }
  161. const key = String(code)
  162. if (errorCode[key]) {
  163. return errorCode[key]
  164. }
  165. return errorCode.default || '请求失败'
  166. }
  167. function showErrorToast(message) {
  168. const title = (message && String(message).trim()) || errorCode.default || '请求失败'
  169. uni.showToast({
  170. title: title.length > 40 ? title.slice(0, 40) + '…' : title,
  171. icon: 'none',
  172. duration: 3000
  173. })
  174. }
  175. function handle401SessionExpired() {
  176. if (isRelogin.show) {
  177. return
  178. }
  179. isRelogin.show = true
  180. uni.showToast({
  181. title: SESSION_EXPIRED_MSG,
  182. icon: 'none',
  183. duration: 2000
  184. })
  185. setTimeout(() => {
  186. const userStore = useUserStore()
  187. userStore.fedLogOut().finally(() => {
  188. isRelogin.show = false
  189. uni.reLaunch({ url: LOGIN_PAGE_URL })
  190. })
  191. }, LOGIN_REDIRECT_DELAY_MS)
  192. }
  193. export default request