index.vue 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. <template>
  2. <router-layout v-if="isQianKun" />
  3. <ele-pro-layout
  4. v-else
  5. :menus="menus"
  6. :tabs="theme.tabs"
  7. :collapse="theme.collapse"
  8. :side-nav-collapse="theme.sideNavCollapse"
  9. :body-fullscreen="theme.bodyFullscreen"
  10. :show-tabs="theme.showTabs"
  11. :show-footer="theme.showFooter"
  12. :head-style="theme.headStyle"
  13. :side-style="theme.sideStyle"
  14. :layout-style="theme.layoutStyle"
  15. :side-menu-style="theme.sideMenuStyle"
  16. :tab-style="theme.tabStyle"
  17. :fixed-header="theme.fixedHeader"
  18. :fixed-sidebar="theme.fixedSidebar"
  19. :fixed-body="theme.fixedBody"
  20. :body-full="theme.bodyFull"
  21. :logo-auto-size="theme.logoAutoSize"
  22. :colorful-icon="theme.colorfulIcon"
  23. :side-unique-open="theme.sideUniqueOpen"
  24. :style-responsive="theme.styleResponsive"
  25. :project-name="PROJECT_NAME"
  26. :hide-footers="HIDE_FOOTERS"
  27. :hide-sidebars="HIDE_SIDEBARS"
  28. :repeatable-tabs="REPEATABLE_TABS"
  29. :home-title="HOME_TITLE || $t('layout.home')"
  30. :home-path="HOME_PATH"
  31. :layout-path="LAYOUT_PATH"
  32. :redirect-path="REDIRECT_PATH"
  33. :tab-sortable="true"
  34. :locale="locale"
  35. :i18n="i18n"
  36. @update:collapse="updateCollapse"
  37. @update:side-nav-collapse="updateSideNavCollapse"
  38. @update:body-fullscreen="updateBodyFullscreen"
  39. @tab-add="addPageTab"
  40. @tab-remove="removePageTab"
  41. @tab-remove-all="removeAllPageTab"
  42. @tab-remove-left="removeLeftPageTab"
  43. @tab-remove-right="removeRightPageTab"
  44. @tab-remove-other="removeOtherPageTab"
  45. @tabSortChange="setPageTabs"
  46. @reload-page="reloadPageTab"
  47. @logo-click="onLogoClick"
  48. @screen-size-change="screenSizeChange"
  49. @set-home-components="setHomeComponents"
  50. @tab-context-menu="onTabContextMenu"
  51. >
  52. <!-- 路由出口 -->
  53. <router-layout />
  54. <!-- logo 图标 -->
  55. <template v-slot:logo>
  56. <el-image fit="contain" src="@/assets/logo.png" alt="logo" />
  57. </template>
  58. <template v-slot:right>
  59. <header-tools :fullscreen="fullscreen" @fullscreen="onFullscreen" />
  60. </template>
  61. <!-- 全局页脚 -->
  62. <!-- <template v-slot:footer>
  63. <page-footer />
  64. </template> -->
  65. <!-- 自定义菜单标题增加徽章、小红点 -->
  66. <template v-slot:title="{ title, item }">
  67. <span>{{ title }} </span>
  68. <span
  69. v-if="item.meta.secretLevel != 1"
  70. :style="getSecretLevelStyle(item)"
  71. >{{ getSecretLevel(item) }}</span
  72. >
  73. <div v-if="item.meta && item.meta.badge" class="ele-menu-badge">
  74. <el-badge :value="item.meta.badge" :type="item.meta.badgeColor" />
  75. </div>
  76. </template>
  77. <template v-slot:top-title="{ title, item }">
  78. <span>{{ title }} </span>
  79. <span
  80. v-if="item.meta.secretLevel != 1"
  81. :style="getSecretLevelStyle(item)"
  82. >{{ getSecretLevel(item) }}</span
  83. >
  84. <div v-if="item.meta && item.meta.badge" class="ele-menu-badge">
  85. <el-badge :value="item.meta.badge" :type="item.meta.badgeColor" />
  86. </div>
  87. </template>
  88. <template v-slot:nav-title="{ title, item }">
  89. <span>{{ title }} </span>
  90. <span
  91. v-if="item.meta.secretLevel != 1"
  92. :style="getSecretLevelStyle(item)"
  93. >{{ getSecretLevel(item) }}</span
  94. >
  95. <div v-if="item.meta && item.meta.badge" class="ele-menu-badge">
  96. <el-badge :value="item.meta.badge" :type="item.meta.badgeColor" />
  97. </div>
  98. </template>
  99. </ele-pro-layout>
  100. </template>
  101. <script>
  102. import { mapGetters } from 'vuex';
  103. import { toggleFullscreen, isFullscreen } from 'ele-admin';
  104. import RouterLayout from '@/components/RouterLayout/index.vue';
  105. import HeaderTools from './components/header-tools.vue';
  106. import PageFooter from './components/page-footer.vue';
  107. import {
  108. PROJECT_NAME,
  109. HIDE_SIDEBARS,
  110. HIDE_FOOTERS,
  111. REPEATABLE_TABS,
  112. HOME_TITLE,
  113. HOME_PATH,
  114. LAYOUT_PATH,
  115. REDIRECT_PATH,
  116. I18N_ENABLE
  117. } from '@/config/setting';
  118. import {
  119. addPageTab,
  120. removePageTab,
  121. removeAllPageTab,
  122. removeLeftPageTab,
  123. removeRightPageTab,
  124. removeOtherPageTab,
  125. reloadPageTab,
  126. setHomeComponents,
  127. setPageTabs
  128. } from '@/utils/page-tab-util';
  129. import { secretLevelList } from '@/enum/dict';
  130. export default {
  131. name: 'EleLayout',
  132. components: {
  133. RouterLayout,
  134. HeaderTools
  135. },
  136. data() {
  137. return {
  138. PROJECT_NAME,
  139. HIDE_SIDEBARS,
  140. HIDE_FOOTERS,
  141. REPEATABLE_TABS,
  142. HOME_PATH,
  143. HOME_TITLE,
  144. LAYOUT_PATH,
  145. REDIRECT_PATH,
  146. // 是否全屏
  147. fullscreen: false
  148. };
  149. },
  150. computed: {
  151. isQianKun() {
  152. return window.__POWERED_BY_QIANKUN__;
  153. },
  154. // 当前语言
  155. locale() {
  156. return this.$i18n.locale;
  157. },
  158. // 菜单数据
  159. menus() {
  160. return this.$store.state.user.menus;
  161. },
  162. // 主题状态
  163. ...mapGetters(['theme'])
  164. },
  165. methods: {
  166. getSecretLevelStyle(item) {
  167. return {
  168. color: item.meta.secretLevel > 1 ? 'red' : 'green',
  169. fontWeight: 'bold',
  170. fontSize: '15px'
  171. };
  172. },
  173. getSecretLevel(item) {
  174. let find =
  175. secretLevelList.find((i) => item.meta.secretLevel == i.value) || {};
  176. return '(' + find.label + ')';
  177. },
  178. /* 侧栏折叠切换 */
  179. updateCollapse(value) {
  180. // console.log('value:', this.$store.state.user.menus);
  181. this.$store.dispatch('theme/setCollapse', value);
  182. },
  183. /* 双侧栏一级折叠切换 */
  184. updateSideNavCollapse(value) {
  185. this.$store.dispatch('theme/setSideNavCollapse', value);
  186. },
  187. /* 内容区域全屏切换 */
  188. updateBodyFullscreen(value) {
  189. this.$store.dispatch('theme/setBodyFullscreen', value);
  190. },
  191. /* logo 点击事件 */
  192. onLogoClick(isHome) {
  193. isHome || this.$router.push(LAYOUT_PATH);
  194. },
  195. /* 监听屏幕尺寸改变 */
  196. screenSizeChange() {
  197. this.$store.dispatch('theme/updateScreenSize');
  198. this.fullscreen = isFullscreen();
  199. },
  200. /* 全屏切换 */
  201. onFullscreen() {
  202. try {
  203. this.fullscreen = toggleFullscreen();
  204. } catch (e) {
  205. this.$message.error('您的浏览器不支持全屏模式');
  206. }
  207. },
  208. /* 页签右键菜单点击事件 */
  209. onTabContextMenu({ key, tabKey, item, active }) {
  210. switch (key) {
  211. case 'reload': // 刷新
  212. reloadPageTab({
  213. isHome: !item,
  214. fullPath: item?.fullPath ?? tabKey
  215. });
  216. break;
  217. case 'close': // 关闭当前
  218. removePageTab({
  219. key: item?.fullPath ?? tabKey,
  220. active
  221. });
  222. break;
  223. case 'left': // 关闭左侧
  224. removeLeftPageTab({
  225. key: tabKey,
  226. active
  227. });
  228. break;
  229. case 'right': // 关闭右侧
  230. removeRightPageTab({
  231. key: tabKey,
  232. active
  233. });
  234. break;
  235. case 'other': // 关闭其他
  236. removeOtherPageTab({
  237. key: tabKey,
  238. active
  239. });
  240. break;
  241. }
  242. },
  243. /* 菜单标题国际化 */
  244. i18n(_path, key) {
  245. if (!I18N_ENABLE || !key) {
  246. return;
  247. }
  248. const k = 'route.' + key + '._name';
  249. const title = this.$t(k);
  250. if (title !== k) {
  251. return title;
  252. }
  253. },
  254. //
  255. addPageTab,
  256. removePageTab,
  257. removeAllPageTab,
  258. removeLeftPageTab,
  259. removeRightPageTab,
  260. removeOtherPageTab,
  261. reloadPageTab,
  262. setHomeComponents,
  263. setPageTabs
  264. }
  265. };
  266. </script>
  267. <style lang="scss">
  268. .ele-admin-logo {
  269. font-size: 18px !important;
  270. justify-content: flex-start !important;
  271. align-items: center !important;
  272. img {
  273. height: 35px !important;
  274. max-width: 86px;
  275. width: auto;
  276. margin-right: 6px;
  277. }
  278. }
  279. // 侧栏菜单徽章样式,定位在右侧垂直居中并调小尺寸
  280. .ele-menu-badge {
  281. position: absolute;
  282. top: 50%;
  283. right: 14px;
  284. line-height: 1;
  285. margin-top: -9px;
  286. font-size: 0;
  287. .el-badge__content {
  288. height: 18px;
  289. line-height: 18px;
  290. border-radius: 9px;
  291. border: none;
  292. min-width: 18px;
  293. padding: 0 4px;
  294. box-sizing: border-box;
  295. }
  296. }
  297. // 父级菜单标题中右侧多定位一点,避免与箭头重合
  298. .el-submenu > .el-submenu__title .ele-menu-badge {
  299. right: 36px;
  300. }
  301. // 折叠悬浮中样式调整
  302. .el-menu--popup {
  303. .el-submenu > .el-submenu__title .ele-menu-badge {
  304. right: 20px;
  305. }
  306. }
  307. // 侧栏折叠后样式调整
  308. .ele-admin-collapse .ele-admin-sidebar-menus > .el-scrollbar {
  309. & > .el-scrollbar__wrap > .el-scrollbar__view > .el-menu {
  310. & > .el-menu-item,
  311. & > .el-submenu > .el-submenu__title {
  312. .ele-menu-badge {
  313. top: 2px;
  314. right: 2px;
  315. margin: 0;
  316. }
  317. }
  318. }
  319. }
  320. // 顶栏菜单标题中样式调整
  321. .ele-admin-header-nav > .el-scrollbar > .el-scrollbar__wrap {
  322. & > .el-scrollbar__view > .el-menu {
  323. & > .el-menu-item,
  324. & > .el-submenu > .el-submenu__title {
  325. .ele-menu-badge {
  326. position: static;
  327. right: auto;
  328. top: auto;
  329. display: inline-block;
  330. vertical-align: 6px;
  331. margin: 0 0 0 2px;
  332. }
  333. }
  334. }
  335. }
  336. // 双侧栏时一级侧栏菜单中样式调整,定位在右上角
  337. .ele-admin-sidebar-nav-menu > .el-scrollbar > .el-scrollbar__wrap {
  338. & > .el-scrollbar__view > .el-menu {
  339. & > .el-menu-item,
  340. & > .el-submenu > .el-submenu__title {
  341. .ele-menu-badge {
  342. top: 0;
  343. right: 0;
  344. margin: 0;
  345. }
  346. }
  347. }
  348. }
  349. // 双侧栏时一级侧栏菜单折叠后样式调整
  350. .ele-admin-nav-collapse .ele-admin-sidebar-nav-menu > .el-scrollbar {
  351. & > .el-scrollbar__wrap > .el-scrollbar__view > .el-menu {
  352. & > .el-menu-item,
  353. & > .el-submenu > .el-submenu__title {
  354. .ele-menu-badge {
  355. top: 0;
  356. right: 0;
  357. }
  358. }
  359. }
  360. }
  361. </style>