index.ts 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. import axios, { AxiosRequestConfig } from 'axios'
  2. import { v4 } from 'uuid'
  3. //import qs from 'qs'
  4. import cryptojs from 'crypto-js'
  5. //import { addPending, removePending } from './pending'
  6. import { encryptBody, decryptBody } from '@/services/websocket/package/crypto'
  7. import { IMessageHead } from '@/types/proto/proto'
  8. import { useGlobalStore, useLoginStore, useAccountStore, useErrorInfoStore } from '@/stores'
  9. import { CommonResult, ResultCode, SendMsgToMQ } from './types'
  10. import { FunCode } from '@/constants/funcode'
  11. import service from '@/services'
  12. import tradeService from '@/services/websocket/trade'
  13. import eventBus from '@/services/bus'
  14. export default new (class {
  15. private readonly axiosInstance = axios.create({
  16. timeout: 30000,
  17. })
  18. constructor() {
  19. // 请求拦截器
  20. this.axiosInstance.interceptors.request.use(
  21. (config) => {
  22. const globalStore = useGlobalStore()
  23. const loginStore = useLoginStore()
  24. //addPending(config) //将当前请求添加到列表中
  25. //设置请求头
  26. if (globalStore.getSystemInfo('tradeChannel') === 'ws') {
  27. config.headers = {
  28. Authorization: loginStore.token
  29. }
  30. } else {
  31. config.headers = {
  32. Authorization: loginStore.token,
  33. LoginID: loginStore.loginId,
  34. Group: loginStore.getClientType(),
  35. 'x-token': loginStore.token
  36. }
  37. }
  38. return config
  39. },
  40. (err) => {
  41. console.error(err)
  42. return Promise.reject('发生错误,请稍后再试')
  43. }
  44. )
  45. // 响应拦截器
  46. this.axiosInstance.interceptors.response.use(
  47. (res) => {
  48. //removePending(res) //在请求结束后,移除本次请求
  49. return res
  50. },
  51. (err) => {
  52. if (err.message === 'Network Error') {
  53. return Promise.reject('网络或服务器错误')
  54. }
  55. if (err.response) {
  56. const { msg, message } = err.response.data ?? {}
  57. switch (err.response.status) {
  58. case 401: {
  59. const loginStore = useLoginStore()
  60. if (loginStore.token) {
  61. eventBus.$emit('LogoutNotify', '登录失效,请重新登录')
  62. }
  63. return Promise.reject(msg || message)
  64. }
  65. case 408: {
  66. return Promise.reject('请求超时,请稍后再试')
  67. }
  68. default: {
  69. return Promise.reject(msg || message)
  70. }
  71. }
  72. }
  73. return Promise.reject('发生错误,请稍后再试')
  74. }
  75. )
  76. }
  77. /** 请求响应集合 */
  78. private resultMap = new Set<() => void>()
  79. /**
  80. * 建议在过渡动画中启用,动画结束时禁用
  81. * 可防止在动画过程中同时请求数据,数据请求先于动画完成,双绑数据的页面会实时渲染,导致动画卡顿的问题
  82. */
  83. private _pending = false
  84. /** 全局 pending 状态 */
  85. get pending() {
  86. return this._pending
  87. }
  88. /** 在动画开始时设置一个 pending 状态,在动画结束后取消 pending 状态 */
  89. set pending(status: boolean) {
  90. this._pending = status
  91. if (!status) {
  92. // 当 pending 状态为 false 时返回所有请求的回调
  93. this.resultMap.forEach((fn) => {
  94. fn()
  95. this.resultMap.delete(fn)
  96. })
  97. }
  98. }
  99. /**
  100. * Http 请求
  101. * @param config
  102. * @param errMsg
  103. * @returns
  104. */
  105. request<T>(config: AxiosRequestConfig, errMsg?: string) {
  106. return new Promise<T>((resolve, reject) => {
  107. this.axiosInstance(config).then((res) => {
  108. if (this.pending) {
  109. this.resultMap.add(() => resolve(res.data))
  110. } else {
  111. resolve(res.data)
  112. }
  113. }).catch((err) => {
  114. const msg = err ?? (errMsg ? '请求失败: ' + errMsg : '请求失败,请稍后重试')
  115. reject(msg)
  116. })
  117. })
  118. }
  119. /**
  120. * Http 通用请求
  121. * @param config
  122. * @param errMsg
  123. * @returns
  124. */
  125. async commonRequest<T>(config: AxiosRequestConfig, errMsg?: string) {
  126. const baseUrl = service.getConfig('goCommonSearchUrl')
  127. config.url = baseUrl + config.url
  128. const res = await this.request<CommonResult<T>>(config, errMsg)
  129. switch (res.code) {
  130. case ResultCode.InvalidToken: {
  131. return Promise.reject('令牌无效')
  132. }
  133. case ResultCode.Success: {
  134. return res
  135. }
  136. default: {
  137. return Promise.reject(res.msg)
  138. }
  139. }
  140. }
  141. /**
  142. * Http 通用请求
  143. * @param config
  144. * @param errMsg
  145. * @returns
  146. */
  147. async goRequest<T>(config: AxiosRequestConfig, errMsg?: string) {
  148. const baseUrl = service.getConfig('goAccess')
  149. config.url = baseUrl + config.url
  150. const res = await this.request<CommonResult<T>>(config, errMsg)
  151. switch (res.code) {
  152. case ResultCode.InvalidToken: {
  153. return Promise.reject('令牌无效')
  154. }
  155. case 0: {
  156. return res
  157. }
  158. default: {
  159. return Promise.reject(res.msg)
  160. }
  161. }
  162. }
  163. /**
  164. * Http 通用请求
  165. * @param config
  166. * @param errMsg
  167. * @returns
  168. */
  169. async mqRequest<T extends {
  170. RetCode: number;
  171. RetDesc: string;
  172. Status?: number;
  173. }>({ data, requestCode, responseCode, marketId = 0 }: SendMsgToMQ<{ Header?: IMessageHead }>, errMsg?: string) {
  174. const globalStore = useGlobalStore()
  175. const loginStore = useLoginStore()
  176. const accountStore = useAccountStore()
  177. const requestId = FunCode[requestCode]
  178. const responseId = FunCode[responseCode]
  179. if (data) {
  180. data.Header = {
  181. AccountID: accountStore.currentAccountId,
  182. FunCode: requestId,
  183. UUID: v4(),
  184. UserID: loginStore.userId,
  185. MarketID: marketId,
  186. ...data.Header,
  187. }
  188. }
  189. console.log(requestCode, data)
  190. try {
  191. if (globalStore.getSystemInfo('tradeChannel') === 'ws') {
  192. // websocket 通道
  193. const res = await tradeService.send<T>({
  194. data,
  195. requestCode,
  196. responseCode
  197. })
  198. return await this.pkg50Response<T>(res, responseCode)
  199. } else {
  200. // http 通道
  201. const config: AxiosRequestConfig = {
  202. method: 'post',
  203. url: '/MQ/SendMsgToMQ',
  204. data: {
  205. data: encryptBody(JSON.stringify(data ?? '{}')),
  206. funCodeReq: requestId,
  207. funCodeRsp: responseId,
  208. isEncrypted: true,
  209. }
  210. }
  211. const res = await this.goRequest<{ data: string }>(config, errMsg)
  212. const decryptedData = decryptBody(res.data.data) // 解析 package50 数据
  213. return await this.pkg50Response<T>(JSON.parse(decryptedData), responseCode)
  214. }
  215. } catch (err) {
  216. return await Promise.reject(err)
  217. }
  218. }
  219. /**
  220. * 处理 package50 响应
  221. * @param responseCode
  222. * @param data
  223. * @returns
  224. */
  225. private pkg50Response<T extends {
  226. RetCode: number;
  227. RetDesc: string;
  228. Status?: number;
  229. }>(response: T, responseCode: keyof typeof FunCode) {
  230. console.log(responseCode, response)
  231. const res = { ...response } // websocket 消息对象未定义的属性可能会有默认值
  232. switch (res.RetCode) {
  233. case 0: {
  234. return Promise.resolve(res)
  235. }
  236. case 12018: {
  237. if (res.RetDesc) {
  238. const word = cryptojs.enc.Base64.parse(res.RetDesc) // 解析base64
  239. res.RetDesc = cryptojs.enc.Utf8.stringify(word)
  240. }
  241. return Promise.reject(res.RetDesc)
  242. }
  243. default: {
  244. // 银行 业务 以 Status 作为判断依据
  245. if (res.Status === 0 || res.Status == 6007) {
  246. return Promise.resolve(res)
  247. }
  248. const { getErrorInfoByCode } = useErrorInfoStore()
  249. const msg = getErrorInfoByCode(res.Status && [6003, 6066, 6019].includes(res.Status) ? res.Status : res.RetCode)
  250. const error = String(res.RetDesc || res.RetCode || res.Status)
  251. return Promise.reject(msg ?? error)
  252. }
  253. }
  254. }
  255. })