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

@@ -0,0 +1,109 @@
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import { modulesApi, type ModuleStatus } from '@/api/modules'
import { log } from '@/utils/logger'
export const useModuleStore = defineStore('modules', () => {
const modules = ref<Record<string, ModuleStatus>>({})
const loaded = ref(false)
const loading = ref(false)
const error = ref<string | null>(null)
/**
* 获取所有模块状态
*/
async function fetchModules() {
if (loading.value) return
loading.value = true
error.value = null
try {
modules.value = await modulesApi.getAllStatus()
loaded.value = true
} catch (err: any) {
log.error('Failed to fetch modules status', err)
error.value = err.response?.data?.detail || '获取模块状态失败'
} finally {
loading.value = false
}
}
/**
* 检查模块是否部署可用
*/
function isAvailable(moduleName: string): boolean {
return modules.value[moduleName]?.available ?? false
}
/**
* 检查模块是否运行启用
*/
function isEnabled(moduleName: string): boolean {
return modules.value[moduleName]?.enabled ?? false
}
/**
* 检查模块是否最终激活
*/
function isActive(moduleName: string): boolean {
return modules.value[moduleName]?.active ?? false
}
/**
* 设置模块启用状态
*/
async function setEnabled(moduleName: string, enabled: boolean) {
try {
await modulesApi.setEnabled(moduleName, enabled)
// 刷新所有模块状态,确保依赖模块的 active 状态同步更新
await fetchModules()
return true
} catch (err: any) {
log.error(`Failed to set module ${moduleName} enabled=${enabled}`, err)
error.value = err.response?.data?.detail || '设置模块状态失败'
return false
}
}
/**
* 获取可用的管理菜单项available 即显示)
*/
const availableAdminMenuItems = computed(() => {
return Object.values(modules.value)
.filter((m) => m.available && m.admin_route)
.sort((a, b) => a.admin_menu_order - b.admin_menu_order)
})
/**
* 按分组获取可用的管理菜单项
*/
const availableAdminMenuItemsByGroup = computed(() => {
const items = availableAdminMenuItems.value
const groups: Record<string, ModuleStatus[]> = {}
for (const item of items) {
const group = item.admin_menu_group || 'other'
if (!groups[group]) {
groups[group] = []
}
groups[group].push(item)
}
return groups
})
return {
modules,
loaded,
loading,
error,
fetchModules,
isAvailable,
isEnabled,
isActive,
setEnabled,
availableAdminMenuItems,
availableAdminMenuItemsByGroup,
}
})