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.

402 lines
11 KiB

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