diff --git a/packages/effects/plugins/src/alova/index.ts b/packages/effects/plugins/src/alova/index.ts index 1164cb3e1..62e709c1a 100644 --- a/packages/effects/plugins/src/alova/index.ts +++ b/packages/effects/plugins/src/alova/index.ts @@ -9,167 +9,267 @@ import type { RespondedAlovaGenerics, ResponseCompleteHandler, ResponseErrorHandler, + StatesHook, } from 'alova'; import type { AlovaRequestAdapterUnified, - ClientTokenAuthenticationOptions, + TokenAuthenticationResult, } from 'alova/client'; import { createAlova } from 'alova'; -import { createServerTokenAuthentication } from 'alova/client'; import adapterFetch from 'alova/fetch'; import VueHook from 'alova/vue'; -type RequestMethod = (method: Method) => Promise | void; +/** + * 请求拦截器方法类型 + */ +type RequestMethod = ( + method: Method, +) => Promise | void; -class AlovaClient { - public readonly instance: Alova; +/** + * 标准响应数据结构 + */ +interface ResponseData { + code?: number; + data?: T; + message?: string; + [key: string]: unknown; +} + +/** + * 响应成功拦截器方法类型 + */ +type ResponseSuccessMethod = ( + json: ResponseData, +) => Promise>; + +/** + * Alova HTTP客户端封装类 + * @template T 泛型参数,继承自AlovaGenerics + */ +class AlovaClient { + public readonly instance: Alova; + + /** + * 请求拦截器数组 + */ + public requestInterceptor: RequestMethod[] = []; + + /** + * 请求完成拦截器数组 + */ + public responseCompleteInterceptor: ResponseCompleteHandler[] = []; + + /** + * 请求错误拦截器数组 + */ + public responseErrorInterceptor: ResponseErrorHandler[] = []; - public requestInterceptor: RequestMethod[] = []; - public responseCompleteInterceptor: ResponseCompleteHandler[] = - []; - public responseErrorInterceptor: ResponseErrorHandler[] = []; - // public responseSuccessInterceptor: RespondedHandler[] = []; - public responseSuccessInterceptor: (( - Json: Record, - ) => Promise>)[] = []; + /** + * 请求成功拦截器数组 + */ + public responseSuccessInterceptor: ResponseSuccessMethod[] = []; + /** + * 构造函数 + * @param options Alova配置选项 + * @param authOptions 认证选项 + */ constructor( - options: AlovaOptions, - tokenOptions?: ClientTokenAuthenticationOptions, + options: AlovaOptions, + authOptions: TokenAuthenticationResult< + StatesHook, + AlovaRequestAdapterUnified + > = {}, ) { - const { baseURL = '' } = options; - // const { onAuthRequired, onResponseRefreshToken } = - // createClientTokenAuthentication({ - // // ... - // ...tokenOptions, - // }); - const { onAuthRequired, onResponseRefreshToken } = - createServerTokenAuthentication({ - // ... - ...tokenOptions, - }); + const { onAuthRequired, onResponseRefreshToken } = authOptions; + const beforeRequest = async (method: Method) => { + for (const interceptor of this.requestInterceptor) { + await interceptor(method); + } + }; + const responded = { + // 请求成功的拦截器 + // 当使用 `alova/fetch` 请求适配器时,第一个参数接收Response对象 + // 第二个参数为当前请求的method实例,你可以用它同步请求前后的配置信息 + onSuccess: async (response: Response, method: Method) => { + if (response.status >= 400) { + throw new Error(response.statusText); + } + const json = await response.json(); + + let result = json; + for (const interceptor of this.responseSuccessInterceptor) { + result = await interceptor(json); + } + + return result; + }, + + onError: async (err: Error, method: Method) => { + for (const interceptor of this.responseErrorInterceptor) { + await interceptor(err, method); + } + }, + + // 请求完成的拦截器 + // 当你需要在请求不论是成功、失败、还是命中缓存都需要执行的逻辑时,可以在创建alova实例时指定全局的`onComplete`拦截器,例如关闭请求 loading 状态。 + // 接收当前请求的method实例 + onComplete: async (method: Method) => { + // 处理请求完成逻辑 + for (const interceptor of this.responseCompleteInterceptor) { + await interceptor(method); + } + }, + }; this.instance = createAlova({ - baseURL, + baseURL: '', requestAdapter: adapterFetch(), statesHook: VueHook, - beforeRequest: onAuthRequired(async (method) => { - for (const interceptor of this.requestInterceptor) { - await interceptor(method); - } - }), + beforeRequest: onAuthRequired + ? onAuthRequired(beforeRequest) + : beforeRequest, // 使用 responded 对象分别指定请求成功的拦截器和请求失败的拦截器 - responded: onResponseRefreshToken({ - // 请求成功的拦截器 - // 当使用 `alova/fetch` 请求适配器时,第一个参数接收Response对象 - // 第二个参数为当前请求的method实例,你可以用它同步请求前后的配置信息 - onSuccess: async (response, method) => { - if (response.status >= 400) { - throw new Error(response.statusText); - } - const json = await response.json(); - - let result; - for (const interceptor of this.responseSuccessInterceptor) { - result = await interceptor(json); - } - - return result; - }, - - onError: async (err, method) => { - console.log(222); - for (const interceptor of this.responseErrorInterceptor) { - await interceptor(err, method); - } - }, - - // 请求完成的拦截器 - // 当你需要在请求不论是成功、失败、还是命中缓存都需要执行的逻辑时,可以在创建alova实例时指定全局的`onComplete`拦截器,例如关闭请求 loading 状态。 - // 接收当前请求的method实例 - onComplete: async (method) => { - // 处理请求完成逻辑 - for (const interceptor of this.responseCompleteInterceptor) { - await interceptor(method); - } - }, - }), + responded: onResponseRefreshToken + ? onResponseRefreshToken(responded) + : responded, + ...options, }); } - public addRequestInterceptor( - method: (method: Method) => Promise | void, - ) { + /** + * 添加请求拦截器 + * @param method 拦截器方法 + */ + public addRequestInterceptor(method: RequestMethod) { this.requestInterceptor.push(method); } - public addResponseCompleteInterceptor( - method: ResponseCompleteHandler, - ) { + /** + * 添加请求完成拦截器 + * @param method 拦截器方法 + */ + public addResponseCompleteInterceptor(method: ResponseCompleteHandler) { this.responseCompleteInterceptor.push(method); } - public addResponseErrorInterceptor( - method: ResponseErrorHandler, - ) { + /** + * 添加请求错误拦截器 + * @param method 拦截器方法 + */ + public addResponseErrorInterceptor(method: ResponseErrorHandler) { this.responseErrorInterceptor.push(method); } - public addResponseSuccessInterceptor( - method: (Json: Record) => Promise>, - ) { + /** + * 添加请求成功拦截器 + * @param method 拦截器方法 + */ + public addResponseSuccessInterceptor(method: ResponseSuccessMethod) { this.responseSuccessInterceptor.push(method); } + /** + * 发送DELETE请求 + * @param url 请求地址 + * @param data 请求数据 + * @param config 请求配置 + * @returns Method实例 + */ public delete( url: string, data?: RequestBody, - config?: AlovaMethodCreateConfig, - ): Method> { + config?: AlovaMethodCreateConfig, + ): Method> { return this.instance.Delete(url, config, data); } + /** + * 发送GET请求 + * @param url 请求地址 + * @param config 请求配置 + * @returns Method实例 + */ public get( url: string, - config?: AlovaMethodCreateConfig, - ): Method> { + config?: AlovaMethodCreateConfig, + ): Method> { return this.instance.Get(url, config); } + /** + * 发送HEAD请求 + * @param url 请求地址 + * @param config 请求配置 + * @returns Method实例 + */ public head( url: string, - config?: AlovaMethodCreateConfig, - ): Method> { + config?: AlovaMethodCreateConfig, + ): Method> { return this.instance.Head(url, config); } + /** + * 发送OPTIONS请求 + * @param url 请求地址 + * @param config 请求配置 + * @returns Method实例 + */ public options( url: string, - config?: AlovaMethodCreateConfig, - ): Method> { + config?: AlovaMethodCreateConfig, + ): Method> { return this.instance.Options(url, config); } + /** + * 发送PATCH请求 + * @param url 请求地址 + * @param data 请求数据 + * @param config 请求配置 + * @returns Method实例 + */ public patch( url: string, data?: RequestBody, - config?: AlovaMethodCreateConfig, - ): Method> { + config?: AlovaMethodCreateConfig, + ): Method> { return this.instance.Patch(url, data, config); } + /** + * 发送POST请求 + * @param url 请求地址 + * @param data 请求数据 + * @param config 请求配置 + * @returns Method实例 + */ public post( url: string, data?: RequestBody, - config?: AlovaMethodCreateConfig, - ): Method> { + config?: AlovaMethodCreateConfig, + ): Method> { return this.instance.Post(url, data, config); } + /** + * 发送PUT请求 + * @param url 请求地址 + * @param data 请求数据 + * @param config 请求配置 + * @returns Method实例 + */ public put( url: string, data?: RequestBody, - config?: AlovaMethodCreateConfig, - ): Method> { + config?: AlovaMethodCreateConfig, + ): Method> { return this.instance.Put(url, data, config); } + /** + * 发送自定义请求 + * @param config 请求配置 + * @returns Method实例 + */ public request( - config: AlovaMethodCommonConfig, - ): Method> { + config: AlovaMethodCommonConfig, + ): Method> { return this.instance.Request(config); } } -export { AlovaClient }; +export { AlovaClient, VueHook }; export * from 'alova'; export * from 'alova/client'; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3633c0a62..776ede4bb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -153,6 +153,9 @@ catalogs: '@vueuse/motion': specifier: ^3.0.3 version: 3.0.3 + alova: + specifier: ^3.3.4 + version: 3.3.4 ant-design-vue: specifier: ^4.2.6 version: 4.2.6 @@ -1705,6 +1708,9 @@ importers: '@vueuse/motion': specifier: 'catalog:' version: 3.0.3(magicast@0.3.5)(vue@3.5.17(typescript@5.8.3)) + alova: + specifier: 'catalog:' + version: 3.3.4 echarts: specifier: 'catalog:' version: 5.6.0 @@ -2011,6 +2017,9 @@ packages: resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} engines: {node: '>=10'} + '@alova/shared@1.3.1': + resolution: {integrity: sha512-ijSOaFLUFcVzMKSY3avoEE5C03/p9atjMDPBwvNkwnzaCrhv6/m4A121NdadF8YlHCRuifyYfz90IyEdMXTsJg==} + '@ampproject/remapping@2.3.0': resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} @@ -5559,6 +5568,10 @@ packages: alien-signals@1.0.13: resolution: {integrity: sha512-OGj9yyTnJEttvzhTUWuscOvtqxq5vrhF7vL9oS0xJ2mK0ItPYP1/y+vCFebfxoEyAz0++1AIwJ5CMr+Fk3nDmg==} + alova@3.3.4: + resolution: {integrity: sha512-UKKqXdvf8aQ4C7m3brO77YWe5CDz8N59PdAUz7M8gowKUUXTutbk0Vk5DRBrCe0hMUyyNMUhdCZ38llGxCViyQ==} + engines: {node: '>= 18.0.0'} + ansi-align@3.0.1: resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==} @@ -9883,6 +9896,9 @@ packages: resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} engines: {node: '>= 0.6'} + rate-limiter-flexible@5.0.5: + resolution: {integrity: sha512-+/dSQfo+3FYwYygUs/V2BBdwGa9nFtakDwKt4l0bnvNB53TNT++QSFewwHX9qXrZJuMe9j+TUaU21lm5ARgqdQ==} + rc9@2.1.2: resolution: {integrity: sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==} @@ -11857,6 +11873,8 @@ snapshots: '@alloc/quick-lru@5.2.0': {} + '@alova/shared@1.3.1': {} + '@ampproject/remapping@2.3.0': dependencies: '@jridgewell/gen-mapping': 0.3.12 @@ -15912,6 +15930,11 @@ snapshots: alien-signals@1.0.13: {} + alova@3.3.4: + dependencies: + '@alova/shared': 1.3.1 + rate-limiter-flexible: 5.0.5 + ansi-align@3.0.1: dependencies: string-width: 4.2.3 @@ -20549,6 +20572,8 @@ snapshots: range-parser@1.2.1: {} + rate-limiter-flexible@5.0.5: {} + rc9@2.1.2: dependencies: defu: 6.1.4