|
|
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<IRootContext>()({ component: () => (
<div> <FetchLoading/> <Outlet/> <DevTools /> <TanStackRouterDevtools position={'bottom-right'}/> </div> ), beforeLoad: ({ location }) => { if (location.pathname === '/') { return redirect({ to: '/dashboard' }) } }, loader: () => {
}, notFoundComponent: NotFound, pendingComponent: PageLoading, errorComponent: ({ error }) => <ErrorPage error={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: () => <div>404 Not Found</div> }) }
//处理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<IRootContext> }) => {
generateDynamicRoutes(props.context.menuData ?? [], layoutAuthRoute)
const router = createRouter({ routeTree, context: { queryClient, menuData: [] }, defaultPreload: 'intent' })
return ( <QueryClientProvider client={queryClient}> <RouterProvider router={router} context={{ ...props.context, queryClient }}/> </QueryClientProvider> ) })
|