This commit is contained in:
2025-12-13 15:41:17 +08:00
parent 2d0691153d
commit 00b52253a8
149 changed files with 164 additions and 128745 deletions

View File

@@ -0,0 +1,392 @@
#!/usr/bin/env node
// 一键裁剪脚本:根据功能模块删除或屏蔽对应的菜单配置和页面文件
// 设计原则:
// - 先通过运行时模块开关/页面确认要保留哪些模块
// - 然后运行本脚本,选择要“裁剪掉”的模块,以及裁剪模式:
// 1) 仅屏蔽(修改 moduleKey使其永远不会被启用保留页面文件
// 2) 删除(在 1 的基础上,再删除对应 .vue 页面文件)
// - 脚本只操作前端代码,不影响后端
import fs from 'fs'
import path from 'path'
import readline from 'readline'
import { fileURLToPath } from 'url'
const __filename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename)
const projectRoot = path.resolve(__dirname, '..')
/** 模块定义(与 src/config/hertz_modules.ts 保持一致) */
const MODULES = [
{ key: 'admin.user-management', label: '管理端 · 用户管理', group: 'admin' },
{ key: 'admin.department-management', label: '管理端 · 部门管理', group: 'admin' },
{ key: 'admin.menu-management', label: '管理端 · 菜单管理', group: 'admin' },
{ key: 'admin.role-management', label: '管理端 · 角色管理', group: 'admin' },
{ key: 'admin.notification-management', label: '管理端 · 通知管理', group: 'admin' },
{ key: 'admin.log-management', label: '管理端 · 日志管理', group: 'admin' },
{ key: 'admin.knowledge-base', label: '管理端 · 文章管理', group: 'admin' },
{ key: 'admin.yolo-model', label: '管理端 · YOLO 模型相关', group: 'admin' },
{ key: 'user.system-monitor', label: '用户端 · 系统监控', group: 'user' },
{ key: 'user.ai-chat', label: '用户端 · AI 助手', group: 'user' },
{ key: 'user.yolo-detection', label: '用户端 · YOLO 检测', group: 'user' },
{ key: 'user.live-detection', label: '用户端 · 实时检测', group: 'user' },
{ key: 'user.detection-history', label: '用户端 · 检测历史', group: 'user' },
{ key: 'user.alert-center', label: '用户端 · 告警中心', group: 'user' },
{ key: 'user.notice-center', label: '用户端 · 通知中心', group: 'user' },
{ key: 'user.knowledge-center', label: '用户端 · 知识库中心', group: 'user' },
]
/**
* 每个模块对应的裁剪配置:
* - adminModuleKey / userModuleKey: 在路由配置文件中的 moduleKey 值
* - adminComponentNames / userComponentNames: 在组件映射对象中的组件名(*.vue
* - viewFiles: 可以安全删除的页面文件(相对项目根路径)
*/
const PRUNE_CONFIG = {
'admin.user-management': {
adminModuleKey: 'admin.user-management',
adminComponentNames: ['UserManagement.vue'],
userModuleKey: null,
userComponentNames: [],
viewFiles: ['src/views/admin_page/UserManagement.vue'],
},
'admin.department-management': {
adminModuleKey: 'admin.department-management',
adminComponentNames: ['DepartmentManagement.vue'],
userModuleKey: null,
userComponentNames: [],
viewFiles: ['src/views/admin_page/DepartmentManagement.vue'],
},
'admin.menu-management': {
adminModuleKey: 'admin.menu-management',
adminComponentNames: ['MenuManagement.vue'],
userModuleKey: null,
userComponentNames: [],
viewFiles: ['src/views/admin_page/MenuManagement.vue'],
},
'admin.role-management': {
adminModuleKey: 'admin.role-management',
adminComponentNames: ['Role.vue'],
userModuleKey: null,
userComponentNames: [],
viewFiles: ['src/views/admin_page/Role.vue'],
},
'admin.notification-management': {
adminModuleKey: 'admin.notification-management',
adminComponentNames: ['NotificationManagement.vue'],
userModuleKey: null,
userComponentNames: [],
viewFiles: ['src/views/admin_page/NotificationManagement.vue'],
},
'admin.log-management': {
adminModuleKey: 'admin.log-management',
adminComponentNames: ['LogManagement.vue'],
userModuleKey: null,
userComponentNames: [],
viewFiles: ['src/views/admin_page/LogManagement.vue'],
},
'admin.knowledge-base': {
adminModuleKey: 'admin.knowledge-base',
adminComponentNames: ['KnowledgeBaseManagement.vue'],
userModuleKey: null,
userComponentNames: [],
viewFiles: ['src/views/admin_page/KnowledgeBaseManagement.vue'],
},
'admin.yolo-model': {
adminModuleKey: 'admin.yolo-model',
adminComponentNames: [
'ModelManagement.vue',
'AlertLevelManagement.vue',
'AlertProcessingCenter.vue',
'DetectionHistoryManagement.vue',
],
userModuleKey: null,
userComponentNames: [],
viewFiles: [
'src/views/admin_page/ModelManagement.vue',
'src/views/admin_page/AlertLevelManagement.vue',
'src/views/admin_page/AlertProcessingCenter.vue',
'src/views/admin_page/DetectionHistoryManagement.vue',
],
},
'user.system-monitor': {
adminModuleKey: null,
adminComponentNames: [],
userModuleKey: 'user.system-monitor',
userComponentNames: ['SystemMonitor.vue'],
viewFiles: ['src/views/user_pages/SystemMonitor.vue'],
},
'user.ai-chat': {
adminModuleKey: null,
adminComponentNames: [],
userModuleKey: 'user.ai-chat',
userComponentNames: ['AiChat.vue'],
viewFiles: ['src/views/user_pages/AiChat.vue'],
},
'user.yolo-detection': {
adminModuleKey: null,
adminComponentNames: [],
userModuleKey: 'user.yolo-detection',
userComponentNames: ['YoloDetection.vue'],
viewFiles: ['src/views/user_pages/YoloDetection.vue'],
},
'user.live-detection': {
adminModuleKey: null,
adminComponentNames: [],
userModuleKey: 'user.live-detection',
userComponentNames: ['LiveDetection.vue'],
viewFiles: ['src/views/user_pages/LiveDetection.vue'],
},
'user.detection-history': {
adminModuleKey: null,
adminComponentNames: [],
userModuleKey: 'user.detection-history',
userComponentNames: ['DetectionHistory.vue'],
viewFiles: ['src/views/user_pages/DetectionHistory.vue'],
},
'user.alert-center': {
adminModuleKey: null,
adminComponentNames: [],
userModuleKey: 'user.alert-center',
userComponentNames: ['AlertCenter.vue'],
viewFiles: ['src/views/user_pages/AlertCenter.vue'],
},
'user.notice-center': {
adminModuleKey: null,
adminComponentNames: [],
userModuleKey: 'user.notice-center',
userComponentNames: ['NoticeCenter.vue'],
viewFiles: ['src/views/user_pages/NoticeCenter.vue'],
},
'user.knowledge-center': {
adminModuleKey: null,
adminComponentNames: [],
userModuleKey: 'user.knowledge-center',
userComponentNames: ['KnowledgeCenter.vue'],
// 注意:这里只删除 KnowledgeCenter.vue保留 KnowledgeDetail.vue避免复杂路由修改
viewFiles: ['src/views/user_pages/KnowledgeCenter.vue'],
},
}
const ADMIN_MENU_FILE = 'src/router/admin_menu.ts'
const USER_MENU_FILE = 'src/router/user_menu_ai.ts'
/**
* 简单的 CLI 交互封装
*/
const rl = readline.createInterface({ input: process.stdin, output: process.stdout })
function ask(question) {
return new Promise((resolve) => {
rl.question(question, (answer) => {
resolve(answer.trim())
})
})
}
function resolvePath(relativePath) {
return path.resolve(projectRoot, relativePath)
}
function readTextFile(relativePath) {
const full = resolvePath(relativePath)
if (!fs.existsSync(full)) {
return null
}
return fs.readFileSync(full, 'utf8')
}
function writeTextFile(relativePath, content) {
const full = resolvePath(relativePath)
fs.writeFileSync(full, content, 'utf8')
}
function commentComponentLines(content, componentNames) {
if (!componentNames || componentNames.length === 0) return content
const lines = content.split('\n')
const nameSet = new Set(componentNames)
const updated = lines.map((line) => {
const trimmed = line.trim()
if (trimmed.startsWith('//')) return line
for (const name of nameSet) {
if (line.includes(`'${name}'`)) {
return `// ${line}`
}
}
return line
})
return updated.join('\n')
}
function updateModuleKey(content, originalKey) {
if (!originalKey) return content
const patterns = [
`moduleKey: '${originalKey}'`,
`moduleKey: "${originalKey}"`,
]
const pruned = `moduleKey: '__pruned__${originalKey}'`
if (content.includes(pruned)) {
return content
}
let updated = content
let found = false
for (const p of patterns) {
if (updated.includes(p)) {
updated = updated.replace(p, pruned)
found = true
}
}
if (!found) {
console.warn(`⚠️ 未在文件中找到 moduleKey: ${originalKey}`)
}
return updated
}
function collectViewFilesForModules(selectedKeys) {
const files = new Set()
for (const key of selectedKeys) {
const cfg = PRUNE_CONFIG[key]
if (!cfg) continue
for (const f of cfg.viewFiles) {
files.add(f)
}
}
return Array.from(files)
}
async function main() {
console.log('===== Hertz 模板 · 一键裁剪脚本 =====')
console.log('说明:')
console.log('1. 建议先在浏览器里通过“模板模式 + 模块选择页”确认要保留的模块')
console.log('2. 然后关闭 dev 服务器,运行本脚本选择要裁剪掉的模块')
console.log('3. 先可选择“仅屏蔽”,确认无误后,再选择“删除”彻底缩减代码体积')
console.log('')
console.log('当前可裁剪模块:')
MODULES.forEach((m, index) => {
console.log(`${index + 1}. [${m.group}] ${m.label} (${m.key})`)
})
console.log('')
const indexAnswer = await ask('请输入要“裁剪掉”的模块序号(多个用逗号分隔,例如 2,4,7或直接回车取消')
if (!indexAnswer) {
console.log('未选择任何模块,退出。')
rl.close()
return
}
const indexes = indexAnswer
.split(',')
.map((s) => parseInt(s.trim(), 10))
.filter((n) => !Number.isNaN(n) && n >= 1 && n <= MODULES.length)
if (indexes.length === 0) {
console.log('未解析出有效的序号,退出。')
rl.close()
return
}
const selectedModules = Array.from(new Set(indexes.map((i) => MODULES[i - 1])))
console.log('\n将要裁剪的模块')
selectedModules.forEach((m) => {
console.log(`- [${m.group}] ${m.label} (${m.key})`)
})
console.log('\n裁剪模式')
console.log('1) 仅屏蔽模块:')
console.log(' - 修改 router 配置中的 moduleKey 为 __pruned__...')
console.log(' - 生成的菜单和路由中将完全隐藏这些模块')
console.log(' - 不删除任何 .vue 页面文件(可随时恢复)')
console.log('2) 删除模块:')
console.log(' - 在 1 的基础上,额外删除对应的 .vue 页面文件')
console.log(' - 删除操作不可逆,请确保已经提交或备份代码\n')
const modeAnswer = await ask('请选择裁剪模式1 = 仅屏蔽2 = 删除):')
const mode = modeAnswer === '2' ? 'delete' : 'comment'
const viewFiles = collectViewFilesForModules(selectedModules.map((m) => m.key))
console.log('\n即将进行如下修改')
console.log('- 修改文件: src/router/admin_menu.ts按需')
console.log('- 修改文件: src/router/user_menu_ai.ts按需')
if (mode === 'delete') {
console.log('- 删除页面文件:')
viewFiles.forEach((f) => console.log(` · ${f}`))
} else {
console.log('- 不删除任何页面文件,仅屏蔽模块')
}
const confirm = await ask('\n确认执行这些修改吗(y/N): ')
if (confirm.toLowerCase() !== 'y') {
console.log('已取消操作。')
rl.close()
return
}
// 1) 修改 admin_menu.ts
let adminMenuContent = readTextFile(ADMIN_MENU_FILE)
if (adminMenuContent) {
const adminKeys = selectedModules.map((m) => m.key).filter((k) => PRUNE_CONFIG[k]?.adminModuleKey)
if (adminKeys.length > 0) {
for (const key of adminKeys) {
const cfg = PRUNE_CONFIG[key]
adminMenuContent = updateModuleKey(adminMenuContent, cfg.adminModuleKey)
adminMenuContent = commentComponentLines(adminMenuContent, cfg.adminComponentNames)
}
writeTextFile(ADMIN_MENU_FILE, adminMenuContent)
console.log('✅ 已更新 src/router/admin_menu.ts')
}
}
// 2) 修改 user_menu_ai.ts
let userMenuContent = readTextFile(USER_MENU_FILE)
if (userMenuContent) {
const userKeys = selectedModules.map((m) => m.key).filter((k) => PRUNE_CONFIG[k]?.userModuleKey)
if (userKeys.length > 0) {
for (const key of userKeys) {
const cfg = PRUNE_CONFIG[key]
userMenuContent = updateModuleKey(userMenuContent, cfg.userModuleKey)
userMenuContent = commentComponentLines(userMenuContent, cfg.userComponentNames)
}
writeTextFile(USER_MENU_FILE, userMenuContent)
console.log('✅ 已更新 src/router/user_menu_ai.ts')
}
}
// 3) 删除 .vue 页面文件(仅在 delete 模式下)
if (mode === 'delete') {
console.log('\n开始删除页面文件...')
for (const relative of viewFiles) {
const full = resolvePath(relative)
if (fs.existsSync(full)) {
fs.rmSync(full)
console.log(`🗑️ 已删除: ${relative}`)
} else {
console.log(`⚠️ 文件不存在,跳过: ${relative}`)
}
}
}
console.log('\n🎉 裁剪完成。建议执行以下操作检查:')
console.log('- 重新运行: npm run dev')
console.log('- 在浏览器中确认菜单和路由是否符合预期')
console.log('- 如需恢复,请使用 Git 回退或重新拷贝模板')
rl.close()
}
main().catch((err) => {
console.error('执行过程中发生错误:', err)
rl.close()
process.exit(1)
})