You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
403 lines
11 KiB
403 lines
11 KiB
<script setup>
|
|
// 导航栏在这
|
|
import { computed, ref } from 'vue'
|
|
import { useRoute, useRouter } from 'vue-router'
|
|
import { ElMessage } from 'element-plus'
|
|
import dmmn from '../assets/link.png'
|
|
import ChangePassword from '@/components/changePassword.vue'
|
|
import { useAdminStore } from '@/store'
|
|
import { storeToRefs } from 'pinia'
|
|
import { filterMenu, getRoutePath } from "@/utils/menuUtils.js";
|
|
import SettingsIcon from '@/assets/blue.png';
|
|
|
|
|
|
// 存储接口返回的菜单数据
|
|
const menuList = ref([])
|
|
|
|
// 获取仓库实例
|
|
const adminStore = useAdminStore()
|
|
// 解构状态(保持响应式) 获得 adminData(用户信息) 和 menuTree(菜单树)
|
|
const { adminData, menuTree } = storeToRefs(adminStore)
|
|
|
|
// 筛选权限菜单 ,menuTree 是组件通信拿的
|
|
menuList.value = filterMenu(menuTree.value)
|
|
|
|
console.log("menuList", menuList.value)
|
|
// 获取当前路由
|
|
const route = useRoute()
|
|
|
|
// 通用函数:从菜单树中递归找出最匹配的 index
|
|
function findBestMatch(menuList, path) {
|
|
let bestMatch = ''
|
|
|
|
function traverse(menus) {
|
|
for (const item of menus) {
|
|
const itemPath = getRoutePath(item)
|
|
// 如果当前菜单的 path 是当前路径的前缀,可能是候选项
|
|
if (path.startsWith(itemPath) && itemPath.length > bestMatch.length) {
|
|
bestMatch = itemPath
|
|
}
|
|
|
|
if (item.children && item.children.length > 0) {
|
|
traverse(item.children)
|
|
}
|
|
}
|
|
}
|
|
|
|
traverse(menuList)
|
|
return bestMatch || path // fallback 到当前路径
|
|
}
|
|
|
|
// 响应式高亮菜单
|
|
const activeMenu = computed(() => {
|
|
return findBestMatch(menuList.value, route.path)
|
|
})
|
|
const router = useRouter()
|
|
const imgrule1 = dmmn
|
|
const messageVisible = ref(false)
|
|
|
|
|
|
// 查看个人信息弹出框
|
|
const openMessage = function () {
|
|
messageVisible.value = true
|
|
}
|
|
// 关闭个人信息
|
|
const closeMessage = function () {
|
|
messageVisible.value = false
|
|
}
|
|
const message = function () {
|
|
openMessage()
|
|
}
|
|
|
|
// 显示修改密码弹窗
|
|
const showPasswordDialog = ref(false)
|
|
const pwdRef = ref()
|
|
|
|
//打开修改密码弹窗
|
|
const openChangePassword = () => {
|
|
showPasswordDialog.value = true
|
|
}
|
|
//关闭后清空密码表单
|
|
function onPwdDialogClosed() {
|
|
// 调用子组件暴露的 resetFields
|
|
pwdRef.value?.resetFields()
|
|
}
|
|
|
|
function logout() {
|
|
const machineId = localStorage.getItem('machineId')
|
|
localStorage.removeItem('token')
|
|
adminStore.clearState()
|
|
router.push('/login?machineId=' + machineId)
|
|
ElMessage.success('退出成功')
|
|
}
|
|
|
|
|
|
</script>
|
|
|
|
<template>
|
|
<div class="main-container">
|
|
<!-- 背景毛玻璃层(作为内容容器) -->
|
|
<div class="background-glass">
|
|
<!-- 侧边栏 -->
|
|
<div class="sidebar-container">
|
|
<el-aside class="sidebar-layout">
|
|
<div class="logo">
|
|
<img src="../assets/新logo.png" alt="logo" style="width: 9vh; height: 9vh" />
|
|
</div>
|
|
|
|
<div class="menu-scroll-container">
|
|
<el-menu :router="true" :default-active="activeMenu" style="min-height: 80vh;border:none;">
|
|
<!-- 递归渲染菜单层级 -->
|
|
<template v-for="menu in menuList" :key="menu.id">
|
|
<!-- 有子菜单的父级菜单(menuType=2 且存在children) -->
|
|
<el-sub-menu v-if="menu.children && menu.children.length > 0" :index="menu.id.toString()">
|
|
<template #title>
|
|
<el-icon>
|
|
<Folder />
|
|
</el-icon>
|
|
<span>{{ menu.menuName }}</span>
|
|
</template>
|
|
<!-- 子菜单 -->
|
|
<template v-for="child in menu.children" :key="child.id">
|
|
<!-- 子菜单为叶子节点(无children) -->
|
|
<el-menu-item v-if="!child.children || child.children.length === 0" :index="getRoutePath(child)">
|
|
<span>{{ child.menuName }}</span>
|
|
</el-menu-item>
|
|
|
|
<!-- 子菜单有下级 -->
|
|
<el-sub-menu v-else :index="child.id.toString()">
|
|
<template #title>
|
|
<span>{{ child.menuName }}</span>
|
|
</template>
|
|
<!-- 递归 下一级-->
|
|
<template v-for="grandChild in child.children" :key="grandChild.id">
|
|
<el-menu-item :index="getRoutePath(grandChild)">
|
|
<span>{{ grandChild.menuName }}</span>
|
|
</el-menu-item>
|
|
</template>
|
|
</el-sub-menu>
|
|
</template>
|
|
</el-sub-menu>
|
|
|
|
<!-- 无子菜单的一级菜单 -->
|
|
<el-menu-item v-else :index="getRoutePath(menu)">
|
|
<el-icon>
|
|
<Folder />
|
|
</el-icon>
|
|
<span>{{ menu.menuName }}</span>
|
|
</el-menu-item>
|
|
</template>
|
|
</el-menu>
|
|
</div>
|
|
|
|
<!-- 底部固定的设置中心 -->
|
|
<div class="settings-container">
|
|
<el-dropdown placement="top-start">
|
|
<span class="el-dropdown-link">
|
|
<img src="@/assets/SvgIcons/设置.svg" alt="设置" style="width: 4vh; height: 4vh" />
|
|
<span>设置中心</span>
|
|
<el-icon class="arrow-icon">
|
|
<ArrowUp />
|
|
</el-icon>
|
|
</span>
|
|
<template #dropdown>
|
|
<el-dropdown-menu>
|
|
<el-dropdown-item @click="message()">查看个人信息</el-dropdown-item>
|
|
<el-dropdown-item @click="openChangePassword">修改密码</el-dropdown-item>
|
|
<el-dropdown-item @click="logout">退出登录</el-dropdown-item>
|
|
</el-dropdown-menu>
|
|
</template>
|
|
</el-dropdown>
|
|
</div>
|
|
</el-aside>
|
|
</div>
|
|
|
|
<!-- 右侧内容区域 -->
|
|
<div class="content-container">
|
|
<!-- 头部 -->
|
|
<el-header class="header">
|
|
|
|
</el-header>
|
|
|
|
<!-- 主内容区域 -->
|
|
<div class="main-area">
|
|
<el-main>
|
|
<router-view></router-view>
|
|
</el-main>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 查看个人信息 -->
|
|
<el-dialog v-model="messageVisible" title="查看个人信息" width="500px">
|
|
<el-form :model="adminData">
|
|
<el-form-item label="用户姓名" label-width="100px" label-position="left">
|
|
<span class="message-font">{{ adminData.adminName }}</span>
|
|
</el-form-item>
|
|
<el-form-item label="精网号" label-width="100px" label-position="left">
|
|
<span class="message-font">{{ adminData.account }}</span>
|
|
</el-form-item>
|
|
<el-form-item label="地区" label-width="100px" label-position="left">
|
|
<span class="message-font">{{ adminData.markets }}</span>
|
|
</el-form-item>
|
|
<el-form-item label="注册时间" label-width="100px" label-position="left">
|
|
<span class="message-font">{{ adminData.createTime }}</span>
|
|
</el-form-item>
|
|
</el-form>
|
|
<template #footer>
|
|
<div>
|
|
<el-button text @click="closeMessage()">关闭</el-button>
|
|
</div>
|
|
</template>
|
|
</el-dialog>
|
|
|
|
<!-- 自定义密码修改弹窗组件 -->
|
|
<el-dialog v-model="showPasswordDialog" :center="true" width="470px" @closed="onPwdDialogClosed">
|
|
<ChangePassword ref="pwdRef" @confirm="showPasswordDialog = false" />
|
|
</el-dialog>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped>
|
|
/* 主容器,设置背景图并居中 */
|
|
.main-container {
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
background-image: url('@/assets/backgroundBlue.png');
|
|
background-size: cover;
|
|
background-position: center center;
|
|
background-repeat: no-repeat;
|
|
overflow: hidden;
|
|
}
|
|
|
|
/* 背景毛玻璃层(作为内容容器) */
|
|
.background-glass {
|
|
position: absolute;
|
|
top: 1vh;
|
|
left: 1vh;
|
|
right: 1vh;
|
|
bottom: 1vh;
|
|
/* 毛玻璃效果 */
|
|
background-image: url('@/assets/半透明background.png');
|
|
|
|
z-index: 1;
|
|
display: flex;
|
|
flex-direction: row;
|
|
padding: 10px;
|
|
border-radius: 12px;
|
|
}
|
|
|
|
/* 侧边栏容器 */
|
|
.sidebar-container {
|
|
flex-shrink: 0;
|
|
}
|
|
.logo {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
height: 12vh;
|
|
|
|
}
|
|
/* 中间可滚动菜单容器 */
|
|
.menu-scroll-container {
|
|
flex: 1;
|
|
overflow-y: auto;
|
|
padding: 10px 0;
|
|
}
|
|
|
|
/* 底部设置中心样式 */
|
|
.settings-container {
|
|
padding: 10px 0 10px 20px; /* 上,右, 下,左 */
|
|
background: rgba(255, 255, 255, 0.85);
|
|
display: flex;
|
|
align-items: center; /* 垂直居中 */
|
|
}
|
|
|
|
/* 调整下拉菜单的样式,确保它向上弹出 */
|
|
|
|
.el-dropdown-link:focus {
|
|
/* 移除异常效果 */
|
|
outline: none;
|
|
text-decoration: none;
|
|
}
|
|
.el-dropdown-link {
|
|
display: flex;
|
|
align-items: center;
|
|
cursor: pointer;
|
|
gap:10px; /* 图标和文字左右间距 */
|
|
}
|
|
.sidebar-layout {
|
|
width: 15vw;
|
|
height: 100%;
|
|
background: rgba(255, 255, 255, 0.85); /* 半透明白色背景 */
|
|
backdrop-filter: blur(5px); /* 毛玻璃效果 */
|
|
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1); /* 添加阴影增强层次感 */
|
|
border-radius: 12px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
position: relative;
|
|
}
|
|
|
|
/* 内容区域容器 */
|
|
.content-container {
|
|
flex: 1;
|
|
display: flex;
|
|
flex-direction: column;
|
|
margin-left: 5px;
|
|
gap: 5px;
|
|
height: 100%;
|
|
overflow: hidden;
|
|
}
|
|
|
|
/* 头部样式 */
|
|
.header {
|
|
background: rgba(255, 255, 255, 0.9);
|
|
/* 半透明白色背景 */
|
|
backdrop-filter: blur(5px);
|
|
/* 毛玻璃效果 */
|
|
height: 8vh;
|
|
border-radius: 12px;
|
|
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
|
|
/* 添加阴影增强层次感 */
|
|
z-index: 80;
|
|
}
|
|
|
|
/* 主内容区域容器 */
|
|
.main-area {
|
|
flex: 1;
|
|
background: rgba(255, 255, 255, 0.9);
|
|
/* 半透明白色背景 */
|
|
backdrop-filter: blur(5px);
|
|
/* 毛玻璃效果 */
|
|
border-radius: 12px;
|
|
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
|
|
/* 添加阴影增强层次感 */
|
|
overflow: hidden;
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
/* 主内容区域样式 */
|
|
.el-main {
|
|
height: 100%;
|
|
padding: 20px;
|
|
background: transparent;
|
|
overflow-y: auto;
|
|
/* 应用自定义滚动条 */
|
|
}
|
|
|
|
|
|
|
|
/* 确保el-menu撑满容器 */
|
|
.sidebar-layout .el-menu {
|
|
width: 100%;
|
|
}
|
|
|
|
/* 感觉没用 */
|
|
.el-menu-demo {
|
|
border: none;
|
|
padding: 0;
|
|
float: right;
|
|
background: transparent !important;
|
|
/* 最高优先级的透明 */
|
|
}
|
|
|
|
/* 侧边栏菜单样式优化 感觉没用*/
|
|
.el-menu {
|
|
background: transparent !important;
|
|
}
|
|
|
|
::v-deep(.el-sub-menu__title:hover) {
|
|
background: transparent !important;
|
|
}
|
|
|
|
.message-font {
|
|
/* 个人信息字体样式 */
|
|
font-size: 16px;
|
|
font-weight: bold;
|
|
}
|
|
|
|
|
|
|
|
/* 确保全局el-container适应容器 */
|
|
:deep(.el-container) {
|
|
/* vue3的深度选择器,用于覆盖element-plus的默认样式 */
|
|
min-height: 100%;
|
|
width: 100%;
|
|
background: transparent;
|
|
}
|
|
|
|
|
|
|
|
/* 为侧边栏和主内容区域添加滚动条样式 */
|
|
.menu-scroll-container,
|
|
.el-main {
|
|
scrollbar-width: thin;
|
|
/* Firefox */
|
|
scrollbar-color: rgba(0, 0, 0, 0.3) rgba(255, 255, 255, 0.2);
|
|
/* Firefox滑块和轨道颜色 */
|
|
}
|
|
</style>
|