完善前端项目结构和依赖配置
- 更新 package.json 中的依赖版本号,包括 element-plus、axios、pinia、vue-router 等 - 删除 HelloWorld 组件,替换为 router-view 以支持路由功能 - 添加 auth、category、customer、dashboard、medicine、role、stock、stockIn、stockOut、 supplier、user 等多个 API 接口文件 - 创建权限指令、主布局组件和全局样式 - 集成 Element Plus UI 框架并注册图标组件 - 实现应用状态管理和用户状态管理 Store - 配置 Vue Router 路由系统,支持动态菜单路由生成 - 移除旧的 CSS 样式文件,改用 SCSS 全局样式 ```
This commit is contained in:
109
frontend/src/router/index.js
Normal file
109
frontend/src/router/index.js
Normal file
@@ -0,0 +1,109 @@
|
||||
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: '/',
|
||||
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'),
|
||||
}
|
||||
|
||||
// 根据后端菜单数据生成路由
|
||||
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
|
||||
}
|
||||
|
||||
// TODO: 暂时跳过登录验证(开发阶段)
|
||||
// if (!userStore.token) {
|
||||
// next('/login')
|
||||
// return
|
||||
// }
|
||||
|
||||
// 动态注册菜单路由(仅首次),开发阶段使用本地 mock 菜单
|
||||
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
|
||||
Reference in New Issue
Block a user