优化仪表盘等

This commit is contained in:
2025-11-13 11:28:00 +08:00
parent db16ee70de
commit 117e2b3440
18 changed files with 863 additions and 442 deletions
+54 -58
View File
@@ -5,36 +5,22 @@
<i class="fa fa-bars"></i>
</el-button>
<el-breadcrumb separator="/" class="bread">
<el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
<el-breadcrumb-item
v-for="(item, index) in breadcrumbs"
:key="index"
:to="(item.label === '首页' || index === breadcrumbs.length - 1) ? { path: item.path } : null"
>
<el-breadcrumb-item :to="{ path: '/' }" style="position: relative !important; top: 1px !important;">首页</el-breadcrumb-item>
<el-breadcrumb-item v-for="(item, index) in breadcrumbs" :key="index"
:to="(item.label === '首页' || index === breadcrumbs.length - 1) ? { path: item.path } : null" style="position: relative !important; top: 1px !important;">
{{ item.label }}
</el-breadcrumb-item>
</el-breadcrumb>
</div>
<div class="r-content">
<!-- 更新缓存按钮 -->
<el-button
circle
:icon="Refresh"
@click="refreshCache"
class="refresh-cache-btn"
:loading="cacheLoading"
title="更新菜单缓存"
/>
<el-button circle :icon="Refresh" @click="refreshCache" class="refresh-cache-btn" :loading="cacheLoading"
title="更新菜单缓存" />
<!-- 主题切换按钮 -->
<el-button
circle
:icon="themeIcon"
@click="toggleTheme"
class="theme-toggle-btn"
:title="currentTheme === 'dark' ? '切换到亮色模式' : '切换到暗色模式'"
/>
<el-button circle :icon="themeIcon" @click="toggleTheme" class="theme-toggle-btn"
:title="currentTheme === 'dark' ? '切换到亮色模式' : '切换到暗色模式'" />
<el-dropdown trigger="click" @command="handleCommand">
<span class="el-dropdown-link" style="cursor: pointer;">
<img :src="getImageUrl('user')" class="user" />
@@ -43,11 +29,15 @@
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item command="profile">
<el-icon><User /></el-icon>
<el-icon>
<User />
</el-icon>
<span>个人中心</span>
</el-dropdown-item>
<el-dropdown-item divided command="logout">
<el-icon><SwitchButton /></el-icon>
<el-icon>
<SwitchButton />
</el-icon>
<span>退出登录</span>
</el-dropdown-item>
</el-dropdown-menu>
@@ -56,13 +46,14 @@
</div>
</div>
</template>
<script setup lang="ts">
import { ref, computed, onMounted, onUnmounted } from "vue";
import { useRouter, useRoute } from "vue-router";
import { useAllDataStore, useMenuStore } from "@/stores";
import { useAuthStore } from "@/stores/auth";
import { User, SwitchButton, Sunny, Moon, Refresh } from '@element-plus/icons-vue';
import { ElMessage } from 'element-plus';
import { ElMessage } from 'element-plus';
const router = useRouter();
const route = useRoute();
@@ -95,19 +86,19 @@ async function refreshCache() {
cacheLoading.value = true;
try {
await menuStore.refreshMenus();
// 重新加载动态路由
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('更新成功');
} catch (error) {
console.error('Failed to refresh cache', error);
@@ -117,14 +108,14 @@ async function refreshCache() {
}
}
onMounted(loadMenu);
onMounted(loadMenu);
// 根据菜单列表和当前路径计算出的面包屑导航
const breadcrumbs = computed(() => {
let chain: Breadcrumb[] = [];
let currentPath = route.path || '/';
if (currentPath === '/' || currentPath === '') {
return [{ label: '仪表盘', path: '/' }];
return [{ label: '仪表盘', path: '/' }];
}
let current = menuList.value.find(m => m.path === currentPath);
if (!current) {
@@ -141,8 +132,8 @@ const breadcrumbs = computed(() => {
parentId = parent.parentId;
} else break;
}
chain = chain.reverse();
return chain;
chain = chain.reverse();
return chain;
});
const store = useAllDataStore();
@@ -156,17 +147,17 @@ const getImageUrl = (user) => {
const displayName = computed(() => {
const user = authStore.user;
if (!user) return '';
// 如果是员工登录,优先显示name
if (user.type === 'employee' && user.name) {
return user.name;
}
// 如果是用户登录,优先显示nickname
if (user.nickname) {
return user.nickname;
}
// 最后显示username
return user.username || '';
});
@@ -192,7 +183,7 @@ const handleCommand = async (command) => {
sessionStorage.removeItem('tabs_list');
// 清除菜单缓存
menuStore.resetMenus();
// 清除所有以 menu_cache_ 开头的本地存储项
const menuCacheKeys: string[] = [];
// 遍历 localStorage
@@ -206,7 +197,7 @@ const handleCommand = async (command) => {
menuCacheKeys.forEach(key => {
localStorage.removeItem(key);
});
// 遍历 sessionStorage
const sessionMenuCacheKeys: string[] = [];
for (let i = 0; i < sessionStorage.length; i++) {
@@ -219,12 +210,12 @@ const handleCommand = async (command) => {
sessionMenuCacheKeys.forEach(key => {
sessionStorage.removeItem(key);
});
// 重置 tabs store 状态
const { useTabsStore } = await import('@/stores');
const tabsStore = useTabsStore();
tabsStore.resetTabs();
router.push('/login');
}
};
@@ -276,7 +267,7 @@ let handleChange: ((e: MediaQueryListEvent) => void) | null = null;
onMounted(() => {
initTheme();
// 监听系统主题变化
mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
handleChange = (e: MediaQueryListEvent) => {
@@ -310,7 +301,7 @@ onUnmounted(() => {
color: var(--el-text-color-primary);
border-bottom: 1px solid var(--el-border-color-lighter);
transition: background-color 0.3s ease, color 0.3s ease, border-color 0.3s ease;
// 亮色主题下使用 #062da3 背景
html:not(.dark) & {
background-color: #062da3;
@@ -333,7 +324,7 @@ onUnmounted(() => {
background-color: var(--el-fill-color-light);
border-color: var(--el-border-color);
color: var(--el-text-color-primary);
&:hover {
background-color: var(--el-fill-color);
border-color: var(--el-border-color-dark);
@@ -348,7 +339,7 @@ onUnmounted(() => {
display: flex;
align-items: center;
gap: 16px;
.refresh-cache-btn,
.theme-toggle-btn {
// 使用 Element Plus 的填充色变量
@@ -356,14 +347,14 @@ onUnmounted(() => {
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;
@@ -371,18 +362,18 @@ onUnmounted(() => {
// 使用 Element Plus 的边框颜色变量
border: 2px solid var(--el-border-color);
transition: border-color 0.3s ease;
&:hover {
border-color: var(--el-color-primary);
}
}
.el-dropdown-link {
display: flex;
align-items: center;
cursor: pointer;
gap: 12px;
.user-name {
font-size: 14px;
color: var(--el-text-color-primary);
@@ -391,7 +382,7 @@ onUnmounted(() => {
max-width: 120px;
overflow: hidden;
text-overflow: ellipsis;
// 亮色主题下使用白色
html:not(.dark) & {
color: #ffffff;
@@ -407,27 +398,27 @@ onUnmounted(() => {
background-color: var(--bg-color-overlay) !important;
border-color: var(--border-color) !important;
padding: 4px 0;
.el-dropdown-menu__item {
display: flex;
align-items: center;
gap: 8px;
color: var(--text-color-primary) !important;
transition: background-color 0.2s ease, color 0.2s ease;
span {
margin-left: 0;
}
.el-icon {
color: var(--text-color-primary) !important;
}
&:not(.is-disabled):hover {
background-color: var(--fill-color-light) !important;
color: var(--text-color-primary) !important;
}
&.is-divided {
border-top-color: var(--border-color) !important;
}
@@ -437,18 +428,23 @@ onUnmounted(() => {
}
:deep(.bread) {
// 面包屑使用白色
.el-breadcrumb__inner {
color: #ffffff !important;
}
.el-breadcrumb__inner.is-link {
color: #ffffff !important;
cursor: pointer !important;
&:hover {
color: rgba(255, 255, 255, 0.8) !important;
}
}
}
:deep(.el-tabs__nav){
height: 36px !important;
}
</style>