index.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636
  1. <template>
  2. <!-- 经典布局 -->
  3. <a-layout v-if="layout === 'classical'">
  4. <a-layout-sider
  5. v-if="!isMobile"
  6. v-model:collapsed="menuIsCollapse"
  7. :trigger="null"
  8. collapsible
  9. :theme="sideTheme"
  10. width="210"
  11. >
  12. <header id="snowyHeaderLogo" class="snowy-header-logo">
  13. <div class="snowy-header-left">
  14. <div class="logo-bar">
  15. <img class="logo" :src="sysBaseConfig.SNOWY_SYS_LOGO" />
  16. <span>{{ sysBaseConfig.SNOWY_SYS_NAME }}</span>
  17. </div>
  18. </div>
  19. </header>
  20. <div :class="menuIsCollapse ? 'admin-ui-side isCollapse' : 'admin-ui-side'">
  21. <div class="admin-ui-side-scroll">
  22. <a-menu
  23. v-model:openKeys="openKeys"
  24. v-model:selectedKeys="selectedKeys"
  25. :theme="sideTheme"
  26. mode="inline"
  27. @select="onSelect"
  28. @openChange="onOpenChange"
  29. >
  30. <NavMenu :nav-menus="menu" />
  31. </a-menu>
  32. </div>
  33. </div>
  34. </a-layout-sider>
  35. <!-- 手机端情况下的左侧菜单 -->
  36. <Side-m v-if="isMobile" />
  37. <!-- 右侧布局 -->
  38. <a-layout>
  39. <div id="snowyHeader" class="snowy-header">
  40. <div class="snowy-header-left" style="padding-left: 0px">
  41. <div v-if="!isMobile" class="panel-item hidden-sm-and-down" @click="menuIsCollapseClick">
  42. <MenuUnfoldOutlined v-if="menuIsCollapse" />
  43. <MenuFoldOutlined v-else />
  44. </div>
  45. <moduleMenu v-if="moduleMenuShow" @switchModule="switchModule" />
  46. <top-bar v-if="!isMobile && breadcrumbOpen" />
  47. </div>
  48. <div class="snowy-header-right">
  49. <user-bar />
  50. </div>
  51. </div>
  52. <!-- 多标签 -->
  53. <Tags v-if="!isMobile && layoutTagsOpen" />
  54. <a-layout-content class="main-content-wrapper">
  55. <div id="admin-ui-main" class="admin-ui-main">
  56. <router-view v-slot="{ Component }">
  57. <keep-alive :include="kStore.keepLiveRoute">
  58. <component :is="Component" v-if="kStore.routeShow" :key="route.name" />
  59. </keep-alive>
  60. </router-view>
  61. <iframe-view />
  62. <div class="main-bottom-wrapper">
  63. <a style="color: #a0a0a0" :href="sysBaseConfig.SNOWY_SYS_COPYRIGHT_URL" target="_blank">{{
  64. sysBaseConfig.SNOWY_SYS_COPYRIGHT
  65. }}</a>
  66. </div>
  67. </div>
  68. </a-layout-content>
  69. </a-layout>
  70. </a-layout>
  71. <!-- 双排菜单布局 -->
  72. <a-layout v-else-if="layout === 'doublerow'">
  73. <a-layout-sider v-if="!isMobile" width="80" :theme="sideTheme" :trigger="null" collapsible>
  74. <header id="snowyHeaderLogo" class="snowy-header-logo">
  75. <div class="snowy-header-left">
  76. <div class="logo-bar">
  77. <router-link to="/">
  78. <img class="logo" :title="sysBaseConfig.SNOWY_SYS_NAME" :src="sysBaseConfig.SNOWY_SYS_LOGO" />
  79. </router-link>
  80. </div>
  81. </div>
  82. </header>
  83. <a-menu
  84. v-model:selectedKeys="doublerowSelectedKey"
  85. :theme="sideTheme"
  86. class="snowy-doublerow-layout-menu"
  87. v-for="item in menu"
  88. :key="item.path"
  89. >
  90. <a-menu-item
  91. :key="item.path"
  92. style="
  93. text-align: center;
  94. border-radius: 2px;
  95. height: auto;
  96. line-height: 20px;
  97. flex: none;
  98. display: block;
  99. padding: 12px 0 !important;
  100. "
  101. @click="showMenu(item)"
  102. v-if="!item.meta.hidden"
  103. >
  104. <a v-if="item.meta && item.meta.type === 'link'" :href="item.path" target="_blank" @click.stop="() => {}" />
  105. <template #icon>
  106. <component :is="item.meta.icon" style="padding-left: 10px" />
  107. </template>
  108. <div class="snowy-doublerow-layout-menu-item-fort-div">
  109. <span class="snowy-doublerow-layout-menu-item-fort-div-span">
  110. {{ item.meta.title }}
  111. </span>
  112. </div>
  113. </a-menu-item>
  114. </a-menu>
  115. </a-layout-sider>
  116. <a-layout-sider
  117. v-if="!isMobile"
  118. v-show="layoutSiderDowbleMenu"
  119. v-model:collapsed="menuIsCollapse"
  120. :trigger="null"
  121. width="170"
  122. collapsible
  123. :theme="secondMenuSideTheme"
  124. >
  125. <div v-if="!menuIsCollapse" id="snowyDoublerowSideTop" class="snowy-doublerow-side-top">
  126. <h2 class="snowy-title">{{ pMenu.meta.title }}</h2>
  127. </div>
  128. <a-menu
  129. v-model:collapsed="menuIsCollapse"
  130. v-model:openKeys="openKeys"
  131. v-model:selectedKeys="selectedKeys"
  132. mode="inline"
  133. :theme="secondMenuSideTheme"
  134. @select="onSelect"
  135. >
  136. <NavMenu :nav-menus="nextMenu" />
  137. </a-menu>
  138. </a-layout-sider>
  139. <!-- 手机端情况下的左侧菜单 -->
  140. <Side-m v-if="isMobile" />
  141. <a-layout>
  142. <div id="snowyHeader" class="snowy-header">
  143. <div class="snowy-header-left" style="padding-left: 0px">
  144. <moduleMenu v-if="moduleMenuShow" @switchModule="switchModule" />
  145. <top-bar v-if="!isMobile && breadcrumbOpen" />
  146. </div>
  147. <div class="snowy-header-right">
  148. <user-bar />
  149. </div>
  150. </div>
  151. <!-- 多标签 -->
  152. <Tags v-if="!isMobile && layoutTagsOpen" />
  153. <a-layout-content class="main-content-wrapper">
  154. <div id="admin-ui-main" class="admin-ui-main">
  155. <router-view v-slot="{ Component }">
  156. <keep-alive :include="kStore.keepLiveRoute">
  157. <component :is="Component" v-if="kStore.routeShow" :key="route.name" />
  158. </keep-alive>
  159. </router-view>
  160. <iframe-view />
  161. <div class="main-bottom-wrapper">
  162. <a style="color: #a0a0a0" :href="sysBaseConfig.SNOWY_SYS_COPYRIGHT_URL" target="_blank">{{
  163. sysBaseConfig.SNOWY_SYS_COPYRIGHT
  164. }}</a>
  165. </div>
  166. </div>
  167. </a-layout-content>
  168. </a-layout>
  169. </a-layout>
  170. <!-- 双列菜单布局 -->
  171. <div class="doublecol" v-else-if="layout === 'doublecol'">
  172. <div id="snowyHeader" class="doublecol-header" style="height: 100px">
  173. <div class="snowy-header-left" style="padding-left: 0px; margin-left: 10px">
  174. <div
  175. class="logo"
  176. style="
  177. background: url('/img/SYS_LOGO.png') no-repeat center;
  178. background-size: cover;
  179. width: 324px;
  180. height: 39px;
  181. "
  182. ></div>
  183. <top-bar v-if="!isMobile && breadcrumbOpen" />
  184. </div>
  185. <div class="snowy-header-right">
  186. <ColModuleMenu v-if="moduleMenuShow" @switchModule="switchModule" />
  187. <ColUserBar />
  188. </div>
  189. </div>
  190. <a-layout id="admin-ui-main" class="admin-ui-main" style="padding: 11px 0 0 0; height: calc(100% - 100px)">
  191. <a-layout-sider v-if="!isMobile" width="80" :theme="sideTheme" :trigger="null" collapsible>
  192. <a-menu
  193. v-model:selectedKeys="doublerowSelectedKey"
  194. :theme="sideTheme"
  195. class="snowy-doublerow-layout-menu"
  196. v-for="item in menu"
  197. :key="item.path"
  198. >
  199. <a-menu-item
  200. :key="item.path"
  201. style="
  202. text-align: center;
  203. border-radius: 2px;
  204. height: auto;
  205. line-height: 20px;
  206. flex: none;
  207. display: block;
  208. padding: 12px 0 !important;
  209. "
  210. @click="showMenu(item)"
  211. v-if="!item.meta.hidden"
  212. >
  213. <a v-if="item.meta && item.meta.type === 'link'" :href="item.path" target="_blank" @click.stop="() => {}" />
  214. <template #icon>
  215. <component :is="item.meta.icon" style="padding-left: 10px" />
  216. </template>
  217. <div class="snowy-doublerow-layout-menu-item-fort-div">
  218. <span class="snowy-doublerow-layout-menu-item-fort-div-span">
  219. {{ item.meta.title }}
  220. </span>
  221. </div>
  222. </a-menu-item>
  223. </a-menu>
  224. </a-layout-sider>
  225. <a-layout-sider
  226. v-if="!isMobile"
  227. v-show="layoutSiderDowbleMenu"
  228. v-model:collapsed="menuIsCollapse"
  229. :trigger="null"
  230. width="170"
  231. collapsible
  232. :theme="secondMenuSideTheme"
  233. >
  234. <div v-if="!menuIsCollapse" id="snowyDoublerowSideTop" class="snowy-doublerow-side-top">
  235. <h2 class="snowy-title">{{ pMenu.meta.title }}</h2>
  236. </div>
  237. <a-menu
  238. v-model:collapsed="menuIsCollapse"
  239. v-model:openKeys="openKeys"
  240. v-model:selectedKeys="selectedKeys"
  241. mode="inline"
  242. :theme="secondMenuSideTheme"
  243. @select="onSelect"
  244. >
  245. <NavMenu :nav-menus="nextMenu" />
  246. </a-menu>
  247. </a-layout-sider>
  248. <!-- 手机端情况下的左侧菜单 -->
  249. <Side-m v-if="isMobile" />
  250. <a-layout-content style="margin: 0 10px; overflow: hidden auto">
  251. <!-- 多标签 -->
  252. <Tags v-if="!isMobile && layoutTagsOpen" />
  253. <router-view v-slot="{ Component }">
  254. <keep-alive :include="kStore.keepLiveRoute">
  255. <component :is="Component" v-if="kStore.routeShow" :key="route.name" />
  256. </keep-alive>
  257. </router-view>
  258. <iframe-view />
  259. <div class="main-bottom-wrapper">
  260. <a style="color: #a0a0a0" :href="sysBaseConfig.SNOWY_SYS_COPYRIGHT_URL" target="_blank">{{
  261. sysBaseConfig.SNOWY_SYS_COPYRIGHT
  262. }}</a>
  263. </div>
  264. </a-layout-content>
  265. </a-layout>
  266. </div>
  267. <!-- 退出最大化 -->
  268. <div class="main-maximize-exit" @click="exitMaximize">
  269. <fullscreen-exit-outlined style="color: #fff" />
  270. </div>
  271. </template>
  272. <script setup>
  273. import ColUserBar from '@/layout/components/doublecol_userbar.vue'
  274. import UserBar from '@/layout/components/userbar.vue'
  275. import Tags from '@/layout/components/tags.vue'
  276. import SideM from '@/layout/components/sideM.vue'
  277. import NavMenu from '@/layout/components/NavMenu.vue'
  278. import ModuleMenu from '@/layout/components/moduleMenu.vue'
  279. import ColModuleMenu from '@/layout/components/doublecol_moduleMenu.vue'
  280. import IframeView from '@/layout/components/iframeView.vue'
  281. import TopBar from '@/layout/components/topbar.vue'
  282. import { globalStore, keepAliveStore } from '@/store'
  283. import { ThemeModeEnum } from '@/utils/enum'
  284. import { useRoute, useRouter } from 'vue-router'
  285. import tool from '@/utils/tool'
  286. import { message } from 'ant-design-vue'
  287. const store = globalStore()
  288. const kStore = keepAliveStore()
  289. const route = useRoute()
  290. const router = useRouter()
  291. const menu = ref([])
  292. const pMenu = ref({})
  293. const nextMenu = ref([])
  294. const selectedKeys = ref([])
  295. const openKeys = ref([])
  296. const onSelectTag = ref(false)
  297. const moduleMenuData = ref([])
  298. const moduleMenuShow = ref(true)
  299. const doublerowSelectedKey = ref([])
  300. const layoutSiderDowbleMenu = ref(false)
  301. // computed计算方法 - start
  302. const layout = computed(() => {
  303. return store.layout
  304. })
  305. const isMobile = computed(() => {
  306. return store.isMobile
  307. })
  308. const menuIsCollapse = computed(() => {
  309. return store.menuIsCollapse
  310. })
  311. const theme = computed(() => {
  312. return store.theme
  313. })
  314. const layoutTagsOpen = computed(() => {
  315. // 当关闭多标签时,清理keepAlive的缓存
  316. if (!store.layoutTagsOpen) {
  317. kStore.keepLiveRoute = []
  318. }
  319. return store.layoutTagsOpen
  320. })
  321. const breadcrumbOpen = computed(() => {
  322. return store.breadcrumbOpen
  323. })
  324. const topHeaderThemeColorOpen = computed(() => {
  325. return store.topHeaderThemeColorOpen
  326. })
  327. const topHeaderThemeColorSpread = computed(() => {
  328. return store.topHeaderThemeColorSpread
  329. })
  330. const sideUniqueOpen = computed(() => {
  331. return store.sideUniqueOpen
  332. })
  333. const sysBaseConfig = computed(() => {
  334. return store.sysBaseConfig
  335. })
  336. const module = computed(() => {
  337. return store.module
  338. })
  339. const sideTheme = computed(() => {
  340. return theme.value === ThemeModeEnum.REAL_DARK ? ThemeModeEnum.DARK : theme.value
  341. })
  342. const secondMenuSideTheme = computed(() => {
  343. return theme.value === ThemeModeEnum.REAL_DARK ? ThemeModeEnum.DARK : ThemeModeEnum.LIGHT
  344. })
  345. // 路由监听高亮
  346. const showThis = () => {
  347. pMenu.value = route.meta.breadcrumb ? route.meta.breadcrumb[0] : {}
  348. // 展开的
  349. nextTick(() => {
  350. // 取得默认路由地址并设置展开
  351. let active = route.meta.active || route.path
  352. // 如果是目录,必须往下找
  353. if (route.meta.type === 'catalog') {
  354. active = traverseChild(pMenu.value.children, active).path
  355. }
  356. selectedKeys.value = new Array(active)
  357. const pidKey = getParentKeys(pMenu.value.children, active)
  358. // 判断是隐藏的路由,找其上级
  359. if (route.meta.hidden && pidKey) {
  360. if (pidKey.length > 1) {
  361. selectedKeys.value = new Array(pidKey[1])
  362. }
  363. }
  364. const nextTickMenu = pMenu.value.children
  365. if (pidKey) {
  366. const modelPidKey = getParentKeys(moduleMenuData.value, route.path)
  367. moduleMenuData.value.forEach((item) => {
  368. if (modelPidKey.includes(item.path)) {
  369. tagSwitchModule(item.id)
  370. }
  371. })
  372. const parentPath = pidKey[pidKey.length - 1]
  373. if (layout.value === 'doublerow') {
  374. // 这一串操作下来只为取到最上面的路由的孩子们,最后成为双排菜单的第二排
  375. const nextMenuTemp = nextTickMenu.filter((item) => item.path === parentPath)[0].children
  376. if (nextMenuTemp) {
  377. nextMenu.value = nextTickMenu.filter((item) => item.path === parentPath)[0].children
  378. }
  379. }
  380. }
  381. if (!onSelectTag.value || sideUniqueOpen.value) {
  382. openKeys.value = pidKey
  383. }
  384. // 双排菜单下
  385. if (layout.value === 'doublerow') {
  386. setDoubleRowSelectedKey()
  387. }
  388. })
  389. }
  390. // 执行-start
  391. moduleMenuData.value = router.getMenu()
  392. // 获取缓存中的菜单模块是哪个
  393. const menuModuleId = tool.data.get('SNOWY_MENU_MODULE_ID')
  394. if (menuModuleId) {
  395. // 防止切换一个无此应用的人
  396. const module = router.getMenu().filter((item) => item.id === menuModuleId)
  397. if (module.length > 0) {
  398. menu.value = module[0].children
  399. } else {
  400. menu.value = router.getMenu()[0].children
  401. }
  402. } else {
  403. menu.value = router.getMenu()[0].children
  404. }
  405. showThis()
  406. onMounted(() => {
  407. onLayoutResize()
  408. window.addEventListener('resize', onLayoutResize)
  409. switchoverTopHeaderThemeColor()
  410. })
  411. watch(route, (newValue) => {
  412. // 清理选中的
  413. selectedKeys.value = []
  414. showThis()
  415. })
  416. // 监听是否开启了顶栏颜色
  417. watch(layout, (newValue) => {
  418. document.body.setAttribute('data-layout', newValue)
  419. if (newValue.includes('doublerow')) {
  420. showThis()
  421. setDoubleRowSelectedKey()
  422. }
  423. nextTick(() => {
  424. // 顶栏主题色
  425. switchoverTopHeaderThemeColor()
  426. })
  427. })
  428. watch(topHeaderThemeColorOpen, (newValue) => {
  429. switchoverTopHeaderThemeColor()
  430. })
  431. watch(topHeaderThemeColorSpread, (newValue) => {
  432. switchoverTopHeaderThemeColor()
  433. })
  434. const menuIsCollapseClick = () => {
  435. store.toggleConfig('menuIsCollapse')
  436. }
  437. // 切换顶栏颜色
  438. const switchoverTopHeaderThemeColor = () => {
  439. // 界面顶栏设置颜色
  440. const header = document.getElementById('snowyHeader')
  441. topHeaderThemeColorOpen.value
  442. ? header.classList.add('snowy-header-primary-color')
  443. : header.classList.remove('snowy-header-primary-color')
  444. // 判断是否开启了通栏
  445. const headerLogin = document.getElementById('snowyHeaderLogo')
  446. try {
  447. topHeaderThemeColorSpread.value
  448. ? headerLogin.classList.add('snowy-header-logo-primary-color')
  449. : headerLogin.classList.remove('snowy-header-logo-primary-color')
  450. // eslint-disable-next-line no-empty
  451. } catch (e) {}
  452. // 如果是双排菜单,吧第二排的也给渲染了
  453. if (layout.value === 'doublerow') {
  454. const snowyDoublerowSideTop = document.getElementById('snowyDoublerowSideTop')
  455. try {
  456. topHeaderThemeColorSpread.value
  457. ? snowyDoublerowSideTop.classList.add('snowy-doublerow-side-top-primary-color')
  458. : snowyDoublerowSideTop.classList.remove('snowy-doublerow-side-top-primary-color')
  459. // eslint-disable-next-line no-empty
  460. } catch (e) {}
  461. }
  462. }
  463. // 设置双排菜单下的首列默认选中
  464. const setDoubleRowSelectedKey = () => {
  465. const pidKey = getParentKeys(menu.value, selectedKeys.value.toString())
  466. nextTick(() => {
  467. const pidKeyArray = []
  468. for (const key in pidKey) {
  469. pidKeyArray.push(key)
  470. }
  471. layoutSiderDowbleMenu.value = pidKeyArray.length > 1
  472. })
  473. // 设置第一排选中的
  474. menu.value.forEach((item) => {
  475. if (pidKey !== undefined) {
  476. if (pidKey[pidKey.length - 1].toString() === item.path) {
  477. doublerowSelectedKey.value = [item.path]
  478. }
  479. }
  480. })
  481. }
  482. // 菜单展开/关闭的回调
  483. const onOpenChange = (keys) => {
  484. if (sideUniqueOpen.value) {
  485. // 获取最新的
  486. const openKey = keys[keys.length - 1]
  487. if (keys.length > 1) {
  488. // 获取上级
  489. openKeys.value = getParentKeys(menu.value, openKey)
  490. } else {
  491. openKeys.value = Array.of(openKey) // new Array(openKey);
  492. }
  493. } else {
  494. openKeys.value = keys
  495. }
  496. }
  497. // 获取上级keys
  498. const getParentKeys = (data, val) => {
  499. const traverse = (array, val) => {
  500. // 递归父级key
  501. for (const element of array) {
  502. if (element.path === val) {
  503. return [element.path]
  504. }
  505. if (element.children) {
  506. const far = traverse(element.children, val)
  507. if (far) {
  508. return far.concat(element.path)
  509. }
  510. }
  511. }
  512. }
  513. return traverse(data, val)
  514. }
  515. // 双排菜单下点击显示右侧分栏
  516. const showMenu = (route) => {
  517. pMenu.value = route
  518. if (pMenu.value.children) {
  519. nextMenu.value = pMenu.value.children
  520. }
  521. if (!route.children || route.children.length === 0) {
  522. layoutSiderDowbleMenu.value = false
  523. router.push({ path: route.path })
  524. } else {
  525. if (route.children) {
  526. let hidden = 0
  527. route.children.forEach((item) => {
  528. if (item.meta.hidden && item.meta.hidden === true) {
  529. hidden++
  530. }
  531. })
  532. // 如果全部都隐藏了,就跳转这个,不展开另一排
  533. if (hidden === route.children.length) {
  534. layoutSiderDowbleMenu.value = false
  535. router.push({ path: route.path })
  536. } else {
  537. layoutSiderDowbleMenu.value = true
  538. }
  539. } else {
  540. layoutSiderDowbleMenu.value = false
  541. }
  542. }
  543. if (layout.value === 'doublerow') {
  544. doublerowSelectedKey.value = [route.path]
  545. }
  546. }
  547. // 当菜单被选中时
  548. const onSelect = (obj) => {
  549. onSelectTag.value = true
  550. const pathLength = obj.keyPath.length
  551. const path = obj.keyPath[pathLength - 1]
  552. router.push({ path })
  553. // 设置选中
  554. selectedKeys.value = obj.selectedKeys
  555. }
  556. const onLayoutResize = () => {
  557. const clientWidth = document.body.clientWidth
  558. store.setIsMobile(clientWidth < 992)
  559. }
  560. // 切换应用
  561. const switchModule = (id) => {
  562. if (moduleMenuData.value.length > 0) {
  563. showThis()
  564. const menus = moduleMenuData.value.filter((item) => item.id === id)[0].children
  565. if (menus.length > 0) {
  566. // 正儿八百的菜单
  567. menu.value = menus
  568. const firstMenu = traverseChild(menu.value)
  569. const path = firstMenu.path
  570. // 如果是外链
  571. if (firstMenu.menuType === 'LINK') {
  572. window.open(path)
  573. } else {
  574. // 将此模块的唯一值加入缓存
  575. tool.data.set('SNOWY_MENU_MODULE_ID', id)
  576. // 然后将其跳转至指定界面,默认始终取排序第一的
  577. router.push({ path })
  578. }
  579. } else {
  580. message.warning('该模块下无任何菜单')
  581. }
  582. }
  583. }
  584. // 通过标签切换应用
  585. const tagSwitchModule = (id) => {
  586. // 将此模块的唯一值加入缓存
  587. tool.data.set('SNOWY_MENU_MODULE_ID', id)
  588. store.setModule(id)
  589. // 正儿八百的菜单
  590. menu.value = moduleMenuData.value.filter((item) => item.id === id)[0].children
  591. }
  592. // 遍历获取子集
  593. const traverseChild = (menu) => {
  594. if (menu[0] && menu[0].children !== undefined) {
  595. if (menu[0].children.length > 0) {
  596. if (menu[0].children[0] && menu[0].children[0].meta.hidden && menu[0].children[0].meta.hidden === true) {
  597. return menu[0]
  598. } else {
  599. return traverseChild(menu[0].children)
  600. }
  601. }
  602. } else {
  603. return menu[0]
  604. }
  605. }
  606. // 退出最大化
  607. const exitMaximize = () => {
  608. document.getElementById('app').classList.remove('main-maximize')
  609. moduleMenuShow.value = false
  610. nextTick(() => {
  611. moduleMenuShow.value = true
  612. })
  613. }
  614. </script>
  615. <style lang="less">
  616. .doublecol {
  617. height: 100%;
  618. .ant-menu-item {
  619. &.ant-menu-item-selected {
  620. background: #3870d0;
  621. color: #fff;
  622. a {
  623. color: #fff;
  624. }
  625. }
  626. }
  627. }
  628. </style>