feat: 实现功能模块系统,支持模块的动态注册与启用控制

- 新增 ModuleRegistry 核心,支持模块注册、可用性检查和启用状态管理
- 新增模块管理 API(管理端和公共端),提供模块状态查询和启用控制
- 将 LDAP 功能迁移到模块系统,支持通过环境变量和数据库配置控制
- 前端新增模块管理页面和 store,支持模块启用/禁用操作
- 路由守卫集成模块状态检查,未激活模块的页面自动重定向
- 面包屑导航支持模块配置页面的层级显示
- Switch 组件新增 disabled 属性支持
This commit is contained in:
fawney19
2026-01-16 16:14:12 +08:00
parent 50343d5459
commit 6c98816f9f
17 changed files with 1332 additions and 39 deletions

View File

@@ -1,6 +1,7 @@
import { createRouter, createWebHistory } from 'vue-router'
import type { RouteRecordRaw } from 'vue-router'
import { useAuthStore } from '@/stores/auth'
import { useModuleStore } from '@/stores/modules'
import { importWithRetry } from '@/utils/importRetry'
import { log } from '@/utils/logger'
@@ -116,6 +117,11 @@ const routes: RouteRecordRaw[] = [
name: 'SystemSettings',
component: () => importWithRetry(() => import('@/views/admin/SystemSettings.vue'))
},
{
path: 'modules',
name: 'ModuleManagement',
component: () => importWithRetry(() => import('@/views/admin/ModuleManagement.vue'))
},
{
path: 'email',
name: 'EmailSettings',
@@ -124,7 +130,8 @@ const routes: RouteRecordRaw[] = [
{
path: 'ldap',
name: 'LdapSettings',
component: () => importWithRetry(() => import('@/views/admin/LdapSettings.vue'))
component: () => importWithRetry(() => import('@/views/admin/LdapSettings.vue')),
meta: { module: 'ldap' }
},
{
path: 'audit-logs',
@@ -164,6 +171,7 @@ function isNetworkError(error: any): boolean {
router.beforeEach(async (to, from, next) => {
const authStore = useAuthStore()
const moduleStore = useModuleStore()
try {
// 如果有token但没有用户信息,尝试获取用户信息
@@ -186,6 +194,7 @@ router.beforeEach(async (to, from, next) => {
// 检查整个路由匹配记录链中的 meta
const requiresAuth = to.matched.some(record => record.meta.requiresAuth !== false)
const requiresAdmin = to.matched.some(record => record.meta.requiresAdmin)
const moduleName = to.matched.find(record => record.meta.module)?.meta.module as string | undefined
// 如果需要认证但没有token,跳转到首页
if (requiresAuth && !authStore.token) {
@@ -212,6 +221,26 @@ router.beforeEach(async (to, from, next) => {
log.warn('Non-admin user attempted to access admin page, redirecting to user dashboard')
next('/dashboard')
} else {
// 检查模块可用性
if (moduleName) {
// 确保模块状态已加载
if (!moduleStore.loaded) {
try {
await moduleStore.fetchModules()
} catch (error) {
// fail-close: 获取模块状态失败时拒绝访问
log.warn('Failed to fetch modules status, denying access', { error })
next('/admin/dashboard')
return
}
}
// 如果模块未激活available && enabled重定向到管理员首页
if (!moduleStore.isActive(moduleName)) {
log.warn(`Module ${moduleName} is not active, redirecting to admin dashboard`)
next('/admin/dashboard')
return
}
}
next()
}
} else {