优化菜单加载
This commit is contained in:
@@ -58,7 +58,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, onMounted } from 'vue';
|
||||
import { ref, computed, onMounted, onUnmounted } from 'vue';
|
||||
import { useRouter, useRoute } from 'vue-router';
|
||||
import { useAllDataStore } from '@/stores';
|
||||
import { getAllMenus } from '@/api/menu';
|
||||
@@ -245,6 +245,17 @@ onMounted(() => {
|
||||
setTimeout(() => {
|
||||
fetchMenus();
|
||||
}, 100);
|
||||
|
||||
// 监听菜单缓存刷新事件
|
||||
window.addEventListener('menu-cache-refreshed', fetchMenus);
|
||||
});
|
||||
|
||||
// 组件卸载时清理事件监听
|
||||
onUnmounted(() => {
|
||||
if (themeObserver) {
|
||||
themeObserver.disconnect();
|
||||
}
|
||||
window.removeEventListener('menu-cache-refreshed', fetchMenus);
|
||||
});
|
||||
|
||||
// 计算属性:统一排序所有菜单项(不再区分有无子菜单)
|
||||
@@ -294,8 +305,14 @@ const handleMenuSelect = (index) => {
|
||||
}
|
||||
|
||||
const menuItem = findMenuItemByPath(list.value, index);
|
||||
if (menuItem && menuItem.route) {
|
||||
emit('menu-click', menuItem);
|
||||
if (menuItem && menuItem.path) {
|
||||
// 使用 path 而不是 route,确保菜单项有路径
|
||||
const menuToEmit = {
|
||||
...menuItem,
|
||||
route: menuItem.path, // 兼容性:添加 route 字段
|
||||
label: menuItem.name || menuItem.label
|
||||
};
|
||||
emit('menu-click', menuToEmit);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -16,6 +16,16 @@
|
||||
</el-breadcrumb>
|
||||
</div>
|
||||
<div class="r-content">
|
||||
<!-- 更新缓存按钮 -->
|
||||
<el-button
|
||||
circle
|
||||
:icon="Refresh"
|
||||
@click="refreshCache"
|
||||
class="refresh-cache-btn"
|
||||
:loading="cacheLoading"
|
||||
title="更新菜单缓存"
|
||||
/>
|
||||
|
||||
<!-- 主题切换按钮 -->
|
||||
<el-button
|
||||
circle
|
||||
@@ -50,8 +60,9 @@ import { ref, computed, onMounted, onUnmounted } from "vue";
|
||||
import { useRouter, useRoute } from "vue-router";
|
||||
import { useAllDataStore } from "@/stores";
|
||||
import { useAuthStore } from "@/stores/auth";
|
||||
import { User, SwitchButton, Sunny, Moon } from '@element-plus/icons-vue';
|
||||
import { getAllMenus } from '@/api/menu';
|
||||
import { User, SwitchButton, Sunny, Moon, Refresh } from '@element-plus/icons-vue';
|
||||
import { getAllMenus } from '@/api/menu';
|
||||
import { ElMessage } from 'element-plus';
|
||||
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
@@ -69,14 +80,95 @@ interface Breadcrumb {
|
||||
}
|
||||
|
||||
const menuList = ref<Menu[]>([]);
|
||||
const cacheLoading = ref(false);
|
||||
const MENU_CACHE_KEY = 'menu_cache';
|
||||
|
||||
async function loadMenu() {
|
||||
// 从缓存加载菜单
|
||||
function loadMenuFromCache(): Menu[] | null {
|
||||
try {
|
||||
const cached = localStorage.getItem(MENU_CACHE_KEY);
|
||||
if (cached) {
|
||||
const menuData = JSON.parse(cached);
|
||||
// 检查缓存是否过期(可选:设置过期时间,这里暂时不设置)
|
||||
return menuData;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to load menu from cache', error);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// 保存菜单到缓存
|
||||
function saveMenuToCache(menus: Menu[]) {
|
||||
try {
|
||||
localStorage.setItem(MENU_CACHE_KEY, JSON.stringify(menus));
|
||||
} catch (error) {
|
||||
console.error('Failed to save menu to cache', error);
|
||||
}
|
||||
}
|
||||
|
||||
// 从API加载菜单
|
||||
async function loadMenuFromAPI(updateCache = true) {
|
||||
try {
|
||||
const res = await getAllMenus();
|
||||
menuList.value = res.data || [];
|
||||
const menus = res.data || [];
|
||||
if (updateCache && menus.length > 0) {
|
||||
saveMenuToCache(menus);
|
||||
}
|
||||
return menus;
|
||||
} catch (error) {
|
||||
console.error('Failed to load menu', error);
|
||||
menuList.value = [];
|
||||
console.error('Failed to load menu from API', error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
// 加载菜单(优先从缓存)
|
||||
async function loadMenu() {
|
||||
// 先尝试从缓存加载
|
||||
const cachedMenus = loadMenuFromCache();
|
||||
if (cachedMenus && cachedMenus.length > 0) {
|
||||
menuList.value = cachedMenus;
|
||||
// 异步更新缓存(后台更新,不阻塞UI)
|
||||
loadMenuFromAPI(true).then(menus => {
|
||||
if (menus.length > 0) {
|
||||
menuList.value = menus;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// 缓存不存在,从API加载
|
||||
menuList.value = await loadMenuFromAPI(true);
|
||||
}
|
||||
}
|
||||
|
||||
// 更新缓存(手动刷新)
|
||||
async function refreshCache() {
|
||||
cacheLoading.value = true;
|
||||
try {
|
||||
const menus = await loadMenuFromAPI(true);
|
||||
if (menus.length > 0) {
|
||||
menuList.value = menus;
|
||||
|
||||
// 重新加载动态路由
|
||||
const { loadAndAddDynamicRoutes, resetDynamicRoutes } = await import('@/router/index');
|
||||
// 重置路由加载状态,强制重新加载
|
||||
resetDynamicRoutes();
|
||||
await loadAndAddDynamicRoutes();
|
||||
|
||||
// 等待路由完全加载(给Vue Router一些时间更新路由表)
|
||||
await new Promise(resolve => setTimeout(resolve, 200));
|
||||
|
||||
// 触发菜单刷新事件,通知CommonAside组件刷新菜单
|
||||
window.dispatchEvent(new CustomEvent('menu-cache-refreshed'));
|
||||
|
||||
ElMessage.success('菜单缓存和路由更新成功');
|
||||
} else {
|
||||
ElMessage.warning('未获取到菜单数据');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to refresh cache', error);
|
||||
ElMessage.error('更新缓存失败,请检查网络连接');
|
||||
} finally {
|
||||
cacheLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,7 +211,7 @@ const handleCollapse = () => {
|
||||
store.state.isCollapse = !store.state.isCollapse;
|
||||
};
|
||||
|
||||
const handleCommand = (command) => {
|
||||
const handleCommand = async (command) => {
|
||||
if (command === 'profile') {
|
||||
router.push('/user/userProfile');
|
||||
} else if (command === 'logout') {
|
||||
@@ -130,6 +222,18 @@ const handleCommand = (command) => {
|
||||
//清除租户数据
|
||||
localStorage.removeItem('tenant');
|
||||
sessionStorage.removeItem('tenant');
|
||||
//清除tabs_list缓存
|
||||
localStorage.removeItem('tabs_list');
|
||||
localStorage.removeItem('active_tab');
|
||||
sessionStorage.removeItem('tabs_list');
|
||||
// 清除菜单缓存
|
||||
localStorage.removeItem(MENU_CACHE_KEY);
|
||||
|
||||
// 重置 tabs store 状态
|
||||
const { useTabsStore } = await import('@/stores');
|
||||
const tabsStore = useTabsStore();
|
||||
tabsStore.resetTabs();
|
||||
|
||||
router.push('/login');
|
||||
}
|
||||
};
|
||||
@@ -254,6 +358,21 @@ onUnmounted(() => {
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
|
||||
.refresh-cache-btn,
|
||||
.theme-toggle-btn {
|
||||
// 使用 Element Plus 的填充色变量
|
||||
background-color: var(--el-fill-color-light);
|
||||
border-color: var(--el-border-color);
|
||||
color: var(--el-text-color-primary);
|
||||
margin-left: 0 !important;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--el-fill-color);
|
||||
border-color: var(--el-border-color-dark);
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
}
|
||||
|
||||
.user {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
|
||||
Reference in New Issue
Block a user