187 lines
4.7 KiB
Vue
187 lines
4.7 KiB
Vue
<template>
|
||
<div :class="classObj" class="app-wrapper" :style="{'--current-color': theme}">
|
||
<div v-if="device==='mobile'&&sidebar.opened" class="drawer-bg" @click="handleClickOutside"/>
|
||
<sidebar v-if="!sidebar.hide && device !== 'mobile'" class="sidebar-container"/>
|
||
<div :class="{hasTagsView:needTagsView,sidebarHide:sidebar.hide, 'mobile-layout': device === 'mobile'}" class="main-container">
|
||
<div :class="{'fixed-header':fixedHeader}">
|
||
<navbar @setLayout="setLayout"/>
|
||
<tags-view v-if="needTagsView && device !== 'mobile'"/>
|
||
</div>
|
||
<app-main/>
|
||
<settings ref="settingRef"/>
|
||
</div>
|
||
<!-- 移动端底部导航:key 随接口路由更新,确保菜单与跳转使用最新路由 -->
|
||
<mobile-bottom-nav
|
||
v-if="device === 'mobile'"
|
||
:key="mobileNavKey"
|
||
:items="mobileNavItems"
|
||
/>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
import { AppMain, Navbar, Settings, Sidebar, TagsView } from './components'
|
||
import MobileBottomNav from '@/components/MobileBottomNav'
|
||
import ResizeMixin from './mixin/ResizeHandler'
|
||
import { mapState, mapGetters } from 'vuex'
|
||
import variables from '@/assets/styles/variables.scss'
|
||
|
||
export default {
|
||
name: 'Layout',
|
||
components: {
|
||
AppMain,
|
||
Navbar,
|
||
Settings,
|
||
Sidebar,
|
||
TagsView,
|
||
MobileBottomNav
|
||
},
|
||
mixins: [ResizeMixin],
|
||
computed: {
|
||
...mapState({
|
||
theme: state => state.settings.theme,
|
||
sideTheme: state => state.settings.sideTheme,
|
||
sidebar: state => state.app.sidebar,
|
||
device: state => state.app.device,
|
||
needTagsView: state => state.settings.tagsView,
|
||
fixedHeader: state => state.settings.fixedHeader
|
||
}),
|
||
...mapGetters(['sidebarRouters']),
|
||
/** 接口路由更新后变化,使底部导航重新渲染并拉取最新菜单,避免点击跳错页 */
|
||
mobileNavKey() {
|
||
const routes = this.sidebarRouters || []
|
||
const len = routes.length
|
||
const firstPath = (len && routes[0]) ? (routes[0].path || '') : ''
|
||
return `${len}-${firstPath}`
|
||
},
|
||
mobileNavItems() {
|
||
return [
|
||
{ path: '/sloworder/index', label: '慢单', icon: 'el-icon-tickets' },
|
||
{ path: '/jd-instruction/index', label: '中控', icon: 'el-icon-s-operation' },
|
||
{ path: '/mobile/fadan', label: '发单', icon: 'el-icon-edit-outline' },
|
||
{ path: '/mobile/xianyu-publish', label: '发品', icon: 'el-icon-goods' },
|
||
{ path: '/mobile/zhongcao', label: '种草', icon: 'el-icon-chat-dot-round' }
|
||
]
|
||
},
|
||
classObj() {
|
||
return {
|
||
hideSidebar: false, // 侧边栏始终展开
|
||
openSidebar: true, // 侧边栏始终展开
|
||
withoutAnimation: this.sidebar.withoutAnimation,
|
||
mobile: this.device === 'mobile'
|
||
}
|
||
},
|
||
variables() {
|
||
return variables
|
||
}
|
||
},
|
||
methods: {
|
||
handleClickOutside() {
|
||
this.$store.dispatch('app/closeSideBar', { withoutAnimation: false })
|
||
},
|
||
setLayout() {
|
||
this.$refs.settingRef.openSetting()
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
@import "~@/assets/styles/mixin.scss";
|
||
@import "~@/assets/styles/variables.scss";
|
||
|
||
.app-wrapper {
|
||
@include clearfix;
|
||
position: relative;
|
||
height: 100%;
|
||
width: 100%;
|
||
|
||
&.mobile.openSidebar {
|
||
position: fixed;
|
||
top: 0;
|
||
}
|
||
|
||
@media (max-width: 768px) {
|
||
&.mobile {
|
||
height: auto;
|
||
min-height: 100vh;
|
||
position: relative;
|
||
|
||
&.openSidebar {
|
||
position: relative;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.drawer-bg {
|
||
background: #000;
|
||
opacity: 0.3;
|
||
width: 100%;
|
||
top: 0;
|
||
height: 100%;
|
||
position: absolute;
|
||
z-index: 999;
|
||
}
|
||
|
||
.fixed-header {
|
||
position: fixed;
|
||
top: 0;
|
||
right: 0;
|
||
z-index: 9;
|
||
width: calc(100% - #{$base-sidebar-width});
|
||
transition: width 0.28s;
|
||
}
|
||
|
||
.hideSidebar .fixed-header {
|
||
width: calc(100% - 54px);
|
||
}
|
||
|
||
.sidebarHide .fixed-header {
|
||
width: 100%;
|
||
}
|
||
|
||
.mobile .fixed-header {
|
||
width: 100%;
|
||
}
|
||
|
||
// 移动端优化
|
||
@media (max-width: 768px) {
|
||
.app-wrapper {
|
||
&.mobile {
|
||
.sidebar-container {
|
||
display: none; // 移动端完全隐藏侧边栏,使用底部导航
|
||
}
|
||
}
|
||
|
||
.drawer-bg {
|
||
display: none; // 移动端不需要遮罩
|
||
}
|
||
|
||
.main-container {
|
||
margin-left: 0 !important;
|
||
width: 100%;
|
||
height: auto !important;
|
||
min-height: 100vh;
|
||
overflow: visible;
|
||
|
||
&.mobile-layout {
|
||
padding-bottom: 60px; // 为底部导航预留空间
|
||
}
|
||
}
|
||
|
||
.fixed-header {
|
||
width: 100% !important;
|
||
left: 0;
|
||
}
|
||
|
||
// 移动端隐藏标签页
|
||
.hasTagsView {
|
||
.fixed-header + .app-main {
|
||
padding-top: 48px !important;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
</style>
|