cpms_operation_platform/src/router/utils.ts

90 lines
2.4 KiB
TypeScript
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.

import { h, type Component, type VNode } from 'vue';
import type { RouteRecordRaw } from 'vue-router';
/** 路由 meta 类型 */
export type AppMeta = {
/** 页面 / 菜单标题,同时用于面包屑 */
title: string;
/**
* 菜单图标(仅一级菜单需要),支持两种写法:
* - iconfont 的 class 名,如 'icon-changguan1'
* - 组件,如 ant-design 图标 BarChartOutlined
*/
icon?: Component | string;
/** 是否在侧边栏菜单中隐藏(详情页等) */
hideInMenu?: boolean;
/** 高亮的菜单 key路径不等于菜单 key 的场景,如详情页) */
activeMenu?: string;
};
/**
* 快速创建路由记录
* 根据路径自动生成 PascalCase 路由 name
*/
export function createRoute(
path: string,
component: RouteRecordRaw['component'],
meta: AppMeta,
children: RouteRecordRaw[] = [],
): RouteRecordRaw {
const cleanPath = path.replace(/[:/]/g, '-');
const name = cleanPath
.split('-')
.filter(Boolean)
.map((p) => p.charAt(0).toUpperCase() + p.slice(1))
.join('');
return {
path,
name: name || undefined,
meta,
component,
children,
};
}
/** 侧边栏菜单项ant-design-vue Menu 的 items 结构) */
export interface MenuItem {
key: string;
label: string;
icon?: VNode;
children?: MenuItem[];
}
/**
* 根据路由表生成侧边栏菜单
*
* @description
* 菜单完全由路由派生,路由是「菜单 / 面包屑」唯一的数据源:
* - 仅收录带 meta.title 且未标记 hideInMenu 的路由;
* - 有子路由的生成子菜单(父级本身不跳转,点击展开);
* - 图标取自 meta.icon。
*
* @param routes 需要遍历的路由数组(通常传入主布局的 children
*/
export function generateMenu(routes: RouteRecordRaw[] = []): MenuItem[] {
const items: MenuItem[] = [];
for (const route of routes) {
const meta = route.meta as AppMeta | undefined;
if (!meta?.title || meta.hideInMenu) {
continue;
}
const children = generateMenu(route.children);
const item: MenuItem = { key: route.path, label: meta.title };
if (meta.icon) {
// 字符串 -> iconfont 图标(<i class="iconfont icon-xxx" />);组件 -> 直接渲染
item.icon =
typeof meta.icon === 'string' ? h('i', { class: ['iconfont', meta.icon] }) : h(meta.icon);
}
if (children.length) {
item.children = children;
}
items.push(item);
}
return items;
}