fix: avoid sidebar menu flicker when loading and sorting (#12066)

This commit is contained in:
ssongliu
2026-03-05 02:37:04 +00:00
committed by GitHub
parent c986b04667
commit 17cb12df8b
2 changed files with 64 additions and 75 deletions
+24
View File
@@ -16,6 +16,7 @@ import (
"net/url"
"os"
"path"
"sort"
"strconv"
"strings"
"time"
@@ -82,6 +83,15 @@ func (u *SettingService) GetSettingInfo() (*dto.SettingInfo, error) {
for _, set := range setting {
settingMap[set.Key] = set.Value
}
if hideMenu, ok := settingMap["HideMenu"]; ok && len(hideMenu) > 0 {
var menus []dto.ShowMenu
if err := json.Unmarshal([]byte(hideMenu), &menus); err == nil {
sortShowMenus(menus)
if sortedBytes, err := json.Marshal(menus); err == nil {
settingMap["HideMenu"] = string(sortedBytes)
}
}
}
var info dto.SettingInfo
arr, err := json.Marshal(settingMap)
if err != nil {
@@ -103,6 +113,20 @@ func (u *SettingService) GetSettingInfo() (*dto.SettingInfo, error) {
return &info, err
}
func sortShowMenus(menus []dto.ShowMenu) {
for i := range menus {
if len(menus[i].Children) > 0 {
sortShowMenus(menus[i].Children)
}
}
sort.SliceStable(menus, func(i, j int) bool {
if menus[i].Sort == menus[j].Sort {
return menus[i].ID < menus[j].ID
}
return menus[i].Sort < menus[j].Sort
})
}
func (u *SettingService) Update(key, value string) error {
oldVal, err := settingRepo.Get(repo.WithByKey(key))
if err != nil {
@@ -39,7 +39,6 @@ import { GlobalStore, MenuStore } from '@/store';
import { isString } from '@vueuse/core';
import { getSettingInfo } from '@/api/modules/setting';
import PrimaryMenu from '@/assets/images/menu-bg.svg?component';
import { sortMenu } from '@/utils/util';
const route = useRoute();
const menuStore = MenuStore();
@@ -72,13 +71,13 @@ const handleMenuClick = (path) => {
emit('menuClick', path);
};
function getCheckedLabels(menu: any, showMap: any) {
function getCheckedLabels(menu: any, showSet: Set<string>) {
for (const item of menu) {
if (item.isShow) {
showMap[item.label] = true;
showSet.add(item.label);
}
if (item.children) {
getCheckedLabels(item.children, showMap);
getCheckedLabels(item.children, showSet);
}
}
}
@@ -88,73 +87,50 @@ const openTask = () => {
};
const search = async () => {
const res = await getSettingInfo();
version.value = res.data.systemVersion;
let hideMenu = JSON.parse(res.data.hideMenu);
sortMenu(hideMenu);
const showMap = new Map();
getCheckedLabels(hideMenu, showMap);
const rootMap = new Map();
hideMenu.forEach((m, index) => {
rootMap.set(m.label, index);
});
let rstMenuList: RouteRecordRaw[] = [];
let resMenuList: RouteRecordRaw[] = [];
resMenuList = adjustAndCleanMenu(hideMenu, menuStore.menuList);
for (const menu of resMenuList) {
let menuItem = JSON.parse(JSON.stringify(menu));
if (!showMap[menuItem.name]) {
continue;
} else if (menuItem.name === 'Xpack-Menu') {
menuItem.meta.hideInSidebar = false;
}
const childMenu = hideMenu.find((item) => item.label == menu.name);
const childMap = buildIndexMap(childMenu?.children || []);
const itemChildren =
(menuItem.children ?? [])
.filter(
try {
const res = await getSettingInfo();
version.value = res.data.systemVersion;
let hideMenu = JSON.parse(res.data.hideMenu);
const showSet = new Set<string>();
getCheckedLabels(hideMenu, showSet);
const rstMenuList: RouteRecordRaw[] = [];
const resMenuList = adjustAndCleanMenu(hideMenu, menuList);
for (const menu of resMenuList) {
let menuItem = JSON.parse(JSON.stringify(menu));
if (!showSet.has(menuItem.name as string)) {
continue;
} else if (menuItem.name === 'Xpack-Menu') {
menuItem.meta.hideInSidebar = false;
}
const itemChildren =
(menuItem.children ?? []).filter(
(item) =>
item.name && showMap[item.name as string] && !(item.name === 'Upage' && globalStore.isIntl),
)
.sort(sortByMap(childMap)) || [];
item.name && showSet.has(item.name as string) && !(item.name === 'Upage' && globalStore.isIntl),
) || [];
if (itemChildren.length === 1) {
menuItem.meta.icon = itemChildren[0].meta.icon;
menuItem.meta.title = itemChildren[0].meta.title;
if (itemChildren.length === 1) {
menuItem.meta.icon = itemChildren[0].meta.icon;
menuItem.meta.title = itemChildren[0].meta.title;
}
menuItem.children = itemChildren;
rstMenuList.push(menuItem);
}
if (!isSameMenuList(menuStore.menuList as RouteRecordRaw[], rstMenuList)) {
menuStore.setMenuList(rstMenuList);
}
} catch (error) {
if (!menuStore.menuList || menuStore.menuList.length === 0) {
menuStore.setMenuList(menuList);
}
menuItem.children = itemChildren;
rstMenuList.push(menuItem);
}
rstMenuList.sort((a, b) => {
const labelA = a.name;
const labelB = b.name;
const indexA = rootMap.get(labelA) ?? Infinity;
const indexB = rootMap.get(labelB) ?? Infinity;
return indexA - indexB;
});
menuStore.menuList = rstMenuList;
};
function buildIndexMap(list: any[]): Map<string, number> {
const map = new Map<string, number>();
list.forEach((m, i) => map.set(m.label, i));
return map;
}
function sortByMap(map: Map<string, number>) {
return (a: { name: string }, b: { name: string }) => {
const indexA = map.get(a.name) ?? Infinity;
const indexB = map.get(b.name) ?? Infinity;
return indexA - indexB;
};
function isSameMenuList(source: RouteRecordRaw[], target: RouteRecordRaw[]) {
return JSON.stringify(source) === JSON.stringify(target);
}
function adjustAndCleanMenu(menuItem, list) {
const menuList = JSON.parse(JSON.stringify(list));
const orderMap = new Map();
menuItem.forEach((item, index) => {
orderMap.set(item.label, index);
});
const itemMap = new Map();
for (const parent of menuList) {
itemMap.set(parent.name, parent);
@@ -175,15 +151,7 @@ function adjustAndCleanMenu(menuItem, list) {
if (!matched) continue;
if (Array.isArray(ref.children) && ref.children.length > 0) {
const childMap = buildIndexMap(ref.children || []);
matched.children = buildTree(ref.children);
matched.children.sort((a, b) => {
const labelA = a.name;
const labelB = b.name;
const indexA = childMap.get(labelA) ?? Infinity;
const indexB = childMap.get(labelB) ?? Infinity;
return indexA - indexB;
});
} else {
delete matched.children;
}
@@ -195,11 +163,6 @@ function adjustAndCleanMenu(menuItem, list) {
}
const newMenu = buildTree(menuItem);
newMenu.sort((a, b) => {
const indexA = orderMap.get(a.name) ?? Infinity;
const indexB = orderMap.get(b.name) ?? Infinity;
return indexA - indexB;
});
for (const menu of newMenu) {
if (menu.children?.length === 1) {
menu.meta.icon = menu.children[0].meta.icon;
@@ -211,7 +174,9 @@ function adjustAndCleanMenu(menuItem, list) {
}
onMounted(() => {
menuStore.setMenuList(menuList);
if (!menuStore.menuList || menuStore.menuList.length === 0) {
menuStore.setMenuList(menuList);
}
search();
});
</script>