You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

314 lines
8.3 KiB

1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
  1. import NotPermission from '@/components/error/403.tsx'
  2. import NotFound from '@/components/error/404.tsx'
  3. import ErrorPage from '@/components/error/error.tsx'
  4. import FetchLoading from '@/components/loading/FetchLoading.tsx'
  5. import PageLoading from '@/components/page-loading'
  6. import { Route as AuthenticatedImport } from '@/layout/_authenticated.tsx'
  7. import EmptyLayout from '@/layout/EmptyLayout.tsx'
  8. import ListPageLayout from '@/layout/ListPageLayout.tsx'
  9. import { Route as DashboardImport } from '@/pages/dashboard'
  10. import { Route as LoginRouteImport } from '@/pages/login'
  11. import { generateUUID } from '@/utils/uuid.ts'
  12. import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
  13. import {
  14. AnyRoute,
  15. createLazyRoute,
  16. createRootRouteWithContext,
  17. createRoute,
  18. createRouter,
  19. Outlet,
  20. redirect,
  21. RouterProvider,
  22. } from '@tanstack/react-router'
  23. import { TanStackRouterDevtools } from '@tanstack/router-devtools'
  24. import { memo } from 'react'
  25. import RootLayout from './layout/RootLayout'
  26. import { IRootContext, MenuItem } from './types'
  27. import { DevTools } from 'jotai-devtools'
  28. export const queryClient = new QueryClient({
  29. defaultOptions: {
  30. queries: {
  31. retry: false,
  32. }
  33. }
  34. })
  35. const rootRoute = createRootRouteWithContext<IRootContext>()({
  36. component: () => (
  37. <div>
  38. <FetchLoading/>
  39. <Outlet/>
  40. <DevTools />
  41. <TanStackRouterDevtools position={'bottom-right'}/>
  42. </div>
  43. ),
  44. beforeLoad: ({ location }) => {
  45. if (location.pathname === '/') {
  46. return redirect({ to: '/dashboard' })
  47. }
  48. },
  49. loader: () => {
  50. },
  51. notFoundComponent: NotFound,
  52. pendingComponent: PageLoading,
  53. errorComponent: ({ error }) => <ErrorPage error={error}/>,
  54. })
  55. const emptyRoute = createRoute({
  56. getParentRoute: () => rootRoute,
  57. id: '/_empty',
  58. component: EmptyLayout,
  59. })
  60. const authRoute = AuthenticatedImport.update({
  61. getParentRoute: () => rootRoute,
  62. id: '/_authenticated',
  63. } as any)
  64. const layoutNormalRoute = createRoute({
  65. getParentRoute: () => rootRoute,
  66. id: '/_normal_layout',
  67. component: RootLayout,
  68. })
  69. const layoutAuthRoute = createRoute({
  70. getParentRoute: () => authRoute,
  71. id: '/_auth_layout',
  72. component: RootLayout,
  73. })
  74. const notAuthRoute = createRoute({
  75. getParentRoute: () => layoutNormalRoute,
  76. path: '/not-auth',
  77. component: NotPermission
  78. })
  79. // const dashboardRoute = DashboardImport.update({
  80. // path: '/dashboard',
  81. // getParentRoute: () => layoutAuthRoute,
  82. // } as any)
  83. const loginRoute = LoginRouteImport.update({
  84. path: '/login',
  85. getParentRoute: () => emptyRoute,
  86. } as any)
  87. const menusRoute = createRoute({
  88. getParentRoute: () => layoutAuthRoute,
  89. path: '/system/menus',
  90. }).lazy(async () => await import('@/pages/system/menus').then(d => d.Route))
  91. const departmentsRoute = createRoute({
  92. getParentRoute: () => layoutAuthRoute,
  93. path: '/system/departments',
  94. }).lazy(async () => await import('@/pages/system/departments').then(d => d.Route))
  95. const usersRoute = createRoute({
  96. getParentRoute: () => layoutAuthRoute,
  97. path: '/system/users',
  98. }).lazy(async () => await import('@/pages/system/users').then(d => d.Route))
  99. const rolesRoute = createRoute({
  100. getParentRoute: () => layoutAuthRoute,
  101. path: '/system/roles',
  102. }).lazy(async () => await import('@/pages/system/roles').then(d => d.Route))
  103. declare module '@tanstack/react-router' {
  104. interface FileRoutesByPath {
  105. '/_authenticated': {
  106. preLoaderRoute: typeof AuthenticatedImport
  107. parentRoute: typeof rootRoute
  108. },
  109. '/_normal_layout': {
  110. preLoaderRoute: typeof layoutNormalRoute
  111. parentRoute: typeof rootRoute
  112. },
  113. '/_layout': {
  114. preLoaderRoute: typeof layoutAuthRoute
  115. parentRoute: typeof rootRoute
  116. },
  117. '/': {
  118. preLoaderRoute: typeof DashboardImport
  119. parentRoute: typeof layoutAuthRoute
  120. },
  121. '/dashboard': {
  122. preLoaderRoute: typeof DashboardImport
  123. parentRoute: typeof layoutAuthRoute
  124. },
  125. '/login': {
  126. preLoaderRoute: typeof LoginRouteImport
  127. parentRoute: typeof rootRoute
  128. },
  129. '/system/menus': {
  130. preLoaderRoute: typeof menusRoute
  131. parentRoute: typeof layoutAuthRoute
  132. },
  133. '/system/departments': {
  134. preLoaderRoute: typeof departmentsRoute
  135. parentRoute: typeof layoutAuthRoute
  136. },
  137. '/system/users': {
  138. preLoaderRoute: typeof usersRoute
  139. parentRoute: typeof layoutAuthRoute
  140. },
  141. '/system/roles': {
  142. preLoaderRoute: typeof rolesRoute
  143. parentRoute: typeof layoutAuthRoute
  144. },
  145. '/welcome': {
  146. preLoaderRoute: typeof rootRoute
  147. parentRoute: typeof layoutAuthRoute
  148. },
  149. }
  150. }
  151. export const generateDynamicRoutes = (menuData: MenuItem[], parentRoute: AnyRoute) => {
  152. // 递归生成路由,如果有routes则递归生成子路由
  153. const generateRoutes = (menu: MenuItem, parentRoute: AnyRoute) => {
  154. console.log('gen route', menu)
  155. const path = menu.path?.replace(parentRoute.options?.path, '')
  156. const isLayout = menu.children && menu.children.length > 0 && menu.type === 'menu'
  157. if (isLayout && (!menu.path || !menu.component)) {
  158. //没有component的layout,直接返回
  159. console.log('no-page')
  160. return createRoute({
  161. getParentRoute: () => layoutAuthRoute,
  162. id: `/layout-no-path-${generateUUID()}`,
  163. component: RootLayout,
  164. })
  165. }
  166. // @ts-ignore 添加menu属性,方便后面获取
  167. const options = {
  168. getParentRoute: () => parentRoute,
  169. menu,
  170. } as any
  171. if (isLayout) {
  172. options.id = path ?? `/layout-${generateUUID()}`
  173. } else {
  174. if (!path) {
  175. console.log(`${menu.name}没有设置视图`)
  176. } else {
  177. options.path = path
  178. }
  179. }
  180. console.log('gen route', options)
  181. //删除掉parentRoute的path,避免重复
  182. const route = createRoute(options).lazy(async () => {
  183. // @ts-ignore 获取route中的menu属性
  184. const menu = route.options.menu as MenuItem
  185. let component = menu.component
  186. // menu.type
  187. // 1,组件(页面),2,IFrame,3,外链接,4,按钮
  188. if (menu.type === 'iframe') {
  189. component = '@/components/Iframe'
  190. }
  191. if (!component) {
  192. return createLazyRoute(options.path)({
  193. component: () => <div>404 Not Found</div>
  194. })
  195. }
  196. //处理component路径
  197. component = component.replace(/^\/pages/, '')
  198. component = component.replace(/^\//, '')
  199. console.log('load', `/pages/${component}`)
  200. /* @vite-ignore */
  201. const d = await import(`/pages/${component}`)
  202. if (d.Route) {
  203. console.log(d.Route)
  204. return d.Route
  205. }
  206. if (d.GenRoute) {
  207. return d.GenRoute(options.path)
  208. }
  209. return createLazyRoute(options.path)({
  210. component: d.default || d
  211. })
  212. })
  213. return route
  214. }
  215. // 对menuData递归生成路由,只处理type =1 的菜单
  216. const did = (menus: MenuItem[], parentRoute: AnyRoute) => {
  217. return menus.filter((item) => item.type === 'menu').map((item, index) => {
  218. // 如果有children则递归生成子路由,同样只处理type =1 的菜单
  219. const route = generateRoutes(item, parentRoute)
  220. // console.log(route)
  221. if (item.children && item.children.length > 0) {
  222. const children = did(item.children, route)
  223. if (children.length > 0) {
  224. route.addChildren(children)
  225. }
  226. }
  227. route.init({ originalIndex: index })
  228. return route
  229. })
  230. }
  231. const routes = did(menuData, parentRoute)
  232. parentRoute.addChildren(routes)
  233. }
  234. const routeTree = rootRoute.addChildren(
  235. [
  236. //非Layout
  237. loginRoute,
  238. emptyRoute,
  239. //不带权限Layout
  240. layoutNormalRoute.addChildren([
  241. notAuthRoute,
  242. ]),
  243. //带权限Layout
  244. // dashboardRoute,
  245. authRoute.addChildren(
  246. [
  247. layoutAuthRoute
  248. /*.addChildren(
  249. [
  250. menusRoute,
  251. departmentsRoute,
  252. usersRoute,
  253. rolesRoute,
  254. ]
  255. ),*/
  256. ]),
  257. ]
  258. )
  259. export const RootProvider = memo((props: { context: Partial<IRootContext> }) => {
  260. generateDynamicRoutes(props.context.menuData ?? [], layoutAuthRoute)
  261. const router = createRouter({
  262. routeTree,
  263. context: { queryClient, menuData: [] },
  264. defaultPreload: 'intent'
  265. })
  266. return (
  267. <QueryClientProvider client={queryClient}>
  268. <RouterProvider router={router} context={{ ...props.context, queryClient }}/>
  269. </QueryClientProvider>
  270. )
  271. })