21 changed files with 875 additions and 41 deletions
-
1src/assets/styles/index.scss
-
89src/assets/styles/topbar.scss
-
81src/components/Breadcrumb/index.vue
-
44src/components/Hamburger/index.vue
-
119src/layout/components/Navbar.vue
-
24src/layout/components/Sidebar/FixiOSBug.js
-
0src/layout/components/Sidebar/Item.vue
-
37src/layout/components/Sidebar/Link.vue
-
82src/layout/components/Sidebar/Logo.vue
-
79src/layout/components/Sidebar/SidebarItem.vue
-
49src/layout/components/Sidebar/index.vue
-
31src/layout/components/TopMenus.vue
-
207src/layout/components/Topbar.vue
-
4src/layout/components/index.js
-
39src/layout/index.vue
-
1src/router/index.js
-
11src/router/routers.js
-
6src/settings.js
-
3src/store/getters.js
-
9src/store/modules/permission.js
-
0src/views/home.vue
@ -0,0 +1,89 @@ |
|||
.top-nav { |
|||
// margin-left: $sideBarWidth; |
|||
width: 100%; |
|||
background-color: #304156; |
|||
position: fixed; |
|||
top: 0; |
|||
left: 0; |
|||
z-index: 1001; |
|||
overflow: hidden; |
|||
|
|||
.log { |
|||
padding: 0 20px; |
|||
line-height: 56px; |
|||
font-size: 24px; |
|||
font-weight: bold; |
|||
color: rgb(191, 203, 217); |
|||
float: left; |
|||
} |
|||
.el-menu { |
|||
float: left; |
|||
border: none!important; |
|||
background-color: #304156; |
|||
|
|||
.nav-item { |
|||
display: inline-block; |
|||
.el-menu-item { |
|||
color: rgb(191, 203, 217); |
|||
&:hover { |
|||
background-color: $subMenuHover !important; |
|||
} |
|||
&:focus { |
|||
background-color: $subMenuHover !important; |
|||
// color: $subMenuActiveText !important; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
.right-menu { |
|||
float: right; |
|||
height: 100%; |
|||
|
|||
&:focus { |
|||
outline: none; |
|||
} |
|||
|
|||
.right-menu-item { |
|||
display: inline-block; |
|||
padding: 0 8px; |
|||
height: 100%; |
|||
font-size: 18px; |
|||
color: #5a5e66; |
|||
vertical-align: text-bottom; |
|||
|
|||
&.hover-effect { |
|||
cursor: pointer; |
|||
transition: background .3s; |
|||
|
|||
&:hover { |
|||
background: rgba(0, 0, 0, .025) |
|||
} |
|||
} |
|||
} |
|||
|
|||
.avatar-container { |
|||
margin-right: 30px; |
|||
|
|||
.avatar-wrapper { |
|||
margin-top: 5px; |
|||
position: relative; |
|||
|
|||
.user-avatar { |
|||
cursor: pointer; |
|||
width: 40px; |
|||
height: 40px; |
|||
border-radius: 10px; |
|||
} |
|||
|
|||
.el-icon-caret-bottom { |
|||
cursor: pointer; |
|||
position: absolute; |
|||
right: -20px; |
|||
top: 25px; |
|||
font-size: 12px; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,81 @@ |
|||
<template> |
|||
<el-breadcrumb class="app-breadcrumb" separator="/"> |
|||
<transition-group name="breadcrumb"> |
|||
<el-breadcrumb-item v-for="(item,index) in levelList" :key="item.path"> |
|||
<span v-if="item.redirect==='noredirect'||index==levelList.length-1" class="no-redirect">{{ item.meta.title }}</span> |
|||
<a v-else @click.prevent="handleLink(item)">{{ item.meta.title }}</a> |
|||
</el-breadcrumb-item> |
|||
</transition-group> |
|||
</el-breadcrumb> |
|||
</template> |
|||
|
|||
<script> |
|||
import pathToRegexp from 'path-to-regexp' |
|||
|
|||
export default { |
|||
data() { |
|||
return { |
|||
levelList: null |
|||
} |
|||
}, |
|||
watch: { |
|||
$route(route) { |
|||
// if you go to the redirect page, do not update the breadcrumbs |
|||
if (route.path.startsWith('/redirect/')) { |
|||
return |
|||
} |
|||
this.getBreadcrumb() |
|||
} |
|||
}, |
|||
created() { |
|||
this.getBreadcrumb() |
|||
}, |
|||
methods: { |
|||
getBreadcrumb() { |
|||
// only show routes with meta.title |
|||
let matched = this.$route.matched.filter(item => item.meta && item.meta.title) |
|||
const first = matched[0] |
|||
|
|||
if (!this.isDashboard(first)) { |
|||
matched = [{ path: '/dashboard', meta: { title: '首页' }}].concat(matched) |
|||
} |
|||
|
|||
this.levelList = matched.filter(item => item.meta && item.meta.title && item.meta.breadcrumb !== false) |
|||
}, |
|||
isDashboard(route) { |
|||
const name = route && route.name |
|||
if (!name) { |
|||
return false |
|||
} |
|||
return name.trim().toLocaleLowerCase() === 'Dashboard'.toLocaleLowerCase() |
|||
}, |
|||
pathCompile(path) { |
|||
// To solve this problem https://github.com/PanJiaChen/vue-element-admin/issues/561 |
|||
const { params } = this.$route |
|||
var toPath = pathToRegexp.compile(path) |
|||
return toPath(params) |
|||
}, |
|||
handleLink(item) { |
|||
const { redirect, path } = item |
|||
if (redirect) { |
|||
this.$router.push(redirect) |
|||
return |
|||
} |
|||
this.$router.push(this.pathCompile(path)) |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.app-breadcrumb.el-breadcrumb { |
|||
display: inline-block; |
|||
font-size: 14px; |
|||
line-height: 50px; |
|||
margin-left: 8px; |
|||
.no-redirect { |
|||
color: #97a8be; |
|||
cursor: text; |
|||
} |
|||
} |
|||
</style> |
@ -0,0 +1,44 @@ |
|||
<template> |
|||
<div style="padding: 0 15px;" @click="toggleClick"> |
|||
<svg |
|||
:class="{'is-active':isActive}" |
|||
class="hamburger" |
|||
viewBox="0 0 1024 1024" |
|||
xmlns="http://www.w3.org/2000/svg" |
|||
width="64" |
|||
height="64" |
|||
> |
|||
<path d="M408 442h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-8 204c0 4.4 3.6 8 8 8h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56zm504-486H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 632H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM142.4 642.1L298.7 519a8.84 8.84 0 0 0 0-13.9L142.4 381.9c-5.8-4.6-14.4-.5-14.4 6.9v246.3a8.9 8.9 0 0 0 14.4 7z" /> |
|||
</svg> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
name: 'Hamburger', |
|||
props: { |
|||
isActive: { |
|||
type: Boolean, |
|||
default: false |
|||
} |
|||
}, |
|||
methods: { |
|||
toggleClick() { |
|||
this.$emit('toggleClick') |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.hamburger { |
|||
display: inline-block; |
|||
vertical-align: middle; |
|||
width: 20px; |
|||
height: 20px; |
|||
} |
|||
|
|||
.hamburger.is-active { |
|||
transform: rotate(180deg); |
|||
} |
|||
</style> |
@ -0,0 +1,119 @@ |
|||
<template> |
|||
<div class="navbar"> |
|||
<hamburger id="hamburger-container" :is-active="sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" /> |
|||
<breadcrumb id="breadcrumb-container" class="breadcrumb-container" /> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import { mapGetters } from 'vuex' |
|||
import Breadcrumb from '@/components/Breadcrumb' |
|||
import Hamburger from '@/components/Hamburger' |
|||
// import Avatar from '@/assets/images/avatar.png' |
|||
// import variables from '@/assets/styles/variables.scss' |
|||
// import Sidebar from './Sidebar/index' |
|||
|
|||
export default { |
|||
components: { |
|||
Breadcrumb, |
|||
Hamburger |
|||
}, |
|||
computed: { |
|||
...mapGetters(['sidebar']) |
|||
}, |
|||
methods: { |
|||
toggleSideBar() { |
|||
this.$store.dispatch('app/toggleSideBar') |
|||
} |
|||
|
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.navbar { |
|||
height: 60px; |
|||
overflow: hidden; |
|||
position: relative; |
|||
background: #fff; |
|||
box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08); |
|||
|
|||
.navmenu { |
|||
float: left; |
|||
} |
|||
|
|||
.hamburger-container { |
|||
line-height: 46px; |
|||
height: 100%; |
|||
float: left; |
|||
cursor: pointer; |
|||
transition: background 0.3s; |
|||
-webkit-tap-highlight-color: transparent; |
|||
|
|||
&:hover { |
|||
background: rgba(0, 0, 0, 0.025); |
|||
} |
|||
} |
|||
|
|||
.breadcrumb-container { |
|||
float: left; |
|||
} |
|||
|
|||
.errLog-container { |
|||
display: inline-block; |
|||
vertical-align: top; |
|||
} |
|||
|
|||
.right-menu { |
|||
float: right; |
|||
height: 100%; |
|||
line-height: 50px; |
|||
|
|||
&:focus { |
|||
outline: none; |
|||
} |
|||
|
|||
.right-menu-item { |
|||
display: inline-block; |
|||
padding: 0 8px; |
|||
height: 100%; |
|||
font-size: 18px; |
|||
color: #5a5e66; |
|||
vertical-align: text-bottom; |
|||
|
|||
&.hover-effect { |
|||
cursor: pointer; |
|||
transition: background 0.3s; |
|||
|
|||
&:hover { |
|||
background: rgba(0, 0, 0, 0.025); |
|||
} |
|||
} |
|||
} |
|||
|
|||
.avatar-container { |
|||
margin-right: 30px; |
|||
|
|||
.avatar-wrapper { |
|||
margin-top: 5px; |
|||
position: relative; |
|||
|
|||
.user-avatar { |
|||
cursor: pointer; |
|||
width: 40px; |
|||
height: 40px; |
|||
border-radius: 10px; |
|||
} |
|||
|
|||
.el-icon-caret-bottom { |
|||
cursor: pointer; |
|||
position: absolute; |
|||
right: -20px; |
|||
top: 25px; |
|||
font-size: 12px; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
</style> |
@ -0,0 +1,24 @@ |
|||
export default { |
|||
computed: { |
|||
device() { |
|||
return this.$store.state.app.device |
|||
} |
|||
}, |
|||
mounted() { |
|||
this.fixBugIniOS() |
|||
}, |
|||
methods: { |
|||
fixBugIniOS() { |
|||
const $subMenu = this.$refs.subMenu |
|||
if ($subMenu) { |
|||
const handleMouseleave = $subMenu.handleMouseleave |
|||
$subMenu.handleMouseleave = (e) => { |
|||
if (this.device === 'mobile') { |
|||
return |
|||
} |
|||
handleMouseleave(e) |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,37 @@ |
|||
<template> |
|||
<!-- eslint-disable vue/require-component-is --> |
|||
<!-- 防止语法报错 --> |
|||
<component v-bind="linkProps(to)"> |
|||
<slot /> |
|||
</component> |
|||
</template> |
|||
|
|||
<script> |
|||
import { isExternal } from '@/utils/validate' |
|||
|
|||
export default { |
|||
props: { |
|||
to: { |
|||
type: String, |
|||
required: true |
|||
} |
|||
}, |
|||
methods: { |
|||
linkProps(url) { |
|||
if (isExternal(url)) { |
|||
return { |
|||
is: 'a', |
|||
href: url, |
|||
target: '_blank', |
|||
rel: 'noopener' |
|||
} |
|||
} |
|||
return { |
|||
is: 'router-link', |
|||
to: url |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
</script> |
@ -0,0 +1,82 @@ |
|||
<template> |
|||
<div class="sidebar-logo-container" :class="{'collapse':collapse}"> |
|||
<transition name="sidebarLogoFade"> |
|||
<router-link v-if="collapse" key="collapse" class="sidebar-logo-link" to="/"> |
|||
<img v-if="logo" :src="logo" class="sidebar-logo"> |
|||
<h1 v-else class="sidebar-title">{{ title }}</h1> |
|||
</router-link> |
|||
<router-link v-else key="expand" class="sidebar-logo-link" to="/"> |
|||
<img v-if="logo" :src="logo" class="sidebar-logo"> |
|||
<h1 class="sidebar-title">{{ title }} </h1> |
|||
</router-link> |
|||
</transition> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import Logo from '@/assets/images/logo.png' |
|||
export default { |
|||
name: 'SidebarLogo', |
|||
props: { |
|||
collapse: { |
|||
type: Boolean, |
|||
required: true |
|||
} |
|||
}, |
|||
data() { |
|||
return { |
|||
title: '阅行资源后台管理系统', |
|||
logo: Logo |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.sidebarLogoFade-enter-active { |
|||
transition: opacity 1.5s; |
|||
} |
|||
|
|||
.sidebarLogoFade-enter, |
|||
.sidebarLogoFade-leave-to { |
|||
opacity: 0; |
|||
} |
|||
|
|||
.sidebar-logo-container { |
|||
position: relative; |
|||
width: 100%; |
|||
height: 50px; |
|||
line-height: 50px; |
|||
text-align: center; |
|||
overflow: hidden; |
|||
|
|||
& .sidebar-logo-link { |
|||
height: 100%; |
|||
width: 100%; |
|||
|
|||
& .sidebar-logo { |
|||
width: 32px; |
|||
height: 32px; |
|||
vertical-align: middle; |
|||
margin-right: 6px; |
|||
} |
|||
|
|||
& .sidebar-title { |
|||
display: inline-block; |
|||
margin: 0; |
|||
color: #fff; |
|||
font-weight: 600; |
|||
line-height: 50px; |
|||
font-size: 14px; |
|||
font-family: Avenir, Helvetica Neue, Arial, Helvetica, sans-serif; |
|||
vertical-align: middle; |
|||
} |
|||
} |
|||
|
|||
&.collapse { |
|||
.sidebar-logo { |
|||
margin-right: 0px; |
|||
} |
|||
} |
|||
} |
|||
</style> |
@ -0,0 +1,79 @@ |
|||
<template> |
|||
<div v-if="!item.hidden" class="menu-wrapper"> |
|||
<template v-if="hasOneShowingChild(item.children, item) && (!onlyOneChild.children || onlyOneChild.noShowingChildren) && !item.alwaysShow"> |
|||
<app-link v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path)"> |
|||
<el-menu-item :index="resolvePath(onlyOneChild.path)" :class="{ 'submenu-title-noDropdown': !isNest }"> |
|||
<item :icon="onlyOneChild.meta.icon || (item.meta && item.meta.icon)" :title="onlyOneChild.meta.title" /> |
|||
</el-menu-item> |
|||
</app-link> |
|||
</template> |
|||
|
|||
<el-submenu v-else ref="subMenu" :index="resolvePath(item.path)" popper-append-to-body> |
|||
<template slot="title"> |
|||
<item v-if="item.meta" :icon="item.meta && item.meta.icon" :title="item.meta.title" /> |
|||
</template> |
|||
<sidebar-item v-for="child in item.children" :key="child.path" :is-nest="true" :item="child" :base-path="resolvePath(child.path)" class="nest-menu" /> |
|||
</el-submenu> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import path from 'path' |
|||
import { isExternal } from '@/utils/validate' |
|||
|
|||
export default { |
|||
name: 'SidebarItem', |
|||
|
|||
props: { |
|||
// route object |
|||
item: { |
|||
type: Object, |
|||
required: true |
|||
}, |
|||
isNest: { |
|||
type: Boolean, |
|||
default: false |
|||
}, |
|||
basePath: { |
|||
type: String, |
|||
default: '' |
|||
} |
|||
}, |
|||
data() { |
|||
this.onlyOneChild = null |
|||
return {} |
|||
}, |
|||
methods: { |
|||
hasOneShowingChild(children = [], parent) { |
|||
const showingChildren = children.filter((item) => { |
|||
if (item.hidden) { |
|||
return false |
|||
} else { |
|||
this.onlyOneChild = item |
|||
return true |
|||
} |
|||
}) |
|||
|
|||
if (showingChildren.length === 1) { |
|||
return true |
|||
} |
|||
|
|||
if (showingChildren.length === 0) { |
|||
this.onlyOneChild = { ...parent, path: '', noShowingChildren: true } |
|||
return true |
|||
} |
|||
|
|||
return false |
|||
}, |
|||
resolvePath(routePath) { |
|||
if (isExternal(routePath)) { |
|||
return routePath |
|||
} |
|||
if (isExternal(this.basePath)) { |
|||
return this.basePath |
|||
} |
|||
return path.resolve(this.basePath, routePath) |
|||
} |
|||
} |
|||
} |
|||
</script> |
@ -0,0 +1,49 @@ |
|||
<template> |
|||
<div :class="{ 'has-logo': showLogo }"> |
|||
<logo v-if="showLogo" :collapse="isCollapse" /> |
|||
<el-scrollbar wrap-class="scrollbar-wrapper"> |
|||
<el-menu :default-active="activeMenu" :collapse="isCollapse" :background-color="variables.menuBg" :text-color="variables.menuText" :active-text-color="variables.menuActiveText" :collapse-transition="false" mode="vertical"> |
|||
<sidebar-item v-for="route in routes" :key="route.path" :item="route" :base-path="route.path" /> |
|||
</el-menu> |
|||
</el-scrollbar> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import { mapGetters } from 'vuex' |
|||
import Logo from './Logo' |
|||
import SidebarItem from './SidebarItem' |
|||
import variables from '@/assets/styles/variables.scss' |
|||
|
|||
export default { |
|||
components: { SidebarItem, Logo }, |
|||
props: { |
|||
|
|||
}, |
|||
computed: { |
|||
...mapGetters(['sidebar']), |
|||
routes() { |
|||
return this.$store.state.permission.currentRoutes.children |
|||
}, |
|||
activeMenu() { |
|||
const route = this.$route |
|||
const { meta, path } = route |
|||
|
|||
if (meta.activeMenu) { |
|||
return meta.activeMenu |
|||
} |
|||
return path |
|||
}, |
|||
showLogo() { |
|||
return this.$store.state.settings.sidebarLogo |
|||
}, |
|||
variables() { |
|||
return variables |
|||
}, |
|||
isCollapse() { |
|||
return !this.sidebar.opened |
|||
} |
|||
} |
|||
|
|||
} |
|||
</script> |
@ -1,31 +0,0 @@ |
|||
<template> |
|||
<div> |
|||
<el-menu :default-active="activeMenu" :background-color="variables.menuBg" :text-color="variables.menuText" :active-text-color="variables.menuActiveText" :collapse-transition="false" mode="horizontal"> |
|||
<el-menu-item v-for="route in sidebarRouters" :key="route.path" :item="route" :base-path="route.path" /> |
|||
</el-menu> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import { mapGetters } from 'vuex' |
|||
import variables from '@/assets/styles/variables.scss' |
|||
|
|||
export default { |
|||
name: 'TopMenus', |
|||
computed: { |
|||
...mapGetters(['sidebarRouters', 'sidebar']), |
|||
activeMenu() { |
|||
const route = this.$route |
|||
const { meta, path } = route |
|||
|
|||
if (meta.activeMenu) { |
|||
return meta.activeMenu |
|||
} |
|||
return path |
|||
}, |
|||
variables() { |
|||
return variables |
|||
} |
|||
} |
|||
} |
|||
</script> |
@ -0,0 +1,207 @@ |
|||
<template> |
|||
<div class="top-nav"> |
|||
<el-menu :active-text-color="variables.menuActiveText" :default-active="activeMenu" mode="horizontal" @select="handleSelect"> |
|||
<div v-for="item in routes" :key="item.path" class="nav-item"> |
|||
<app-link :to="resolvePath(item)"> |
|||
<el-menu-item v-if="!item.hidden" :index="item.path"> |
|||
{{ item.meta ? item.meta.title : item.children[0].meta.title }} |
|||
</el-menu-item> |
|||
</app-link> |
|||
</div> |
|||
</el-menu> |
|||
|
|||
<div class="right-menu"> |
|||
<!-- <template v-if="device !== 'mobile'"> |
|||
<search id="header-search" class="right-menu-item" /> |
|||
<el-tooltip content="项目文档" effect="dark" placement="bottom"> |
|||
<Doc class="right-menu-item hover-effect" /> |
|||
</el-tooltip> |
|||
<el-tooltip content="全屏缩放" effect="dark" placement="bottom"> |
|||
<screenfull id="screenfull" class="right-menu-item hover-effect" /> |
|||
</el-tooltip> |
|||
<el-tooltip content="布局设置" effect="dark" placement="bottom"> |
|||
<size-select id="size-select" class="right-menu-item hover-effect" /> |
|||
</el-tooltip> |
|||
</template> --> |
|||
|
|||
<el-dropdown class="avatar-container right-menu-item hover-effect" trigger="click"> |
|||
<div class="avatar-wrapper"> |
|||
<img :src="user.avatarName ? baseApi + '/avatar/' + user.avatarName : Avatar" class="user-avatar"> |
|||
<i class="el-icon-caret-bottom" /> |
|||
</div> |
|||
<el-dropdown-menu slot="dropdown"> |
|||
<span style="display:block;" @click="show = true"> |
|||
<el-dropdown-item> |
|||
布局设置 |
|||
</el-dropdown-item> |
|||
</span> |
|||
<router-link to="/user/center"> |
|||
<el-dropdown-item> |
|||
个人中心 |
|||
</el-dropdown-item> |
|||
</router-link> |
|||
<span style="display:block;" @click="open"> |
|||
<el-dropdown-item divided> |
|||
退出登录 |
|||
</el-dropdown-item> |
|||
</span> |
|||
</el-dropdown-menu> |
|||
</el-dropdown> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import { mapGetters } from 'vuex' |
|||
import AppLink from './Sidebar/Link' |
|||
import variables from '@/assets/styles/variables.scss' |
|||
import { isExternal } from '@/utils/validate' |
|||
import Avatar from '@/assets/images/avatar.png' |
|||
|
|||
export default { |
|||
name: 'Topbar', |
|||
components: { |
|||
AppLink |
|||
}, |
|||
data() { |
|||
return { |
|||
Avatar: Avatar, |
|||
dialogVisible: false, |
|||
routes: this.$store.getters.navMenus |
|||
} |
|||
}, |
|||
computed: { |
|||
...mapGetters(['device', 'user', 'baseApi']), |
|||
activeMenu() { |
|||
const route = this.$route |
|||
const { meta, path } = route |
|||
console.log(this.routes) |
|||
// if set path, the sidebar will highlight the path you set |
|||
if (meta.activeMenu) { |
|||
return meta.activeMenu |
|||
} |
|||
// 如果是首页,首页高亮 |
|||
if (path === '/dashboard') { |
|||
return '/' |
|||
} |
|||
// 如果不是首页,高亮一级菜单 |
|||
const activeMenu = '/' + path.split('/')[1] |
|||
return activeMenu |
|||
}, |
|||
variables() { |
|||
return variables |
|||
}, |
|||
sidebar() { |
|||
return this.$store.state.app.sidebar |
|||
}, |
|||
show: { |
|||
get() { |
|||
return this.$store.state.settings.showSettings |
|||
}, |
|||
set(val) { |
|||
this.$store.dispatch('settings/changeSetting', { |
|||
key: 'showSettings', |
|||
value: val |
|||
}) |
|||
} |
|||
} |
|||
|
|||
}, |
|||
methods: { |
|||
// 通过当前路径找到二级菜单对应项,存到store,用来渲染左侧菜单 |
|||
initCurrentRoutes() { |
|||
const { path } = this.$route |
|||
console.log(this.routes) |
|||
let route = this.routes.find( |
|||
item => item.path === '/' + path.split('/')[1] |
|||
) |
|||
// 如果找不到这个路由,说明是首页 |
|||
if (!route) { |
|||
route = this.routes.find(item => item.path === '/') |
|||
} |
|||
this.$store.commit('permission/SET_CURRENT_ROUTES', route) |
|||
this.setSidebarHide(route) |
|||
}, |
|||
// 判断该路由是否只有一个子项或者没有子项,如果是,则在一级菜单添加跳转路由 |
|||
isOnlyOneChild(item) { |
|||
if (item.children && item.children.length === 1) { |
|||
return true |
|||
} |
|||
return false |
|||
}, |
|||
resolvePath(item) { |
|||
// 如果是个完成的url直接返回 |
|||
if (isExternal(item.path)) { |
|||
return item.path |
|||
} |
|||
// 如果是首页,就返回重定向路由 |
|||
if (item.path === '/') { |
|||
const path = item.redirect |
|||
return path |
|||
} |
|||
|
|||
// 如果有子项,默认跳转第一个子项路由 |
|||
let path = '' |
|||
/** |
|||
* item 路由子项 |
|||
* parent 路由父项 |
|||
*/ |
|||
const getDefaultPath = (item, parent) => { |
|||
// 如果path是个外部链接(不建议),直接返回链接,存在个问题:如果是外部链接点击跳转后当前页内容还是上一个路由内容 |
|||
if (isExternal(item.path)) { |
|||
path = item.path |
|||
return |
|||
} |
|||
// 第一次需要父项路由拼接,所以只是第一个传parent |
|||
if (parent) { |
|||
path += (parent.path + '/' + item.path) |
|||
} else { |
|||
path += ('/' + item.path) |
|||
} |
|||
// 如果还有子项,继续递归 |
|||
if (item.children) { |
|||
getDefaultPath(item.children[0]) |
|||
} |
|||
} |
|||
|
|||
if (item.children) { |
|||
getDefaultPath(item.children[0], item) |
|||
return path |
|||
} |
|||
|
|||
return item.path |
|||
}, |
|||
handleSelect(key, keyPath) { |
|||
// 把选中路由的子路由保存store |
|||
const route = this.routes.find(item => item.path === key) |
|||
this.$store.commit('permission/SET_CURRENT_ROUTES', route) |
|||
this.setSidebarHide(route) |
|||
}, |
|||
// 设置侧边栏的显示和隐藏 |
|||
setSidebarHide(route) { |
|||
if (!route.children || route.children.length === 1) { |
|||
this.$store.dispatch('app/toggleSideBarHide', true) |
|||
} else { |
|||
this.$store.dispatch('app/toggleSideBarHide', false) |
|||
} |
|||
}, |
|||
toggleSideBar() { |
|||
this.$store.dispatch('app/toggleSideBar') |
|||
}, |
|||
open() { |
|||
this.$confirm('确定注销并退出系统吗?', '提示', { |
|||
confirmButtonText: '确定', |
|||
cancelButtonText: '取消', |
|||
type: 'warning' |
|||
}).then(() => { |
|||
this.logout() |
|||
}) |
|||
}, |
|||
logout() { |
|||
this.$store.dispatch('LogOut').then(() => { |
|||
location.reload() |
|||
}) |
|||
} |
|||
} |
|||
} |
|||
</script> |
@ -1,2 +1,4 @@ |
|||
export { default as AppMain } from './AppMain' |
|||
export { default as TopMenus } from './TopMenus' |
|||
export { default as Navbar } from './Navbar' |
|||
export { default as Sidebar } from './Sidebar' |
|||
export { default as Topbar } from './Topbar' |
Write
Preview
Loading…
Cancel
Save
Reference in new issue