init: 管理会计OS初始代码
包含前后端完整代码: - 前端:Vue3+Vite+ElementPlus - 后端:FastAPI+SQLAlchemy - 模块:驾驶舱/KPI/战略地图/预警/预算/成本/预测/改善行动 - 当前版本:v1.0.0
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
import { hasRouteAccess } from '../permission'
|
||||
|
||||
const routes = [
|
||||
{ path: '/login', name: 'Login', component: () => import('@/views/Login.vue'), meta: { noAuth: true } },
|
||||
{ path: '/', component: () => import('@/layouts/MainLayout.vue'), redirect: '/dashboard',
|
||||
children: [
|
||||
{ path: 'dashboard', name: 'Dashboard', component: () => import('@/views/Dashboard.vue'), meta: { title: '驾驶舱', roles: ['ceo', 'finance', 'business', 'it'] } },
|
||||
{ path: 'kpis', name: 'KPIs', component: () => import('@/views/KPIList.vue'), meta: { title: 'KPI字典', roles: ['ceo', 'finance', 'business', 'it'] } },
|
||||
{ path: 'kpis/:id', name: 'KPIDetail', component: () => import('@/views/KPIDetail.vue'), meta: { title: 'KPI详情', roles: ['ceo', 'finance', 'business', 'it'] } },
|
||||
{ path: 'maps', name: 'Maps', component: () => import('@/views/MapList.vue'), meta: { title: '战略地图', roles: ['ceo', 'finance'] } },
|
||||
{ path: 'maps-review', name: 'MapReviewList', component: () => import('@/views/MapReview.vue'), meta: { title: '战略回顾会', roles: ['ceo', 'finance'] } },
|
||||
{ path: 'maps/canvas/:id', name: 'MapCanvas', component: () => import('@/views/MapCanvas.vue'), meta: { title: '战略地图画布', roles: ['ceo', 'finance'] } },
|
||||
{ path: 'maps/review/:id', name: 'MapReview', component: () => import('@/views/MapReview.vue'), meta: { title: '战略回顾会', roles: ['ceo', 'finance'] } },
|
||||
{ path: 'my-dashboard', name: 'MyDashboard', component: () => import('@/views/MyDashboard.vue'), meta: { title: '我的工作台', roles: ['ceo', 'finance', 'business', 'it'] } },
|
||||
{ path: 'knowledge', name: 'CMAKnowledge', component: () => import('@/views/CMAKnowledge.vue'), meta: { title: 'CMA知识库', roles: ['ceo', 'finance', 'business', 'it'] } },
|
||||
{ path: 'guide', name: 'NewUserGuide', component: () => import('@/views/NewUserGuide.vue'), meta: { title: '新手引导', roles: ['ceo', 'finance', 'business', 'it'] } },
|
||||
{ path: 'alerts', name: 'Alerts', component: () => import('@/views/AlertList.vue'), meta: { title: '预警中心', roles: ['ceo', 'finance', 'business', 'it'] } },
|
||||
{ path: 'data', name: 'Data', component: () => import('@/views/DataManage.vue'), meta: { title: '数据管理', roles: ['ceo', 'finance', 'it'] } },
|
||||
{ path: 'users', name: 'Users', component: () => import('@/views/UserManage.vue'), meta: { title: '用户管理', roles: ['ceo', 'it'] } },
|
||||
{ path: 'notifications', name: 'Notifications', component: () => import('@/views/NotificationManage.vue'), meta: { title: '通知配置', roles: ['ceo', 'it'] } },
|
||||
{ path: 'permissions', name: 'RolePermissions', component: () => import('@/views/RolePermissions.vue'), meta: { title: '系统设置', roles: ['ceo', 'it'] } },
|
||||
{ path: 'budget', name: 'BudgetManagement', component: () => import('@/views/BudgetManagement.vue'), meta: { title: '预算管理', roles: ['ceo', 'finance', 'it'] } },
|
||||
{ path: 'org', name: 'OrgManage', component: () => import('@/views/OrgManage.vue'), meta: { title: '组织管理', roles: ['ceo', 'it'] } },
|
||||
{ path: 'deviations', name: 'DeviationDashboard', component: () => import('@/views/DeviationDashboard.vue'), meta: { title: '差异分析', roles: ['ceo', 'finance', 'business', 'it'] } },
|
||||
{ path: 'cost', name: 'CostDashboard', component: () => import('@/views/CostDashboard.vue'), meta: { title: '成本分析', roles: ['ceo', 'finance', 'it'] } },
|
||||
{ path: 'predict', name: 'PredictDashboard', component: () => import('@/views/PredictDashboard.vue'), meta: { title: '预测模拟', roles: ['ceo', 'finance', 'it'] } },
|
||||
{ path: 'action-plans', name: 'ActionPlans', component: () => import('@/views/AlertList.vue'), meta: { title: '改善行动', roles: ['ceo', 'finance', 'business', 'it'], tab: 'plans' } },
|
||||
]
|
||||
},
|
||||
]
|
||||
|
||||
const router = createRouter({ history: createWebHistory(), routes })
|
||||
|
||||
router.beforeEach((to, _from, next) => {
|
||||
// 路由切换时清理所有残留的弹窗遮罩
|
||||
document.querySelectorAll('.el-overlay').forEach(el => el.remove())
|
||||
|
||||
const token = localStorage.getItem('cma_token')
|
||||
const userStr = localStorage.getItem('cma_user')
|
||||
|
||||
// 不需要登录的页面(如登录页)
|
||||
if (to.meta.noAuth) {
|
||||
if (token && to.path === '/login') {
|
||||
next('/dashboard')
|
||||
} else {
|
||||
next()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 检查登录
|
||||
if (!token || !userStr) {
|
||||
next('/login')
|
||||
return
|
||||
}
|
||||
|
||||
// 检查角色权限
|
||||
try {
|
||||
const user = JSON.parse(userStr)
|
||||
const role = user.role || ''
|
||||
const routeRoles = to.meta.roles as string[] | undefined
|
||||
|
||||
if (routeRoles && !routeRoles.includes(role)) {
|
||||
// 权限不足,跳转到驾驶舱或401页
|
||||
next('/dashboard')
|
||||
return
|
||||
}
|
||||
} catch {
|
||||
next('/login')
|
||||
return
|
||||
}
|
||||
|
||||
next()
|
||||
})
|
||||
|
||||
router.afterEach(() => {
|
||||
// 只清理残留的孤立遮罩(没有对应dialog的),不干扰正常弹窗
|
||||
setTimeout(() => {
|
||||
document.querySelectorAll('.el-overlay').forEach(el => {
|
||||
// 如果这个遮罩没有对应的dialog,说明是残留的,才删除
|
||||
const dialogId = el.getAttribute('aria-describedby')
|
||||
if (!dialogId || !document.querySelector(`#${dialogId}`)) {
|
||||
// 等待一帧确保 dialog 已渲染
|
||||
requestAnimationFrame(() => {
|
||||
if (!el.parentElement?.querySelector('.el-dialog')) {
|
||||
el.remove()
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}, 100)
|
||||
})
|
||||
|
||||
export default router
|
||||
Reference in New Issue
Block a user