/**
|
* 菜单数据转换工具
|
* 将后端菜单格式转换为 Vben Admin 菜单格式
|
*/
|
import type { RouteRecordRaw } from 'vue-router';
|
import type { BackendMenuNode } from '@/api/modules/menu';
|
|
/** Element Plus 图标名称映射 */
|
const iconMap: Record<string, string> = {
|
'el-icon-menu': 'Menu',
|
'el-icon-user': 'User',
|
'el-icon-setting': 'Setting',
|
'el-icon-home': 'HomeFilled',
|
'el-icon-document': 'Document',
|
'el-icon-edit': 'Edit',
|
'el-icon-view': 'View',
|
'el-icon-delete': 'Delete',
|
'el-icon-search': 'Search',
|
'el-icon-refresh': 'Refresh',
|
'el-icon-download': 'Download',
|
'el-icon-upload': 'Upload',
|
'el-icon-goods': 'Goods',
|
'el-icon-box': 'Box',
|
'el-icon-truck': 'Van',
|
'el-icon-shop': 'Shop',
|
'el-icon-list': 'List',
|
'el-icon-grid': 'Grid',
|
'el-icon-s-custom': 'UserFilled',
|
'el-icon-s-order': 'List',
|
'el-icon-s-grid': 'Grid',
|
'el-icon-s-home': 'HomeFilled',
|
'el-icon-s-data': 'DataLine',
|
'el-icon-s-check': 'CircleCheck',
|
'el-icon-s-management': 'Management',
|
};
|
|
/**
|
* 转换图标名称
|
* el-icon-menu -> Menu
|
*/
|
export function transformIcon(icon?: string): string {
|
if (!icon) return 'Menu';
|
return iconMap[icon] || 'Menu';
|
}
|
|
/**
|
* 标准化菜单路径
|
* "/Manager/home" -> "/home"
|
*/
|
export function normalizePath(url?: string): string {
|
if (!url) return '/';
|
let path = url.replace('/Manager', '') || '/';
|
if (!path.startsWith('/')) {
|
path = '/' + path;
|
}
|
return path;
|
}
|
|
/**
|
* 检查是否为外部链接
|
*/
|
function isExternalUrl(url?: string): boolean {
|
if (!url) return false;
|
return url.startsWith('http://') || url.startsWith('https://');
|
}
|
|
/**
|
* 将后端菜单节点转换为 Vben 菜单项
|
*/
|
export function transformMenuItem(menu: BackendMenuNode): RouteRecordRaw | null {
|
const name = menu.name || menu.text || '未命名';
|
const url = menu.url || menu.path || '';
|
const path = normalizePath(url);
|
|
// 跳过外部链接
|
if (isExternalUrl(url)) {
|
return null;
|
}
|
|
const route: RouteRecordRaw = {
|
path,
|
name: path.replace(/\//g, '_').replace(/^_/, '') || 'root',
|
meta: {
|
title: name,
|
icon: menu.icon || 'el-icon-menu',
|
},
|
};
|
|
// 递归处理子菜单
|
if (menu.children?.length) {
|
const children = menu.children
|
.map((child) => transformMenuItem(child))
|
.filter((r): r is RouteRecordRaw => r !== null);
|
if (children.length > 0) {
|
route.children = children;
|
}
|
}
|
|
return route;
|
}
|
|
/**
|
* 将后端菜单数组转换为路由数组
|
*/
|
export function transformMenuToRoutes(menus: BackendMenuNode[]): RouteRecordRaw[] {
|
const routes: RouteRecordRaw[] = [];
|
|
menus.forEach((menu) => {
|
const route = transformMenuItem(menu);
|
if (route) {
|
routes.push(route);
|
}
|
});
|
|
return routes;
|
}
|
|
/**
|
* 将后端菜单数组标准化
|
*/
|
export function normalizeMenus(menus: BackendMenuNode[]): BackendMenuNode[] {
|
return menus.map((menu) => ({
|
...menu,
|
path: normalizePath(menu.url || menu.path),
|
icon: menu.icon || 'el-icon-menu',
|
children: menu.children ? normalizeMenus(menu.children) : undefined,
|
}));
|
}
|
|
/**
|
* 为菜单列表添加首页项
|
*/
|
export function addHomeMenu(menus: BackendMenuNode[]): BackendMenuNode[] {
|
const normalized = normalizeMenus(menus);
|
normalized.push({
|
id: 'home',
|
name: '首页',
|
text: '首页',
|
path: '/home',
|
icon: 'el-icon-home',
|
});
|
return normalized;
|
}
|