From df689df9515e0587428a1492fb7ae914194818d9 Mon Sep 17 00:00:00 2001 From: "DESKTOP-31IBRMI\\Administrator" <1509326266@qq.com> Date: Tue, 10 Sep 2024 14:57:26 +0800 Subject: [PATCH] refactor(projects): add logout route --- build/plugins/router.ts | 3 +- packages/simple-router/src/router.tsx | 2 - packages/simple-router/src/types/index.ts | 5 +- src/hooks/common/routerPush.ts | 9 +- .../global-header/components/UserAvatar.tsx | 18 +-- src/locales/langs/en-us/route.ts | 1 + src/locales/langs/zh-cn/route.ts | 1 + src/router/elegant/transform.ts | 108 +++++++++--------- src/router/routes/builtin.ts | 35 +++++- src/router/routes/index.ts | 5 - src/store/index.ts | 15 +-- src/store/slice/auth/index.ts | 1 + src/store/slice/route/index.ts | 33 ++---- src/types/elegant-router.d.ts | 4 + 14 files changed, 126 insertions(+), 114 deletions(-) diff --git a/build/plugins/router.ts b/build/plugins/router.ts index 1c6b294..51ff310 100644 --- a/build/plugins/router.ts +++ b/build/plugins/router.ts @@ -22,7 +22,8 @@ export function setupElegantRouter() { 'document_vite', 'document_unocss', 'document_proComponents', - 'document_antd' + 'document_antd', + 'logout' ] }, onRouteMetaGen(routeName) { diff --git a/packages/simple-router/src/router.tsx b/packages/simple-router/src/router.tsx index e31193c..94f1540 100644 --- a/packages/simple-router/src/router.tsx +++ b/packages/simple-router/src/router.tsx @@ -10,7 +10,6 @@ import CreateRouterMatcher from './matcher'; import type { RouteRecordNormalized, RouteRecordRaw } from './matcher/types'; import { START_LOCATION_NORMALIZED } from './types'; import { RouterContext } from './hooks/useRouter'; - import { warn } from './warning'; const historyCreatorMap: Record< @@ -102,7 +101,6 @@ class CreateRouter { return reactRoute; }) .filter(Boolean); - console.log(this.reactRouter); // Add to react-router's routes this.reactRouter.patchRoutes(parent, reactRoutes); diff --git a/packages/simple-router/src/types/index.ts b/packages/simple-router/src/types/index.ts index 19c25bb..f017188 100644 --- a/packages/simple-router/src/types/index.ts +++ b/packages/simple-router/src/types/index.ts @@ -1,5 +1,6 @@ -// eslint-disable-next-line @typescript-eslint/ban-ts-comment - +/* eslint-disable */ +/* prettier-ignore */ +// @ts-nocheck import type { ElegantConstRoute, RouteMeta } from '@ohh-889/react-auto-route'; import type { RouteObject } from 'react-router-dom'; import type { Router as RemixRouter } from '@remix-run/router'; diff --git a/src/hooks/common/routerPush.ts b/src/hooks/common/routerPush.ts index ad88f37..3b5def0 100644 --- a/src/hooks/common/routerPush.ts +++ b/src/hooks/common/routerPush.ts @@ -75,11 +75,7 @@ export function useRouterPush() { async function toLogin(loginModule?: UnionKey.LoginModule, redirectUrl?: string) { const module = loginModule || 'pwd-login'; - const options: RouterPushOptions = { - params: { - module - } - }; + const options: RouterPushOptions = {}; const redirect = redirectUrl || router.currentRoute.fullPath; @@ -87,7 +83,7 @@ export function useRouterPush() { redirect }; - return routerPushByKey('login', options); + return routerPushByKey(`login_${module}`, options); } /** @@ -119,6 +115,7 @@ export function useRouterPush() { return { routerPush, routerBack, + routerPushByKey, toLogin, routerPushByKeyWithMetaQuery, redirectFromLogin, diff --git a/src/layouts/modules/global-header/components/UserAvatar.tsx b/src/layouts/modules/global-header/components/UserAvatar.tsx index 99143b8..20abe93 100644 --- a/src/layouts/modules/global-header/components/UserAvatar.tsx +++ b/src/layouts/modules/global-header/components/UserAvatar.tsx @@ -1,14 +1,16 @@ import { Button, Dropdown } from 'antd'; import type { MenuProps } from 'antd'; -import { useNavigate } from 'react-router-dom'; -import { resetStore, selectToken, selectUserInfo } from '@/store/slice/auth'; +import { useSubmit } from 'react-router-dom'; +import { selectToken, selectUserInfo } from '@/store/slice/auth'; const UserAvatar = memo(() => { const token = useAppSelector(selectToken); - const dispatch = useAppDispatch(); const { t } = useTranslation(); const userInfo = useAppSelector(selectUserInfo); - const navigate = useNavigate(); + const submit = useSubmit(); + const route = useRoute(); + const router = useRouterPush(); + function logout() { window?.$modal?.confirm({ title: t('common.tip'), @@ -16,7 +18,9 @@ const UserAvatar = memo(() => { okText: t('common.confirm'), cancelText: t('common.cancel'), onOk: () => { - loginOrRegister(); + let needRedirect = false; + if (!route.meta?.constant) needRedirect = true; + submit({ redirectFullPath: route.fullPath, needRedirect }, { method: 'post', action: '/logout' }); } }); } @@ -25,11 +29,11 @@ const UserAvatar = memo(() => { if (key === '1') { logout(); } else { - navigate('/user-center'); + router.routerPushByKey('user-center'); } } function loginOrRegister() { - dispatch(resetStore()); + router.routerPushByKey('login'); } const items: MenuProps['items'] = [ diff --git a/src/locales/langs/en-us/route.ts b/src/locales/langs/en-us/route.ts index fcc1f8e..ae63791 100644 --- a/src/locales/langs/en-us/route.ts +++ b/src/locales/langs/en-us/route.ts @@ -6,6 +6,7 @@ const route: App.I18n.Schema['translation']['route'] = { 'iframe-page': 'Iframe', home: 'Home', document: 'Document', + logout: 'Logout', document_project: 'Project Document', 'document_project-link': 'Project Document(External Link)', document_react: 'React Document', diff --git a/src/locales/langs/zh-cn/route.ts b/src/locales/langs/zh-cn/route.ts index 787973f..4a8f813 100644 --- a/src/locales/langs/zh-cn/route.ts +++ b/src/locales/langs/zh-cn/route.ts @@ -6,6 +6,7 @@ const route: App.I18n.Schema['translation']['route'] = { 'iframe-page': '外链页面', home: '首页', document: '文档', + logout: '退出登录', document_project: '项目文档', 'document_project-link': '项目文档(外链)', document_react: 'React文档', diff --git a/src/router/elegant/transform.ts b/src/router/elegant/transform.ts index 2cf759d..c1c3093 100644 --- a/src/router/elegant/transform.ts +++ b/src/router/elegant/transform.ts @@ -5,21 +5,20 @@ // Vue auto route: https://github.com/soybeanjs/elegant-router -import type { LazyRouteFunction, RouteObject,IndexRouteObject } from "react-router-dom"; -import type { FunctionComponent } from "react"; +import type { IndexRouteObject, LazyRouteFunction,RouteObject } from "react-router-dom"; +import type { FunctionComponent } from 'react'; import type { ElegantConstRoute } from '@ohh-889/react-auto-route'; -import type { RouteMap, RouteKey, RoutePath } from '@elegant-router/types'; -import { redirect as redirectTo } from 'react-router-dom' +import type { RouteKey, RouteMap, RoutePath } from '@elegant-router/types'; +import { redirect as redirectTo } from 'react-router-dom'; import ErrorBoundary from "../../../ErrorBoundary.tsx" - -type CustomRouteObject = Omit & { - Component?: React.ComponentType|null; +type CustomRouteObject = Omit & { + Component?: React.ComponentType | null; }; - /** * transform elegant const routes to react routes + * * @param routes elegant const routes * @param layouts layout components * @param views view components @@ -34,6 +33,7 @@ export function transformElegantRoutesToReactRoutes( /** * transform elegant route to react route + * * @param route elegant const route * @param layouts layout components * @param views view components @@ -41,8 +41,8 @@ export function transformElegantRoutesToReactRoutes( export function transformElegantRouteToReactRoute( route: ElegantConstRoute, layouts: Record>, - views: Record> -):RouteObject { + views: Record> +): RouteObject { const LAYOUT_PREFIX = 'layout.'; const VIEW_PREFIX = 'view.'; const ROUTE_DEGREE_SPLITTER = '_'; @@ -55,7 +55,7 @@ export function transformElegantRouteToReactRoute( function getLayoutName(component: string) { const layout = component.replace(LAYOUT_PREFIX, ''); - if(!layouts[layout]) { + if (!layouts[layout]) { throw new Error(`Layout component "${layout}" not found`); } @@ -69,7 +69,7 @@ export function transformElegantRouteToReactRoute( function getViewName(component: string) { const view = component.replace(VIEW_PREFIX, ''); - if(!views[view]) { + if (!views[view]) { throw new Error(`View component "${view}" not found`); } @@ -88,31 +88,36 @@ export function transformElegantRouteToReactRoute( const [layout, view] = component.split(FIRST_LEVEL_ROUTE_COMPONENT_SPLIT); return { - layout: layout?getLayoutName(layout):undefined, + layout: layout ? getLayoutName(layout) : undefined, view: getViewName(view) }; } + const { name, props, path, meta, component, children, redirect, layout, ...rest } = route; - const { name,props, path,meta, component, children,redirect,layout,loader, ...rest } = route; - - const reactRoute = {id:name, path,handle: { - ...meta - }, children:[],ErrorBoundary }as RouteObject + const reactRoute = { + id: name, + path, + handle: { + ...meta + }, + children: [], + ErrorBoundary + } as RouteObject; try { if (component) { if (isSingleLevelRoute(route)) { const { layout, view } = getSingleLevelRouteComponent(component); - if (layout) { - const singleLevelRoute:RouteObject= { + if (layout) { + const singleLevelRoute: RouteObject = { path, lazy: layouts[layout], ErrorBoundary, children: [ { - id:name, + id: name, index: true, lazy: views[view], handle: { @@ -123,77 +128,67 @@ export function transformElegantRouteToReactRoute( ] }; - return singleLevelRoute; + return singleLevelRoute; } - return { + return { path, lazy: views[view], id: name, ...rest - } as RouteObject; + } as RouteObject; } if (isLayout(component)) { if (layout) { - reactRoute.lazy=views[name] + reactRoute.lazy = views[name]; } else { const layoutName = getLayoutName(component); reactRoute.lazy = layouts[layoutName]; } - } - if (isView(component)) { const viewName = getViewName(component); if (props) { reactRoute.lazy = async () => { - const data= (await views[viewName]()).Component as FunctionComponent + const data = (await views[viewName]()).Component as FunctionComponent; return { - Component: ()=>data(props) , - ErrorBoundary: null - } - } + Component: () => data(props), + ErrorBoundary: null + }; + }; } else { - reactRoute.lazy = views[viewName] + reactRoute.lazy = views[viewName]; } } - - } + } else if (!layout && !redirect) { + return Object.assign(reactRoute, rest); + } } catch (error: any) { - console.error(`Error transforming route "${route.name}": ${error.toString()}`); + console.error(`Error transforming route "${route.name}": ${error.toString()}`); return {}; } - - - - - if (children?.length) { + if (children?.length) { reactRoute.children = children.flatMap(child => transformElegantRouteToReactRoute(child, layouts, views)); - const defaultRedirectPath = redirect || getRedirectPath(path as string, children[0].path as string); - - reactRoute.children.unshift({ - index: true, - loader: () => redirectTo(defaultRedirectPath), - ...rest - }); - }else if (redirect) { - reactRoute.loader=()=>redirectTo(redirect) - } - - if (loader) { - reactRoute.loader = () => loader + const defaultRedirectPath = redirect || getRedirectPath(path as string, children[0].path as string); + + reactRoute.children.unshift({ + index: true, + loader: () => redirectTo(defaultRedirectPath), + ...rest + }); + } else if (redirect) { + reactRoute.loader = () => redirectTo(redirect); } if (layout) { - return { lazy: layouts[layout], children: [reactRoute], ErrorBoundary - }as RouteObject; + } as RouteObject; } return reactRoute; @@ -217,6 +212,7 @@ const routeMap: RouteMap = { "document_unocss": "unocss", "document_procomponents": "procomponents", "document_antd": "antd", + "logout": "/logout", "403": "/403", "404": "/404", "500": "/500", diff --git a/src/router/routes/builtin.ts b/src/router/routes/builtin.ts index e43541b..c6f2c0f 100644 --- a/src/router/routes/builtin.ts +++ b/src/router/routes/builtin.ts @@ -1,5 +1,9 @@ import type { CustomRoute } from '@elegant-router/types'; import type { ElegantConstRoute } from '@ohh-889/react-auto-route'; +import type { ActionFunctionArgs } from 'react-router-dom'; +import { redirect } from 'react-router-dom'; +import { store } from '@/store'; +import { resetStore } from '@/store/slice/auth'; import { getRoutePath } from '../elegant/transform'; export const ROOT_ROUTE: CustomRoute = { @@ -22,5 +26,34 @@ const NOT_FOUND_ROUTE: CustomRoute = { } }; +/** - logout route 通过 action 触发做相关的登出操作 */ +/** - logout route triggers related logout operations through the action */ +const LOG_OUT_ROUTE: CustomRoute = { + name: 'logout', + path: '/logout', + action: async ({ request }: ActionFunctionArgs) => { + const formData = await request.formData(); + + store.dispatch(resetStore()); + + // 如果需要还需要调用登出接口 也是在这里 去做相关的操作 + // If needed, you can also call the logout API and perform related operations here + + const needRedirect = formData.get('needRedirect'); + + if (needRedirect) { + const redirectFullPath = formData.get('redirectFullPath'); + return redirect(`/login/pwd-login?redirect=${redirectFullPath}`); + } + + return redirect('/login/pwd-login'); + }, + meta: { + title: 'logout', + i18nKey: 'route.logout', + hideInMenu: true + } +}; + /** builtin routes, it must be constant and setup in vue-router */ -export const builtinRoutes: ElegantConstRoute[] = [ROOT_ROUTE, NOT_FOUND_ROUTE]; +export const builtinRoutes: ElegantConstRoute[] = [ROOT_ROUTE, NOT_FOUND_ROUTE, LOG_OUT_ROUTE]; diff --git a/src/router/routes/index.ts b/src/router/routes/index.ts index 889a066..0e35236 100644 --- a/src/router/routes/index.ts +++ b/src/router/routes/index.ts @@ -1,11 +1,6 @@ import type { CustomRoute, ElegantRoute } from '@elegant-router/types'; import { generatedRoutes } from '../elegant/routes'; -/** - * custom routes - * - * @link https://github.com/soybeanjs/elegant-router?tab=readme-ov-file#custom-route - */ /** * custom routes * diff --git a/src/store/index.ts b/src/store/index.ts index ee7b789..d6fb67f 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -5,22 +5,17 @@ import { themeSlice } from './slice/theme/index'; import { authSlice } from './slice/auth/index'; import { routeSlice } from './slice/route'; import { tabSlice } from './slice/tab'; + // `combineSlices` automatically combines the reducers using // their `reducerPath`s, therefore we no longer need to call `combineReducers`. const rootReducer = combineSlices(routeSlice, appSlice, authSlice, themeSlice, tabSlice); + // Infer the `RootState` type from the root reducer export type RootState = ReturnType; -export const makeStore = (preloadedState?: Partial) => { - const store = configureStore({ - reducer: rootReducer, - preloadedState - }); - // configure listeners using the provided defaults - // optional, but required for `refetchOnFocus`/`refetchOnReconnect` behaviors - return store; -}; -export const store = makeStore(); +export const store = configureStore({ + reducer: rootReducer +}); // Infer the type of `store` export type AppStore = typeof store; diff --git a/src/store/slice/auth/index.ts b/src/store/slice/auth/index.ts index 2dd3adc..e840c05 100644 --- a/src/store/slice/auth/index.ts +++ b/src/store/slice/auth/index.ts @@ -79,6 +79,7 @@ export const resetStore = (): AppThunk => dispatch => { clearAuthStorage(); dispatch(resetAuth()); + dispatch(resetRouteStore()); dispatch(cacheTabs()); diff --git a/src/store/slice/route/index.ts b/src/store/slice/route/index.ts index f1ff817..5243b0a 100644 --- a/src/store/slice/route/index.ts +++ b/src/store/slice/route/index.ts @@ -94,21 +94,6 @@ export const { getAuthRoutes, getSortRoutes, getIsInitConstantRoute, getConstant const authRouteMode = import.meta.env.VITE_AUTH_ROUTE_MODE; -/** - * Navigate to login page - * - * @param loginModule The login module - * @param redirectUrl The redirect url, if not specified, it will be the current route fullPath - */ -export const toLogin = - (redirectUrl?: string): AppThunk => - () => { - const nowRouteFullPath = router.currentRoute.fullPath; - - const redirect = redirectUrl || nowRouteFullPath; - - router.push({ name: 'login_pwd-login', query: { redirect } }); - }; const handleConstantOrAuthRoutes = (mode: 'constant' | 'auth'): AppThunk => (dispatch, getState) => { @@ -127,6 +112,7 @@ const handleConstantOrAuthRoutes = dispatch(addSortRoutes(sortRoutes)); }; + export const initConstantRoute = (): AppThunk => async dispatch => { const staticRoute = createStaticRoutes(); @@ -140,10 +126,12 @@ export const initConstantRoute = (): AppThunk => async dispatch => { dispatch(setConstantRoutes(staticRoute.constantRoutes)); } } + dispatch(handleConstantOrAuthRoutes('constant')); dispatch(setIsInitConstantRoute(true)); }; + const initStaticAuthRoute = (): AppThunk => (dispatch, getState) => { const { authRoutes: staticAuthRoutes } = createStaticRoutes(); @@ -159,23 +147,20 @@ const initStaticAuthRoute = (): AppThunk => (dispatch, getState) => { dispatch(handleConstantOrAuthRoutes('auth')); dispatch(setIsInitAuthRoute(true)); }; + export const initAuthRoute = (): AppThunk => (dispatch, getState) => { if (authRouteMode === 'static') { dispatch(initStaticAuthRoute()); } const routeHomeName = getRouteHome(getState()); + const homeRoute = router.getRouteByName(routeHomeName); + if (homeRoute) dispatch(initHomeTab({ route: homeRoute, homeRouteName: routeHomeName as LastLevelRouteKey })); }; export const resetRouteStore = (): AppThunk => dispatch => { - const currentRoute = router.currentRoute; - if (!currentRoute.meta?.constant) { - dispatch(toLogin()); - } - setTimeout(() => { - dispatch(resetRoute()); - router.resetRoute(); - dispatch(initConstantRoute()); - }, 100); + router.resetRoute(); + dispatch(resetRoute()); + dispatch(initConstantRoute()); }; diff --git a/src/types/elegant-router.d.ts b/src/types/elegant-router.d.ts index 020e3d8..5a602b0 100644 --- a/src/types/elegant-router.d.ts +++ b/src/types/elegant-router.d.ts @@ -31,6 +31,7 @@ declare module "@elegant-router/types" { "document_unocss": "unocss"; "document_procomponents": "procomponents"; "document_antd": "antd"; + "logout": "/logout"; "403": "/403"; "404": "/404"; "500": "/500"; @@ -95,6 +96,7 @@ declare module "@elegant-router/types" { | "document_unocss" | "document_procomponents" | "document_antd" + | "logout" >; /** @@ -129,6 +131,7 @@ declare module "@elegant-router/types" { | "not-found" | "exception" | "document" + | "logout" >; /** @@ -181,6 +184,7 @@ declare module "@elegant-router/types" { | "document_unocss" | "document_procomponents" | "document_antd" + | "logout" >; /**