feat: 重构菜单项生成逻辑,优化路由处理并支持分组结构
All checks were successful
/ depcheck (push) Successful in 1m30s
/ build-and-deploy-to-vercel (push) Successful in 1m42s
/ playwright (push) Successful in 1m56s

This commit is contained in:
严浩
2024-12-27 14:56:49 +08:00
parent c6594a1254
commit 6b6e313195
2 changed files with 61 additions and 94 deletions

View File

@ -1,37 +1,75 @@
<script setup lang="ts"> <script setup lang="ts">
import { createGetRoutes } from '@/plugins/router'; import { createGetRoutes } from '@/plugins/router';
import type { MenuItem } from 'primevue/menuitem'; import type { MenuItem } from 'primevue/menuitem';
import type { PanelMenuProps } from 'primevue/panelmenu';
import type { RouteRecordRaw } from 'vue-router/auto';
const router = useRouter(); const router = useRouter();
// 递归处理路由生成菜单项 const menuItems = computed(() => {
const _generateMenuItems = (routes: RouteRecordRaw[]): PanelMenuProps['model'] => { let flatArray: MenuItem[] = createGetRoutes(router)()
return [];
};
const cmptItems = computed(() => {
return createGetRoutes(router)()
.filter((route) => !route.path.includes('/:')) .filter((route) => !route.path.includes('/:'))
.map((route, index) => { .map((route) => ({
return { id: route.path,
label: `${index}. ${(route.name as string) || route.path}`, label: `${(route.name as string) || route.path}`,
icon: (route.meta?.icon as string) || 'pi pi-fw pi-home', }));
// url: route.path,
command: route.children?.length flatArray = flatArray.map((item, index) => {
? undefined let id = item.id;
: () => { if (flatArray.some((item) => item.id.startsWith(`${id}/`))) {
router.push(route); id = `${id}/index`;
}, }
} satisfies MenuItem; // 去掉最前面的 /
id = id.replace(/^\//, '');
let parentId = id.replace(/\/[^/]+$/, '');
if (parentId === id) {
parentId = '_ROOT_';
}
return {
...item,
parentId,
};
});
const groupItems = flatArray.reduce(
(acc, flatArrItem) => {
if (
!acc.some((item) => item.id === flatArrItem.parentId) && //
flatArrItem.parentId !== '_ROOT_'
) {
let groupItemParentId = flatArrItem.parentId.replace(/\/[^/]+$/, '');
if (groupItemParentId === flatArrItem.parentId) groupItemParentId = '_ROOT_';
acc.push({
id: flatArrItem.parentId,
label: `Group ${flatArrItem.parentId}`,
parentId: groupItemParentId,
});
}
return acc;
},
[] as Record<string, string>[],
);
console.debug(`groupItems :>> `, groupItems);
const tree = arrayToTree(flatArray.concat(groupItems), { id: 'id', parentId: 'parentId', rootId: '_ROOT_' });
// 递归把 children 改为 items
function _convertChildrenToItems(tree: MenuItem[]): MenuItem[] {
return tree.map((item) => {
if (item.children.length) {
item.items = _convertChildrenToItems(item.children);
} else {
item.command = (event) => {
router.push({ name: item.label as never });
};
}
delete item.children;
return item;
}); });
}
return _convertChildrenToItems(tree);
}); });
</script> </script>
<template> <template>
<PanelMenu :model="cmptItems" /> <PanelMenu :model="menuItems" />
</template> </template>
<style lang="scss" scoped></style> <style lang="scss" scoped></style>

View File

@ -4,69 +4,6 @@ import type { MenuItem } from 'primevue/menuitem';
import { routes } from 'vue-router/auto-routes'; import { routes } from 'vue-router/auto-routes';
const router = useRouter(); const router = useRouter();
const menuItems = computed(() => {
let flatArray: MenuItem[] = createGetRoutes(router)()
.filter((route) => !route.path.includes('/:'))
.map((route) => ({
id: route.path,
label: `${(route.name as string) || route.path}`,
}));
flatArray = flatArray.map((item, index) => {
let id = item.id;
if (flatArray.some((item) => item.id.startsWith(`${id}/`))) {
id = `${id}/index`;
}
// 去掉最前面的 /
id = id.replace(/^\//, '');
let parentId = id.replace(/\/[^/]+$/, '');
if (parentId === id) {
parentId = '_ROOT_';
}
return {
...item,
parentId,
};
});
const groupItems = flatArray.reduce(
(acc, flatArrItem) => {
if (
!acc.some((item) => item.id === flatArrItem.parentId) && //
flatArrItem.parentId !== '_ROOT_'
) {
let groupItemParentId = flatArrItem.parentId.replace(/\/[^/]+$/, '');
if (groupItemParentId === flatArrItem.parentId) groupItemParentId = '_ROOT_';
acc.push({
id: flatArrItem.parentId,
label: `Group ${flatArrItem.parentId}`,
parentId: groupItemParentId,
});
}
return acc;
},
[] as Record<string, string>[],
);
console.debug(`groupItems :>> `, groupItems);
const tree = arrayToTree(flatArray.concat(groupItems), { id: 'id', parentId: 'parentId', rootId: '_ROOT_' });
// 递归把 children 改为 items
function _convertChildrenToItems(tree: MenuItem[]): MenuItem[] {
return tree.map((item) => {
if (item.children.length) {
item.items = _convertChildrenToItems(item.children);
} else {
item.command = (event) => {
router.push({ name: item.label as never });
};
}
delete item.children;
return item;
});
}
return _convertChildrenToItems(tree);
});
const list = [ const list = [
{ {
title: 'routes', title: 'routes',
@ -98,22 +35,14 @@ const list = [
components: undefined, components: undefined,
})), })),
}, },
{
title: 'menuItems',
json: menuItems.value,
},
]; ];
</script> </script>
<template> <template>
<Tabs value="MenuTest" scrollable> <Tabs :value="list[0].title" scrollable>
<TabList> <TabList>
<Tab value="MenuTest"> MenuTest </Tab>
<Tab v-for="item in list" :key="item.title" :value="item.title">{{ item.title }}</Tab> <Tab v-for="item in list" :key="item.title" :value="item.title">{{ item.title }}</Tab>
</TabList> </TabList>
<TabPanels> <TabPanels>
<TabPanel value="MenuTest">
<PanelMenu :model="menuItems" />
</TabPanel>
<TabPanel v-for="item in list" :key="item.title" :value="item.title"> <TabPanel v-for="item in list" :key="item.title" :value="item.title">
<pre>{{ item.json }}</pre> <pre>{{ item.json }}</pre>
</TabPanel> </TabPanel>