项目初始
This commit is contained in:
48
src/layout/components/AppMain.vue
Normal file
48
src/layout/components/AppMain.vue
Normal file
@@ -0,0 +1,48 @@
|
||||
<template>
|
||||
<section class="app-main" style="height: calc(100vh - 140px);">
|
||||
<transition name="fade-transform" mode="out-in">
|
||||
<keep-alive :include="cachedViews">
|
||||
<router-view :key="key" />
|
||||
</keep-alive>
|
||||
</transition>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'AppMain',
|
||||
computed: {
|
||||
cachedViews() {
|
||||
return this.$store.state.tagsView.cachedViews
|
||||
},
|
||||
key() {
|
||||
return this.$route.path
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.app-main {
|
||||
/*50 = navbar */
|
||||
height: calc(100vh - 140px);
|
||||
position: relative;
|
||||
background-color: #FFFFFF;
|
||||
/* margin-left:10px; */
|
||||
/*padding: 0 20px;*/
|
||||
overflow-x: hidden;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
.fixed-header+.app-main {
|
||||
padding-top: 50px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- <style lang="scss">
|
||||
// fix css style bug in open el-dialog
|
||||
.el-popup-parent--hidden {
|
||||
.fixed-header {
|
||||
padding-right: 15px;
|
||||
}
|
||||
}
|
||||
</style> -->
|
||||
168
src/layout/components/Navbar.vue
Normal file
168
src/layout/components/Navbar.vue
Normal file
@@ -0,0 +1,168 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="navbar">
|
||||
<p class="breadcrumb-container"><img src="@/assets/loginImg/logo.png" style="width: 45px;height: 45px;margin-right: 10px;"/>山海光伏监管平台</p>
|
||||
<!-- <h3 class="breadcrumb-container">汇融银行供应链贷后监管平台</h3> -->
|
||||
<div class="right-menu">
|
||||
<!-- <p>{{Orgname}} {{departmentName}} 欢迎, {{name}}</p>-->
|
||||
<p>欢迎您,{{name}}</p>
|
||||
<p class="dy" @click="logout()"><img src="@/assets/images/dy.png"></p>
|
||||
</div>
|
||||
</div>
|
||||
<el-footer class="footer" height="40px">Copyright © {{ year }} 山海光伏监管平台 All Rights Reserved</el-footer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
name: '',
|
||||
year:'',
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.name = window.sessionStorage.getItem('userName')
|
||||
var nowDate = new Date()
|
||||
this.year = nowDate.getFullYear()
|
||||
},
|
||||
methods: {
|
||||
logout() {
|
||||
this.$confirm('确定要退出吗, 是否继续?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
// this.$store.commit('user/SET_UESRINFO', '')
|
||||
this.$router.push({
|
||||
path: '/login'
|
||||
})
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "~@/styles/variables.scss";
|
||||
|
||||
.navbar {
|
||||
height: 60px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
background: $header-bg;
|
||||
padding: 0 30px;
|
||||
box-shadow: 0 1px 4px rgba(0, 21, 41, .08);
|
||||
|
||||
.hamburger-container {
|
||||
line-height: 46px;
|
||||
height: 100%;
|
||||
float: left;
|
||||
cursor: pointer;
|
||||
transition: background .3s;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
|
||||
&:hover {
|
||||
background: rgba(0, 0, 0, .025)
|
||||
}
|
||||
}
|
||||
|
||||
.breadcrumb-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: #fff;
|
||||
font-size: 26px;
|
||||
line-height: 60px;
|
||||
margin: 0;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.right-menu {
|
||||
float: right;
|
||||
height: 100%;
|
||||
line-height: 60px;
|
||||
color: #fff;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
p {
|
||||
display: inline-block;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
padding: 0 15px;
|
||||
}
|
||||
|
||||
img {
|
||||
vertical-align: middle;
|
||||
margin: 0 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.backToHome {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
padding: 0 15px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.backToHome:hover {
|
||||
background: #087dba;
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.footer {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
line-height: 40px;
|
||||
background: #E9F1F7;
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
}
|
||||
</style>
|
||||
26
src/layout/components/Sidebar/FixiOSBug.js
Normal file
26
src/layout/components/Sidebar/FixiOSBug.js
Normal file
@@ -0,0 +1,26 @@
|
||||
export default {
|
||||
computed: {
|
||||
device() {
|
||||
return this.$store.state.app.device
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// In order to fix the click on menu on the ios device will trigger the mouseleave bug
|
||||
// https://github.com/PanJiaChen/vue-element-admin/issues/1135
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
41
src/layout/components/Sidebar/Item.vue
Normal file
41
src/layout/components/Sidebar/Item.vue
Normal file
@@ -0,0 +1,41 @@
|
||||
<script>
|
||||
export default {
|
||||
name: 'MenuItem',
|
||||
functional: true,
|
||||
props: {
|
||||
icon: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
render(h, context) {
|
||||
const { icon, title } = context.props
|
||||
const vnodes = []
|
||||
|
||||
if (icon) {
|
||||
if (icon.includes('el-icon')) {
|
||||
vnodes.push(<i class={[icon, 'sub-el-icon']} />)
|
||||
} else {
|
||||
vnodes.push(<svg-icon icon-class={icon}/>)
|
||||
}
|
||||
}
|
||||
|
||||
if (title) {
|
||||
vnodes.push(<span slot='title'>{(title)}</span>)
|
||||
}
|
||||
return vnodes
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.sub-el-icon {
|
||||
color: currentColor;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
}
|
||||
</style>
|
||||
43
src/layout/components/Sidebar/Link.vue
Normal file
43
src/layout/components/Sidebar/Link.vue
Normal file
@@ -0,0 +1,43 @@
|
||||
<template>
|
||||
<component :is="type" v-bind="linkProps(to)">
|
||||
<slot />
|
||||
</component>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { isExternal } from '@/utils/validate'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
to: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isExternal() {
|
||||
return isExternal(this.to)
|
||||
},
|
||||
type() {
|
||||
if (this.isExternal) {
|
||||
return 'a'
|
||||
}
|
||||
return 'router-link'
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
linkProps(to) {
|
||||
if (this.isExternal) {
|
||||
return {
|
||||
href: to,
|
||||
target: '_blank',
|
||||
rel: 'noopener'
|
||||
}
|
||||
}
|
||||
return {
|
||||
to: to
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
82
src/layout/components/Sidebar/Logo.vue
Normal file
82
src/layout/components/Sidebar/Logo.vue
Normal file
@@ -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>
|
||||
export default {
|
||||
name: 'SidebarLogo',
|
||||
props: {
|
||||
collapse: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
title: 'Vue Admin Template',
|
||||
logo: 'https://wpimg.wallstcn.com/69a1c46c-eb1c-4b46-8bd4-e9e686ef5251.png'
|
||||
}
|
||||
}
|
||||
}
|
||||
</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;
|
||||
background: #2b2f3a;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
|
||||
& .sidebar-logo-link {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
|
||||
& .sidebar-logo {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
vertical-align: middle;
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
& .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>
|
||||
117
src/layout/components/Sidebar/SidebarItem.vue
Normal file
117
src/layout/components/Sidebar/SidebarItem.vue
Normal file
@@ -0,0 +1,117 @@
|
||||
<template>
|
||||
<div v-if="!item.hidden">
|
||||
<template v-if="hasOneShowingChild(item.children,item)">
|
||||
<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'
|
||||
import Item from './Item'
|
||||
import AppLink from './Link'
|
||||
import FixiOSBug from './FixiOSBug'
|
||||
|
||||
export default {
|
||||
name: 'SidebarItem',
|
||||
components: { Item, AppLink },
|
||||
mixins: [FixiOSBug],
|
||||
props: {
|
||||
// route object
|
||||
item: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
isNest: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
basePath: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
data() {
|
||||
// To fix https://github.com/PanJiaChen/vue-admin-template/issues/237
|
||||
// TODO: refactor with render function
|
||||
this.onlyOneChild = null
|
||||
return {
|
||||
// onlyOneChild:null
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
hasOneShowingChild(children = [], parent) {
|
||||
// debugger
|
||||
// var tempItem=null
|
||||
const showingChildren = children.filter(item => {
|
||||
if (item.hidden) {
|
||||
return false
|
||||
} else {
|
||||
// Temp set(will be used if only has one showing child)
|
||||
this.onlyOneChild = item
|
||||
return true
|
||||
}
|
||||
})
|
||||
|
||||
// When there is only one child
|
||||
// if (showingChildren.length === 1) {
|
||||
// this.onlyOneChild=item()
|
||||
// return true
|
||||
// }
|
||||
|
||||
// Show parent if there are no child router to display
|
||||
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>
|
||||
<style scoped>
|
||||
/deep/ .el-submenu__title {
|
||||
height: 40px !important;
|
||||
line-height: 40px !important;
|
||||
font-size: 15px!important;
|
||||
}
|
||||
|
||||
/deep/ .el-submenu .el-menu-item {
|
||||
height: 40px !important;
|
||||
line-height: 40px !important;
|
||||
}
|
||||
|
||||
/deep/ .el-menu-item {
|
||||
height: 40px !important;
|
||||
line-height: 40px !important;
|
||||
font-size: 15px!important;
|
||||
}
|
||||
</style>
|
||||
282
src/layout/components/Sidebar/index.vue
Normal file
282
src/layout/components/Sidebar/index.vue
Normal file
@@ -0,0 +1,282 @@
|
||||
<template>
|
||||
<div :class="{ 'has-logo': showLogo }">
|
||||
<logo v-if="showLogo" :collapse="isCollapse" />
|
||||
<el-scrollbar wrap-class="scrollbar-wrapper">
|
||||
<el-menu
|
||||
:default-active="$route.path"
|
||||
:background-color="variables.menuBg"
|
||||
:text-color="variables.menuText"
|
||||
:unique-opened="false"
|
||||
: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 "@/styles/variables.scss";
|
||||
import { getrolemenus, loginDetails } from "@/api/system/Role/role.js";
|
||||
import { getStorage } from "@/utils/auth";
|
||||
export default {
|
||||
components: {
|
||||
SidebarItem,
|
||||
Logo,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
YongHuid: [],
|
||||
// routes: [],
|
||||
params: {
|
||||
sourceSid: "9d048c07-7677-4774-9177-aa02b049ff06",
|
||||
userSid: "",
|
||||
},
|
||||
routes: [
|
||||
{
|
||||
alwaysShow: true,
|
||||
component: "supervise",
|
||||
meta: {
|
||||
icon: "el-icon-menu",
|
||||
title: "进销存管理",
|
||||
},
|
||||
name: "supervise",
|
||||
path: "/supervise",
|
||||
children: [
|
||||
{
|
||||
alwaysShow: true,
|
||||
component: "recordOilTank",
|
||||
meta: {
|
||||
icon: "el-icon-help",
|
||||
title: "出库申请",
|
||||
},
|
||||
name: "oilTypeInBound",
|
||||
path: "/oilTypeInBound",
|
||||
children: [
|
||||
{
|
||||
alwaysShow: true,
|
||||
component: "oilTypeInBound",
|
||||
meta: {
|
||||
icon: "el-icon-help",
|
||||
title: "出库申请",
|
||||
},
|
||||
name: "/supervise/oilTypeInBound",
|
||||
path: "/supervise/oilTypeInBound",
|
||||
},
|
||||
{
|
||||
alwaysShow: true,
|
||||
component: "oilTypeOutBound",
|
||||
meta: {
|
||||
icon: "el-icon-help",
|
||||
title: "出库记录列表",
|
||||
},
|
||||
name: "/supervise/oilTypeOutBound",
|
||||
path: "/supervise/oilTypeOutBound",
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
alwaysShow: true,
|
||||
component: "index",
|
||||
meta: {
|
||||
icon: "el-icon-help",
|
||||
title: "入库申请",
|
||||
},
|
||||
name: "recordOilTank",
|
||||
path: "/recordOilTank",
|
||||
children: [
|
||||
{
|
||||
alwaysShow: true,
|
||||
component: "recordOilTank",
|
||||
meta: {
|
||||
icon: "el-icon-help",
|
||||
title: "入库申请",
|
||||
},
|
||||
name: "/supervise/recordOilTank",
|
||||
path: "/supervise/recordOilTank",
|
||||
},
|
||||
{
|
||||
alwaysShow: true,
|
||||
component: "rukujilu",
|
||||
meta: {
|
||||
icon: "el-icon-help",
|
||||
title: "入库记录列表",
|
||||
},
|
||||
name: "/supervise/rukujilu",
|
||||
path: "/supervise/rukujilu",
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
alwaysShow: true,
|
||||
component: "churuku",
|
||||
meta: {
|
||||
icon: "el-icon-help",
|
||||
title: "出入库记录",
|
||||
},
|
||||
name: "/supervise/churuku",
|
||||
path: "/supervise/churuku",
|
||||
},
|
||||
{
|
||||
alwaysShow: true,
|
||||
component: "inventory",
|
||||
meta: {
|
||||
icon: "el-icon-help",
|
||||
title: "库存管理",
|
||||
},
|
||||
name: "/supervise/inventory",
|
||||
path: "/supervise/inventory",
|
||||
},
|
||||
{
|
||||
alwaysShow: true,
|
||||
component: "churukuHT",
|
||||
meta: {
|
||||
icon: "el-icon-help",
|
||||
title: "出入库合同管理",
|
||||
},
|
||||
name: "/supervise/churukuHT",
|
||||
path: "/supervise/churukuHT",
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
alwaysShow: true,
|
||||
component: "MaterialBrand",
|
||||
meta: {
|
||||
icon: "el-icon-menu",
|
||||
title: "物料品牌",
|
||||
},
|
||||
name: "/MaterialBrand/index",
|
||||
path: "/MaterialBrand/index"
|
||||
},
|
||||
{
|
||||
alwaysShow: true,
|
||||
component: "materialManagement",
|
||||
meta: {
|
||||
icon: "el-icon-menu",
|
||||
title: "物料管理",
|
||||
},
|
||||
name: "/materialManagement/index",
|
||||
path: "/materialManagement/index"
|
||||
},
|
||||
{
|
||||
alwaysShow: true,
|
||||
component: "storeManagement",
|
||||
meta: {
|
||||
icon: "el-icon-menu",
|
||||
title: "仓库管理",
|
||||
},
|
||||
name: "/storeManagement/index",
|
||||
path: "/storeManagement/index"
|
||||
},
|
||||
{
|
||||
alwaysShow: true,
|
||||
component: "supplierManagement",
|
||||
meta: {
|
||||
icon: "el-icon-menu",
|
||||
title: "供应商管理",
|
||||
},
|
||||
name: "/supplierManagement/index",
|
||||
path: "/supplierManagement/index"
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(["sidebar"]),
|
||||
// routes() {
|
||||
// f4d2e507-c4ed-451c-b364-04c08f962045
|
||||
// console.log('78979789', this.$router.options.routes)
|
||||
// return this.$router.options.routes
|
||||
// },
|
||||
activeMenu() {
|
||||
// const route = this.$route
|
||||
// const {
|
||||
// meta,
|
||||
// path
|
||||
// } = route
|
||||
// // if set path, the sidebar will highlight the path you set
|
||||
// if (meta.activeMenu) {
|
||||
// return meta.activeMenu
|
||||
// }
|
||||
return "/index";
|
||||
},
|
||||
showLogo() {
|
||||
return this.$store.state.settings.sidebarLogo;
|
||||
},
|
||||
variables() {
|
||||
return variables;
|
||||
},
|
||||
isCollapse() {
|
||||
return !this.sidebar.opened;
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.postHuoquyonghu();
|
||||
},
|
||||
methods: {
|
||||
// 获取用户信息
|
||||
postHuoquyonghu() {
|
||||
// var token = getStorage()
|
||||
// loginDetails(token).then((response) => {
|
||||
// console.log('resss', response)
|
||||
// if (response.code === '200') {
|
||||
// this.YongHuid = response.data
|
||||
// this.params.userSid = this.YongHuid.sid
|
||||
// getrolemenus(this.params).then((res) => {
|
||||
// const userRoles = this.resRouter(res.data)
|
||||
this.routes.push({
|
||||
path: "*",
|
||||
redirect: "/404",
|
||||
hidden: true,
|
||||
});
|
||||
console.log("左侧菜单", this.routes);
|
||||
return this.routes;
|
||||
// })
|
||||
// }
|
||||
// })
|
||||
},
|
||||
resRouter(menus) {
|
||||
// 递归,将后台传来数组
|
||||
for (var i = 0; i < menus.length; i++) {
|
||||
if (menus[i].children && menus[i].children.length != 0) {
|
||||
this.resRouter(menus[i].children);
|
||||
}
|
||||
if (menus[i].children.length == 0) {
|
||||
delete menus[i].children;
|
||||
delete menus[i].redirect;
|
||||
}
|
||||
if (menus[i].component == "") {
|
||||
console.log("55555", menus[i]);
|
||||
menus[i] = {
|
||||
path: menus[i].path,
|
||||
component: "",
|
||||
redirect: menus[i].path,
|
||||
children: [menus[i]],
|
||||
};
|
||||
} else {
|
||||
// menus[i] = {
|
||||
// path: menus[i].path,
|
||||
// component: '',
|
||||
// redirect: menus[i].path,
|
||||
// children: [menus[i]],
|
||||
// }
|
||||
}
|
||||
}
|
||||
this.routes = menus;
|
||||
console.log("左侧菜单", this.routes);
|
||||
return menus;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
87
src/layout/components/TagsView/ScrollPane.vue
Normal file
87
src/layout/components/TagsView/ScrollPane.vue
Normal file
@@ -0,0 +1,87 @@
|
||||
<template>
|
||||
<el-scrollbar ref="scrollContainer" :vertical="false" class="scroll-container" @wheel.native.prevent="handleScroll">
|
||||
<slot />
|
||||
</el-scrollbar>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const tagAndTagSpacing = 4 // tagAndTagSpacing
|
||||
export default {
|
||||
name: 'ScrollPane',
|
||||
data() {
|
||||
return {
|
||||
left: 0
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
scrollWrapper() {
|
||||
return this.$refs.scrollContainer.$refs.wrap
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.scrollWrapper.addEventListener('scroll', this.emitScroll, true)
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.scrollWrapper.removeEventListener('scroll', this.emitScroll)
|
||||
},
|
||||
methods: {
|
||||
handleScroll(e) {
|
||||
const eventDelta = e.wheelDelta || -e.deltaY * 40
|
||||
const $scrollWrapper = this.scrollWrapper
|
||||
$scrollWrapper.scrollLeft = $scrollWrapper.scrollLeft + eventDelta / 4
|
||||
},
|
||||
emitScroll() {
|
||||
this.$emit('scroll')
|
||||
},
|
||||
moveToTarget(currentTag) {
|
||||
const $container = this.$refs.scrollContainer.$el
|
||||
const $containerWidth = $container.offsetWidth
|
||||
const $scrollWrapper = this.scrollWrapper
|
||||
const tagList = this.$parent.$refs.tag
|
||||
let firstTag = null
|
||||
let lastTag = null
|
||||
// find first tag and last tag
|
||||
if (tagList.length > 0) {
|
||||
firstTag = tagList[0]
|
||||
lastTag = tagList[tagList.length - 1]
|
||||
}
|
||||
if (firstTag === currentTag) {
|
||||
$scrollWrapper.scrollLeft = 0
|
||||
} else if (lastTag === currentTag) {
|
||||
$scrollWrapper.scrollLeft = $scrollWrapper.scrollWidth - $containerWidth
|
||||
} else {
|
||||
// find preTag and nextTag
|
||||
const currentIndex = tagList.findIndex(item => item === currentTag)
|
||||
const prevTag = tagList[currentIndex - 1]
|
||||
const nextTag = tagList[currentIndex + 1]
|
||||
// the tag's offsetLeft after of nextTag
|
||||
const afterNextTagOffsetLeft = nextTag.$el.offsetLeft + nextTag.$el.offsetWidth + tagAndTagSpacing
|
||||
// the tag's offsetLeft before of prevTag
|
||||
const beforePrevTagOffsetLeft = prevTag.$el.offsetLeft - tagAndTagSpacing
|
||||
if (afterNextTagOffsetLeft > $scrollWrapper.scrollLeft + $containerWidth) {
|
||||
$scrollWrapper.scrollLeft = afterNextTagOffsetLeft - $containerWidth
|
||||
} else if (beforePrevTagOffsetLeft < $scrollWrapper.scrollLeft) {
|
||||
$scrollWrapper.scrollLeft = beforePrevTagOffsetLeft
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.scroll-container {
|
||||
white-space: nowrap;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
::v-deep {
|
||||
.el-scrollbar__bar {
|
||||
bottom: 0px;
|
||||
}
|
||||
.el-scrollbar__wrap {
|
||||
height: 59px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
333
src/layout/components/TagsView/index.vue
Normal file
333
src/layout/components/TagsView/index.vue
Normal file
@@ -0,0 +1,333 @@
|
||||
<template>
|
||||
<div id="tags-view-container" class="tags-view-container">
|
||||
<scroll-pane ref="scrollPane" class="tags-view-wrapper" @scroll="handleScroll">
|
||||
<router-link
|
||||
v-for="(tag,index) in visitedViews"
|
||||
ref="tag"
|
||||
:key="tag.path"
|
||||
:class="isActive(tag)?'active':''"
|
||||
:to="{ path: tag.path, query: tag.query, fullPath: tag.fullPath }"
|
||||
tag="span"
|
||||
class="tags-view-item"
|
||||
@click.middle.native="!isAffix(tag)?closeSelectedTag(tag):''"
|
||||
@contextmenu.prevent.native="openMenu(tag,$event)"
|
||||
>
|
||||
{{ tag.title }}
|
||||
<span v-if="!isAffix(tag)" class="el-icon-close" @click.prevent.stop="closeSelectedTag(tag)" />
|
||||
</router-link>
|
||||
</scroll-pane>
|
||||
<!--<div class="tags-close-box">
|
||||
<el-dropdown @command="handleTags">
|
||||
<el-button size="mini" type="primary"> 标签选项<i class="el-icon-arrow-down el-icon--right"></i> </el-button>
|
||||
<el-dropdown-menu size="small" slot="dropdown">
|
||||
<el-dropdown-item command="other">关闭其他</el-dropdown-item>
|
||||
<el-dropdown-item command="all">关闭所有</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
</div>-->
|
||||
|
||||
|
||||
<ul v-show="visible" :style="{left:left+'px',top:top+'px'}" class="contextmenu">
|
||||
<li @click="refreshSelectedTag(selectedTag)">刷新</li>
|
||||
<li v-if="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)">关闭</li>
|
||||
<li @click="closeOthersTags">关闭其他</li>
|
||||
<li @click="closeAllTags(selectedTag)">关闭所有</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ScrollPane from './ScrollPane'
|
||||
import path from 'path'
|
||||
export default {
|
||||
components: { ScrollPane },
|
||||
data() {
|
||||
return {
|
||||
visible: false,
|
||||
top: 0,
|
||||
left: 0,
|
||||
selectedTag: {},
|
||||
affixTags: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
visitedViews() {
|
||||
return this.$store.state.tagsView.visitedViews
|
||||
},
|
||||
routes() {
|
||||
return this.$store.state.permission.routes
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
$route() {
|
||||
this.addTags()
|
||||
this.moveToCurrentTag()
|
||||
},
|
||||
visible(value) {
|
||||
if (value) {
|
||||
document.body.addEventListener('click', this.closeMenu)
|
||||
} else {
|
||||
document.body.removeEventListener('click', this.closeMenu)
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.initTags()
|
||||
this.addTags()
|
||||
},
|
||||
methods: {
|
||||
isActive(route) {
|
||||
return route.path === this.$route.path
|
||||
},
|
||||
isAffix(tag) {
|
||||
return tag.meta && tag.meta.affix
|
||||
},
|
||||
filterAffixTags(routes, basePath = '/') {
|
||||
let tags = []
|
||||
routes.forEach(route => {
|
||||
if (route.meta && route.meta.affix) {
|
||||
const tagPath = path.resolve(basePath, route.path)
|
||||
tags.push({
|
||||
fullPath: tagPath,
|
||||
path: tagPath,
|
||||
name: route.name,
|
||||
meta: { ...route.meta }
|
||||
})
|
||||
}
|
||||
if (route.children) {
|
||||
const tempTags = this.filterAffixTags(route.children, route.path)
|
||||
if (tempTags.length >= 1) {
|
||||
tags = [...tags, ...tempTags]
|
||||
}
|
||||
}
|
||||
})
|
||||
return tags
|
||||
},
|
||||
initTags() {
|
||||
const affixTags = this.affixTags = this.filterAffixTags(this.routes)
|
||||
for (const tag of affixTags) {
|
||||
// Must have tag name
|
||||
if (tag.name) {
|
||||
this.$store.dispatch('tagsView/addVisitedView', tag)
|
||||
}
|
||||
}
|
||||
},
|
||||
addTags() {
|
||||
const { name } = this.$route
|
||||
if (name) {
|
||||
this.$store.dispatch('tagsView/addView', this.$route)
|
||||
}
|
||||
return false
|
||||
},
|
||||
moveToCurrentTag() {
|
||||
const tags = this.$refs.tag
|
||||
this.$nextTick(() => {
|
||||
for (const tag of tags) {
|
||||
if (tag.to.path === this.$route.path) {
|
||||
this.$refs.scrollPane.moveToTarget(tag)
|
||||
// when query is different then update
|
||||
if (tag.to.fullPath !== this.$route.fullPath) {
|
||||
this.$store.dispatch('tagsView/updateVisitedView', this.$route)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
refreshSelectedTag(view) {
|
||||
this.$store.dispatch('tagsView/delCachedView', view).then(() => {
|
||||
const { fullPath } = view
|
||||
this.$nextTick(() => {
|
||||
this.$router.replace({
|
||||
path: '/redirect' + fullPath
|
||||
})
|
||||
})
|
||||
})
|
||||
},
|
||||
closeSelectedTag(tag) {
|
||||
this.$store.dispatch('tagsView/delView', tag).then(({ visitedViews }) => {
|
||||
if (this.isActive(tag)) {
|
||||
this.toLastView(visitedViews, tag)
|
||||
}
|
||||
})
|
||||
},
|
||||
closeOthersTags() {
|
||||
this.$router.push(this.selectedTag)
|
||||
this.$store.dispatch('tagsView/delOthersViews', this.selectedTag).then(() => {
|
||||
this.moveToCurrentTag()
|
||||
})
|
||||
},
|
||||
closeAllTags(view) {
|
||||
this.$store.dispatch('tagsView/delAllViews').then(({ visitedViews }) => {
|
||||
if (this.affixTags.some(tag => tag.path === view.path)) {
|
||||
return
|
||||
}
|
||||
this.toLastView(visitedViews, view)
|
||||
})
|
||||
},
|
||||
toLastView(visitedViews, view) {
|
||||
const latestView = visitedViews.slice(-1)[0]
|
||||
if (latestView) {
|
||||
this.$router.push(latestView.fullPath)
|
||||
} else {
|
||||
// now the default is to redirect to the home page if there is no tags-view,
|
||||
// you can adjust it according to your needs.
|
||||
if (view.name === 'Dashboard') {
|
||||
// to reload home page
|
||||
this.$router.replace({ path: '/redirect' + view.fullPath })
|
||||
} else {
|
||||
this.$router.push('/')
|
||||
}
|
||||
}
|
||||
},
|
||||
openMenu(tag, e) {
|
||||
const menuMinWidth = 105
|
||||
const offsetLeft = this.$el.getBoundingClientRect().left // container margin left
|
||||
const offsetWidth = this.$el.offsetWidth // container width
|
||||
const maxLeft = offsetWidth - menuMinWidth // left boundary
|
||||
const left = e.clientX - offsetLeft + 15 // 15: margin right
|
||||
if (left > maxLeft) {
|
||||
this.left = maxLeft
|
||||
} else {
|
||||
this.left = left
|
||||
}
|
||||
this.top = e.clientY - 32
|
||||
this.visible = true
|
||||
this.selectedTag = tag
|
||||
},
|
||||
closeMenu() {
|
||||
this.visible = false
|
||||
},
|
||||
handleScroll() {
|
||||
this.closeMenu()
|
||||
},
|
||||
handleTags(command) {
|
||||
command === 'other' ? this.closeOther() : this.closeAll()
|
||||
},
|
||||
// 关闭全部标签
|
||||
closeAll() {
|
||||
// this.visitedViews = [];
|
||||
this.visitedViews.splice(0, this.visitedViews.length)
|
||||
this.$router.push('/index')
|
||||
},
|
||||
// 关闭其他标签
|
||||
closeOther() {
|
||||
return this.visitedViews.filter((item) => {
|
||||
return item.path === this.$route.fullPath
|
||||
})
|
||||
// this.visitedViews = curItem;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "~@/styles/variables.scss";
|
||||
.tags-view-container {
|
||||
position:relative;
|
||||
height: 40px;
|
||||
width: 100%;
|
||||
// background: $menuHover;
|
||||
background: #FFFFFF;
|
||||
border-bottom: 1px solid #d8dce5;
|
||||
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, .12), 0 0 3px 0 rgba(0, 0, 0, .04);
|
||||
.tags-view-wrapper {
|
||||
height: 40px;
|
||||
.tags-view-item {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
border-radius: 10px 10px 0 0;
|
||||
color: #495060;
|
||||
border: 1px solid #d8dce5;
|
||||
background: #FFFFFF;
|
||||
padding: 0 10px;
|
||||
font-size: 14px;
|
||||
margin-left: 5px;
|
||||
margin-top: 9px;
|
||||
&:first-of-type {
|
||||
margin-left: 15px;
|
||||
}
|
||||
&:last-of-type {
|
||||
margin-right: 15px;
|
||||
}
|
||||
&.active {
|
||||
background-color: $menuHover;
|
||||
color: #FFFFFF;
|
||||
&::before {
|
||||
content: '';
|
||||
background: #FFFFFF;
|
||||
display: inline-block;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
position: relative;
|
||||
margin-right: 2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.contextmenu {
|
||||
margin: 0;
|
||||
background: #fff;
|
||||
z-index: 3000;
|
||||
position: absolute;
|
||||
list-style-type: none;
|
||||
padding: 5px 0;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
color: #333;
|
||||
box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, .3);
|
||||
li {
|
||||
margin: 0;
|
||||
padding: 7px 16px;
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
background: #eee;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss">
|
||||
//reset element css of el-icon-close
|
||||
.tags-view-wrapper {
|
||||
.tags-view-item {
|
||||
.el-icon-close {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
vertical-align: 1px;
|
||||
border-radius: 50%;
|
||||
text-align: center;
|
||||
transition: all .3s cubic-bezier(.645, .045, .355, 1);
|
||||
transform-origin: 100% 50%;
|
||||
&:before {
|
||||
// transform: scale(.6);
|
||||
// display: inline-block;
|
||||
vertical-align: -1px;
|
||||
}
|
||||
&:hover {
|
||||
background-color: #b4bccc;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.tags-close-box {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
box-sizing: border-box;
|
||||
padding-top: 1px;
|
||||
text-align: center;
|
||||
width: 110px;
|
||||
height: 30px;
|
||||
background: #fff;
|
||||
box-shadow: -3px 0 15px 3px rgba(0, 0, 0, 0.1);
|
||||
z-index: 10;
|
||||
}
|
||||
</style>
|
||||
4
src/layout/components/index.js
Normal file
4
src/layout/components/index.js
Normal file
@@ -0,0 +1,4 @@
|
||||
export { default as Navbar } from './Navbar'
|
||||
export { default as Sidebar } from './Sidebar'
|
||||
export { default as AppMain } from './AppMain'
|
||||
export { default as TagsView } from './TagsView/index.vue'
|
||||
114
src/layout/index.vue
Normal file
114
src/layout/index.vue
Normal file
@@ -0,0 +1,114 @@
|
||||
<template>
|
||||
<div :class="classObj" class="app-wrapper">
|
||||
<div class="fixed-header">
|
||||
<navbar />
|
||||
</div>
|
||||
<div
|
||||
v-if="device === 'mobile' && sidebar.opened"
|
||||
class="drawer-bg"
|
||||
@click="handleClickOutside"
|
||||
/>
|
||||
<div class="main-container">
|
||||
<div class="home-box">
|
||||
<a href="javascript:window.opener=null;window.open('','_self');window.close();" class="text-center">平台首页</a>
|
||||
<a href="javascript:void(0);" class="text-center">光伏</a>
|
||||
</div>
|
||||
<sidebar class="sidebar-container" />
|
||||
<!--菜单-->
|
||||
<div class="TagsView">
|
||||
<tags-view />
|
||||
<!--横向标签-->
|
||||
</div>
|
||||
<app-main />
|
||||
<!--<el-footer height="40px">Copyright © 2021 技术支持集团 All Rights Reserved</el-footer>-->
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { AppMain, Navbar, Sidebar, TagsView } from './components'
|
||||
import ResizeMixin from './mixin/ResizeHandler'
|
||||
import { mapState } from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'Layout',
|
||||
components: {
|
||||
AppMain,
|
||||
Navbar,
|
||||
Sidebar,
|
||||
TagsView
|
||||
},
|
||||
mixins: [ResizeMixin],
|
||||
computed: {
|
||||
...mapState({
|
||||
sidebar: (state) => state.app.sidebar,
|
||||
device: (state) => state.app.device
|
||||
}),
|
||||
classObj() {
|
||||
return {
|
||||
hideSidebar: !this.sidebar.opened,
|
||||
openSidebar: this.sidebar.opened,
|
||||
withoutAnimation: this.sidebar.withoutAnimation,
|
||||
mobile: this.device === 'mobile'
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleClickOutside() {
|
||||
this.$store.dispatch('app/closeSideBar', {
|
||||
withoutAnimation: false
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "~@/styles/mixin.scss";
|
||||
@import "~@/styles/variables.scss";
|
||||
|
||||
.app-wrapper {
|
||||
@include clearfix;
|
||||
position: relative;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
|
||||
&.mobile.openSidebar {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.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: 100%;
|
||||
transition: width 0.28s;
|
||||
}
|
||||
|
||||
// .hideSidebar .fixed-header {
|
||||
// width: calc(100% - 54px)
|
||||
// }
|
||||
|
||||
.mobile .fixed-header {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.el-footer {
|
||||
line-height: 40px;
|
||||
text-align: center;
|
||||
background-color: #f7f9fc;
|
||||
}
|
||||
</style>
|
||||
45
src/layout/mixin/ResizeHandler.js
Normal file
45
src/layout/mixin/ResizeHandler.js
Normal file
@@ -0,0 +1,45 @@
|
||||
import store from '@/store'
|
||||
|
||||
const { body } = document
|
||||
const WIDTH = 992 // refer to Bootstrap's responsive design
|
||||
|
||||
export default {
|
||||
watch: {
|
||||
$route(route) {
|
||||
if (this.device === 'mobile' && this.sidebar.opened) {
|
||||
store.dispatch('app/closeSideBar', { withoutAnimation: false })
|
||||
}
|
||||
}
|
||||
},
|
||||
beforeMount() {
|
||||
window.addEventListener('resize', this.$_resizeHandler)
|
||||
},
|
||||
beforeDestroy() {
|
||||
window.removeEventListener('resize', this.$_resizeHandler)
|
||||
},
|
||||
mounted() {
|
||||
const isMobile = this.$_isMobile()
|
||||
if (isMobile) {
|
||||
store.dispatch('app/toggleDevice', 'mobile')
|
||||
store.dispatch('app/closeSideBar', { withoutAnimation: true })
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// use $_ for mixins properties
|
||||
// https://vuejs.org/v2/style-guide/index.html#Private-property-names-essential
|
||||
$_isMobile() {
|
||||
const rect = body.getBoundingClientRect()
|
||||
return rect.width - 1 < WIDTH
|
||||
},
|
||||
$_resizeHandler() {
|
||||
if (!document.hidden) {
|
||||
const isMobile = this.$_isMobile()
|
||||
store.dispatch('app/toggleDevice', isMobile ? 'mobile' : 'desktop')
|
||||
|
||||
if (isMobile) {
|
||||
store.dispatch('app/closeSideBar', { withoutAnimation: true })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user