From 002cf50440c8e3e5d87f934c6edfb09c52043746 Mon Sep 17 00:00:00 2001 From: iczer <1126263215@qq.com> Date: Fri, 28 Aug 2020 14:25:54 +0800 Subject: [PATCH 01/12] update docs; --- docs/advance/async.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/advance/async.md b/docs/advance/async.md index 0e2ff8a..750f6d7 100644 --- a/docs/advance/async.md +++ b/docs/advance/async.md @@ -24,7 +24,7 @@ module.exports = { } ``` ### 注册路由组件 -基础路由组件包含路由基本配置和对应的视图组件,我们统一在 `/router/router.map.js` 文件中注册它们。它和正常的路由配置基本无异,相当于把完整的路由拆分成单个的路由配置进行注册,为后面的路由动态配置打好基础。 +基础路由组件包含路由基本配置和对应的视图组件,我们统一在 `/router/async/router.map.js` 文件中注册它们。它和正常的路由配置基本无异,相当于把完整的路由拆分成单个的路由配置进行注册,为后面的路由动态配置打好基础。 一个单独的路由组件注册示例如下: ```jsx registerName: { //路由组件注册名称,唯一标识 @@ -108,7 +108,7 @@ export default routerMap ``` ::: ### 配置基本路由 -如果没有任何路由,你的应用是无法访问的,所以我们需要在本地配置一些基本的路由,比如登录页、404、403 等。你可以在 `/router/config.async.js` 文件中配置一些本地必要的路由。如下: +如果没有任何路由,你的应用是无法访问的,所以我们需要在本地配置一些基本的路由,比如登录页、404、403 等。你可以在 `/router/async/config.async.js` 文件中配置一些本地必要的路由。如下: ```js const routesConfig = [ 'login', //匹配 router.map.js 中注册的 registerName = login 的路由 @@ -163,25 +163,25 @@ export default options 那么我们就需要先从后端服务获取异步路由配置,后端返回的异步路由配置 `routesConfig` 是一个异步路由配置数组, 应当如下格式: ```jsx [{ - router: 'root', //匹配 /router/router.map.js 中注册名 registerName = root 的路由 + router: 'root', //匹配 router.map.js 中注册名 registerName = root 的路由 children: [ //root 路由的子路由配置 { - router: 'dashboard', //匹配 /router/router.map.js 中注册名 registerName = dashboard 的路由 + router: 'dashboard', //匹配 router.map.js 中注册名 registerName = dashboard 的路由 children: ['workplace', 'analysis'], //dashboard 路由的子路由配置,依次匹配 registerName 为 workplace 和 analysis 的路由 }, { - router: 'form', //匹配 /router/router.map.js 中注册名 registerName = form 的路由 + router: 'form', //匹配 router.map.js 中注册名 registerName = form 的路由 children: [ //form 路由的子路由配置 - 'basicForm', //匹配 /router/router.map.js 中注册名 registerName = basicForm 的路由 - 'stepForm', //匹配 /router/router.map.js 中注册名 registerName = stepForm 的路由 + 'basicForm', //匹配 router.map.js 中注册名 registerName = basicForm 的路由 + 'stepForm', //匹配 router.map.js 中注册名 registerName = stepForm 的路由 { - router: 'advanceForm', //匹配 /router/router.map.js 中注册名 registerName = advanceForm 的路由 + router: 'advanceForm', //匹配 router.map.js 中注册名 registerName = advanceForm 的路由 path: 'advance' //重写 advanceForm 路由的 path 属性 } ] }, { - router: 'basicForm', //匹配 /router/router.map.js 中注册名 registerName = basicForm 的路由 + router: 'basicForm', //匹配 router.map.js 中注册名 registerName = basicForm 的路由 name: '验权表单', //重写 basicForm 路由的 name 属性 icon: 'file-excel', //重写 basicForm 路由的 icon 属性 authority: 'form' //重写 basicForm 路由的 authority 属性 @@ -203,7 +203,7 @@ getRoutesConfig().then(result => { 至此,异步路由的加载就完成了,你可以访问异步加载的路由了。 :::tip 上面获取异步路由的代码,在 /pages/login/Login.vue 文件中可以找到。 -loadRoutes 方法会合并 /router/config.async.js 文件中配置的基本路由。 +loadRoutes 方法会合并 /router/async/config.async.js 文件中配置的基本路由。 ::: :::details 点击查看 loadRoutes 的详细代码 ```js From 094935b758c4de7a15de17d7f8925f6aa1d4b051 Mon Sep 17 00:00:00 2001 From: iczer <1126263215@qq.com> Date: Mon, 31 Aug 2020 12:23:56 +0800 Subject: [PATCH 02/12] =?UTF-8?q?feat:=20add=20mixed=20navigation=20mode;?= =?UTF-8?q?=20:star:=20#102=20=E6=96=B0=E5=A2=9E=EF=BC=9A=E6=B7=B7?= =?UTF-8?q?=E5=90=88=E5=AF=BC=E8=88=AA=E8=8F=9C=E5=8D=95=E6=A8=A1=E5=BC=8F?= =?UTF-8?q?=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/guards.js | 25 +++++++++++++++++- src/store/modules/setting.js | 26 ++++++++++++++++++ src/utils/i18n.js | 3 ++- 10 files changed, 115 insertions(+), 20 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/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..904c173 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 : [] + } + }, 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 } From cbda23e3dbd567165c619e2df677c7ad327a6e32 Mon Sep 17 00:00:00 2001 From: iczer <1126263215@qq.com> Date: Mon, 31 Aug 2020 12:38:49 +0800 Subject: [PATCH 03/12] =?UTF-8?q?fix:=20style=20problem=20of=20tooltip=20i?= =?UTF-8?q?n=20setting=20pane;=20:bug:=20=E4=BF=AE=E5=A4=8D=EF=BC=9A?= =?UTF-8?q?=E8=AE=BE=E7=BD=AE=E9=9D=A2=E6=9D=BF=E4=B8=AD=20tooltip=20?= =?UTF-8?q?=E7=BB=84=E4=BB=B6=E7=9A=84=E6=A0=B7=E5=BC=8F=E9=97=AE=E9=A2=98?= =?UTF-8?q?=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/checkbox/ImgCheckbox.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/checkbox/ImgCheckbox.vue b/src/components/checkbox/ImgCheckbox.vue index b59dd22..ca06bdd 100644 --- a/src/components/checkbox/ImgCheckbox.vue +++ b/src/components/checkbox/ImgCheckbox.vue @@ -1,5 +1,5 @@