335 lines
8.4 KiB
Vue
335 lines
8.4 KiB
Vue
<template>
|
|
<a-layout class="vab-layout-wrap">
|
|
<div
|
|
v-if="device === 'mobile' && !collapse"
|
|
class="vab-mask"
|
|
@click="handleFoldSideBar"
|
|
></div>
|
|
<a-layout-sider
|
|
collapsible
|
|
class="vab-sider"
|
|
width="250"
|
|
v-model:collapsed="collapse"
|
|
:class="classObj"
|
|
:trigger="null"
|
|
>
|
|
<vab-logo />
|
|
<a-menu
|
|
class="vab-menu"
|
|
mode="inline"
|
|
v-model:selectedKeys="selectedKeys"
|
|
v-model:openKeys="openKeys"
|
|
>
|
|
<vab-menu v-for="route in routes" :key="route.path" :item="route" />
|
|
</a-menu>
|
|
</a-layout-sider>
|
|
<a-layout
|
|
class="vab-layout"
|
|
:class="'mobile' === device ? 'vab-mobile-layout' : ''"
|
|
>
|
|
<a-layout-header class="vab-header">
|
|
<a-row>
|
|
<!-- 展开收起图标 -->
|
|
<a-col :xs="1" :sm="1" :md="1" :lg="1" :xl="1">
|
|
<menu-unfold-outlined
|
|
v-if="collapse"
|
|
class="trigger"
|
|
@click="toggleCollapse"
|
|
/>
|
|
<menu-fold-outlined
|
|
v-else
|
|
class="trigger"
|
|
@click="toggleCollapse"
|
|
/>
|
|
</a-col>
|
|
<!-- 刷新图标 -->
|
|
<a-col :xs="1" :sm="1" :md="1" :lg="1" :xl="1">
|
|
<sync-outlined class="trigger" @click="reload" />
|
|
</a-col>
|
|
<!-- 消息图标 -->
|
|
<a-col :xs="19" :sm="19" :md="19" :lg="19" :xl="19">
|
|
<bell-outlined class="trigger" />
|
|
</a-col>
|
|
<!-- F11 全屏 -->
|
|
<a-col :xs="1" :sm="1" :md="1" :lg="1" :xl="1">
|
|
<arrows-alt-outlined
|
|
class="trigger"
|
|
v-if="flag"
|
|
@click="fullScreen"
|
|
/>
|
|
<shrink-outlined class="trigger" v-if="!flag" @click="fullScreen" />
|
|
</a-col>
|
|
<!-- 右侧用户图标 -->
|
|
<a-col :xs="2" :sm="2" :md="2" :lg="2" :xl="2">
|
|
<vab-avatar />
|
|
</a-col>
|
|
</a-row>
|
|
</a-layout-header>
|
|
<vab-tabs />
|
|
<vab-content :key="time" />
|
|
</a-layout>
|
|
</a-layout>
|
|
</template>
|
|
<script>
|
|
import VabLogo from './vab-logo'
|
|
import VabAvatar from './vab-avatar'
|
|
import VabMenu from './vab-menu'
|
|
import VabTabs from './vab-tabs'
|
|
import VabContent from './vab-content'
|
|
import { mapActions, mapGetters } from 'vuex'
|
|
import {
|
|
MenuUnfoldOutlined,
|
|
MenuFoldOutlined,
|
|
SyncOutlined,
|
|
BellOutlined,
|
|
ArrowsAltOutlined,
|
|
ShrinkOutlined,
|
|
} from '@ant-design/icons-vue'
|
|
|
|
export default {
|
|
components: {
|
|
VabLogo,
|
|
VabAvatar,
|
|
VabMenu,
|
|
VabTabs,
|
|
VabContent,
|
|
MenuUnfoldOutlined,
|
|
MenuFoldOutlined,
|
|
SyncOutlined,
|
|
BellOutlined,
|
|
ArrowsAltOutlined,
|
|
ShrinkOutlined,
|
|
},
|
|
inject: ['reload'],
|
|
data() {
|
|
return {
|
|
selectedKeys: [],
|
|
openKeys: [],
|
|
flag: true,
|
|
time: new Date(),
|
|
}
|
|
},
|
|
computed: {
|
|
...mapGetters({
|
|
collapse: 'settings/collapse',
|
|
routes: 'routes/routes',
|
|
device: 'settings/device',
|
|
}),
|
|
classObj() {
|
|
return {
|
|
'vab-mobile': this.device === 'mobile',
|
|
'vab-collapse': this.collapse,
|
|
}
|
|
},
|
|
},
|
|
watch: {
|
|
$route: {
|
|
handler({ path, matched }) {
|
|
matched[0].children.length > 1
|
|
? (this.selectedKeys = [path])
|
|
: (this.selectedKeys = [matched[0].path])
|
|
this.openKeys = [matched[0].path]
|
|
},
|
|
immediate: true,
|
|
},
|
|
},
|
|
beforeMount() {
|
|
window.addEventListener('resize', this.handleLayouts)
|
|
},
|
|
beforeUnmount() {
|
|
window.removeEventListener('resize', this.handleLayouts)
|
|
},
|
|
mounted() {
|
|
this.handleLayouts()
|
|
},
|
|
methods: {
|
|
...mapActions({
|
|
toggleDevice: 'settings/toggleDevice',
|
|
handleFoldSideBar: 'settings/foldSideBar',
|
|
toggleCollapse: 'settings/toggleCollapse',
|
|
}),
|
|
handleLayouts() {
|
|
const width = document.body.getBoundingClientRect().width
|
|
if (this.width !== width) {
|
|
const isMobile = width - 1 < 992
|
|
this.toggleDevice(isMobile ? 'mobile' : 'desktop')
|
|
this.width = width
|
|
}
|
|
},
|
|
fullScreen() {
|
|
if (this.flag) {
|
|
this.flag = !this.flag
|
|
var element = document.documentElement
|
|
if (element.requestFullscreen) {
|
|
element.requestFullscreen()
|
|
} else if (element.msRequestFullscreen) {
|
|
element.msRequestFullscreen()
|
|
} else if (element.mozRequestFullScreen) {
|
|
element.mozRequestFullScreen()
|
|
} else if (element.webkitRequestFullscreen) {
|
|
element.webkitRequestFullscreen()
|
|
}
|
|
} else {
|
|
this.flag = !this.flag
|
|
if (document.exitFullscreen) {
|
|
document.exitFullscreen()
|
|
} else if (document.msExitFullscreen) {
|
|
document.msExitFullscreen()
|
|
} else if (document.mozCancelFullScreen) {
|
|
document.mozCancelFullScreen()
|
|
} else if (document.webkitExitFullscreen) {
|
|
document.webkitExitFullscreen()
|
|
}
|
|
}
|
|
},
|
|
reload() {
|
|
this.time = new Date()
|
|
},
|
|
},
|
|
}
|
|
</script>
|
|
<style lang="less">
|
|
.vab-layout-wrap {
|
|
.vab-sider {
|
|
position: fixed;
|
|
left: 0;
|
|
height: 100vh;
|
|
overflow: auto;
|
|
background-color: #2a3764;
|
|
.vab-menu {
|
|
height: calc(100vh - @vab-header-height);
|
|
background-color: #2a3764;
|
|
font-size: 20px;
|
|
color: #fff;
|
|
.ant-menu-item {
|
|
.ant-menu-title-content {
|
|
.anticon {
|
|
i {
|
|
font-size: 22px;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
.ant-menu-item-selected {
|
|
background-color: rgba(17, 130, 251, 0.2);
|
|
color: #fff;
|
|
&::after {
|
|
border-right: 6px solid #1890ff;
|
|
}
|
|
}
|
|
.ant-menu-submenu {
|
|
.ant-menu-submenu-title {
|
|
.ant-menu-title-content {
|
|
.anticon {
|
|
i {
|
|
font-size: 22px;
|
|
}
|
|
}
|
|
}
|
|
.ant-menu-submenu-arrow {
|
|
color: #fff;
|
|
}
|
|
}
|
|
.ant-menu-sub {
|
|
background-color: #212d57;
|
|
// height: 48px;
|
|
color: #fff;
|
|
.ant-menu-item-selected {
|
|
background-color: rgba(17, 130, 251, 0.2);
|
|
color: #fff;
|
|
&::after {
|
|
border-right: 6px solid #1890ff;
|
|
}
|
|
}
|
|
.ant-menu-item {
|
|
height: 48px;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
.vab-layout {
|
|
padding-left: 250px;
|
|
transition: all 0.2s;
|
|
}
|
|
.vab-mobile-layout {
|
|
padding-left: 0;
|
|
transition: all 0.2s;
|
|
}
|
|
.vab-collapse {
|
|
.vab-logo .anticon + span {
|
|
display: inline-block;
|
|
max-width: 0;
|
|
opacity: 0;
|
|
transition: all 0.2s;
|
|
}
|
|
& + .vab-layout {
|
|
padding-left: 81px;
|
|
transition: all 0.2s;
|
|
}
|
|
}
|
|
.vab-mask {
|
|
position: fixed;
|
|
top: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
left: 0;
|
|
z-index: 998;
|
|
width: 100%;
|
|
height: 100vh;
|
|
overflow: hidden;
|
|
background: #000;
|
|
opacity: 0.5;
|
|
}
|
|
.vab-mobile {
|
|
position: fixed !important;
|
|
z-index: 999;
|
|
&.vab-collapse {
|
|
width: 0 !important;
|
|
min-width: 0 !important;
|
|
max-width: 0 !important;
|
|
* {
|
|
display: none !important;
|
|
width: 0 !important;
|
|
min-width: 0 !important;
|
|
max-width: 0 !important;
|
|
}
|
|
.ant-menu-item,
|
|
.ant-menu-submenu {
|
|
display: none !important;
|
|
width: 0 !important;
|
|
min-width: 0 !important;
|
|
max-width: 0 !important;
|
|
}
|
|
& + .vab-layout {
|
|
padding-left: 0px !important;
|
|
transition: all 0.2s;
|
|
}
|
|
}
|
|
}
|
|
.vab-header {
|
|
padding: 0;
|
|
background: #fff;
|
|
.ant-col + .ant-col {
|
|
display: flex;
|
|
justify-content: flex-end;
|
|
padding: 0 @vab-padding;
|
|
}
|
|
.trigger {
|
|
height: @vab-header-height;
|
|
padding: 0 @vab-padding;
|
|
font-size: 18px;
|
|
line-height: @vab-header-height;
|
|
cursor: pointer;
|
|
transition: color 0.3s;
|
|
&:hover {
|
|
color: #1890ff;
|
|
}
|
|
}
|
|
.sync {
|
|
padding: 0 30px;
|
|
}
|
|
}
|
|
}
|
|
</style>
|