| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275 |
- import axios, { AxiosRequestConfig } from 'axios'
- import { v4 } from 'uuid'
- //import qs from 'qs'
- import cryptojs from 'crypto-js'
- //import { addPending, removePending } from './pending'
- import { encryptBody, decryptBody } from '@/services/websocket/package/crypto'
- import { IMessageHead } from '@/types/proto/proto'
- import { useGlobalStore, useLoginStore, useAccountStore, useErrorInfoStore } from '@/stores'
- import { CommonResult, ResultCode, SendMsgToMQ } from './types'
- import { FunCode } from '@/constants/funcode'
- import service from '@/services'
- import tradeService from '@/services/websocket/trade'
- import eventBus from '@/services/bus'
- export default new (class {
- private readonly axiosInstance = axios.create({
- timeout: 30000,
- })
- constructor() {
- // 请求拦截器
- this.axiosInstance.interceptors.request.use(
- (config) => {
- const globalStore = useGlobalStore()
- const loginStore = useLoginStore()
- //addPending(config) //将当前请求添加到列表中
- //设置请求头
- if (globalStore.getSystemInfo('tradeChannel') === 'ws') {
- const key = 'dZChvstdjmqIt5fP'
- const timestamp = globalStore.getTimestamp()
- const verification = cryptojs.HmacSHA256(loginStore.token + timestamp, key)
- config.headers = {
- Authorization: loginStore.token,
- Timestamp: timestamp,
- Verification: verification.toString()
- }
- } else {
- config.headers = {
- Authorization: loginStore.token,
- LoginID: loginStore.loginId,
- Group: loginStore.getClientType(),
- 'x-token': loginStore.token
- }
- }
- return config
- },
- (err) => {
- console.error(err)
- return Promise.reject('发生错误,请稍后再试')
- }
- )
- // 响应拦截器
- this.axiosInstance.interceptors.response.use(
- (res) => {
- //removePending(res) //在请求结束后,移除本次请求
- return res
- },
- (err) => {
- if (err.message === 'Network Error') {
- return Promise.reject('网络或服务器错误')
- }
- if (err.response) {
- const { code, msg, message } = err.response.data ?? {}
- switch (err.response.status) {
- case 408: {
- return Promise.reject('请求超时,请稍后再试')
- }
- default: {
- const loginStore = useLoginStore()
- if (loginStore.token && code === ResultCode.InvalidToken) {
- eventBus.$emit('LogoutNotify', '登录失效,请重新登录')
- }
- return Promise.reject(msg || message)
- }
- }
- }
- return Promise.reject('发生错误,请稍后再试')
- }
- )
- }
- /** 请求响应集合 */
- private resultMap = new Set<() => void>()
- /**
- * 建议在过渡动画中启用,动画结束时禁用
- * 可防止在动画过程中同时请求数据,数据请求先于动画完成,双绑数据的页面会实时渲染,导致动画卡顿的问题
- */
- private _pending = false
- /** 全局 pending 状态 */
- get pending() {
- return this._pending
- }
- /** 在动画开始时设置一个 pending 状态,在动画结束后取消 pending 状态 */
- set pending(status: boolean) {
- this._pending = status
- if (!status) {
- // 当 pending 状态为 false 时返回所有请求的回调
- this.resultMap.forEach((fn) => {
- fn()
- this.resultMap.delete(fn)
- })
- }
- }
- /**
- * Http 请求
- * @param config
- * @param errMsg
- * @returns
- */
- request<T>(config: AxiosRequestConfig, errMsg?: string) {
- return new Promise<T>((resolve, reject) => {
- this.axiosInstance(config).then((res) => {
- if (this.pending) {
- this.resultMap.add(() => resolve(res.data))
- } else {
- resolve(res.data)
- }
- }).catch((err) => {
- const msg = err ?? (errMsg ? '请求失败: ' + errMsg : '请求失败,请稍后重试')
- reject(msg)
- })
- })
- }
- /**
- * Http 通用请求
- * @param config
- * @param errMsg
- * @returns
- */
- async commonRequest<T>(config: AxiosRequestConfig, errMsg?: string) {
- const baseUrl = service.getConfig('goCommonSearchUrl')
- config.url = baseUrl + config.url
- const res = await this.request<CommonResult<T>>(config, errMsg)
- switch (res.code) {
- case ResultCode.InvalidToken: {
- return Promise.reject('令牌无效')
- }
- case ResultCode.Success: {
- return res
- }
- default: {
- return Promise.reject(res.msg)
- }
- }
- }
- /**
- * Http 通用请求
- * @param config
- * @param errMsg
- * @returns
- */
- async goRequest<T>(config: AxiosRequestConfig, errMsg?: string) {
- const baseUrl = service.getConfig('goAccess')
- config.url = baseUrl + config.url
- const res = await this.request<CommonResult<T>>(config, errMsg)
- switch (res.code) {
- case ResultCode.InvalidToken: {
- return Promise.reject('令牌无效')
- }
- case 0: {
- return res
- }
- default: {
- return Promise.reject(res.msg)
- }
- }
- }
- /**
- * Http 通用请求
- * @param config
- * @param errMsg
- * @returns
- */
- async mqRequest<T extends {
- RetCode: number;
- RetDesc: string;
- Status?: number;
- }>({ data, requestCode, responseCode, marketId = 0 }: SendMsgToMQ<{ Header?: IMessageHead }>, errMsg?: string) {
- const globalStore = useGlobalStore()
- const loginStore = useLoginStore()
- const accountStore = useAccountStore()
- const requestId = FunCode[requestCode]
- const responseId = FunCode[responseCode]
- if (data) {
- data.Header = {
- AccountID: accountStore.currentAccountId,
- FunCode: requestId,
- UUID: v4(),
- UserID: loginStore.userId,
- MarketID: marketId,
- ...data.Header,
- }
- }
- console.log(requestCode, data)
- try {
- if (globalStore.getSystemInfo('tradeChannel') === 'ws') {
- // websocket 通道
- const res = await tradeService.send<T>({
- data,
- requestCode,
- responseCode
- })
- return await this.pkg50Response<T>(res, responseCode)
- } else {
- // http 通道
- const config: AxiosRequestConfig = {
- method: 'post',
- url: '/MQ/SendMsgToMQ',
- data: {
- data: encryptBody(JSON.stringify(data ?? '{}')),
- funCodeReq: requestId,
- funCodeRsp: responseId,
- isEncrypted: true,
- }
- }
- const res = await this.goRequest<{ data: string }>(config, errMsg)
- const decryptedData = decryptBody(res.data.data) // 解析 package50 数据
- return await this.pkg50Response<T>(JSON.parse(decryptedData), responseCode)
- }
- } catch (err) {
- return await Promise.reject(err)
- }
- }
- /**
- * 处理 package50 响应
- * @param responseCode
- * @param data
- * @returns
- */
- private pkg50Response<T extends {
- RetCode: number;
- RetDesc: string;
- Status?: number;
- }>(response: T, responseCode: keyof typeof FunCode) {
- console.log(responseCode, response)
- const res = { ...response } // websocket 消息对象未定义的属性可能会有默认值
- switch (res.RetCode) {
- case 0: {
- return Promise.resolve(res)
- }
- case -1: {
- return Promise.reject(res.RetDesc)
- }
- case 12018: {
- if (res.RetDesc) {
- const word = cryptojs.enc.Base64.parse(res.RetDesc) // 解析base64
- res.RetDesc = cryptojs.enc.Utf8.stringify(word)
- }
- return Promise.reject(res.RetDesc)
- }
- default: {
- // 银行 业务 以 Status 作为判断依据
- if (res.Status === 0 || res.Status == 6007) {
- return Promise.resolve(res)
- }
- const { getErrorInfoByCode } = useErrorInfoStore()
- const msg = getErrorInfoByCode(res.RetCode ?? res.Status)
- const error = String(res.RetDesc || res.RetCode || res.Status)
- return Promise.reject(msg ?? error)
- }
- }
- }
- })
|