import { createRouter, createWebHistory } from 'vue-router' import { useUserStore } from '@/stores/user' import MainLayout from '@/layout/MainLayout.vue' // 静态路由(无需权限) const constantRoutes = [ { path: '/login', name: 'Login', component: () => import('@/views/login/LoginView.vue'), meta: { title: '登录', noAuth: true }, }, { path: '/register', name: 'Register', component: () => import('@/views/login/RegisterView.vue'), meta: { title: '注册', noAuth: true }, }, { path: '/', name: 'MainLayout', component: MainLayout, redirect: '/dashboard', children: [ { path: 'dashboard', name: 'Dashboard', component: () => import('@/views/dashboard/DashboardView.vue'), meta: { title: '仪表盘', icon: 'Odometer' }, }, ], }, { path: '/:pathMatch(.*)*', redirect: '/dashboard', }, ] const router = createRouter({ history: createWebHistory(), routes: constantRoutes, }) // 动态路由映射(后端菜单 component 路径 → 页面组件) export const componentMap = { 'views/medicine/MedicineList': () => import('@/views/medicine/MedicineList.vue'), 'views/category/CategoryList': () => import('@/views/category/CategoryList.vue'), 'views/supplier/SupplierList': () => import('@/views/supplier/SupplierList.vue'), 'views/customer/CustomerList': () => import('@/views/customer/CustomerList.vue'), 'views/stock/StockList': () => import('@/views/stock/StockList.vue'), 'views/stockIn/StockInList': () => import('@/views/stockIn/StockInList.vue'), 'views/stockIn/StockInForm': () => import('@/views/stockIn/StockInForm.vue'), 'views/stockOut/StockOutList': () => import('@/views/stockOut/StockOutList.vue'), 'views/stockOut/StockOutForm': () => import('@/views/stockOut/StockOutForm.vue'), 'views/user/UserList': () => import('@/views/user/UserList.vue'), 'views/role/RoleList': () => import('@/views/role/RoleList.vue'), 'views/menu/MenuList': () => import('@/views/menu/MenuList.vue'), } // 根据后端菜单数据生成路由 function generateRoutes(menus) { const routes = [] menus.forEach((menu) => { if (menu.type === 2 && menu.path && menu.component) { routes.push({ path: menu.path.toLowerCase(), name: menu.name, component: componentMap[menu.component] || null, meta: { title: menu.name, icon: menu.icon }, }) } if (menu.children?.length) { routes.push(...generateRoutes(menu.children)) } }) return routes } let isMenusLoaded = false router.beforeEach(async (to, _from, next) => { const userStore = useUserStore() if (to.meta.noAuth) { next() return } if (!userStore.token) { next('/login') return } // 动态注册菜单路由(仅首次) if (!isMenusLoaded) { try { const menus = await userStore.getMenus() if (menus.length) { const dynamicRoutes = generateRoutes(menus) dynamicRoutes.forEach((route) => { router.addRoute('MainLayout', route) }) } } catch { // 后端未启动,跳过 } isMenusLoaded = true next({ ...to, replace: true }) return } next() }) export default router