| import cache from '@/plugins/cache' | 
| import axiosInstance from './index' | 
| import Vue from 'vue' | 
| import TwoFAWindow from '@/components/common/TwoFAWindow' | 
| const requestMethods = ['get', 'post', 'delete', 'put', 'head', 'options', 'patch', 'request'] | 
| const extendsMethods = {} | 
|   | 
| /** | 
|  * 模拟Promise,达到Promise的then,catch和finally可以重复执行 | 
|  * | 
|  * @param fn 回调 | 
|  */ | 
| const RepeatablePromise = function (fn) { | 
|   this.__then = [] | 
|   this.__catch = null | 
|   this.__finally = null | 
|   this.then = function (thenFn) { | 
|     this.__then.push(thenFn) | 
|     return this | 
|   } | 
|   this.catch = function (catchFn) { | 
|     this.__catch = catchFn | 
|     return this | 
|   } | 
|   this.finally = function (finallyFn) { | 
|     this.__finally = finallyFn | 
|     return this | 
|   } | 
|   fn(data => { | 
|     try { | 
|       let returnData = null | 
|       for (let i = 0; i < this.__then.length; i++) { | 
|         if (i === 0) { | 
|           returnData = this.__then[i](data) | 
|         } else { | 
|           returnData = this.__then[i](returnData) | 
|         } | 
|       } | 
|     } catch (e) { | 
|       if (this.__catch) { | 
|         throw new Error('Eva: ') | 
|       } | 
|       this.__catch && this.__catch(e) | 
|     } | 
|     this.__finally && this.__finally() | 
|   }, e => { | 
|     this.__catch && this.__catch(e) | 
|     this.__finally && this.__finally() | 
|   }) | 
| } | 
|   | 
| /** | 
|  * 构建基础请求对象Promise代理对象 | 
|  * | 
|  * @param method 请求方式 | 
|  * @param args 请求参数 | 
|  * @returns {{__access(*, *=): *, finally(): *, then(): *, catch(): *, __result_promise: null, __arguments: *}|*} | 
|  */ | 
| const buildBasePromiseProxy = (method, args) => { | 
|   return { | 
|     // post,get等请求方法的调用参数 | 
|     __arguments: args, | 
|     // 请求结果的promise对象 | 
|     __result_promise: null, | 
|     // 代理then方法,直接调用目标promise的then方法 | 
|     then () { | 
|       return this.__access('then', arguments) | 
|     }, | 
|     // 代理catch方法,直接调用目标promise的catch方法 | 
|     catch () { | 
|       return this.__access('catch', arguments) | 
|     }, | 
|     // 代理finally方法,直接调用目标promise的finally方法 | 
|     finally () { | 
|       return this.__access('finally', arguments) | 
|     }, | 
|     __access (methodName, args) { | 
|       if (this.__result_promise != null) { | 
|         return this.__result_promise[methodName].apply(this.__result_promise, args) | 
|       } | 
|       // 开启了2FA认证 | 
|       if (this.__with_2fa) { | 
|         if (this.__2fa_window != null) { | 
|           this.__result_promise = new RepeatablePromise((resolve, reject) => { | 
|             this.__2fa_window.$on('then', resolve) | 
|             this.__2fa_window.$on('catch', reject) | 
|             this.__2fa_window.$on('cancel', reject) | 
|           }) | 
|           // - 打开窗口,在此处打开窗口,意味着必须执行then,catch或finally才会打开2fa认证窗口 | 
|           this.__2fa_window.open(axiosInstance, method, this.__arguments) | 
|         } | 
|       } | 
|       // 未开启2fa的情况下,直接发送请求 | 
|       if (this.__result_promise == null) { | 
|         this.__result_promise = axiosInstance[method].apply(axiosInstance, this.__arguments) | 
|       } | 
|       // 如果开启了缓存,则在请求成功后写入缓存 | 
|       if (this.__with_cache) { | 
|         this.__result_promise.then(data => { | 
|           this.__cache_impl.set(this.__cache_key, data) | 
|           return data | 
|         }) | 
|       } | 
|       return this.__result_promise[methodName].apply(this.__result_promise, args) | 
|     } | 
|   } | 
| } | 
|   | 
| /** | 
|  * 构建缓存请求对象Promise代理对象 | 
|  * | 
|  * @param cacheKey 缓存key | 
|  * @param method 请求方式 | 
|  * @param args 请求参数 | 
|  * @param cacheImplName 缓存实现名称 | 
|  * @returns {{cache(): *, __with_cache: boolean, __cache_key: *, __cache_impl: *}|Promise<any>|buildCachePromiseProxy} | 
|  */ | 
| const buildCachePromiseProxy = (cacheKey, method, args, cacheImplName) => { | 
|   return { | 
|     // 缓存标记 | 
|     __with_cache: true, | 
|     // 缓存key | 
|     __cache_key: cacheKey, | 
|     // 缓存实现 | 
|     __cache_impl: cache[cacheImplName], | 
|     // 从缓存中获取数据 | 
|     cache () { | 
|       // 从缓存中获取数据 | 
|       const data = this.__cache_impl.get(cacheKey) | 
|       // 如果从缓存中获取到了数据,则直接构造一个成功的promise | 
|       if (data != null) { | 
|         this.__result_promise = Promise.resolve(data) | 
|       } | 
|       // 如果已经获取到了数据,则由以上成功的promise来接手then和catch的处理 | 
|       if (this.__result_promise != null) { | 
|         return this.__result_promise | 
|       } | 
|       return this | 
|     } | 
|   } | 
| } | 
|   | 
| /** | 
|  * 构建2FA请求对象Promise代理对象 | 
|  * | 
|  * @param twoFAWindow 2FA认证窗口实例 | 
|  * @returns {{__2fa_window: *, __with_2fa: boolean}} | 
|  */ | 
| const build2FAPromiseProxy = twoFAWindow => { | 
|   return { | 
|     // 2fa标记 | 
|     __with_2fa: true, | 
|     // 2fa窗口对象 | 
|     __2fa_window: twoFAWindow | 
|   } | 
| } | 
|   | 
| /** | 
|  * 扩展方法:开启缓存 | 
|  * | 
|  * @param cacheKey 缓存的key | 
|  * @param isLocal 是否缓存到本地缓存LocalStorage,为false时缓存到SessionStorage | 
|  * @usage:request.cache('test').[post(), get()...] | 
|  * @returns {{isExtendsAxiosInstance: boolean, post: Function, get: Function, ...}} | 
|  */ | 
| extendsMethods.cache = function (cacheKey, isLocal = false) { | 
|   if (cacheKey == null) { | 
|     throw Error('Request cache key can not be null.') | 
|   } | 
|   let cacheAxiosInstance = { | 
|     // 标记为axios扩展实例,用于与原生axios作区分 | 
|     isExtendsAxiosInstance: true | 
|   } | 
|   if (this.isExtendsAxiosInstance) { | 
|     cacheAxiosInstance = this | 
|   } | 
|   for (const method of requestMethods) { | 
|     if (cacheAxiosInstance[method] == null) { | 
|       cacheAxiosInstance[method] = function () { | 
|         return { | 
|           ...buildBasePromiseProxy(method, arguments), | 
|           ...buildCachePromiseProxy(cacheKey, method, arguments, isLocal ? 'local' : 'session') | 
|         } | 
|       } | 
|       continue | 
|     } | 
|     // 不为null时说明在调用cache前调用了其他扩展方法,此时诸如post,get方法的返回值做合并,防止扩展方法丢失。 | 
|     const originMethod = cacheAxiosInstance[method] | 
|     cacheAxiosInstance[method] = function () { | 
|       const request = originMethod() | 
|       Object.assign(request, { | 
|         ...buildBasePromiseProxy(method, arguments), | 
|         ...buildCachePromiseProxy(cacheKey, method, arguments, isLocal ? 'local' : 'session') | 
|       }) | 
|       return request | 
|     } | 
|   } | 
|   // 添加扩展方法 | 
|   for (const key in extendsMethods) { | 
|     cacheAxiosInstance[key] = extendsMethods[key] | 
|   } | 
|   return cacheAxiosInstance | 
| } | 
|   | 
| /** | 
|  * 扩展方法:开启2FA认证 | 
|  * | 
|  * @usage:request.twoFA().[post(), get()...] | 
|  * @returns {{isExtendsAxiosInstance: boolean, post: Function, get: Function, ...}} | 
|  */ | 
| extendsMethods.twoFA = function (props) { | 
|   // 打开2FA窗口 | 
|   let $twoFAWindow = null | 
|   // - 只有在为获取到密码时(未保存密码或密码已过期)时才打开2FA窗口 | 
|   if (cache.twoFA.getPassword() == null) { | 
|     const TwoFAWindowVue = Vue.extend(TwoFAWindow) | 
|     $twoFAWindow = new TwoFAWindowVue({ | 
|       el: document.createElement('div'), | 
|       propsData: props | 
|     }) | 
|     document.body.appendChild($twoFAWindow.$el) | 
|   } | 
|   let twofaAxiosInstance = { | 
|     // 标记为axios扩展实例,用于与原生axios作区分 | 
|     isExtendsAxiosInstance: true | 
|   } | 
|   if (this.isExtendsAxiosInstance) { | 
|     twofaAxiosInstance = this | 
|   } | 
|   for (const method of requestMethods) { | 
|     if (twofaAxiosInstance[method] == null) { | 
|       twofaAxiosInstance[method] = function () { | 
|         return { | 
|           ...buildBasePromiseProxy(method, arguments), | 
|           ...build2FAPromiseProxy($twoFAWindow) | 
|         } | 
|       } | 
|       continue | 
|     } | 
|     // 不为null时说明在调用twoFA前调用了其他扩展方法,此时诸如post,get方法的返回值做合并,防止扩展方法丢失。 | 
|     const originMethod = twofaAxiosInstance[method] | 
|     twofaAxiosInstance[method] = function () { | 
|       const request = originMethod() | 
|       Object.assign(request, { | 
|         ...buildBasePromiseProxy(method, arguments), | 
|         ...build2FAPromiseProxy($twoFAWindow) | 
|       }) | 
|       return request | 
|     } | 
|   } | 
|   // 添加扩展方法 | 
|   for (const key in extendsMethods) { | 
|     twofaAxiosInstance[key] = extendsMethods[key] | 
|   } | 
|   return twofaAxiosInstance | 
| } | 
|   | 
| export default extendsMethods |