From b493d8ffbb4736b1dcae13691214245be3fd460e Mon Sep 17 00:00:00 2001 From: skycurtain Date: Wed, 6 Aug 2025 14:09:00 +0800 Subject: [PATCH] chore: request & query util --- src/axios.d.ts | 10 ++++ src/main.tsx | 19 +++++-- src/utils/request.ts | 129 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 154 insertions(+), 4 deletions(-) create mode 100644 src/axios.d.ts create mode 100644 src/utils/request.ts diff --git a/src/axios.d.ts b/src/axios.d.ts new file mode 100644 index 0000000..97d0566 --- /dev/null +++ b/src/axios.d.ts @@ -0,0 +1,10 @@ +export interface Result { + code: number + data: T + errorMsg: string + extra: unknown + isSuccess: boolean + msg: string + path?: string + timestamp: string +} diff --git a/src/main.tsx b/src/main.tsx index 24b2901..34c5e6e 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -1,16 +1,26 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; import { createRouter, RouterProvider } from '@tanstack/react-router'; import { StrictMode } from 'react'; import { createRoot } from 'react-dom/client'; - -import { routeTree } from './routeTree.gen.ts'; - import '@ant-design/v5-patch-for-react-19'; import 'antd/dist/reset.css'; +import { routeTree } from './routeTree.gen.ts'; +import { getAppEnvConfig } from './utils/env.ts'; + const router = createRouter({ routeTree }); -const queryClient = new QueryClient(); +const queryClient = new QueryClient({ + defaultOptions: { + queries: { + refetchInterval: getAppEnvConfig().requestInterval * 1000, + refetchIntervalInBackground: false, + refetchOnReconnect: true, + refetchOnWindowFocus: true, + }, + }, +}); declare module '@tanstack/react-router' { interface Register { @@ -24,6 +34,7 @@ if (!rootElement.innerHTML) { + , ); diff --git a/src/utils/request.ts b/src/utils/request.ts new file mode 100644 index 0000000..c20aa64 --- /dev/null +++ b/src/utils/request.ts @@ -0,0 +1,129 @@ +import type { AxiosError, AxiosInstance, AxiosRequestConfig, AxiosResponse, CreateAxiosDefaults } from 'axios'; + +import axios from 'axios'; + +import type { Result } from '@/axios'; + +import { getAppEnvConfig } from './env'; + +export type Response = [err: AxiosError | null, data: T | null, resp: Result | null]; + +export class Request { + private instance: AxiosInstance; + + private abortController: AbortController; + private lastAbortController: AbortController | null; + private uniq: boolean; + + constructor(config?: CreateAxiosDefaults) { + this.instance = axios.create(config); + this.abortController = new AbortController(); + this.lastAbortController = null; + this.uniq = false; + + this.instance.interceptors.request.use((config) => { + // 取消上一次请求 + if (this.uniq && this.lastAbortController?.signal) { + this.lastAbortController.abort(); + } + this.lastAbortController = this.abortController; + this.abortController = new AbortController(); + // 业务登录所需headers + const { lampAuthorization, lampClientId, lampClientSecret } = getAppEnvConfig(); + const newAuthorization = window.btoa(`${lampClientId}:${lampClientSecret}`); + const authorization = lampAuthorization.trim() !== '' ? lampAuthorization : newAuthorization; + config.headers.set('accept-language', 'zh-CN,zh;q=0.9'); + config.headers.set('accept', 'application/json, text/plain, */*'); + // config.headers.set('Applicationid', '') + config.headers.set('Tenantid', '1'); + config.headers.set('Authorization', authorization); + // config.headers.set('token', this.extraInfo?.token ?? '') + return config; + }); + + this.instance.interceptors.response.use( + (response) => { + return response; + }, + (error) => { + const err = error as AxiosError; + if (err.status === 401) { + // + } + if (err.status === 404) { + // + } + return Promise.reject(error); + }, + ); + } + + get(url: string, option?: AxiosRequestConfig & { uniq?: boolean }): Promise> { + const { uniq, ...reqConfig } = option ?? {}; + this.uniq = !!uniq; + return new Promise((resolve) => { + this.instance + .get>(url, { + ...reqConfig, + signal: this.abortController.signal, + }) + .then((res) => { + resolve([null, res.data.data, res.data]); + }) + .catch((err) => { + resolve([err as AxiosError, null, null]); + }); + }); + } + + post(url: string, data: AxiosRequestConfig['data'], option?: Partial> & { retRaw?: boolean; uniq?: boolean; upload?: boolean }): Promise> { + const { retRaw, uniq, upload, ...reqConfig } = option ?? {}; + this.uniq = !!uniq; + return new Promise((resolve) => { + this.instance + .post(url, data, { ...reqConfig, headers: { 'content-type': upload ? 'multipart/form-data' : 'application/json' } }) + .then((res) => { + if (retRaw) { + const data = res as T; + resolve([null, data, null]); + } else { + const resp = res as AxiosResponse>; + resolve([null, resp.data.data, resp.data]); + } + }) + .catch((err) => { + resolve([err as AxiosError, null, null]); + }); + }); + } + + put(url: string, data: AxiosRequestConfig['data'], option?: Partial> & { uniq?: boolean }): Promise> { + const { uniq, ...reqConfig } = option ?? {}; + this.uniq = !!uniq; + return new Promise((resolve) => { + this.instance + .put>(url, data, { ...reqConfig }) + .then((res) => { + resolve([null, res.data.data, res.data]); + }) + .catch((err) => { + resolve([err as AxiosError, null, null]); + }); + }); + } + + delete(url: string, idList: string[], option?: Partial> & { uniq?: boolean }): Promise> { + const { uniq, ...reqConfig } = option ?? {}; + this.uniq = !!uniq; + return new Promise((resolve) => { + this.instance + .delete>(url, { ...reqConfig, data: { ids: idList } }) + .then((res) => { + resolve([null, res.data.data, res.data]); + }) + .catch((err) => { + resolve([err as AxiosError, null, null]); + }); + }); + } +}