diff --git a/ruoyi-ui/src/assets/styles/ruoyi.scss b/ruoyi-ui/src/assets/styles/ruoyi.scss index 55118fad..579e82db 100644 --- a/ruoyi-ui/src/assets/styles/ruoyi.scss +++ b/ruoyi-ui/src/assets/styles/ruoyi.scss @@ -176,6 +176,12 @@ color: #FFFFFF; } +/* submenu item */ +.el-menu--horizontal > .el-submenu .el-submenu__title { + height: 50px !important; + line-height: 50px !important; +} + /* text color */ .text-navy { color: #1ab394; diff --git a/ruoyi-ui/src/assets/styles/sidebar.scss b/ruoyi-ui/src/assets/styles/sidebar.scss index 9fad7998..3f45751e 100644 --- a/ruoyi-ui/src/assets/styles/sidebar.scss +++ b/ruoyi-ui/src/assets/styles/sidebar.scss @@ -135,9 +135,6 @@ margin-left: 20px; } - .el-submenu__icon-arrow { - display: none; - } } } diff --git a/ruoyi-ui/src/components/TopNav/index.vue b/ruoyi-ui/src/components/TopNav/index.vue new file mode 100644 index 00000000..fb15c59e --- /dev/null +++ b/ruoyi-ui/src/components/TopNav/index.vue @@ -0,0 +1,143 @@ +<template> + <el-menu + :default-active="activeMenu" + mode="horizontal" + @select="handleSelect" + > + <template v-for="(item, index) in topMenus"> + <el-menu-item :index="item.path" :key="index" v-if="index < visibleNumber" + ><svg-icon :icon-class="item.meta.icon" /> + {{ item.meta.title }}</el-menu-item + > + </template> + + <!-- 顶部菜单超出数量折叠 --> + <el-submenu index="more" v-if="topMenus.length > visibleNumber"> + <template slot="title">更多菜单</template> + <template v-for="(item, index) in topMenus"> + <el-menu-item + :index="item.path" + :key="index" + v-if="index >= visibleNumber" + ><svg-icon :icon-class="item.meta.icon" /> + {{ item.meta.title }}</el-menu-item + > + </template> + </el-submenu> + </el-menu> +</template> + +<script> +import { constantRoutes } from "@/router"; + +export default { + data() { + return { + // 顶部栏初始数 + visibleNumber: 5, + // 是否为首次加载 + isFrist: false, + }; + }, + computed: { + // 顶部显示菜单 + topMenus() { + return this.routers.map((menu) => ({ + ...menu, + children: undefined, + })); + }, + // 所有的路由信息 + routers() { + return this.$store.state.permission.topbarRouters; + }, + // 设置子路由 + childrenMenus() { + var childrenMenus = []; + this.routers.map((router) => { + for (var item in router.children) { + if (router.children[item].parentPath === undefined) { + router.children[item].path = router.path + "/" + router.children[item].path; + router.children[item].parentPath = router.path; + } + childrenMenus.push(router.children[item]); + } + }); + return constantRoutes.concat(childrenMenus); + }, + // 默认激活的菜单 + activeMenu() { + const path = this.$route.path; + let activePath = this.routers[0].path; + if (path.lastIndexOf("/") > 0) { + const tmpPath = path.substring(1, path.length); + activePath = "/" + tmpPath.substring(0, tmpPath.indexOf("/")); + } else if ("/index" == path || "" == path) { + if (!this.isFrist) { + this.isFrist = true; + } else { + activePath = "index"; + } + } + this.activeRoutes(activePath); + return activePath; + }, + }, + mounted() { + this.setVisibleNumber(); + }, + methods: { + // 根据宽度计算设置显示栏数 + setVisibleNumber() { + const width = document.body.getBoundingClientRect().width - 200; + const elWidth = this.$el.getBoundingClientRect().width; + const menuItemNodes = this.$el.children; + const menuWidth = Array.from(menuItemNodes).map( + (i) => i.getBoundingClientRect().width + ); + this.visibleNumber = ( + parseInt(width - elWidth) / parseInt(menuWidth) + ).toFixed(0); + }, + // 菜单选择事件 + handleSelect(key, keyPath) { + if (key.indexOf("http://") !== -1 || key.indexOf("https://") !== -1) { + // http(s):// 路径新窗口打开 + window.open(key, "_blank"); + } else { + this.activeRoutes(key); + } + }, + // 当前激活的路由 + activeRoutes(key) { + var routes = []; + if (this.childrenMenus && this.childrenMenus.length > 0) { + this.childrenMenus.map((item) => { + if (key == item.parentPath || (key == "index" && "" == item.path)) { + routes.push(item); + } + }); + } + this.$store.commit("SET_SIDEBAR_ROUTERS", routes); + }, + }, +}; +</script> + +<style lang="scss" scoped> +.el-menu--horizontal > .el-menu-item { + float: left; + height: 50px; + line-height: 50px; + margin: 0; + border-bottom: 3px solid transparent; + color: #999093; + padding: 0 5px; + margin: 0 10px; +} + +.el-menu--horizontal > .el-menu-item.is-active { + border-bottom: 3px solid #409eff; + color: #303133; +} +</style> diff --git a/ruoyi-ui/src/layout/components/Navbar.vue b/ruoyi-ui/src/layout/components/Navbar.vue index db46ec55..db69e1df 100644 --- a/ruoyi-ui/src/layout/components/Navbar.vue +++ b/ruoyi-ui/src/layout/components/Navbar.vue @@ -2,7 +2,8 @@ <div class="navbar"> <hamburger id="hamburger-container" :is-active="sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" /> - <breadcrumb id="breadcrumb-container" class="breadcrumb-container" /> + <breadcrumb id="breadcrumb-container" class="breadcrumb-container" v-if="!topNav"/> + <top-nav id="topmenu-container" class="breadcrumb-container" v-if="topNav"/> <div class="right-menu"> <template v-if="device!=='mobile'"> @@ -48,6 +49,7 @@ <script> import { mapGetters } from 'vuex' import Breadcrumb from '@/components/Breadcrumb' +import TopNav from '@/components/TopNav' import Hamburger from '@/components/Hamburger' import Screenfull from '@/components/Screenfull' import SizeSelect from '@/components/SizeSelect' @@ -58,6 +60,7 @@ import RuoYiDoc from '@/components/RuoYi/Doc' export default { components: { Breadcrumb, + TopNav, Hamburger, Screenfull, SizeSelect, @@ -81,6 +84,11 @@ export default { value: val }) } + }, + topNav: { + get() { + return this.$store.state.settings.topNav + } } }, methods: { diff --git a/ruoyi-ui/src/layout/components/Settings/index.vue b/ruoyi-ui/src/layout/components/Settings/index.vue index 7e495b7b..7e36d48d 100644 --- a/ruoyi-ui/src/layout/components/Settings/index.vue +++ b/ruoyi-ui/src/layout/components/Settings/index.vue @@ -41,6 +41,11 @@ <el-divider/> <h3 class="drawer-title">系统布局配置</h3> + + <div class="drawer-item"> + <span>开启 TopNav</span> + <el-switch v-model="topNav" class="drawer-switch" /> + </div> <div class="drawer-item"> <span>开启 Tags-Views</span> @@ -87,6 +92,20 @@ export default { }) } }, + topNav: { + get() { + return this.$store.state.settings.topNav + }, + set(val) { + this.$store.dispatch('settings/changeSetting', { + key: 'topNav', + value: val + }) + if (!val) { + this.$store.commit("SET_SIDEBAR_ROUTERS", this.$store.state.permission.defaultRoutes); + } + } + }, tagsView: { get() { return this.$store.state.settings.tagsView diff --git a/ruoyi-ui/src/settings.js b/ruoyi-ui/src/settings.js index 8eb92945..0e74c710 100644 --- a/ruoyi-ui/src/settings.js +++ b/ruoyi-ui/src/settings.js @@ -11,6 +11,11 @@ module.exports = { */ showSettings: false, + /** + * 是否显示顶部导航 + */ + topNav: false, + /** * 是否显示 tagsView */ diff --git a/ruoyi-ui/src/store/getters.js b/ruoyi-ui/src/store/getters.js index ea4f90e1..8d723813 100644 --- a/ruoyi-ui/src/store/getters.js +++ b/ruoyi-ui/src/store/getters.js @@ -11,6 +11,8 @@ const getters = { roles: state => state.user.roles, permissions: state => state.user.permissions, permission_routes: state => state.permission.routes, + topbarRouters:state => state.permission.topbarRouters, + defaultRoutes:state => state.permission.defaultRoutes, sidebarRouters:state => state.permission.sidebarRouters, } export default getters diff --git a/ruoyi-ui/src/store/modules/permission.js b/ruoyi-ui/src/store/modules/permission.js index 61f681cd..f3a1d11f 100644 --- a/ruoyi-ui/src/store/modules/permission.js +++ b/ruoyi-ui/src/store/modules/permission.js @@ -7,6 +7,8 @@ const permission = { state: { routes: [], addRoutes: [], + defaultRoutes: [], + topbarRouters: [], sidebarRouters: [] }, mutations: { @@ -14,8 +16,19 @@ const permission = { state.addRoutes = routes state.routes = constantRoutes.concat(routes) }, - SET_SIDEBAR_ROUTERS: (state, routers) => { - state.sidebarRouters = constantRoutes.concat(routers) + SET_DEFAULT_ROUTES: (state, routes) => { + state.defaultRoutes = constantRoutes.concat(routes) + }, + SET_TOPBAR_ROUTES: (state, routes) => { + // 顶部导航菜单默认添加统计报表栏指向首页 + const index = [{ + path: 'index', + meta: { title: '统计报表', icon: 'dashboard'} + }] + state.topbarRouters = routes.concat(index); + }, + SET_SIDEBAR_ROUTERS: (state, routes) => { + state.sidebarRouters = routes }, }, actions: { @@ -30,7 +43,9 @@ const permission = { const rewriteRoutes = filterAsyncRouter(rdata, false, true) rewriteRoutes.push({ path: '*', redirect: '/404', hidden: true }) commit('SET_ROUTES', rewriteRoutes) - commit('SET_SIDEBAR_ROUTERS', sidebarRoutes) + commit('SET_SIDEBAR_ROUTERS', constantRoutes.concat(sidebarRoutes)) + commit('SET_DEFAULT_ROUTES', sidebarRoutes) + commit('SET_TOPBAR_ROUTES', sidebarRoutes) resolve(rewriteRoutes) }) }) diff --git a/ruoyi-ui/src/store/modules/settings.js b/ruoyi-ui/src/store/modules/settings.js index a246a3c4..f113e9a8 100644 --- a/ruoyi-ui/src/store/modules/settings.js +++ b/ruoyi-ui/src/store/modules/settings.js @@ -1,12 +1,13 @@ import variables from '@/assets/styles/element-variables.scss' import defaultSettings from '@/settings' -const { sideTheme, showSettings, tagsView, fixedHeader, sidebarLogo } = defaultSettings +const { sideTheme, showSettings, topNav, tagsView, fixedHeader, sidebarLogo } = defaultSettings const state = { theme: variables.theme, sideTheme: sideTheme, showSettings: showSettings, + topNav: topNav, tagsView: tagsView, fixedHeader: fixedHeader, sidebarLogo: sidebarLogo