init
This commit is contained in:
90
frontend/src/router/AppRouter.tsx
Normal file
90
frontend/src/router/AppRouter.tsx
Normal file
@@ -0,0 +1,90 @@
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import { Navigate, type RouteObject, useRoutes } from "react-router-dom";
|
||||
import { fetchDynamicRoutes } from "../api/upms";
|
||||
import { LoadingView } from "../components/LoadingView";
|
||||
import { DefaultLayout } from "../layouts/DefaultLayout";
|
||||
import { SidebarLayout } from "../layouts/SidebarLayout";
|
||||
import { DashboardPage } from "../pages/DashboardPage";
|
||||
import { LoginPage } from "../pages/LoginPage";
|
||||
import { NotFoundPage } from "../pages/NotFoundPage";
|
||||
import { RoutePlaceholderPage } from "../pages/RoutePlaceholderPage";
|
||||
import type { RouteNode } from "../types/route";
|
||||
|
||||
const layoutRegistry = {
|
||||
DEFAULT: DefaultLayout,
|
||||
SIDEBAR: SidebarLayout
|
||||
};
|
||||
|
||||
function toChildRoute(route: RouteNode): RouteObject {
|
||||
const Component = route.component === "dashboard" ? DashboardPage : RoutePlaceholderPage;
|
||||
|
||||
return {
|
||||
path: route.path === "/" ? "" : route.path.replace(/^\//, ""),
|
||||
element: <Component />
|
||||
};
|
||||
}
|
||||
|
||||
function buildRoutes(dynamicRoutes: RouteNode[]): RouteObject[] {
|
||||
const grouped = dynamicRoutes.reduce<Record<string, RouteNode[]>>((acc, route) => {
|
||||
acc[route.layout] ??= [];
|
||||
acc[route.layout].push(route);
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
const layoutRoutes = Object.entries(grouped).map(([layout, routes]) => {
|
||||
const Layout = layoutRegistry[layout as keyof typeof layoutRegistry] ?? DefaultLayout;
|
||||
return {
|
||||
path: "/",
|
||||
element: <Layout />,
|
||||
children: routes.map(toChildRoute)
|
||||
} satisfies RouteObject;
|
||||
});
|
||||
|
||||
return [
|
||||
{ path: "/login", element: <LoginPage /> },
|
||||
...layoutRoutes,
|
||||
{ path: "*", element: <NotFoundPage /> }
|
||||
];
|
||||
}
|
||||
|
||||
export function AppRouter() {
|
||||
const [dynamicRoutes, setDynamicRoutes] = useState<RouteNode[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
fetchDynamicRoutes()
|
||||
.then((routes) => setDynamicRoutes(routes))
|
||||
.catch(() =>
|
||||
setDynamicRoutes([
|
||||
{
|
||||
id: "dashboard",
|
||||
path: "/",
|
||||
name: "dashboard",
|
||||
component: "dashboard",
|
||||
layout: "SIDEBAR",
|
||||
meta: {
|
||||
title: "控制台",
|
||||
hidden: false,
|
||||
permissionCodes: ["dashboard:view"]
|
||||
},
|
||||
children: []
|
||||
}
|
||||
])
|
||||
)
|
||||
.finally(() => setLoading(false));
|
||||
}, []);
|
||||
|
||||
const routes = useMemo(() => {
|
||||
if (loading) {
|
||||
return [{ path: "*", element: <LoadingView message="正在加载路由..." /> }];
|
||||
}
|
||||
|
||||
const nextRoutes = buildRoutes(dynamicRoutes);
|
||||
if (dynamicRoutes.length === 0) {
|
||||
nextRoutes.unshift({ path: "/", element: <Navigate to="/login" replace /> });
|
||||
}
|
||||
return nextRoutes;
|
||||
}, [dynamicRoutes, loading]);
|
||||
|
||||
return useRoutes(routes);
|
||||
}
|
||||
Reference in New Issue
Block a user