From ce523870804a37c636eed006265b62fd86e2fe41 Mon Sep 17 00:00:00 2001 From: kangod Date: Sat, 17 Feb 2024 19:59:18 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=20axios=20=E5=92=8C?= =?UTF-8?q?=20react-query=20=E7=9A=84=E5=B0=81=E8=A3=85=20feat:=20?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E8=8F=9C=E5=8D=95=E6=A8=A1=E5=9D=97=E7=9A=84?= =?UTF-8?q?=E4=B8=9A=E5=8A=A1=20api=20=E8=AE=BF=E9=97=AE=20hooks=EF=BC=8C?= =?UTF-8?q?=E4=BB=A5=E5=8F=8A=E5=85=A8=E5=B1=80=20antd=20=E7=9A=84=20messa?= =?UTF-8?q?ge?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/http/axios/service.ts | 67 ++++++++++++++++++++++++++++++++ src/http/tanstack/react-query.ts | 16 ++++++++ src/main.tsx | 33 +++++----------- src/services/menu.ts | 60 ++++++++++++++++++++++++++++ src/utils/antd-extract.ts | 9 +++++ 5 files changed, 162 insertions(+), 23 deletions(-) create mode 100644 src/http/axios/service.ts create mode 100644 src/http/tanstack/react-query.ts create mode 100644 src/services/menu.ts create mode 100644 src/utils/antd-extract.ts diff --git a/src/http/axios/service.ts b/src/http/axios/service.ts new file mode 100644 index 0000000..7bcbb39 --- /dev/null +++ b/src/http/axios/service.ts @@ -0,0 +1,67 @@ +import axios from 'axios'; + +import { globalError } from '@/utils/antd-extract'; +import { useUserToken } from '@/store/userStore'; + +// 刷新token的API调用 +// const refreshTokenApi = async () => { +// // 调用API +// const res = await service.get('auth/refresh', { +// params: { +// refreshToken: localStorage.getItem('refresh_token'), +// }, +// }); +// if (res) { +// // 更新token数据 +// FetcherStore.setState((state) => { +// state.token = res.data.accessToken; +// }); +// localStorage.setItem('refresh_token', res.data.refreshToken); +// } +// return res; +// }; +// 设置axios的额外配置 +export const service = axios.create({ + baseURL: import.meta.env.VITE_APP_BASE_API, +}); +// 拦截请求处理 +service.interceptors.request.use(async (params) => { + // 添加token + const userToken = useUserToken(); + if (userToken.accessToken) { + params.headers.set('Authorization', `Bearer ${userToken.accessToken}`); + } + return params; +}); +// 拦截响应处理 +service.interceptors.response.use( + async (response) => { + return response; + }, + async (error) => { + // if (import.meta.env.DEV) console.log('respError', error); + if (!error.response) + switch (error.response.status) { + case 401: { + // 如果响应401就把原本的FetcherStore数据设置为空,好让页面跳至登录页 + // FetcherStore.setState((state) => { + // state.token = null; + // }); + // // 响应401且不是刷新token的请求时,去主动调用刷新token请求 + // if (!error.response.config.url.includes('auth/refresh')) { + // const res = await refreshTokenApi(); + // if (res.status === 200) { + // return axios(error.response.config); + // } + // message.error('登录过期,请重新登录'); + // return Promise.reject(res.data); + // } + break; + } + default: + globalError(error); + break; + } + return Promise.reject(error); + }, +); diff --git a/src/http/tanstack/react-query.ts b/src/http/tanstack/react-query.ts new file mode 100644 index 0000000..9a6d15c --- /dev/null +++ b/src/http/tanstack/react-query.ts @@ -0,0 +1,16 @@ +import { QueryClient } from '@tanstack/react-query'; + +// 创建一个 client +export const queryClient = new QueryClient({ + defaultOptions: { + queries: { + // 设置HTTP状态码为403的时候不重试,其他情况取默认值 + retry: (_failureCount, error: any) => error.response?.status !== 403, + cacheTime: 300_000, // 缓存有效期 5m + staleTime: 10_1000, // 数据变得 "陈旧"(stale)的时间 10s + refetchOnWindowFocus: false, // 禁止窗口聚焦时重新获取数据 + refetchOnReconnect: false, // 禁止重新连接时重新获取数据 + refetchOnMount: false, // 禁止组件挂载时重新获取数据 + }, + }, +}); diff --git a/src/main.tsx b/src/main.tsx index c214e05..d06d6c3 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -1,5 +1,5 @@ // react-query -import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { QueryClientProvider } from '@tanstack/react-query'; import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; // react import { Suspense } from 'react'; @@ -10,6 +10,7 @@ import { HelmetProvider } from 'react-helmet-async'; import 'virtual:svg-icons-register'; import App from '@/App'; +import { queryClient } from '@/http/tanstack/react-query'; // i18n import './locales/i18n'; @@ -26,31 +27,17 @@ const charAt = ` `; console.info(`%c${charAt}`, 'color: #5BE49B'); -// 创建一个 client -const queryClient = new QueryClient({ - defaultOptions: { - queries: { - retry: 3, // 失败重试次数 - cacheTime: 300_000, // 缓存有效期 5m - staleTime: 10_1000, // 数据变得 "陈旧"(stale)的时间 10s - refetchOnWindowFocus: false, // 禁止窗口聚焦时重新获取数据 - refetchOnReconnect: false, // 禁止重新连接时重新获取数据 - refetchOnMount: false, // 禁止组件挂载时重新获取数据 - }, - }, -}); - const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement); root.render( - - - - - - - - , + + + + + + + + , ); // 不再使用 mock 数据,调用 nest 后端获取 diff --git a/src/services/menu.ts b/src/services/menu.ts new file mode 100644 index 0000000..3b97426 --- /dev/null +++ b/src/services/menu.ts @@ -0,0 +1,60 @@ +import { useMutation, useQuery } from '@tanstack/react-query'; + +import { InputType, OutputType } from '@/pages/setting/menus/list.page'; +import { globalSuccess } from '@/utils/antd-extract'; +import { service } from '@/http/axios/service'; +import { queryClient } from '@/http/tanstack/react-query'; + +/** + * 树结构查询 + */ +export const useListMenuTree = () => { + return useQuery(['listMenuTree'], async () => + service.get('menu/tree').then((res) => res.data), + ); +}; + +/** + * 树结构查询:给角色模块提供,用于数据隔离 + */ +export const useListMenuTreeForRole = () => { + return useQuery(['listMenuTreeForRole'], async () => + service.get('menu/tree').then((res) => res.data), + ); +}; + +/** + * 更新 + */ +export const useUpdateMenu = () => { + return useMutation(async (params: InputType) => service.patch('/menu', { ...params }), { + onSuccess: () => { + globalSuccess(); + queryClient.invalidateQueries(['listMenuTree']); + }, + }); +}; + +/** + * 新建 + */ +export const useCreateMenu = () => { + return useMutation(async (params: InputType) => service.post('/menu', { ...params }), { + onSuccess: () => { + globalSuccess(); + queryClient.invalidateQueries(['listMenuTree']); + }, + }); +}; + +/** + * 删除 + */ +export const useDeleteMenu = () => { + return useMutation(async (ids: number[]) => service.delete('/menu', { data: { ids } }), { + onSuccess: () => { + globalSuccess(); + queryClient.invalidateQueries(['listMenuTree']); + }, + }); +}; diff --git a/src/utils/antd-extract.ts b/src/utils/antd-extract.ts new file mode 100644 index 0000000..d3d3525 --- /dev/null +++ b/src/utils/antd-extract.ts @@ -0,0 +1,9 @@ +import { message } from 'antd'; +import { AxiosError } from 'axios'; + +import { Result } from '#/api'; + +export const globalSuccess = () => message.success('success', 2); +// export const globalError = (error: AxiosError) => message.error(error.message); +export const globalError = (error: AxiosError) => + message.error(error.response?.data.message ?? error.message);