// 生成菜单配置 Excel 文件的脚本 import fs from 'fs'; import path from 'path'; const VERBOSE_SCRIPT_LOGS = process.env.DEBUG_SCRIPT_LOGS === 'true'; if (!VERBOSE_SCRIPT_LOGS) { console.log = () => {}; console.warn = () => {}; } // 菜单配置数据(从路由配置中提取) const menuData = [ // 一级菜单 - 首页 { level: 1, name: '首页', permissionCode: 'Home', route: '/home', component: null, icon: 'icon-dashboard', order: 0, hideInMenu: false, }, // 二级菜单 - 首页 { level: 2, name: '工作台', permissionCode: 'Home.Workplace', route: '/home/workplace', component: 'views/home/workplace/index', icon: null, order: 1, hideInMenu: false, parentRoute: '/home', }, { level: 2, name: '实时监控', permissionCode: 'Home.Monitor', route: '/home/monitor', component: 'views/home/monitor/index', icon: null, order: 2, hideInMenu: false, parentRoute: '/home', }, // 一级菜单 - API { level: 1, name: 'API', permissionCode: 'Api', route: '/api', component: null, icon: 'icon-computer', order: 1, hideInMenu: false, }, // 二级菜单 - API { level: 2, name: '上游接口', permissionCode: 'Api.UpstreamInterface', route: '/api/upstreamInterface', component: 'views/api/upstreamInterface/index', icon: 'icon-code', order: 1, hideInMenu: false, parentRoute: '/api', }, { level: 2, name: '下游接口', permissionCode: 'Api.DownstreamInterface', route: '/api/downstreamInterface', component: 'views/api/downstreamInterface/index', icon: 'icon-code', order: 2, hideInMenu: false, parentRoute: '/api', }, { level: 2, name: 'App列表', permissionCode: 'Api.AppList', route: '/api/appList', component: 'views/api/appList/index', icon: 'icon-apps', order: 3, hideInMenu: false, parentRoute: '/api', }, { level: 2, name: '请求日志', permissionCode: 'Api.RequestLog', route: '/api/requestLog', component: 'views/api/requestLog/index', icon: 'icon-file-text', order: 4, hideInMenu: false, parentRoute: '/api', }, { level: 2, name: '调用统计', permissionCode: 'Api.CallStatistics', route: '/api/callStatistics', component: 'views/api/callStatistics/index', icon: 'icon-bar-chart', order: 5, hideInMenu: false, parentRoute: '/api', }, { level: 2, name: 'API调试', permissionCode: 'Api.ApiDebugger', route: '/api/apiDebugger', component: 'views/api/apiDebugger/index', icon: 'icon-bug', order: 6, hideInMenu: false, parentRoute: '/api', }, // 隐藏页面 - API { level: 2, name: '创建接口', permissionCode: 'Api.UpstreamInterfaceConfig', route: '/api/upstreamInterfaceConfig', component: 'views/api/upstreamInterface/interfaceConfig', icon: null, order: null, hideInMenu: true, parentRoute: '/api', }, { level: 2, name: '修改接口', permissionCode: 'Api.UpstreamInterfaceConfigEdit', route: '/api/upstreamInterfaceConfigEdit', component: 'views/api/upstreamInterface/interfaceConfig', icon: null, order: null, hideInMenu: true, parentRoute: '/api', }, { level: 2, name: '创建应用', permissionCode: 'Api.AppList.CreateApplication', route: '/api/appList/createApplication', component: 'views/api/appList/components/createApplication', icon: null, order: null, hideInMenu: true, parentRoute: '/api', }, { level: 2, name: '新建端口', permissionCode: 'Api.DownstreamInterface.NewPort', route: '/api/downstreamInterface/newPort', component: 'views/api/downstreamInterface/newPort', icon: null, order: null, hideInMenu: true, parentRoute: '/api', }, // 一级菜单 - 轨迹 { level: 1, name: '轨迹', permissionCode: 'Track', route: '/track', component: null, icon: 'icon-computer', order: 2, hideInMenu: false, }, // 二级菜单 - 轨迹 { level: 2, name: '新手指引', permissionCode: 'Track', route: '/track/guide', component: 'views/track/trackGuide/index', icon: 'icon-book', order: 0, hideInMenu: false, parentRoute: '/track', }, { level: 2, name: '轨迹订单', permissionCode: 'Track.Order', route: '/track/order', component: 'views/track/trackOrder/index', icon: null, order: 1, hideInMenu: false, parentRoute: '/track', }, { level: 2, name: '预警订单', permissionCode: 'Track.WarningOrder', route: '/track/warningOrder', component: 'views/track/trackWarningOrder/index', icon: null, order: 2, hideInMenu: false, parentRoute: '/track', }, { level: 2, name: '轨迹状态', permissionCode: 'Track.State', route: '/track/state', component: 'views/track/trackState/index', icon: null, order: 3, hideInMenu: false, parentRoute: '/track', }, { level: 2, name: '轨迹标记', permissionCode: 'Track.Flag', route: '/track/flag', component: 'views/track/trackFlag/index', icon: null, order: 4, hideInMenu: false, parentRoute: '/track', }, { level: 2, name: '轨迹内容', permissionCode: 'Track.Content', route: '/track/content', component: 'views/track/trackContent/index', icon: null, order: 5, hideInMenu: false, parentRoute: '/track', }, { level: 2, name: '轨迹拉取', permissionCode: 'Track.Pull', route: '/track/pull', component: 'views/track/trackMapping/Pull', icon: null, order: 6, hideInMenu: false, parentRoute: '/track', }, { level: 2, name: '轨迹推送', permissionCode: 'Track.Push', route: '/track/push', component: 'views/track/trackMapping/Push', icon: null, order: 7, hideInMenu: false, parentRoute: '/track', }, { level: 2, name: '预警分区', permissionCode: 'Track.KpiRegion', route: '/track/kpiRegion', component: 'views/track/kpiRegion/index', icon: null, order: 8, hideInMenu: false, parentRoute: '/track', }, { level: 2, name: '预警配置', permissionCode: 'Track.KpiEarlyWarningConfig', route: '/track/kpiEarlyWarningConfig', component: 'views/track/kpiEarlyWarningConfig/index', icon: null, order: 9, hideInMenu: false, parentRoute: '/track', }, // 一级菜单 - 订单 { level: 1, name: '订单', permissionCode: 'Order', route: '/order', component: null, icon: 'icon-file', order: 3, hideInMenu: false, }, // 二级菜单 - 订单 { level: 2, name: '我要查价', permissionCode: 'Order.PriceCheck', route: '/order/priceCheck', component: 'views/order/priceCheck/index', icon: null, order: 1, hideInMenu: false, parentRoute: '/order', }, { level: 2, name: '我要下单', permissionCode: 'Order.PlaceOrder', route: '/order/placeOrder', component: 'views/order/placeOrder/index', icon: null, order: 2, hideInMenu: false, parentRoute: '/order', }, { level: 2, name: '我的订单', permissionCode: 'Order.MyOrders', route: '/order/myOrders', component: 'views/order/myOrders/index', icon: null, order: 3, hideInMenu: false, parentRoute: '/order', }, // 一级菜单 - 渠道 { level: 1, name: '渠道', permissionCode: 'Channel', route: '/channel', component: null, icon: 'icon-link', order: 4, hideInMenu: false, }, // 二级菜单 - 渠道 { level: 2, name: '销售产品', permissionCode: 'Channel.SalesProducts', route: '/channel/salesProducts', component: 'views/channel/salesProducts/index', icon: null, order: 1, hideInMenu: false, parentRoute: '/channel', }, { level: 2, name: '服务渠道', permissionCode: 'Channel.ServiceChannels', route: '/channel/serviceChannels', component: 'views/channel/serviceChannels/index', icon: null, order: 2, hideInMenu: false, parentRoute: '/channel', }, { level: 2, name: '价格分区', permissionCode: 'Channel.PriceArea', route: '/channel/priceArea', component: 'views/channel/priceArea/index', icon: null, order: 3, hideInMenu: false, parentRoute: '/channel', }, { level: 2, name: '黑名单区', permissionCode: 'Channel.Blacklist', route: '/channel/blacklist', component: 'views/channel/blacklist/index', icon: null, order: 4, hideInMenu: false, parentRoute: '/channel', }, { level: 2, name: '偏远分区', permissionCode: 'Channel.RemoteZones', route: '/channel/remoteZones', component: 'views/channel/remoteZones/index', icon: null, order: 5, hideInMenu: false, parentRoute: '/channel', }, { level: 2, name: '计重规则', permissionCode: 'Channel.WeightRules', route: '/channel/weightRules', component: 'views/channel/weightRules/index', icon: null, order: 6, hideInMenu: false, parentRoute: '/channel', }, { level: 2, name: '计重进位', permissionCode: 'Channel.WeightRounding', route: '/channel/weightRounding', component: 'views/channel/weightRounding/index', icon: null, order: 7, hideInMenu: false, parentRoute: '/channel', }, { level: 2, name: '自动触发', permissionCode: 'Channel.AutoTrigger', route: '/channel/autoTrigger', component: 'views/channel/autoTrigger/index', icon: null, order: 8, hideInMenu: false, parentRoute: '/channel', }, // 一级菜单 - 操作 { level: 1, name: '操作', permissionCode: 'Operation', route: '/operation', component: null, icon: 'icon-settings', order: 5, hideInMenu: false, }, // 二级菜单 - 操作 { level: 2, name: '入库扫描', permissionCode: 'Operation.InboundScan', route: '/operation/inboundScan', component: 'views/operation/inboundScan/index', icon: null, order: 1, hideInMenu: false, parentRoute: '/operation', }, { level: 2, name: '出库扫描', permissionCode: 'Operation.OutboundScan', route: '/operation/outboundScan', component: 'views/operation/outboundScan/index', icon: null, order: 2, hideInMenu: false, parentRoute: '/operation', }, { level: 2, name: '打印标签', permissionCode: 'Operation.PrintLabel', route: '/operation/printLabel', component: 'views/operation/printLabel/index', icon: null, order: 3, hideInMenu: false, parentRoute: '/operation', }, // 一级菜单 - 客户 { level: 1, name: '客户', permissionCode: 'User', route: '/user', component: null, icon: 'icon-user', order: 7, hideInMenu: false, }, // 二级菜单 - 客户 { level: 2, name: '资金充值', permissionCode: 'User.Recharge', route: '/user/recharge', component: 'views/user/recharge/deposit', icon: null, order: 1, hideInMenu: true, parentRoute: '/user', }, // 一级菜单 - 财务 { level: 1, name: '财务', permissionCode: 'Finance', route: '/finance', component: null, icon: 'icon-storage', order: 6, hideInMenu: false, }, // 二级菜单 - 财务 { level: 2, name: '充值记录', permissionCode: 'Finance.RechargeRecord', route: '/finance/rechargeRecord', component: 'views/finance/rechargeRecord/index', icon: null, order: 1, hideInMenu: false, parentRoute: '/finance', }, { level: 2, name: '资金流水', permissionCode: 'Finance.AccountFlow', route: '/finance/accountFlow', component: 'views/finance/accountFlow/index', icon: null, order: 2, hideInMenu: false, parentRoute: '/finance', }, { level: 2, name: '应收应付', permissionCode: 'Finance.ReceivablePayable', route: '/finance/receivablePayable', component: 'views/finance/receivablePayable/index', icon: null, order: 3, hideInMenu: false, parentRoute: '/finance', }, // 一级菜单 - 系统 { level: 1, name: '系统', permissionCode: 'Rbac', route: '/system', component: null, icon: 'icon-settings', order: 999, hideInMenu: false, }, // 二级菜单 - 系统 { level: 2, name: '用户管理', permissionCode: 'Rbac.Users', route: '/system/users', component: 'views/system/organization/user/index', icon: null, order: 1, hideInMenu: false, parentRoute: '/system', }, { level: 2, name: '角色管理', permissionCode: 'Rbac.Roles', route: '/system/roles', component: 'views/system/permission/role/index', icon: null, order: 2, hideInMenu: false, parentRoute: '/system', }, { level: 2, name: '菜单管理', permissionCode: 'Rbac.Menus', route: '/system/menus', component: 'views/system/permission/menu/index', icon: null, order: 3, hideInMenu: false, parentRoute: '/system', }, { level: 2, name: '组织管理', permissionCode: 'Rbac.Organizations', route: '/system/organizations', component: 'views/system/organization/index', icon: null, order: 4, hideInMenu: false, parentRoute: '/system', }, ]; // 生成 CSV 内容(UTF-8 BOM 以便 Excel 正确识别中文) function generateCSV() { const headers = ['菜单级别', '父级菜单', '菜单名称', '权限编码', '路由路径', '组件路径', '图标', '排序', '是否隐藏']; const rows = [headers]; menuData.forEach(menu => { // 获取父级菜单名称 let parentName = ''; if (menu.parentRoute) { const parentMenu = menuData.find(m => m.route === menu.parentRoute); parentName = parentMenu ? parentMenu.name : ''; } const row = [ menu.level === 1 ? '一级菜单' : '二级菜单', parentName, menu.name, menu.permissionCode || '', menu.route, menu.component || '', menu.icon || '', menu.order !== null && menu.order !== undefined ? menu.order : '', menu.hideInMenu ? '是' : '否', ]; rows.push(row); }); // 添加 UTF-8 BOM 以便 Excel 正确识别中文 const csvContent = rows.map(row => row.map(cell => { // 处理包含逗号或引号的单元格 if (typeof cell === 'string' && (cell.includes(',') || cell.includes('"') || cell.includes('\n'))) { return `"${cell.replace(/"/g, '""')}"`; } return cell; }).join(',')).join('\n'); return '\ufeff' + csvContent; // UTF-8 BOM } // 生成 Excel XML 格式(更兼容) function generateExcelXML() { const xmlHeader = ` `; const xmlRows = menuData.map((menu, index) => { // 获取父级菜单名称 let parentName = ''; if (menu.parentRoute) { const parentMenu = menuData.find(m => m.route === menu.parentRoute); parentName = parentMenu ? parentMenu.name : ''; } if (index === 0) { // 表头 return ` 菜单级别 父级菜单 菜单名称 权限编码 路由路径 组件路径 图标 排序 是否隐藏 `; } return ` ${menu.level === 1 ? '一级菜单' : '二级菜单'} ${parentName} ${menu.name} ${menu.permissionCode || ''} ${menu.route} ${menu.component || ''} ${menu.icon || ''} ${menu.order !== null && menu.order !== undefined ? menu.order : ''} ${menu.hideInMenu ? '是' : '否'} `; }).join('\n'); const xmlFooter = `
`; return xmlHeader + '\n' + xmlRows + '\n' + xmlFooter; } // 生成文件 const csvContent = generateCSV(); const xmlContent = generateExcelXML(); // 写入 CSV 文件(带 BOM) fs.writeFileSync('菜单配置.csv', csvContent, 'utf-8'); console.log('✅ CSV 文件已生成: 菜单配置.csv (可直接用 Excel 打开)'); // 写入 Excel XML 文件(先写入临时文件,然后重命名) const tempFileName = '菜单配置_temp.xls'; const finalFileName = '菜单配置.xls'; try { // 先删除旧文件(如果存在且未被锁定) if (fs.existsSync(finalFileName)) { try { fs.unlinkSync(finalFileName); } catch (e) { console.log('⚠️ 无法删除旧文件,可能正在被 Excel 打开,请先关闭 Excel 文件'); } } // 写入新文件 fs.writeFileSync(tempFileName, xmlContent, 'utf-8'); // 重命名为最终文件名 if (fs.existsSync(finalFileName)) { fs.unlinkSync(finalFileName); } fs.renameSync(tempFileName, finalFileName); console.log('✅ Excel XML 文件已生成: 菜单配置.xls'); } catch (error) { if (error.code === 'EBUSY') { console.log('⚠️ Excel 文件正在被使用,已生成临时文件: ' + tempFileName); console.log(' 请关闭 Excel 后,将临时文件重命名为: 菜单配置.xls'); } else { throw error; } } console.log(`\n共生成 ${menuData.length} 条菜单记录`);