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.

339 lines
9.8 KiB

3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 weeks ago
3 weeks ago
3 weeks ago
3 months ago
3 weeks ago
3 weeks ago
  1. <script setup>
  2. // 导航栏在这
  3. import { computed, ref } from 'vue'
  4. import { useRoute, useRouter } from 'vue-router'
  5. import { ElMessage } from 'element-plus'
  6. import dmmn from '../assets/link.png'
  7. import ChangePassword from '@/components/changePassword.vue'
  8. import { useAdminStore } from '@/store'
  9. import { storeToRefs } from 'pinia'
  10. import { filterMenu, getRoutePath } from "@/utils/menuUtils.js";
  11. // 存储接口返回的菜单数据
  12. const menuList = ref([])
  13. // 获取仓库实例
  14. const adminStore = useAdminStore()
  15. // 解构状态(保持响应式) 获得 adminData(用户信息) 和 menuTree(菜单树)
  16. const { adminData, menuTree } = storeToRefs(adminStore)
  17. // 筛选权限菜单 ,menuTree 是组件通信拿的
  18. menuList.value = filterMenu(menuTree.value)
  19. console.log("menuList", menuList.value)
  20. // 获取当前路由
  21. const route = useRoute()
  22. // 通用函数:从菜单树中递归找出最匹配的 index
  23. function findBestMatch(menuList, path) {
  24. let bestMatch = ''
  25. function traverse(menus) {
  26. for (const item of menus) {
  27. const itemPath = getRoutePath(item)
  28. // 如果当前菜单的 path 是当前路径的前缀,可能是候选项
  29. if (path.startsWith(itemPath) && itemPath.length > bestMatch.length) {
  30. bestMatch = itemPath
  31. }
  32. if (item.children && item.children.length > 0) {
  33. traverse(item.children)
  34. }
  35. }
  36. }
  37. traverse(menuList)
  38. return bestMatch || path // fallback 到当前路径
  39. }
  40. // 响应式高亮菜单
  41. const activeMenu = computed(() => {
  42. return findBestMatch(menuList.value, route.path)
  43. })
  44. const router = useRouter()
  45. const imgrule1 = dmmn
  46. const messageVisible = ref(false)
  47. // 查看个人信息弹出框
  48. const openMessage = function () {
  49. messageVisible.value = true
  50. }
  51. // 关闭个人信息
  52. const closeMessage = function () {
  53. messageVisible.value = false
  54. }
  55. const message = function () {
  56. openMessage()
  57. }
  58. // 显示修改密码弹窗
  59. const showPasswordDialog = ref(false)
  60. const pwdRef = ref()
  61. //打开修改密码弹窗
  62. const openChangePassword = () => {
  63. showPasswordDialog.value = true
  64. }
  65. //关闭后清空密码表单
  66. function onPwdDialogClosed() {
  67. // 调用子组件暴露的 resetFields
  68. pwdRef.value?.resetFields()
  69. }
  70. function logout() {
  71. const machineId = localStorage.getItem('machineId')
  72. localStorage.removeItem('token')
  73. adminStore.clearState()
  74. router.push('/login?machineId=' + machineId)
  75. ElMessage.success('退出成功')
  76. }
  77. </script>
  78. <template>
  79. <div class="main-container">
  80. <!-- 背景毛玻璃层作为内容容器 -->
  81. <div class="background-glass">
  82. <!-- 侧边栏 -->
  83. <div class="sidebar-container">
  84. <el-aside>
  85. <div class="logo">
  86. <img src="../assets/新logo.png" alt="logo" style="width: 9vh; height: 9vh" />
  87. </div>
  88. <el-menu :router="true" :default-active="activeMenu" style="min-height: 80vh;border:none;">
  89. <!-- 递归渲染菜单层级 -->
  90. <template v-for="menu in menuList" :key="menu.id">
  91. <!-- 有子菜单的父级菜单menuType=2 且存在children -->
  92. <el-sub-menu v-if="menu.children && menu.children.length > 0" :index="menu.id.toString()">
  93. <template #title>
  94. <el-icon>
  95. <Folder />
  96. </el-icon>
  97. <span>{{ menu.menuName }}</span>
  98. </template>
  99. <!-- 子菜单 -->
  100. <template v-for="child in menu.children" :key="child.id">
  101. <!-- 子菜单为叶子节点无children -->
  102. <el-menu-item v-if="!child.children || child.children.length === 0" :index="getRoutePath(child)">
  103. <span>{{ child.menuName }}</span>
  104. </el-menu-item>
  105. <!-- 子菜单有下级 -->
  106. <el-sub-menu v-else :index="child.id.toString()">
  107. <template #title>
  108. <span>{{ child.menuName }}</span>
  109. </template>
  110. <!-- 递归 下一级-->
  111. <template v-for="grandChild in child.children" :key="grandChild.id">
  112. <el-menu-item :index="getRoutePath(grandChild)">
  113. <span>{{ grandChild.menuName }}</span>
  114. </el-menu-item>
  115. </template>
  116. </el-sub-menu>
  117. </template>
  118. </el-sub-menu>
  119. <!-- 无子菜单的一级菜单 -->
  120. <el-menu-item v-else :index="getRoutePath(menu)">
  121. <el-icon>
  122. <Folder />
  123. </el-icon>
  124. <span>{{ menu.menuName }}</span>
  125. </el-menu-item>
  126. </template>
  127. </el-menu>
  128. </el-aside>
  129. </div>
  130. <!-- 右侧内容区域 -->
  131. <div class="content-container">
  132. <!-- 头部 -->
  133. <el-header class="header">
  134. <el-menu class="el-menu-demo" mode="horizontal" :ellipsis="false">
  135. <el-sub-menu index="1">
  136. <template #title>
  137. <el-image :src="imgrule1" style="width: 53px; height: 53px" />
  138. <span style="margin-left: 10px">{{ adminData.name }}</span>
  139. </template>
  140. <el-menu-item @click="message()">查看个人信息</el-menu-item>
  141. <el-menu-item @click="openChangePassword">修改密码</el-menu-item>
  142. <el-menu-item @click="logout">退出登录</el-menu-item>
  143. </el-sub-menu>
  144. </el-menu>
  145. </el-header>
  146. <!-- 主内容区域 -->
  147. <div class="main-area">
  148. <el-main>
  149. <router-view></router-view>
  150. </el-main>
  151. </div>
  152. </div>
  153. </div>
  154. <!-- 查看个人信息 -->
  155. <el-dialog v-model="messageVisible" title="查看个人信息" width="500px">
  156. <el-form :model="adminData">
  157. <el-form-item label="用户姓名" label-width="100px" label-position="left">
  158. <span class="message-font">{{ adminData.adminName }}</span>
  159. </el-form-item>
  160. <el-form-item label="精网号" label-width="100px" label-position="left">
  161. <span class="message-font">{{ adminData.account }}</span>
  162. </el-form-item>
  163. <el-form-item label="地区" label-width="100px" label-position="left">
  164. <span class="message-font">{{ adminData.markets }}</span>
  165. </el-form-item>
  166. <el-form-item label="注册时间" label-width="100px" label-position="left">
  167. <span class="message-font">{{ adminData.createTime }}</span>
  168. </el-form-item>
  169. </el-form>
  170. <template #footer>
  171. <div>
  172. <el-button text @click="closeMessage()">关闭</el-button>
  173. </div>
  174. </template>
  175. </el-dialog>
  176. <!-- 自定义密码修改弹窗组件 -->
  177. <el-dialog v-model="showPasswordDialog" :center="true" width="470px" @closed="onPwdDialogClosed">
  178. <ChangePassword ref="pwdRef" @confirm="showPasswordDialog = false" />
  179. </el-dialog>
  180. </div>
  181. </template>
  182. <style scoped>
  183. /* 主容器,设置背景图并居中 */
  184. .main-container {
  185. position: fixed;
  186. top: 0;
  187. left: 0;
  188. right: 0;
  189. bottom: 0;
  190. background-image: url('@/assets/background.jpg');
  191. background-size: cover;
  192. background-position: center center;
  193. background-repeat: no-repeat;
  194. overflow: hidden;
  195. }
  196. /* 背景毛玻璃层(作为内容容器) */
  197. .background-glass {
  198. position: absolute;
  199. top: 1vh;
  200. left: 1vh;
  201. right: 1vh;
  202. bottom: 1vh;
  203. background: rgba(255, 255, 255, 0.3); /* 更透明的背景 */
  204. backdrop-filter: blur(10px); /* 毛玻璃效果 */
  205. z-index: 1;
  206. display: flex;
  207. flex-direction: row;
  208. padding: 20px;
  209. border-radius: 12px;
  210. }
  211. /* 侧边栏容器 */
  212. .sidebar-container {
  213. flex-shrink: 0;
  214. }
  215. .el-aside {
  216. width: 15vw;
  217. height: 100%;
  218. background: rgba(255, 255, 255, 0.85); /* 半透明白色背景 */
  219. backdrop-filter: blur(5px); /* 毛玻璃效果 */
  220. box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1); /* 添加阴影增强层次感 */
  221. border-radius: 12px;
  222. overflow-y: auto;
  223. /* 应用自定义滚动条 */
  224. }
  225. /* 内容区域容器 */
  226. .content-container {
  227. flex: 1;
  228. display: flex;
  229. flex-direction: column;
  230. margin-left: 5px;
  231. gap: 5px;
  232. height: 100%;
  233. overflow: hidden;
  234. }
  235. /* 头部样式 */
  236. .header {
  237. background: rgba(255, 255, 255, 0.9); /* 半透明白色背景 */
  238. backdrop-filter: blur(5px); /* 毛玻璃效果 */
  239. height: 8vh;
  240. border-radius: 12px;
  241. box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1); /* 添加阴影增强层次感 */
  242. z-index: 80;
  243. }
  244. /* 主内容区域容器 */
  245. .main-area {
  246. flex: 1;
  247. background: rgba(255, 255, 255, 0.9); /* 半透明白色背景 */
  248. backdrop-filter: blur(5px); /* 毛玻璃效果 */
  249. border-radius: 12px;
  250. box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1); /* 添加阴影增强层次感 */
  251. overflow: hidden;
  252. display: flex;
  253. flex-direction: column;
  254. }
  255. /* 主内容区域样式 */
  256. .el-main {
  257. height: 100%;
  258. padding: 20px;
  259. background: transparent;
  260. overflow-y: auto;
  261. /* 应用自定义滚动条 */
  262. }
  263. .logo {
  264. display: flex;
  265. align-items: center;
  266. justify-content: center;
  267. height: 12vh;
  268. }
  269. .el-menu-demo {
  270. border: none;
  271. padding: 0;
  272. float: right;
  273. background: transparent !important; /* 最高优先级的透明 */
  274. }
  275. /* 侧边栏菜单样式优化 */
  276. .el-menu {
  277. background: transparent !important;
  278. }
  279. ::v-deep(.el-sub-menu__title:hover) {
  280. background: transparent !important;
  281. }
  282. .message-font { /* 个人信息字体样式 */
  283. font-size: 16px;
  284. font-weight: bold;
  285. }
  286. /* 确保全局el-container适应容器 */
  287. :deep(.el-container) { /* vue3的深度选择器,用于覆盖element-plus的默认样式 */
  288. min-height: 100%;
  289. width: 100%;
  290. background: transparent;
  291. }
  292. /* 为侧边栏和主内容区域添加滚动条样式 */
  293. .el-aside,
  294. .el-main {
  295. scrollbar-width: thin; /* Firefox */
  296. scrollbar-color: rgba(0, 0, 0, 0.3) rgba(255, 255, 255, 0.2); /* Firefox滑块和轨道颜色 */
  297. }
  298. </style>