front/generate-menu-excel.js
2026-03-02 09:30:14 +08:00

684 lines
17 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 生成菜单配置 Excel 文件的脚本
import fs from 'fs';
import path from 'path';
// 菜单配置数据(从路由配置中提取)
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.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.Blacklist',
route: '/channel/blacklist',
component: 'views/channel/blacklist/index',
icon: null,
order: 3,
hideInMenu: false,
parentRoute: '/channel',
},
{
level: 2,
name: '偏远分区',
permissionCode: 'Channel.RemoteZones',
route: '/channel/remoteZones',
component: 'views/channel/remoteZones/index',
icon: null,
order: 4,
hideInMenu: false,
parentRoute: '/channel',
},
{
level: 2,
name: '计重规则',
permissionCode: 'Channel.WeightRules',
route: '/channel/weightRules',
component: 'views/channel/weightRules/index',
icon: null,
order: 5,
hideInMenu: false,
parentRoute: '/channel',
},
{
level: 2,
name: '计重进位',
permissionCode: 'Channel.WeightRounding',
route: '/channel/weightRounding',
component: 'views/channel/weightRounding/index',
icon: null,
order: 6,
hideInMenu: false,
parentRoute: '/channel',
},
{
level: 2,
name: '自动触发',
permissionCode: 'Channel.AutoTrigger',
route: '/channel/autoTrigger',
component: 'views/channel/autoTrigger/index',
icon: null,
order: 7,
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: 2,
name: '充值记录',
permissionCode: 'User.RechargeRecord',
route: '/user/rechargeRecord',
component: 'views/user/recharge/rechargeRecord',
icon: null,
order: 2,
hideInMenu: false,
parentRoute: '/user',
},
// 一级菜单 - 系统
{
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 = `<?xml version="1.0"?>
<?mso-application progid="Excel.Sheet"?>
<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet"
xmlns:o="urn:schemas-microsoft-com:office:office"
xmlns:x="urn:schemas-microsoft-com:office:excel"
xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
xmlns:html="http://www.w3.org/TR/REC-html40">
<Worksheet ss:Name="菜单配置">
<Table>`;
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 ` <Row>
<Cell><Data ss:Type="String">菜单级别</Data></Cell>
<Cell><Data ss:Type="String">父级菜单</Data></Cell>
<Cell><Data ss:Type="String">菜单名称</Data></Cell>
<Cell><Data ss:Type="String">权限编码</Data></Cell>
<Cell><Data ss:Type="String">路由路径</Data></Cell>
<Cell><Data ss:Type="String">组件路径</Data></Cell>
<Cell><Data ss:Type="String">图标</Data></Cell>
<Cell><Data ss:Type="String">排序</Data></Cell>
<Cell><Data ss:Type="String">是否隐藏</Data></Cell>
</Row>`;
}
return ` <Row>
<Cell><Data ss:Type="String">${menu.level === 1 ? '一级菜单' : '二级菜单'}</Data></Cell>
<Cell><Data ss:Type="String">${parentName}</Data></Cell>
<Cell><Data ss:Type="String">${menu.name}</Data></Cell>
<Cell><Data ss:Type="String">${menu.permissionCode || ''}</Data></Cell>
<Cell><Data ss:Type="String">${menu.route}</Data></Cell>
<Cell><Data ss:Type="String">${menu.component || ''}</Data></Cell>
<Cell><Data ss:Type="String">${menu.icon || ''}</Data></Cell>
<Cell><Data ss:Type="Number">${menu.order !== null && menu.order !== undefined ? menu.order : ''}</Data></Cell>
<Cell><Data ss:Type="String">${menu.hideInMenu ? '是' : '否'}</Data></Cell>
</Row>`;
}).join('\n');
const xmlFooter = ` </Table>
</Worksheet>
</Workbook>`;
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} 条菜单记录`);