import type { ReactNode } from 'react';
|
import { Navigate, Outlet, useLocation, useRoutes } from 'react-router-dom';
|
import type { RouteObject } from 'react-router-dom';
|
import BasicLayout from '@/layouts/BasicLayout';
|
import NotFound from '@/pages/error/NotFound';
|
import Login from '@/pages/login';
|
import { useAuthStore } from '@/store/auth';
|
import {
|
appRoutes,
|
findFirstPath,
|
type AppRouteItem,
|
} from './routeConfig';
|
|
/** 未登录时跳转登录页,并记录来源地址。 */
|
const RequireAuth = ({ children }: { children: ReactNode }) => {
|
const token = useAuthStore((state) => state.token);
|
const location = useLocation();
|
|
if (!token) {
|
return (
|
<Navigate
|
to="/login"
|
replace
|
state={{ from: `${location.pathname}${location.search}` }}
|
/>
|
);
|
}
|
|
return <>{children}</>;
|
};
|
|
/** 分组路由的默认跳转:进入第一个子页面。 */
|
const GroupIndexRedirect = ({ item }: { item: AppRouteItem }) => {
|
const target = findFirstPath(item);
|
|
return <Navigate to={target ?? '/dashboard'} replace />;
|
};
|
|
/** 把嵌套的菜单配置转换成 react-router 的嵌套路由。 */
|
const toRouteObjects = (items: AppRouteItem[], parentPath = ''): RouteObject[] =>
|
items.map((item) => {
|
const relativePath =
|
parentPath && item.path.startsWith(parentPath)
|
? item.path.slice(parentPath.length).replace(/^\//, '')
|
: item.path.replace(/^\//, '');
|
|
const childRoutes = item.children ? toRouteObjects(item.children, item.path) : [];
|
|
const route: RouteObject = {
|
path: relativePath,
|
element: item.element ?? <Outlet />,
|
};
|
|
if (childRoutes.length > 0) {
|
route.children = [
|
{ index: true, element: <GroupIndexRedirect item={item} /> },
|
...childRoutes,
|
];
|
}
|
|
return route;
|
});
|
|
const routes: RouteObject[] = [
|
{ path: '/login', element: <Login /> },
|
{
|
path: '/',
|
element: (
|
<RequireAuth>
|
<BasicLayout />
|
</RequireAuth>
|
),
|
children: [
|
{ index: true, element: <Navigate to="/dashboard" replace /> },
|
...toRouteObjects(appRoutes),
|
{ path: '*', element: <NotFound /> },
|
],
|
},
|
];
|
|
const AppRouter = () => useRoutes(routes);
|
|
export default AppRouter;
|