/** * 扫描前端 hasPermission / 路由 permission,输出三级按钮收集结果 * 用法: node scripts/collect-page-buttons.mjs */ import fs from 'fs'; import path from 'path'; import { fileURLToPath } from 'url'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); const root = path.resolve(__dirname, '..'); const srcDir = path.join(root, 'src'); const ACTION_LABELS = { Query: '查询', Create: '新增', Update: '修改', Delete: '删除', Move: '移动', AssignRoles: '分配角色', AssignPermissions: '分配权限', ResetPassword: '重置密码', Template: '模板管理', Audit: '审计', Use: '使用', Save: '保存', Export: '导出', Import: '导入', }; function walk(dir, ext, out = []) { for (const name of fs.readdirSync(dir)) { const full = path.join(dir, name); const stat = fs.statSync(full); if (stat.isDirectory()) { if (name === 'node_modules') continue; walk(full, ext, out); } else if (full.endsWith(ext)) { out.push(full); } } return out; } function inferParent(code) { const parts = code.split('.'); if (parts.length < 3) return null; // 资源级:Rbac.Menus.Create → Rbac.Menus return `${parts[0]}.${parts[1]}`; } function inferName(code) { const action = code.split('.').pop(); return ACTION_LABELS[action] || action; } const vueFiles = walk(path.join(srcDir, 'views'), '.vue'); const routeFiles = walk(path.join(srcDir, 'router'), '.ts'); const permissionCodes = new Set(); for (const file of [...vueFiles, ...routeFiles]) { const text = fs.readFileSync(file, 'utf8'); const hasPermissionRe = /hasPermission\(\s*['"]([^'"]+)['"]\s*\)/g; const routePermRe = /permission:\s*['"]([^'"]+)['"]/g; let m; while ((m = hasPermissionRe.exec(text))) permissionCodes.add(m[1]); while ((m = routePermRe.exec(text))) permissionCodes.add(m[1]); } const grouped = new Map(); for (const code of [...permissionCodes].sort()) { const parent = inferParent(code); if (!parent || parent === code) continue; if (!grouped.has(parent)) grouped.set(parent, []); grouped.get(parent).push({ permissionCode: code, name: inferName(code) }); } console.log('# 前端页面按钮收集结果\n'); console.log(`扫描文件: ${vueFiles.length} 个 vue, ${routeFiles.length} 个路由`); console.log(`权限码总数: ${permissionCodes.size}`); console.log(`可分组三级按钮父级: ${grouped.size}\n`); for (const [parent, buttons] of [...grouped.entries()].sort((a, b) => a[0].localeCompare(b[0]))) { console.log(`## ${parent}`); buttons.forEach((btn, idx) => { console.log(` ${idx + 1}. ${btn.permissionCode} → ${btn.name}`); }); console.log(''); }