- 配置.env文件支持环境变量管理 - 集成MyBatis Plus ORM框架并配置数据库连接 - 实现JWT认证和Spring Security安全配置 - 添加全局异常处理机制和统一响应结果封装 - 配置CORS跨域资源共享支持 - 实现用户认证API包括登录、注册、刷新token功能 - 开发完整的药品管理系统包含分类、药品、库存管理 - 实现出入库管理功能包括供应商、客户管理 - 添加角色权限管理和菜单配置 - 实现仪表盘统计和过期预警功能 - 配置分页查询和数据验证功能 ```
116 lines
3.2 KiB
JavaScript
116 lines
3.2 KiB
JavaScript
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
|