From e5d56675b8709ed6911ee833d68e5d242158ba3b Mon Sep 17 00:00:00 2001 From: iczer <1126263215@qq.com> Date: Mon, 31 Aug 2020 12:12:32 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20add=20mixed=20navigation=20mode;=20:sta?= =?UTF-8?q?r:=20=E6=96=B0=E5=A2=9E=EF=BC=9A=E6=B7=B7=E5=90=88=E5=AF=BC?= =?UTF-8?q?=E8=88=AA=E6=A8=A1=E5=BC=8F=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/menu/menu.js | 12 +-- src/components/setting/Setting.vue | 1 + src/components/setting/i18n.js | 2 + src/layouts/AdminLayout.vue | 41 +++++++- src/layouts/header/AdminHeader.vue | 17 +++- src/layouts/header/HeaderSearch.vue | 2 + src/layouts/header/index.less | 6 ++ src/router/async/router.map.js | 140 +++++----------------------- src/router/guards.js | 25 ++++- src/store/modules/setting.js | 26 ++++++ src/utils/i18n.js | 3 +- 11 files changed, 137 insertions(+), 138 deletions(-) diff --git a/src/components/menu/menu.js b/src/components/menu/menu.js index 15d18eb..49ef98f 100644 --- a/src/components/menu/menu.js +++ b/src/components/menu/menu.js @@ -77,7 +77,7 @@ export default { }, created () { this.updateMenu() - if (!this.options[0].fullPath) { + if (this.options.length > 0 && !this.options[0].fullPath) { this.formatOptions(this.options, '') } // 自定义国际化配置 @@ -90,7 +90,7 @@ export default { }, watch: { options(val) { - if (!val[0].fullPath) { + if (val.length > 0 && !val[0].fullPath) { this.formatOptions(this.options, '') } }, @@ -195,18 +195,14 @@ export default { }, updateMenu () { const menuRoutes = this.$route.matched.filter(item => item.path !== '') - const route = menuRoutes.pop() - this.selectedKeys = [this.getSelectedKey(route)] + this.selectedKeys = this.getSelectedKey(this.$route) let openKeys = menuRoutes.map(item => item.path) if (!fastEqual(openKeys, this.sOpenKeys)) { this.collapsed || this.mode === 'horizontal' ? this.cachedOpenKeys = openKeys : this.sOpenKeys = openKeys } }, getSelectedKey (route) { - if (route.meta.invisible && route.parent) { - return this.getSelectedKey(route.parent) - } - return route.path + return route.matched.map(item => item.path) } }, render (h) { diff --git a/src/components/setting/Setting.vue b/src/components/setting/Setting.vue index 93ec7f1..d4bdd4d 100644 --- a/src/components/setting/Setting.vue +++ b/src/components/setting/Setting.vue @@ -26,6 +26,7 @@ > + diff --git a/src/components/setting/i18n.js b/src/components/setting/i18n.js index 03873a7..85fb98d 100644 --- a/src/components/setting/i18n.js +++ b/src/components/setting/i18n.js @@ -12,6 +12,7 @@ module.exports = { title: '导航设置', side: '侧边导航', head: '顶部导航', + mix: '混合导航', content: { title: '内容区域宽度', fluid: '流式', @@ -82,6 +83,7 @@ module.exports = { title: 'Navigation Mode', side: 'Side Menu Layout', head: 'Top Menu Layout', + mix: 'Mix Menu Layout', content: { title: 'Content Width', fluid: 'Fluid', diff --git a/src/layouts/AdminLayout.vue b/src/layouts/AdminLayout.vue index 92a9075..dd197fe 100644 --- a/src/layouts/AdminLayout.vue +++ b/src/layouts/AdminLayout.vue @@ -3,7 +3,7 @@ - +
@@ -12,7 +12,7 @@ - +
@@ -32,7 +32,7 @@ import PageFooter from './footer/PageFooter' import Drawer from '../components/tool/Drawer' import SideMenu from '../components/menu/SideMenu' import Setting from '../components/setting/Setting' -import {mapState, mapMutations} from 'vuex' +import {mapState, mapMutations, mapGetters} from 'vuex' const minHeight = window.innerHeight - 64 - 24 - 122 @@ -46,30 +46,61 @@ export default { showSetting: false } }, + watch: { + $route(val) { + this.setActivated(val) + }, + layout() { + this.setActivated(this.$route) + } + }, computed: { ...mapState('setting', ['isMobile', 'theme', 'layout', 'footerLinks', 'copyright', 'fixedHeader', 'fixedSideBar', 'hideSetting', 'menuData']), + ...mapGetters('setting', ['firstMenu', 'subMenu']), sideMenuWidth() { return this.collapsed ? '80px' : '256px' }, headerStyle() { - let width = (this.fixedHeader && this.layout == 'side' && !this.isMobile) ? `calc(100% - ${this.sideMenuWidth})` : '100%' + let width = (this.fixedHeader && this.layout !== 'head' && !this.isMobile) ? `calc(100% - ${this.sideMenuWidth})` : '100%' let position = this.fixedHeader ? 'fixed' : 'static' let transition = this.fixedHeader ? 'transition: width 0.2s' : '' return `width: ${width}; position: ${position}; ${transition}` + }, + headMenuData() { + const {layout, menuData, firstMenu} = this + return layout === 'mix' ? firstMenu : menuData + }, + sideMenuData() { + const {layout, menuData, subMenu} = this + return layout === 'mix' ? subMenu : menuData } }, methods: { - ...mapMutations('setting', ['correctPageMinHeight']), + ...mapMutations('setting', ['correctPageMinHeight', 'setActivatedFirst']), toggleCollapse () { this.collapsed = !this.collapsed }, onMenuSelect () { this.toggleCollapse() }, + setActivated(route) { + if (this.layout === 'mix') { + let matched = route.matched + matched = matched.slice(0, matched.length - 1) + const {firstMenu} = this + for (let menu of firstMenu) { + if (matched.findIndex(item => item.path === menu.fullPath) !== -1) { + this.setActivatedFirst(menu.fullPath) + break + } + } + } + } }, created() { this.correctPageMinHeight(minHeight - 1) + this.setActivated(this.$route) }, beforeDestroy() { this.correctPageMinHeight(-minHeight + 1) diff --git a/src/layouts/header/AdminHeader.vue b/src/layouts/header/AdminHeader.vue index b320432..a65b0ad 100644 --- a/src/layouts/header/AdminHeader.vue +++ b/src/layouts/header/AdminHeader.vue @@ -6,12 +6,12 @@

{{systemName}}

- -
- + +
+
- + @@ -49,7 +49,8 @@ export default { {key: 'CN', name: '简体中文', alias: '简体'}, {key: 'HK', name: '繁體中文', alias: '繁體'}, {key: 'US', name: 'English', alias: 'English'} - ] + ], + searchActive: false } }, computed: { @@ -63,6 +64,12 @@ export default { langAlias() { let lang = this.langList.find(item => item.key == this.lang) return lang.alias + }, + menuWidth() { + const {layout, searchActive} = this + const headWidth = layout === 'head' ? '1236px' : '100%' + const extraWidth = searchActive ? '564px' : '364px' + return `calc(${headWidth} - ${extraWidth})` } }, methods: { diff --git a/src/layouts/header/HeaderSearch.vue b/src/layouts/header/HeaderSearch.vue index bd408cc..ec4f116 100644 --- a/src/layouts/header/HeaderSearch.vue +++ b/src/layouts/header/HeaderSearch.vue @@ -24,10 +24,12 @@ export default { methods: { enterSearchMode () { this.searchMode = true + this.$emit('active', true) setTimeout(() => this.$refs.input.focus(), 300) }, leaveSearchMode () { this.searchMode = false + setTimeout(() => this.$emit('active', false), 300) } } } diff --git a/src/layouts/header/index.less b/src/layouts/header/index.less index 443f030..ba90761 100644 --- a/src/layouts/header/index.less +++ b/src/layouts/header/index.less @@ -4,6 +4,12 @@ box-shadow: @shadow-down; position: relative; background: @base-bg-color; + .head-menu{ + height: 64px; + line-height: 64px; + vertical-align: middle; + box-shadow: none; + } &.dark{ background: @header-bg-color-dark; color: white; diff --git a/src/router/async/router.map.js b/src/router/async/router.map.js index ebf3684..e610a05 100644 --- a/src/router/async/router.map.js +++ b/src/router/async/router.map.js @@ -12,113 +12,10 @@ const routerMap = { path: '/login', component: () => import('@/pages/login') }, - root: { - path: '/', - name: '首页', - redirect: '/login', - component: view.tabs - }, - dashboard: { - name: 'Dashboard', - component: view.blank - }, - workplace: { - name: '工作台', - component: () => import('@/pages/dashboard/workplace') - }, - analysis: { - name: '分析页', - component: () => import('@/pages/dashboard/analysis') - }, - form: { - name: '表单页', - icon: 'form', - component: view.page - }, - basicForm: { - path: 'basic', - name: '基础表单', - component: () => import('@/pages/form/basic') - }, - stepForm: { - path: 'step', - name: '分步表单', - component: () => import('@/pages/form/step') - }, - advanceForm: { - path: 'advance', - name: '高级表单', - component: () => import('@/pages/form/advance') - }, - list: { - name: '列表页', - icon: 'table', - component: view.page - }, - queryList: { - path: 'query', - name: '查询表格', - component: () => import('@/pages/list/QueryList') - }, - primaryList: { - path: 'primary', - name: '标准列表', - component: () => import('@/pages/list/StandardList') - }, - cardList: { - path: 'card', - name: '卡片列表', - component: () => import('@/pages/list/CardList') - }, - searchList: { - path: 'search', - name: '搜索列表', - component: () => import('@/pages/list/search/SearchLayout') - }, - article: { - name: '文章', - component: () => import('@/pages/list/search/ArticleList') - }, - application: { - name: '应用', - component: () => import('@/pages/list/search/ApplicationList') - }, - project: { - name: '项目', - component: () => import('@/pages/list/search/ProjectList') - }, - details: { - name: '详情页', - icon: 'profile', - component: view.blank - }, - basicDetails: { - path: 'basic', - name: '基础详情页', - component: () => import('@/pages/detail/BasicDetail') - }, - advanceDetails: { - path: 'advance', - name: '高级详情页', - component: () => import('@/pages/detail/AdvancedDetail') - }, - result: { - name: '结果页', - icon: 'check-circle-o', - component: view.page - }, - success: { - name: '成功', - component: () => import('@/pages/result/Success') - }, - error: { - name: '失败', - component: () => import('@/pages/result/Error') - }, - exception: { - name: '异常页', - icon: 'warning', - component: view.blank + demo: { + name: '演示页', + renderMenu: false, + component: () => import('@/pages/demo') }, exp403: { authority: '*', @@ -136,19 +33,26 @@ const routerMap = { path: '500', component: () => import('@/pages/exception/500') }, - components: { - name: '小组件', - icon: 'appstore-o', + root: { + path: '/', + name: '首页', + redirect: '/login', + component: view.tabs + }, + parent1: { + name: '父级路由1', + icon: 'dashboard', + component: view.blank + }, + parent2: { + name: '父级路由2', + icon: 'form', component: view.page }, - taskCard: { - name: '任务卡片', - component: () => import('@/pages/components/TaskCard') - }, - palette: { - name: '颜色复选框', - component: () => import('@/pages/components/Palette') + exception: { + name: '异常页', + icon: 'warning', + component: view.blank } } export default routerMap - diff --git a/src/router/guards.js b/src/router/guards.js index b8719f9..67de64c 100644 --- a/src/router/guards.js +++ b/src/router/guards.js @@ -38,7 +38,30 @@ const authorityGuard = (to, from, next, options) => { } } +/** + * 混合导航模式下一级菜单跳转重定向 + * @param to + * @param from + * @param next + * @param options + * @returns {*} + */ +const redirectGuard = (to, from, next, options) => { + const {store} = options + if (store.state.setting.layout === 'mix') { + const firstMenu = store.getters['setting/firstMenu'] + if (firstMenu.find(item => item.fullPath === to.fullPath)) { + store.commit('setting/setActivatedFirst', to.fullPath) + const subMenu = store.getters['setting/subMenu'] + if (subMenu.length > 0) { + return next({path: subMenu[0].fullPath}) + } + } + } + next() +} + export default { - beforeEach: [loginGuard, authorityGuard], + beforeEach: [loginGuard, authorityGuard, redirectGuard], afterEach: [] } diff --git a/src/store/modules/setting.js b/src/store/modules/setting.js index 7f0c22b..49babe6 100644 --- a/src/store/modules/setting.js +++ b/src/store/modules/setting.js @@ -1,5 +1,6 @@ import config from '@/config' import {ADMIN} from '@/config/default' +import {formatFullPath} from '@/utils/i18n' export default { namespaced: true, state: { @@ -8,8 +9,30 @@ export default { palettes: ADMIN.palettes, pageMinHeight: 0, menuData: [], + activatedFirst: undefined, ...config, }, + getters: { + firstMenu(state) { + const {menuData} = state + if (!menuData[0].fullPath) { + formatFullPath(menuData) + } + return menuData.map(item => { + const menuItem = {...item} + delete menuItem.children + return menuItem + }) + }, + subMenu(state) { + const {menuData, activatedFirst} = state + if (!menuData[0].fullPath) { + formatFullPath(menuData) + } + const current = menuData.find(menu => menu.fullPath === activatedFirst) + return current && current.children ? current.children : [] + } + }, mutations: { setDevice (state, isMobile) { state.isMobile = isMobile @@ -49,6 +72,9 @@ export default { }, setAsyncRoutes(state, asyncRoutes) { state.asyncRoutes = asyncRoutes + }, + setActivatedFirst(state, activatedFirst) { + state.activatedFirst = activatedFirst } } } diff --git a/src/utils/i18n.js b/src/utils/i18n.js index 50e3c36..ec64b9f 100644 --- a/src/utils/i18n.js +++ b/src/utils/i18n.js @@ -73,5 +73,6 @@ function mergeI18nFromRoutes(i18n, routes) { export { initI18n, - mergeI18nFromRoutes + mergeI18nFromRoutes, + formatFullPath }