Files
cma-management/frontend/src/router/index.ts
T
Hermes CI Fix a64f184525 feat: 数据分类分级 — 重要数据标记+资产清单+CSV导出(8/20评估办法政策驱动)
- subjects/kpi_definitions 新增 important_flag/data_level/data_category 列
- 新增 /api/cma/data-classification/* API: inventory/stats/标记/批量/export/industry-reference
- 数据级别: core核心/important重要/general一般(GB/T 43697 简化)
- 前端 DataClassification.vue: 统计概览+清单+打标+导出+行业参考目录
- pytest 17例覆盖(含多租户隔离验证)
2026-08-26 07:51:39 +08:00

119 lines
9.8 KiB
TypeScript

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: '/my-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'], editable: true } },
{ path: 'kpis/:id', name: 'KPIDetail', component: () => import('@/views/KPIDetail.vue'), meta: { title: 'KPI详情', roles: ['ceo', 'finance', 'business', 'it'], editable: true } },
{ path: 'maps', name: 'Maps', component: () => import('@/views/MapList.vue'), meta: { title: '战略地图', roles: ['ceo', 'finance'], editable: true } },
{ path: 'customer', name: 'CustomerDimension', component: () => import('@/views/CustomerDashboard.vue'), meta: { title: '客户维度', roles: ['ceo', 'finance', 'business', 'it'] } },
{ path: 'learning-dashboard', name: 'LearningDashboard', component: () => import('@/views/LearningDashboard.vue'), meta: { title: '学习成长看板', roles: ['ceo', 'finance', 'it'] } },
{ 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'], editable: true } },
{ 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'], editable: true } },
{ 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'], editable: true } },
{ 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'], editable: true } },
{ path: 'notifications', name: 'Notifications', component: () => import('@/views/NotificationManage.vue'), meta: { title: '通知配置', roles: ['ceo', 'it'], editable: true } },
{ path: 'permissions', name: 'RolePermissions', component: () => import('@/views/RolePermissions.vue'), meta: { title: '系统设置', roles: ['ceo', 'it'], editable: true } },
{ path: 'budget', name: 'BudgetManagement', component: () => import('@/views/BudgetManagement.vue'), meta: { title: '预算管理', roles: ['ceo', 'finance', 'it'], editable: true } },
{ path: 'org', name: 'OrgManage', component: () => import('@/views/OrgManage.vue'), meta: { title: '组织管理', roles: ['ceo', 'it'], editable: true } },
{ 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: 'predict/accuracy', name: 'PredictAccuracy', component: () => import('@/views/PredictAccuracy.vue'), meta: { title: '预测准确率', roles: ['ceo', 'finance', 'it'] } },
{ path: 'cost-intelligence', name: 'CostIntelligence', component: () => import('@/views/CostIntelligence.vue'), meta: { title: '预测性成本智能', roles: ['ceo', 'finance', 'it'] } },
{ path: 'real-options', name: 'RealOptions', component: () => import('@/views/RealOptions.vue'), meta: { title: '实物期权计算器', roles: ['ceo', 'finance'] } },
{ path: 'action-plans', name: 'ActionPlans', component: () => import('@/views/ActionPlanLibrary.vue'), meta: { title: '改善行动', roles: ['ceo', 'finance', 'business', 'it'], editable: true } },
{ path: 'reports', name: 'ReportCenter', component: () => import('@/views/ReportCenter.vue'), meta: { title: '管理报表', roles: ['ceo', 'finance', 'business'] } },
{ path: 'alignment', name: 'KPIAlignment', component: () => import('@/views/KPIAlignment.vue'), meta: { title: '战略执行看板', roles: ['ceo', 'finance', 'business', 'it'], editable: true } },
{ path: 'dupont-analysis', name: 'DupontAnalysis', component: () => import('@/views/DupontAnalysis.vue'), meta: { title: '杜邦分析', roles: ['ceo', 'finance', 'it'] } },
{ path: 'data-quality', name: 'DataQuality', component: () => import('@/views/DataQuality.vue'), meta: { title: '数据质量', roles: ['ceo', 'finance', 'it'] } },
{ path: 'bi-reports', name: 'BiReports', component: () => import('@/views/BIReportCenter.vue'), meta: { title: 'BI报表', roles: ['ceo', 'finance', 'business'] } },
{ path: 'okr-templates', name: 'OKRTemplates', component: () => import('@/views/OKRTemplates.vue'), meta: { title: 'OKR模板库', roles: ['ceo', 'finance', 'it'], editable: true } },
{ path: 'okr/:id', name: 'OkrDetail', component: () => import('@/views/OkrDetail.vue'), meta: { title: 'OKR详情', roles: ['ceo', 'finance', 'it'] } },
{ path: 'subjects', name: 'SubjectManage', component: () => import('@/views/SubjectManage.vue'), meta: { title: '科目打标', roles: ['ceo', 'finance', 'business', 'it'] } },
{ path: 'data-classification', name: 'DataClassification', component: () => import('@/views/DataClassification.vue'), meta: { title: '数据分类分级', roles: ['ceo', 'finance', 'business', 'it'], editable: true } },
{ path: 'mpm-calculator', name: 'MpmCalculator', component: () => import('@/views/MpmCalculator.vue'), meta: { title: 'MPM计算器', roles: ['ceo', 'finance', 'business'] } },
{ path: 'bot-kpis', name: 'BotKpis', component: () => import('@/views/BotKpiDashboard.vue'), meta: { title: 'Bot KPI看板', roles: ['ceo', 'finance', 'it'] } },
{ path: 'analysis-confidence', name: 'AnalysisConfidence', component: () => import('@/views/AnalysisConfidence.vue'), meta: { title: '分析置信度', roles: ['ceo', 'finance', 'it'] } },
{ path: 'expenses', name: 'ExpenseManage', component: () => import('@/views/ExpenseManage.vue'), meta: { title: '费用审核', roles: ['ceo', 'finance', 'business', 'it'], editable: true } },
{ path: 'cash-plan', name: 'CashPlan', component: () => import('@/views/CashPlan.vue'), meta: { title: '收付款计划', roles: ['ceo', 'finance', 'business', 'it'], editable: true } },
{ path: 'receivables', name: 'Receivables', component: () => import('@/views/Receivables.vue'), meta: { title: '应收款催收', roles: ['ceo', 'finance', 'business'] } },
{ path: 'growth-quality', name: 'GrowthQuality', component: () => import('@/views/GrowthQuality.vue'), meta: { title: '增长质量诊断', roles: ['ceo', 'finance', 'business', 'it'] } },
{ path: 'product-matrix', name: 'ProductMatrix', component: () => import('@/views/ProductMatrix.vue'), meta: { title: '波士顿产品矩阵', roles: ['ceo', 'finance', 'business', 'it'] } },
{ path: 'tax-compliance', name: 'TaxCompliance', component: () => import('@/views/TaxCompliance.vue'), meta: { title: '税务合规', roles: ['ceo', 'finance', 'business', 'it'], editable: true } },
]
},
]
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('/my-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)) {
// 权限不足,跳转到我的工作台
next('/my-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