修复路由和主题
This commit is contained in:
@@ -9,7 +9,7 @@
|
||||
:background-color="asideBgColor"
|
||||
:text-color="asideTextColor"
|
||||
:active-text-color="activeColor"
|
||||
active-background-color="activeBgColor"
|
||||
:active-background-color="activeBgColor"
|
||||
class="el-menu-vertical-demo"
|
||||
@select="handleMenuSelect"
|
||||
:default-active="route.path"
|
||||
@@ -73,31 +73,61 @@ const loading = ref(true);
|
||||
const store = useAllDataStore();
|
||||
const isCollapse = computed(() => store.state.isCollapse);
|
||||
const width = computed(() => store.state.isCollapse ? '64px' : '180px');
|
||||
const asideBgColor = ref('#0074e9');
|
||||
const asideTextColor = ref('#ffffff');
|
||||
const activeColor = ref ('#fff');
|
||||
const activeBgColor = ref ('#0074e9');
|
||||
// 使用 Element Plus 的颜色变量,主题切换时会自动适配
|
||||
// 这些值会被 el-menu 组件使用,el-menu 会自动适配主题
|
||||
// 计算是否为暗色主题(响应式)
|
||||
const isDark = ref(document.documentElement.classList.contains('dark'));
|
||||
|
||||
// 更新主题颜色
|
||||
const updateThemeColors = () => {
|
||||
try {
|
||||
const root = document.documentElement;
|
||||
const bgColor = getComputedStyle(root).getPropertyValue('--aside-bg-color').trim();
|
||||
const textColor = getComputedStyle(root).getPropertyValue('--aside-text-color').trim();
|
||||
|
||||
// 只有当获取到有效值时才更新
|
||||
if (bgColor) {
|
||||
asideBgColor.value = bgColor;
|
||||
}
|
||||
if (textColor) {
|
||||
asideTextColor.value = textColor;
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('更新主题颜色失败:', e);
|
||||
// 出错时保持默认值
|
||||
}
|
||||
// 监听主题变化
|
||||
const updateTheme = () => {
|
||||
isDark.value = document.documentElement.classList.contains('dark');
|
||||
};
|
||||
|
||||
// 使用 MutationObserver 监听 html 元素的 class 变化(主题切换时更新)
|
||||
let themeObserver = null;
|
||||
|
||||
// 自定义颜色配置
|
||||
const BG_COLOR = '#062da3'; // 背景和 active 颜色
|
||||
const HOVER_COLOR = '#4f84ff'; // hover 颜色
|
||||
|
||||
// 将 hex 颜色转换为 rgba
|
||||
function hexToRgba(hex, alpha = 1) {
|
||||
const r = parseInt(hex.slice(1, 3), 16);
|
||||
const g = parseInt(hex.slice(3, 5), 16);
|
||||
const b = parseInt(hex.slice(5, 7), 16);
|
||||
return `rgba(${r}, ${g}, ${b}, ${alpha})`;
|
||||
}
|
||||
|
||||
// 亮色主题使用自定义背景色,暗色主题使用默认背景
|
||||
const asideBgColor = computed(() => {
|
||||
if (isDark.value) {
|
||||
return 'var(--el-bg-color)';
|
||||
}
|
||||
// 亮色主题使用 #062da3 背景
|
||||
return BG_COLOR;
|
||||
});
|
||||
|
||||
const asideTextColor = computed(() => {
|
||||
if (isDark.value) {
|
||||
return 'var(--el-text-color-primary)';
|
||||
}
|
||||
// 亮色主题使用白色文字
|
||||
return '#ffffff';
|
||||
});
|
||||
|
||||
const activeColor = ref('#ffffff'); // active 文字颜色为白色
|
||||
|
||||
// hover 和 active 背景色
|
||||
const activeBgColor = computed(() => {
|
||||
if (isDark.value) {
|
||||
return 'rgba(255, 255, 255, 0.1)';
|
||||
}
|
||||
// 亮色主题 active 使用 #4f84ff
|
||||
return HOVER_COLOR;
|
||||
});
|
||||
|
||||
// 不再需要手动更新主题颜色,因为使用了 Element Plus 的 CSS 变量,会自动适配
|
||||
|
||||
// 将后端数据转换为前端需要的格式
|
||||
const transformMenuData = (menus) => {
|
||||
// 首先映射字段格式
|
||||
@@ -213,25 +243,25 @@ const fetchMenus = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
// 组件挂载时获取菜单
|
||||
// 组件挂载时初始化主题监听和获取菜单
|
||||
onMounted(() => {
|
||||
// 先更新主题颜色,确保组件可见
|
||||
updateThemeColors();
|
||||
// 初始化主题监听
|
||||
themeObserver = new MutationObserver(() => {
|
||||
updateTheme();
|
||||
});
|
||||
|
||||
themeObserver.observe(document.documentElement, {
|
||||
attributes: true,
|
||||
attributeFilter: ['class']
|
||||
});
|
||||
|
||||
// 初始化时检查一次主题
|
||||
updateTheme();
|
||||
|
||||
// 延迟一点获取菜单,确保主题已初始化
|
||||
setTimeout(() => {
|
||||
fetchMenus();
|
||||
}, 100);
|
||||
|
||||
// 监听主题变化事件
|
||||
window.addEventListener('theme-change', updateThemeColors);
|
||||
|
||||
// 监听 CSS 变量变化(MutationObserver)
|
||||
const observer = new MutationObserver(updateThemeColors);
|
||||
observer.observe(document.documentElement, {
|
||||
attributes: true,
|
||||
attributeFilter: ['data-theme']
|
||||
});
|
||||
});
|
||||
|
||||
// 计算属性:统一排序所有菜单项(不再区分有无子菜单)
|
||||
@@ -304,12 +334,18 @@ const findMenuItemByPath = (menus, path) => {
|
||||
<style scoped lang="less">
|
||||
.common-aside {
|
||||
height: 100%;
|
||||
background-color: var(--aside-bg-color, #0074e9);
|
||||
// 亮色主题使用 primary 浅色,暗色主题使用默认背景
|
||||
background-color: var(--el-bg-color);
|
||||
transition: width 0.3s, background-color 0.3s ease;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
display: block !important;
|
||||
visibility: visible !important;
|
||||
|
||||
// 亮色主题下的特殊处理
|
||||
html:not(.dark) & {
|
||||
background-color: #062da3;
|
||||
}
|
||||
}
|
||||
|
||||
.icons {
|
||||
@@ -318,8 +354,10 @@ const findMenuItemByPath = (menus, path) => {
|
||||
margin-right: 8px;
|
||||
font-size: 16px;
|
||||
transition: var(--transition-fast);
|
||||
&:hover {
|
||||
color: var(--primary-color);
|
||||
|
||||
// 亮色主题下默认使用白色
|
||||
html:not(.dark) & {
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -330,6 +368,121 @@ h3{
|
||||
justify-content: center;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
// 亮色主题使用白色,暗色主题使用默认文字颜色
|
||||
color: var(--el-text-color-primary);
|
||||
|
||||
html:not(.dark) & {
|
||||
color: #ffffff;
|
||||
}
|
||||
}
|
||||
|
||||
// 菜单项样式:优化 hover 和 active 状态的视觉效果
|
||||
:deep(.el-menu) {
|
||||
.el-menu-item {
|
||||
transition: all 0.3s ease;
|
||||
position: relative;
|
||||
|
||||
// hover 状态:亮色主题使用 #4f84ff
|
||||
&:hover:not(.is-active) {
|
||||
background-color: #4f84ff !important;
|
||||
color: #ffffff !important;
|
||||
|
||||
// 确保图标在 hover 状态下也有正确的颜色
|
||||
.icons {
|
||||
color: #ffffff !important;
|
||||
}
|
||||
}
|
||||
|
||||
// active 状态:使用 #4f84ff 背景色,白色文字
|
||||
&.is-active {
|
||||
background-color: #4f84ff !important;
|
||||
color: #ffffff !important;
|
||||
font-weight: 600;
|
||||
|
||||
// 添加左侧边框作为指示器(使用更亮的颜色)
|
||||
border-left: 3px solid #ffffff;
|
||||
margin-left: -3px; // 使用负边距补偿,保持文字位置不变
|
||||
|
||||
// 确保图标在 active 状态下也有正确的颜色
|
||||
.icons {
|
||||
color: #ffffff !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 子菜单项也需要相同的效果
|
||||
.el-sub-menu {
|
||||
.el-menu-item {
|
||||
&:hover:not(.is-active) {
|
||||
background-color: #4f84ff !important;
|
||||
color: #ffffff !important;
|
||||
|
||||
.icons {
|
||||
color: #ffffff !important;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-active {
|
||||
background-color: #4f84ff !important;
|
||||
color: #ffffff !important;
|
||||
font-weight: 600;
|
||||
|
||||
// 添加左侧边框作为指示器
|
||||
border-left: 3px solid #ffffff;
|
||||
margin-left: -3px; // 使用负边距补偿,保持文字位置不变
|
||||
|
||||
.icons {
|
||||
color: #ffffff !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 暗色主题下的特殊处理
|
||||
html.dark & {
|
||||
.el-menu-item {
|
||||
&:hover:not(.is-active) {
|
||||
background-color: rgba(255, 255, 255, 0.08) !important;
|
||||
color: var(--el-color-primary-light-3) !important;
|
||||
|
||||
.icons {
|
||||
color: var(--el-color-primary-light-3) !important;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-active {
|
||||
background-color: rgba(255, 255, 255, 0.12) !important;
|
||||
color: var(--el-color-primary-light-3) !important;
|
||||
border-left-color: var(--el-color-primary-light-3);
|
||||
|
||||
.icons {
|
||||
color: var(--el-color-primary-light-3) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.el-sub-menu {
|
||||
.el-menu-item {
|
||||
&:hover:not(.is-active) {
|
||||
background-color: rgba(255, 255, 255, 0.08) !important;
|
||||
color: var(--el-color-primary-light-3) !important;
|
||||
|
||||
.icons {
|
||||
color: var(--el-color-primary-light-3) !important;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-active {
|
||||
background-color: rgba(255, 255, 255, 0.12) !important;
|
||||
color: var(--el-color-primary-light-3) !important;
|
||||
border-left-color: var(--el-color-primary-light-3);
|
||||
|
||||
.icons {
|
||||
color: var(--el-color-primary-light-3) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted } from "vue";
|
||||
import { ref, computed, onMounted, onUnmounted } from "vue";
|
||||
import { useRouter, useRoute } from "vue-router";
|
||||
import { useAllDataStore } from "@/stores";
|
||||
import { useAuthStore } from "@/stores/auth";
|
||||
@@ -138,6 +138,73 @@ const handleCommand = (command) => {
|
||||
router.push('/login');
|
||||
}
|
||||
};
|
||||
|
||||
// Element Plus 主题切换
|
||||
const THEME_STORAGE_KEY = 'element-plus-theme';
|
||||
const isDark = ref(false);
|
||||
|
||||
// 初始化主题:从 localStorage 读取或检测系统偏好
|
||||
const initTheme = () => {
|
||||
const savedTheme = localStorage.getItem(THEME_STORAGE_KEY);
|
||||
if (savedTheme) {
|
||||
isDark.value = savedTheme === 'dark';
|
||||
} else {
|
||||
// 检测系统偏好
|
||||
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||
isDark.value = prefersDark;
|
||||
}
|
||||
applyTheme();
|
||||
};
|
||||
|
||||
// 应用主题:在 html 元素上添加/移除 dark 类
|
||||
const applyTheme = () => {
|
||||
const htmlElement = document.documentElement;
|
||||
if (isDark.value) {
|
||||
htmlElement.classList.add('dark');
|
||||
localStorage.setItem(THEME_STORAGE_KEY, 'dark');
|
||||
} else {
|
||||
htmlElement.classList.remove('dark');
|
||||
localStorage.setItem(THEME_STORAGE_KEY, 'light');
|
||||
}
|
||||
};
|
||||
|
||||
// 切换主题
|
||||
const toggleTheme = () => {
|
||||
isDark.value = !isDark.value;
|
||||
applyTheme();
|
||||
};
|
||||
|
||||
// 计算当前主题
|
||||
const currentTheme = computed(() => isDark.value ? 'dark' : 'light');
|
||||
|
||||
// 计算主题图标
|
||||
const themeIcon = computed(() => isDark.value ? Sunny : Moon);
|
||||
|
||||
// 组件挂载时初始化主题
|
||||
let mediaQuery: MediaQueryList | null = null;
|
||||
let handleChange: ((e: MediaQueryListEvent) => void) | null = null;
|
||||
|
||||
onMounted(() => {
|
||||
initTheme();
|
||||
|
||||
// 监听系统主题变化
|
||||
mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
|
||||
handleChange = (e: MediaQueryListEvent) => {
|
||||
// 如果用户没有手动设置主题,则跟随系统
|
||||
if (!localStorage.getItem(THEME_STORAGE_KEY)) {
|
||||
isDark.value = e.matches;
|
||||
applyTheme();
|
||||
}
|
||||
};
|
||||
mediaQuery.addEventListener('change', handleChange);
|
||||
});
|
||||
|
||||
// 组件卸载时清理
|
||||
onUnmounted(() => {
|
||||
if (mediaQuery && handleChange) {
|
||||
mediaQuery.removeEventListener('change', handleChange);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
@@ -148,9 +215,17 @@ const handleCommand = (command) => {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 0 40px;
|
||||
background-color: var(--header-bg-color, #0074e9);
|
||||
color: var(--header-text-color, #fff);
|
||||
transition: background-color 0.3s ease, color 0.3s ease;
|
||||
// 使用 Element Plus 的背景色变量,暗黑模式下自动适配
|
||||
background-color: var(--el-bg-color);
|
||||
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;
|
||||
border-bottom-color: rgba(79, 132, 255, 0.3);
|
||||
}
|
||||
}
|
||||
|
||||
.icons {
|
||||
@@ -164,13 +239,15 @@ const handleCommand = (command) => {
|
||||
|
||||
.el-button {
|
||||
margin-right: 20px;
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
border-color: rgba(255, 255, 255, 0.2);
|
||||
color: var(--header-text-color, #fff);
|
||||
// 使用 Element Plus 的填充色变量
|
||||
background-color: var(--el-fill-color-light);
|
||||
border-color: var(--el-border-color);
|
||||
color: var(--el-text-color-primary);
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(255, 255, 255, 0.2);
|
||||
border-color: rgba(255, 255, 255, 0.3);
|
||||
background-color: var(--el-fill-color);
|
||||
border-color: var(--el-border-color-dark);
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -186,8 +263,13 @@ const handleCommand = (command) => {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
border: 2px solid rgba(255, 255, 255, 0.3);
|
||||
// 使用 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 {
|
||||
@@ -234,16 +316,17 @@ const handleCommand = (command) => {
|
||||
}
|
||||
|
||||
:deep(.bread) {
|
||||
// 面包屑使用白色
|
||||
.el-breadcrumb__inner {
|
||||
color: var(--header-text-color, #fff) !important;
|
||||
color: #ffffff !important;
|
||||
}
|
||||
|
||||
.el-breadcrumb__inner.is-link {
|
||||
color: var(--header-text-color, #fff) !important;
|
||||
color: #ffffff !important;
|
||||
cursor: pointer !important;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.8;
|
||||
color: rgba(255, 255, 255, 0.8) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user