feat(router): 优化路由排序逻辑并添加菜单排序权重支持
All checks were successful
CI/CD Pipeline / playwright (push) Successful in 2m8s
CI/CD Pipeline / build-and-deploy (push) Successful in 4m21s

This commit is contained in:
严浩
2025-10-24 11:08:54 +08:00
parent 07eae7cab7
commit 990f2811ae
5 changed files with 51 additions and 7 deletions

View File

@@ -44,7 +44,42 @@ function convertRoutesToMenuOptions(routes: Readonly<RouteRecordRaw[]>): MenuOpt
} }
return true; return true;
}) })
.sort((a, b) => a.path.localeCompare(b.path)); // 排序路由,确保父路由总是在子路由之前,同级路由则根据 `meta.order` 排序
.sort((a: RouteRecordRaw, b: RouteRecordRaw) => {
const pathA = a.path;
const pathB = b.path;
const segmentsA = pathA.split('/').filter(Boolean);
const segmentsB = pathB.split('/').filter(Boolean);
const parentAPath = `/${segmentsA.slice(0, -1).join('/')}`;
const parentBPath = `/${segmentsB.slice(0, -1).join('/')}`;
// 如果不是同级路由,则按路径排序,确保父路由在前
if (parentAPath !== parentBPath) {
return pathA.localeCompare(pathB);
}
// 同级路由,处理 `meta.order`
const orderA = a.meta?.order;
const orderB = b.meta?.order;
const hasOrderA = orderA !== undefined;
const hasOrderB = orderB !== undefined;
// 当一个有 order 而另一个没有时,有 order 的排在前面
if (hasOrderA !== hasOrderB) {
return hasOrderA ? -1 : 1;
}
// 当两个都有 order 时,按 order 值升序排序
if (hasOrderA && hasOrderB) {
const orderDiff = orderA - orderB;
if (orderDiff !== 0) {
return orderDiff;
}
}
// order 相同或都没有 order按路径字母顺序排序
return pathA.localeCompare(pathB);
});
// 构建菜单树 // 构建菜单树
for (const route of validRoutes) { for (const route of validRoutes) {

View File

@@ -1,6 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
definePage({ definePage({
meta: {}, meta: {
order: 1,
},
}); });
const { t, locale } = useI18n(); const { t, locale } = useI18n();

View File

@@ -1,4 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
definePage({ meta: { link: !false } }); definePage({
meta: {
link: !false,
},
});
</script> </script>
<template><div>Demos</div></template> <template><div>Demos</div></template>

View File

@@ -1,10 +1,6 @@
import { autoAnimatePlugin } from '@formkit/auto-animate/vue';
export function install({ app }: { app: import('vue').App<Element> }) { export function install({ app }: { app: import('vue').App<Element> }) {
app.config.globalProperties.__DEV__ = __DEV__; app.config.globalProperties.__DEV__ = __DEV__;
app.use(autoAnimatePlugin); // v-auto-animate="{ duration: 100 }"
app.config.errorHandler = (error, instance, info) => { app.config.errorHandler = (error, instance, info) => {
console.error('Global error:', error); console.error('Global error:', error);
console.error('Component:', instance); console.error('Component:', instance);

View File

@@ -43,8 +43,10 @@ declare module 'vue-router' {
* @description 是否在菜单中隐藏 * @description 是否在菜单中隐藏
*/ */
hideInMenu?: boolean; hideInMenu?: boolean;
/** /**
* @description 菜单标题 * @description 菜单标题
* @deprecated //!⚠️请通过多语言标题方案(搜`PageTitleLocalizations`)维护标题
*/ */
title?: string; title?: string;
@@ -59,6 +61,11 @@ declare module 'vue-router' {
* - false: 仅渲染纯文本标签,不可点击(适用于分组标题) * - false: 仅渲染纯文本标签,不可点击(适用于分组标题)
*/ */
link?: boolean; link?: boolean;
/**
* @description 菜单排序权重,数值越小越靠前,未设置则按路径字母顺序排序
*/
order?: number;
} }
} }