import NotPermission from '@/components/error/403.tsx' import NotFound from '@/components/error/404.tsx' import ErrorPage from '@/components/error/error.tsx' import FetchLoading from '@/components/loading/FetchLoading.tsx' import PageLoading from '@/components/page-loading' import { Route as AuthenticatedImport } from '@/layout/_authenticated.tsx' import EmptyLayout from '@/layout/EmptyLayout.tsx' import ListPageLayout from '@/layout/ListPageLayout.tsx' import { Route as DashboardImport } from '@/pages/dashboard' import { Route as LoginRouteImport } from '@/pages/login' import { generateUUID } from '@/utils/uuid.ts' import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { AnyRoute, createLazyRoute, createRootRouteWithContext, createRoute, createRouter, Outlet, redirect, RouterProvider, } from '@tanstack/react-router' import { TanStackRouterDevtools } from '@tanstack/router-devtools' import { memo } from 'react' import RootLayout from './layout/RootLayout' import { IRootContext, MenuItem } from './types' import { DevTools } from 'jotai-devtools' export const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false, } } }) const rootRoute = createRootRouteWithContext()({ component: () => (
), beforeLoad: ({ location }) => { if (location.pathname === '/') { return redirect({ to: '/dashboard' }) } }, loader: () => { }, notFoundComponent: NotFound, pendingComponent: PageLoading, errorComponent: ({ error }) => , }) const emptyRoute = createRoute({ getParentRoute: () => rootRoute, id: '/_empty', component: EmptyLayout, }) const authRoute = AuthenticatedImport.update({ getParentRoute: () => rootRoute, id: '/_authenticated', } as any) const layoutNormalRoute = createRoute({ getParentRoute: () => rootRoute, id: '/_normal_layout', component: RootLayout, }) const layoutAuthRoute = createRoute({ getParentRoute: () => authRoute, id: '/_auth_layout', component: RootLayout, }) const notAuthRoute = createRoute({ getParentRoute: () => layoutNormalRoute, path: '/not-auth', component: NotPermission }) // const dashboardRoute = DashboardImport.update({ // path: '/dashboard', // getParentRoute: () => layoutAuthRoute, // } as any) const loginRoute = LoginRouteImport.update({ path: '/login', getParentRoute: () => emptyRoute, } as any) const menusRoute = createRoute({ getParentRoute: () => layoutAuthRoute, path: '/system/menus', }).lazy(async () => await import('@/pages/system/menus').then(d => d.Route)) const departmentsRoute = createRoute({ getParentRoute: () => layoutAuthRoute, path: '/system/departments', }).lazy(async () => await import('@/pages/system/departments').then(d => d.Route)) const usersRoute = createRoute({ getParentRoute: () => layoutAuthRoute, path: '/system/users', }).lazy(async () => await import('@/pages/system/users').then(d => d.Route)) const rolesRoute = createRoute({ getParentRoute: () => layoutAuthRoute, path: '/system/roles', }).lazy(async () => await import('@/pages/system/roles').then(d => d.Route)) declare module '@tanstack/react-router' { interface FileRoutesByPath { '/_authenticated': { preLoaderRoute: typeof AuthenticatedImport parentRoute: typeof rootRoute }, '/_normal_layout': { preLoaderRoute: typeof layoutNormalRoute parentRoute: typeof rootRoute }, '/_layout': { preLoaderRoute: typeof layoutAuthRoute parentRoute: typeof rootRoute }, '/': { preLoaderRoute: typeof DashboardImport parentRoute: typeof layoutAuthRoute }, '/dashboard': { preLoaderRoute: typeof DashboardImport parentRoute: typeof layoutAuthRoute }, '/login': { preLoaderRoute: typeof LoginRouteImport parentRoute: typeof rootRoute }, '/system/menus': { preLoaderRoute: typeof menusRoute parentRoute: typeof layoutAuthRoute }, '/system/departments': { preLoaderRoute: typeof departmentsRoute parentRoute: typeof layoutAuthRoute }, '/system/users': { preLoaderRoute: typeof usersRoute parentRoute: typeof layoutAuthRoute }, '/system/roles': { preLoaderRoute: typeof rolesRoute parentRoute: typeof layoutAuthRoute }, '/welcome': { preLoaderRoute: typeof rootRoute parentRoute: typeof layoutAuthRoute }, } } export const generateDynamicRoutes = (menuData: MenuItem[], parentRoute: AnyRoute) => { // 递归生成路由,如果有routes则递归生成子路由 const generateRoutes = (menu: MenuItem, parentRoute: AnyRoute) => { console.log('gen route', menu) const path = menu.path?.replace(parentRoute.options?.path, '') const isLayout = menu.children && menu.children.length > 0 && menu.type === 'menu' if (isLayout && (!menu.path || !menu.component)) { //没有component的layout,直接返回 console.log('no-page') return createRoute({ getParentRoute: () => layoutAuthRoute, id: `/layout-no-path-${generateUUID()}`, component: RootLayout, }) } // @ts-ignore 添加menu属性,方便后面获取 const options = { getParentRoute: () => parentRoute, menu, } as any if (isLayout) { options.id = path ?? `/layout-${generateUUID()}` } else { if (!path) { console.log(`${menu.name}没有设置视图`) } else { options.path = path } } console.log('gen route', options) //删除掉parentRoute的path,避免重复 const route = createRoute(options).lazy(async () => { // @ts-ignore 获取route中的menu属性 const menu = route.options.menu as MenuItem let component = menu.component // menu.type // 1,组件(页面),2,IFrame,3,外链接,4,按钮 if (menu.type === 'iframe') { component = '@/components/Iframe' } if (!component) { return createLazyRoute(options.path)({ component: () =>
404 Not Found
}) } //处理component路径 component = component.replace(/^\/pages/, '') component = component.replace(/^\//, '') console.log('load', `/pages/${component}`) /* @vite-ignore */ const d = await import(`/pages/${component}`) if (d.Route) { console.log(d.Route) return d.Route } if (d.GenRoute) { return d.GenRoute(options.path) } return createLazyRoute(options.path)({ component: d.default || d }) }) return route } // 对menuData递归生成路由,只处理type =1 的菜单 const did = (menus: MenuItem[], parentRoute: AnyRoute) => { return menus.filter((item) => item.type === 'menu').map((item, index) => { // 如果有children则递归生成子路由,同样只处理type =1 的菜单 const route = generateRoutes(item, parentRoute) // console.log(route) if (item.children && item.children.length > 0) { const children = did(item.children, route) if (children.length > 0) { route.addChildren(children) } } route.init({ originalIndex: index }) return route }) } const routes = did(menuData, parentRoute) parentRoute.addChildren(routes) } const routeTree = rootRoute.addChildren( [ //非Layout loginRoute, emptyRoute, //不带权限Layout layoutNormalRoute.addChildren([ notAuthRoute, ]), //带权限Layout // dashboardRoute, authRoute.addChildren( [ layoutAuthRoute /*.addChildren( [ menusRoute, departmentsRoute, usersRoute, rolesRoute, ] ),*/ ]), ] ) export const RootProvider = memo((props: { context: Partial }) => { generateDynamicRoutes(props.context.menuData ?? [], layoutAuthRoute) const router = createRouter({ routeTree, context: { queryClient, menuData: [] }, defaultPreload: 'intent' }) return ( ) })