Files
csm/web/src/router/index.ts
iven 60ee38a3c2 feat: 新增补丁管理和异常检测插件及相关功能
feat(protocol): 添加补丁管理和行为指标协议类型
feat(client): 实现补丁管理插件采集功能
feat(server): 添加补丁管理和异常检测API
feat(database): 新增补丁状态和异常检测相关表
feat(web): 添加补丁管理和异常检测前端页面
fix(security): 增强输入验证和防注入保护
refactor(auth): 重构认证检查逻辑
perf(service): 优化Windows服务恢复策略
style: 统一健康评分显示样式
docs: 更新知识库文档
2026-04-11 15:59:53 +08:00

70 lines
3.2 KiB
TypeScript

import { createRouter, createWebHistory } from 'vue-router'
import AppLayout from '../views/Layout.vue'
const router = createRouter({
history: createWebHistory(),
routes: [
{ path: '/login', name: 'Login', component: () => import('../views/Login.vue') },
{
path: '/',
component: AppLayout,
redirect: '/dashboard',
children: [
{ path: 'dashboard', name: 'Dashboard', component: () => import('../views/Dashboard.vue') },
{ path: 'devices', name: 'Devices', component: () => import('../views/Devices.vue') },
{ path: 'devices/:uid', name: 'DeviceDetail', component: () => import('../views/DeviceDetail.vue') },
{ path: 'usb', name: 'UsbPolicy', component: () => import('../views/UsbPolicy.vue') },
{ path: 'alerts', name: 'Alerts', component: () => import('../views/Alerts.vue') },
{ path: 'settings', name: 'Settings', component: () => import('../views/Settings.vue') },
// Phase 2: Plugin pages
{ path: 'plugins/web-filter', name: 'WebFilter', component: () => import('../views/plugins/WebFilter.vue') },
{ path: 'plugins/usage-timer', name: 'UsageTimer', component: () => import('../views/plugins/UsageTimer.vue') },
{ path: 'plugins/software-blocker', name: 'SoftwareBlocker', component: () => import('../views/plugins/SoftwareBlocker.vue') },
{ path: 'plugins/popup-blocker', name: 'PopupBlocker', component: () => import('../views/plugins/PopupBlocker.vue') },
{ path: 'plugins/usb-file-audit', name: 'UsbFileAudit', component: () => import('../views/plugins/UsbFileAudit.vue') },
{ path: 'plugins/watermark', name: 'Watermark', component: () => import('../views/plugins/Watermark.vue') },
{ path: 'plugins/disk-encryption', name: 'DiskEncryption', component: () => import('../views/plugins/DiskEncryption.vue') },
{ path: 'plugins/print-audit', name: 'PrintAudit', component: () => import('../views/plugins/PrintAudit.vue') },
{ path: 'plugins/clipboard-control', name: 'ClipboardControl', component: () => import('../views/plugins/ClipboardControl.vue') },
{ path: 'plugins/plugin-control', name: 'PluginControl', component: () => import('../views/plugins/PluginControl.vue') },
{ path: 'plugins/patch', name: 'PatchManagement', component: () => import('../views/plugins/PatchManagement.vue') },
{ path: 'plugins/anomaly', name: 'AnomalyDetection', component: () => import('../views/plugins/AnomalyDetection.vue') },
],
},
],
})
/** Track whether we've already validated auth this session */
let authChecked = false
router.beforeEach(async (to, _from, next) => {
if (to.path === '/login') {
next()
return
}
// If we've already verified auth this session, allow navigation
// (cookies are sent automatically, no need to check on every route change)
if (authChecked) {
next()
return
}
// Check auth status via /api/auth/me (reads access_token cookie)
try {
const { me } = await import('../lib/api')
await me()
authChecked = true
next()
} catch {
next('/login')
}
})
/** Reset auth check flag (called after logout) */
export function resetAuthCheck() {
authChecked = false
}
export default router