作者 RuoYi

新增菜单导航显示风格TopNav(false为左侧导航菜单,true为顶部导航菜单)

@@ -176,6 +176,12 @@ @@ -176,6 +176,12 @@
176 color: #FFFFFF; 176 color: #FFFFFF;
177 } 177 }
178 178
  179 +/* submenu item */
  180 +.el-menu--horizontal > .el-submenu .el-submenu__title {
  181 + height: 50px !important;
  182 + line-height: 50px !important;
  183 +}
  184 +
179 /* text color */ 185 /* text color */
180 .text-navy { 186 .text-navy {
181 color: #1ab394; 187 color: #1ab394;
@@ -135,9 +135,6 @@ @@ -135,9 +135,6 @@
135 margin-left: 20px; 135 margin-left: 20px;
136 } 136 }
137 137
138 - .el-submenu__icon-arrow {  
139 - display: none;  
140 - }  
141 } 138 }
142 } 139 }
143 140
  1 +<template>
  2 + <el-menu
  3 + :default-active="activeMenu"
  4 + mode="horizontal"
  5 + @select="handleSelect"
  6 + >
  7 + <template v-for="(item, index) in topMenus">
  8 + <el-menu-item :index="item.path" :key="index" v-if="index < visibleNumber"
  9 + ><svg-icon :icon-class="item.meta.icon" />
  10 + {{ item.meta.title }}</el-menu-item
  11 + >
  12 + </template>
  13 +
  14 + <!-- 顶部菜单超出数量折叠 -->
  15 + <el-submenu index="more" v-if="topMenus.length > visibleNumber">
  16 + <template slot="title">更多菜单</template>
  17 + <template v-for="(item, index) in topMenus">
  18 + <el-menu-item
  19 + :index="item.path"
  20 + :key="index"
  21 + v-if="index >= visibleNumber"
  22 + ><svg-icon :icon-class="item.meta.icon" />
  23 + {{ item.meta.title }}</el-menu-item
  24 + >
  25 + </template>
  26 + </el-submenu>
  27 + </el-menu>
  28 +</template>
  29 +
  30 +<script>
  31 +import { constantRoutes } from "@/router";
  32 +
  33 +export default {
  34 + data() {
  35 + return {
  36 + // 顶部栏初始数
  37 + visibleNumber: 5,
  38 + // 是否为首次加载
  39 + isFrist: false,
  40 + };
  41 + },
  42 + computed: {
  43 + // 顶部显示菜单
  44 + topMenus() {
  45 + return this.routers.map((menu) => ({
  46 + ...menu,
  47 + children: undefined,
  48 + }));
  49 + },
  50 + // 所有的路由信息
  51 + routers() {
  52 + return this.$store.state.permission.topbarRouters;
  53 + },
  54 + // 设置子路由
  55 + childrenMenus() {
  56 + var childrenMenus = [];
  57 + this.routers.map((router) => {
  58 + for (var item in router.children) {
  59 + if (router.children[item].parentPath === undefined) {
  60 + router.children[item].path = router.path + "/" + router.children[item].path;
  61 + router.children[item].parentPath = router.path;
  62 + }
  63 + childrenMenus.push(router.children[item]);
  64 + }
  65 + });
  66 + return constantRoutes.concat(childrenMenus);
  67 + },
  68 + // 默认激活的菜单
  69 + activeMenu() {
  70 + const path = this.$route.path;
  71 + let activePath = this.routers[0].path;
  72 + if (path.lastIndexOf("/") > 0) {
  73 + const tmpPath = path.substring(1, path.length);
  74 + activePath = "/" + tmpPath.substring(0, tmpPath.indexOf("/"));
  75 + } else if ("/index" == path || "" == path) {
  76 + if (!this.isFrist) {
  77 + this.isFrist = true;
  78 + } else {
  79 + activePath = "index";
  80 + }
  81 + }
  82 + this.activeRoutes(activePath);
  83 + return activePath;
  84 + },
  85 + },
  86 + mounted() {
  87 + this.setVisibleNumber();
  88 + },
  89 + methods: {
  90 + // 根据宽度计算设置显示栏数
  91 + setVisibleNumber() {
  92 + const width = document.body.getBoundingClientRect().width - 200;
  93 + const elWidth = this.$el.getBoundingClientRect().width;
  94 + const menuItemNodes = this.$el.children;
  95 + const menuWidth = Array.from(menuItemNodes).map(
  96 + (i) => i.getBoundingClientRect().width
  97 + );
  98 + this.visibleNumber = (
  99 + parseInt(width - elWidth) / parseInt(menuWidth)
  100 + ).toFixed(0);
  101 + },
  102 + // 菜单选择事件
  103 + handleSelect(key, keyPath) {
  104 + if (key.indexOf("http://") !== -1 || key.indexOf("https://") !== -1) {
  105 + // http(s):// 路径新窗口打开
  106 + window.open(key, "_blank");
  107 + } else {
  108 + this.activeRoutes(key);
  109 + }
  110 + },
  111 + // 当前激活的路由
  112 + activeRoutes(key) {
  113 + var routes = [];
  114 + if (this.childrenMenus && this.childrenMenus.length > 0) {
  115 + this.childrenMenus.map((item) => {
  116 + if (key == item.parentPath || (key == "index" && "" == item.path)) {
  117 + routes.push(item);
  118 + }
  119 + });
  120 + }
  121 + this.$store.commit("SET_SIDEBAR_ROUTERS", routes);
  122 + },
  123 + },
  124 +};
  125 +</script>
  126 +
  127 +<style lang="scss" scoped>
  128 +.el-menu--horizontal > .el-menu-item {
  129 + float: left;
  130 + height: 50px;
  131 + line-height: 50px;
  132 + margin: 0;
  133 + border-bottom: 3px solid transparent;
  134 + color: #999093;
  135 + padding: 0 5px;
  136 + margin: 0 10px;
  137 +}
  138 +
  139 +.el-menu--horizontal > .el-menu-item.is-active {
  140 + border-bottom: 3px solid #409eff;
  141 + color: #303133;
  142 +}
  143 +</style>
@@ -2,7 +2,8 @@ @@ -2,7 +2,8 @@
2 <div class="navbar"> 2 <div class="navbar">
3 <hamburger id="hamburger-container" :is-active="sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" /> 3 <hamburger id="hamburger-container" :is-active="sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" />
4 4
5 - <breadcrumb id="breadcrumb-container" class="breadcrumb-container" /> 5 + <breadcrumb id="breadcrumb-container" class="breadcrumb-container" v-if="!topNav"/>
  6 + <top-nav id="topmenu-container" class="breadcrumb-container" v-if="topNav"/>
6 7
7 <div class="right-menu"> 8 <div class="right-menu">
8 <template v-if="device!=='mobile'"> 9 <template v-if="device!=='mobile'">
@@ -48,6 +49,7 @@ @@ -48,6 +49,7 @@
48 <script> 49 <script>
49 import { mapGetters } from 'vuex' 50 import { mapGetters } from 'vuex'
50 import Breadcrumb from '@/components/Breadcrumb' 51 import Breadcrumb from '@/components/Breadcrumb'
  52 +import TopNav from '@/components/TopNav'
51 import Hamburger from '@/components/Hamburger' 53 import Hamburger from '@/components/Hamburger'
52 import Screenfull from '@/components/Screenfull' 54 import Screenfull from '@/components/Screenfull'
53 import SizeSelect from '@/components/SizeSelect' 55 import SizeSelect from '@/components/SizeSelect'
@@ -58,6 +60,7 @@ import RuoYiDoc from '@/components/RuoYi/Doc' @@ -58,6 +60,7 @@ import RuoYiDoc from '@/components/RuoYi/Doc'
58 export default { 60 export default {
59 components: { 61 components: {
60 Breadcrumb, 62 Breadcrumb,
  63 + TopNav,
61 Hamburger, 64 Hamburger,
62 Screenfull, 65 Screenfull,
63 SizeSelect, 66 SizeSelect,
@@ -81,6 +84,11 @@ export default { @@ -81,6 +84,11 @@ export default {
81 value: val 84 value: val
82 }) 85 })
83 } 86 }
  87 + },
  88 + topNav: {
  89 + get() {
  90 + return this.$store.state.settings.topNav
  91 + }
84 } 92 }
85 }, 93 },
86 methods: { 94 methods: {
@@ -43,6 +43,11 @@ @@ -43,6 +43,11 @@
43 <h3 class="drawer-title">系统布局配置</h3> 43 <h3 class="drawer-title">系统布局配置</h3>
44 44
45 <div class="drawer-item"> 45 <div class="drawer-item">
  46 + <span>开启 TopNav</span>
  47 + <el-switch v-model="topNav" class="drawer-switch" />
  48 + </div>
  49 +
  50 + <div class="drawer-item">
46 <span>开启 Tags-Views</span> 51 <span>开启 Tags-Views</span>
47 <el-switch v-model="tagsView" class="drawer-switch" /> 52 <el-switch v-model="tagsView" class="drawer-switch" />
48 </div> 53 </div>
@@ -87,6 +92,20 @@ export default { @@ -87,6 +92,20 @@ export default {
87 }) 92 })
88 } 93 }
89 }, 94 },
  95 + topNav: {
  96 + get() {
  97 + return this.$store.state.settings.topNav
  98 + },
  99 + set(val) {
  100 + this.$store.dispatch('settings/changeSetting', {
  101 + key: 'topNav',
  102 + value: val
  103 + })
  104 + if (!val) {
  105 + this.$store.commit("SET_SIDEBAR_ROUTERS", this.$store.state.permission.defaultRoutes);
  106 + }
  107 + }
  108 + },
90 tagsView: { 109 tagsView: {
91 get() { 110 get() {
92 return this.$store.state.settings.tagsView 111 return this.$store.state.settings.tagsView
@@ -12,6 +12,11 @@ module.exports = { @@ -12,6 +12,11 @@ module.exports = {
12 showSettings: false, 12 showSettings: false,
13 13
14 /** 14 /**
  15 + * 是否显示顶部导航
  16 + */
  17 + topNav: true,
  18 +
  19 + /**
15 * 是否显示 tagsView 20 * 是否显示 tagsView
16 */ 21 */
17 tagsView: true, 22 tagsView: true,
@@ -11,6 +11,8 @@ const getters = { @@ -11,6 +11,8 @@ const getters = {
11 roles: state => state.user.roles, 11 roles: state => state.user.roles,
12 permissions: state => state.user.permissions, 12 permissions: state => state.user.permissions,
13 permission_routes: state => state.permission.routes, 13 permission_routes: state => state.permission.routes,
  14 + topbarRouters:state => state.permission.topbarRouters,
  15 + defaultRoutes:state => state.permission.defaultRoutes,
14 sidebarRouters:state => state.permission.sidebarRouters, 16 sidebarRouters:state => state.permission.sidebarRouters,
15 } 17 }
16 export default getters 18 export default getters
@@ -7,6 +7,8 @@ const permission = { @@ -7,6 +7,8 @@ const permission = {
7 state: { 7 state: {
8 routes: [], 8 routes: [],
9 addRoutes: [], 9 addRoutes: [],
  10 + defaultRoutes: [],
  11 + topbarRouters: [],
10 sidebarRouters: [] 12 sidebarRouters: []
11 }, 13 },
12 mutations: { 14 mutations: {
@@ -14,8 +16,19 @@ const permission = { @@ -14,8 +16,19 @@ const permission = {
14 state.addRoutes = routes 16 state.addRoutes = routes
15 state.routes = constantRoutes.concat(routes) 17 state.routes = constantRoutes.concat(routes)
16 }, 18 },
17 - SET_SIDEBAR_ROUTERS: (state, routers) => {  
18 - state.sidebarRouters = constantRoutes.concat(routers) 19 + SET_DEFAULT_ROUTES: (state, routes) => {
  20 + state.defaultRoutes = constantRoutes.concat(routes)
  21 + },
  22 + SET_TOPBAR_ROUTES: (state, routes) => {
  23 + // 顶部导航菜单默认添加统计报表栏指向首页
  24 + const index = [{
  25 + path: 'index',
  26 + meta: { title: '统计报表', icon: 'dashboard'}
  27 + }]
  28 + state.topbarRouters = routes.concat(index);
  29 + },
  30 + SET_SIDEBAR_ROUTERS: (state, routes) => {
  31 + state.sidebarRouters = routes
19 }, 32 },
20 }, 33 },
21 actions: { 34 actions: {
@@ -30,7 +43,9 @@ const permission = { @@ -30,7 +43,9 @@ const permission = {
30 const rewriteRoutes = filterAsyncRouter(rdata, false, true) 43 const rewriteRoutes = filterAsyncRouter(rdata, false, true)
31 rewriteRoutes.push({ path: '*', redirect: '/404', hidden: true }) 44 rewriteRoutes.push({ path: '*', redirect: '/404', hidden: true })
32 commit('SET_ROUTES', rewriteRoutes) 45 commit('SET_ROUTES', rewriteRoutes)
33 - commit('SET_SIDEBAR_ROUTERS', sidebarRoutes) 46 + commit('SET_SIDEBAR_ROUTERS', constantRoutes.concat(sidebarRoutes))
  47 + commit('SET_DEFAULT_ROUTES', sidebarRoutes)
  48 + commit('SET_TOPBAR_ROUTES', sidebarRoutes)
34 resolve(rewriteRoutes) 49 resolve(rewriteRoutes)
35 }) 50 })
36 }) 51 })
1 import variables from '@/assets/styles/element-variables.scss' 1 import variables from '@/assets/styles/element-variables.scss'
2 import defaultSettings from '@/settings' 2 import defaultSettings from '@/settings'
3 3
4 -const { sideTheme, showSettings, tagsView, fixedHeader, sidebarLogo } = defaultSettings 4 +const { sideTheme, showSettings, topNav, tagsView, fixedHeader, sidebarLogo } = defaultSettings
5 5
6 const state = { 6 const state = {
7 theme: variables.theme, 7 theme: variables.theme,
8 sideTheme: sideTheme, 8 sideTheme: sideTheme,
9 showSettings: showSettings, 9 showSettings: showSettings,
  10 + topNav: topNav,
10 tagsView: tagsView, 11 tagsView: tagsView,
11 fixedHeader: fixedHeader, 12 fixedHeader: fixedHeader,
12 sidebarLogo: sidebarLogo 13 sidebarLogo: sidebarLogo