mirror of
https://codeup.aliyun.com/67762337eccfc218f6110e0e/vue/learning-system-portal.git
synced 2025-12-18 23:36:44 +08:00
2022年5月29日从svn移到git
This commit is contained in:
110
src/layout/components/AppMain.vue
Normal file
110
src/layout/components/AppMain.vue
Normal file
@@ -0,0 +1,110 @@
|
||||
<template>
|
||||
<section class="app-main xcontent">
|
||||
<div style="display: flex;">
|
||||
<div style="height: 100%;width: 200px;border: 1px solid #F0F0F0;">
|
||||
<uc-menu></uc-menu>
|
||||
<!-- <div style="height: 20px;"></div> -->
|
||||
</div>
|
||||
<!-- width: 990px; -->
|
||||
<div class="main-body" style="padding: 0px 10px;flex:1; background-color: #FFFFFF;margin-left: 10px;padding-top:20px">
|
||||
<!-- <div style="margin-bottom: 10px;padding:10px; border-bottom: 1px solid #dbdbdb;"> -->
|
||||
<!-- <el-breadcrumb separator-class="el-icon-arrow-right">
|
||||
<el-breadcrumb-item :to="{ path: '/uc/index' }"><i class="el-icon-arrow-right"></i>个人中心</el-breadcrumb-item>
|
||||
<el-breadcrumb-item>{{breadcrumbName}}</el-breadcrumb-item>
|
||||
</el-breadcrumb> -->
|
||||
<!-- </div> -->
|
||||
<transition name="fade-transform" mode="out-in">
|
||||
<keep-alive :include="cachedViews">
|
||||
<div style="background-color: #FFFFFF;min-height: 600px;padding-bottom: 50px;">
|
||||
<router-view :key="key" />
|
||||
</div>
|
||||
</keep-alive>
|
||||
</transition>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ucMenu from '@/components/UserCenter/menu.vue'
|
||||
export default {
|
||||
name: 'AppMain',
|
||||
components:{ucMenu},
|
||||
computed: {
|
||||
cachedViews() {
|
||||
return this.$store.state.tagsView.cachedViews
|
||||
},
|
||||
breadcrumbName(){
|
||||
return this.$route.meta.title;
|
||||
},
|
||||
key() {
|
||||
return this.$route.path
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.upicon{
|
||||
text-align: center;
|
||||
margin-top: 10px;
|
||||
i{font-size: 30px;color: #ffaa00;}
|
||||
div{color: #565656;padding: 5px 0px 10px 0px;}
|
||||
}
|
||||
.app-main {
|
||||
/* 50= navbar 50 */
|
||||
//min-height: calc(100vh - 50px);
|
||||
// min-width: 1366px;
|
||||
// max-width: 1500px;
|
||||
//width: 1500px;
|
||||
// width: 1000px;
|
||||
// margin: 0 auto;
|
||||
padding-top: 10px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.main-body{
|
||||
width: calc(100% - 210px);
|
||||
}
|
||||
.fixed-header+.app-main {
|
||||
padding-top: 50px;
|
||||
}
|
||||
|
||||
.hasTagsView {
|
||||
.app-main {
|
||||
/* 84 = navbar + tags-view = 50 + 34 */
|
||||
min-height: calc(100vh - 84px);
|
||||
}
|
||||
|
||||
.fixed-header+.app-main {
|
||||
padding-top: 84px;
|
||||
}
|
||||
}
|
||||
.uc-menu{
|
||||
padding: 5px;
|
||||
margin: 5px 10px;
|
||||
.uc-menu-header{
|
||||
font-size: 16px;
|
||||
color:#757575;
|
||||
padding: 10px;
|
||||
border-bottom: 1px solid #ececec;
|
||||
}
|
||||
|
||||
}
|
||||
.uc-menu-item{
|
||||
padding: 5px;
|
||||
text-align: center;
|
||||
display: block;
|
||||
margin: 5px 10px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss">
|
||||
// fix css style bug in open el-dialog
|
||||
.el-popup-parent--hidden {
|
||||
.fixed-header {
|
||||
padding-right: 15px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
187
src/layout/components/Navbar.vue
Normal file
187
src/layout/components/Navbar.vue
Normal file
@@ -0,0 +1,187 @@
|
||||
<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 class="right-menu">
|
||||
<template v-if="device!=='mobile'">
|
||||
<search id="header-search" class="right-menu-item" />
|
||||
|
||||
<el-tooltip content="源码地址" effect="dark" placement="bottom">
|
||||
<a href="https://gitee.com/joolun/JooLun-wx" target="_blank" class="right-menu-item hover-effect">
|
||||
<i class="el-icon-connection"></i>
|
||||
</a>
|
||||
</el-tooltip>
|
||||
|
||||
<el-tooltip content="访问官网" effect="dark" placement="bottom">
|
||||
<a href="http://www.joolun.com/" target="_blank" class="right-menu-item hover-effect">
|
||||
<i class="el-icon-house"></i>
|
||||
</a>
|
||||
</el-tooltip>
|
||||
|
||||
<screenfull id="screenfull" class="right-menu-item hover-effect" />
|
||||
|
||||
<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="avatar" class="user-avatar">
|
||||
<i class="el-icon-caret-bottom" />
|
||||
</div>
|
||||
<el-dropdown-menu slot="dropdown">
|
||||
<router-link to="/user/profile">
|
||||
<el-dropdown-item>个人中心</el-dropdown-item>
|
||||
</router-link>
|
||||
<el-dropdown-item @click.native="setting = true">
|
||||
<span>布局设置</span>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item divided @click.native="logout">
|
||||
<span>退出登录</span>
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex'
|
||||
import Breadcrumb from '@/components/Breadcrumb'
|
||||
import Hamburger from '@/components/Hamburger'
|
||||
import Screenfull from '@/components/Screenfull'
|
||||
import SizeSelect from '@/components/SizeSelect'
|
||||
import Search from '@/components/HeaderSearch'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Breadcrumb,
|
||||
Hamburger,
|
||||
Screenfull,
|
||||
SizeSelect,
|
||||
Search
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'sidebar',
|
||||
'avatar',
|
||||
'device'
|
||||
]),
|
||||
setting: {
|
||||
get() {
|
||||
return this.$store.state.settings.showSettings
|
||||
},
|
||||
set(val) {
|
||||
this.$store.dispatch('settings/changeSetting', {
|
||||
key: 'showSettings',
|
||||
value: val
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toggleSideBar() {
|
||||
this.$store.dispatch('app/toggleSideBar')
|
||||
},
|
||||
async logout() {
|
||||
this.$confirm('确定退出系统吗?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
this.$store.dispatch('LogOut').then(() => {
|
||||
location.href = this.webBaseUrl + '/index';
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.navbar {
|
||||
height: 50px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
background: #fff;
|
||||
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 {
|
||||
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 .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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
197
src/layout/components/Settings/index.vue
Normal file
197
src/layout/components/Settings/index.vue
Normal file
@@ -0,0 +1,197 @@
|
||||
<template>
|
||||
<div class="drawer-container">
|
||||
<div>
|
||||
<div class="setting-drawer-content">
|
||||
<div class="setting-drawer-title">
|
||||
<h3 class="drawer-title">主题风格设置</h3>
|
||||
</div>
|
||||
<div class="setting-drawer-block-checbox">
|
||||
<div class="setting-drawer-block-checbox-item" @click="handleTheme('theme-dark')">
|
||||
<img src="@/assets/images/dark.svg" alt="dark">
|
||||
<div v-if="sideTheme === 'theme-dark'" class="setting-drawer-block-checbox-selectIcon" style="display: block;">
|
||||
<i aria-label="图标: check" class="anticon anticon-check">
|
||||
<svg viewBox="64 64 896 896" data-icon="check" width="1em" height="1em" :fill="theme" aria-hidden="true"
|
||||
focusable="false" class="">
|
||||
<path
|
||||
d="M912 190h-69.9c-9.8 0-19.1 4.5-25.1 12.2L404.7 724.5 207 474a32 32 0 0 0-25.1-12.2H112c-6.7 0-10.4 7.7-6.3 12.9l273.9 347c12.8 16.2 37.4 16.2 50.3 0l488.4-618.9c4.1-5.1.4-12.8-6.3-12.8z"/>
|
||||
</svg>
|
||||
</i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="setting-drawer-block-checbox-item" @click="handleTheme('theme-light')">
|
||||
<img src="@/assets/images/light.svg" alt="light">
|
||||
<div v-if="sideTheme === 'theme-light'" class="setting-drawer-block-checbox-selectIcon" style="display: block;">
|
||||
<i aria-label="图标: check" class="anticon anticon-check">
|
||||
<svg viewBox="64 64 896 896" data-icon="check" width="1em" height="1em" :fill="theme" aria-hidden="true"
|
||||
focusable="false" class="">
|
||||
<path
|
||||
d="M912 190h-69.9c-9.8 0-19.1 4.5-25.1 12.2L404.7 724.5 207 474a32 32 0 0 0-25.1-12.2H112c-6.7 0-10.4 7.7-6.3 12.9l273.9 347c12.8 16.2 37.4 16.2 50.3 0l488.4-618.9c4.1-5.1.4-12.8-6.3-12.8z"/>
|
||||
</svg>
|
||||
</i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="drawer-item">
|
||||
<span>主题颜色</span>
|
||||
<theme-picker style="float: right;height: 26px;margin: -3px 8px 0 0;" @change="themeChange" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-divider/>
|
||||
|
||||
<h3 class="drawer-title">系统布局配置</h3>
|
||||
|
||||
<div class="drawer-item">
|
||||
<span>开启 Tags-Views</span>
|
||||
<el-switch v-model="tagsView" class="drawer-switch" />
|
||||
</div>
|
||||
|
||||
<div class="drawer-item">
|
||||
<span>固定 Header</span>
|
||||
<el-switch v-model="fixedHeader" class="drawer-switch" />
|
||||
</div>
|
||||
|
||||
<div class="drawer-item">
|
||||
<span>显示 Logo</span>
|
||||
<el-switch v-model="sidebarLogo" class="drawer-switch" />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ThemePicker from '@/components/ThemePicker'
|
||||
|
||||
export default {
|
||||
components: { ThemePicker },
|
||||
data() {
|
||||
return {}
|
||||
},
|
||||
computed: {
|
||||
theme() {
|
||||
return this.$store.state.settings.theme
|
||||
},
|
||||
sideTheme() {
|
||||
return this.$store.state.settings.sideTheme
|
||||
},
|
||||
fixedHeader: {
|
||||
get() {
|
||||
return this.$store.state.settings.fixedHeader
|
||||
},
|
||||
set(val) {
|
||||
this.$store.dispatch('settings/changeSetting', {
|
||||
key: 'fixedHeader',
|
||||
value: val
|
||||
})
|
||||
}
|
||||
},
|
||||
tagsView: {
|
||||
get() {
|
||||
return this.$store.state.settings.tagsView
|
||||
},
|
||||
set(val) {
|
||||
this.$store.dispatch('settings/changeSetting', {
|
||||
key: 'tagsView',
|
||||
value: val
|
||||
})
|
||||
}
|
||||
},
|
||||
sidebarLogo: {
|
||||
get() {
|
||||
return this.$store.state.settings.sidebarLogo
|
||||
},
|
||||
set(val) {
|
||||
this.$store.dispatch('settings/changeSetting', {
|
||||
key: 'sidebarLogo',
|
||||
value: val
|
||||
})
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
themeChange(val) {
|
||||
this.$store.dispatch('settings/changeSetting', {
|
||||
key: 'theme',
|
||||
value: val
|
||||
})
|
||||
},
|
||||
handleTheme(val) {
|
||||
this.$store.dispatch('settings/changeSetting', {
|
||||
key: 'sideTheme',
|
||||
value: val
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.setting-drawer-content {
|
||||
.setting-drawer-title {
|
||||
margin-bottom: 12px;
|
||||
color: rgba(0, 0, 0, .85);
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.setting-drawer-block-checbox {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.setting-drawer-block-checbox-item {
|
||||
position: relative;
|
||||
margin-right: 16px;
|
||||
border-radius: 2px;
|
||||
cursor: pointer;
|
||||
|
||||
img {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
}
|
||||
|
||||
.setting-drawer-block-checbox-selectIcon {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding-top: 15px;
|
||||
padding-left: 24px;
|
||||
color: #1890ff;
|
||||
font-weight: 700;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.drawer-container {
|
||||
padding: 24px;
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
word-wrap: break-word;
|
||||
|
||||
.drawer-title {
|
||||
margin-bottom: 12px;
|
||||
color: rgba(0, 0, 0, .85);
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
}
|
||||
|
||||
.drawer-item {
|
||||
color: rgba(0, 0, 0, .65);
|
||||
font-size: 14px;
|
||||
padding: 12px 0;
|
||||
}
|
||||
|
||||
.drawer-switch {
|
||||
float: right
|
||||
}
|
||||
}
|
||||
</style>
|
||||
25
src/layout/components/Sidebar/FixiOSBug.js
Normal file
25
src/layout/components/Sidebar/FixiOSBug.js
Normal file
@@ -0,0 +1,25 @@
|
||||
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
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
29
src/layout/components/Sidebar/Item.vue
Normal file
29
src/layout/components/Sidebar/Item.vue
Normal file
@@ -0,0 +1,29 @@
|
||||
<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) {
|
||||
vnodes.push(<svg-icon icon-class={icon}/>)
|
||||
}
|
||||
|
||||
if (title) {
|
||||
vnodes.push(<span slot='title'>{(title)}</span>)
|
||||
}
|
||||
return vnodes
|
||||
}
|
||||
}
|
||||
</script>
|
||||
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>
|
||||
96
src/layout/components/Sidebar/SidebarItem.vue
Normal file
96
src/layout/components/Sidebar/SidebarItem.vue
Normal file
@@ -0,0 +1,96 @@
|
||||
<template>
|
||||
<div v-if="!item.hidden">
|
||||
<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'
|
||||
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() {
|
||||
this.onlyOneChild = null
|
||||
return {}
|
||||
},
|
||||
methods: {
|
||||
hasOneShowingChild(children = [], parent) {
|
||||
if (!children) {
|
||||
children = [];
|
||||
}
|
||||
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 router, the child router is displayed by default
|
||||
if (showingChildren.length === 1) {
|
||||
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>
|
||||
58
src/layout/components/Sidebar/index.vue
Normal file
58
src/layout/components/Sidebar/index.vue
Normal file
@@ -0,0 +1,58 @@
|
||||
<template>
|
||||
<div :class="{'has-logo':showLogo}" :style="{ backgroundColor: settings.sideTheme === 'theme-dark' ? variables.menuBg : variables.menuLightBg }">
|
||||
<el-scrollbar :class="settings.sideTheme" wrap-class="scrollbar-wrapper">
|
||||
<el-menu
|
||||
:default-active="activeMenu"
|
||||
:collapse="isCollapse"
|
||||
:background-color="settings.sideTheme === 'theme-dark' ? variables.menuBg : variables.menuLightBg"
|
||||
:text-color="settings.sideTheme === 'theme-dark' ? variables.menuText : 'rgba(0,0,0,.65)'"
|
||||
:unique-opened="true"
|
||||
:active-text-color="settings.theme"
|
||||
:collapse-transition="false"
|
||||
mode="vertical"
|
||||
>
|
||||
<sidebar-item
|
||||
v-for="(route, index) in sidebarRouters"
|
||||
:key="route.path + index"
|
||||
:item="route"
|
||||
:base-path="route.path"
|
||||
/>
|
||||
</el-menu>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapState } from "vuex";
|
||||
import SidebarItem from "./SidebarItem";
|
||||
import variables from "@/assets/styles/variables.scss";
|
||||
|
||||
export default {
|
||||
components: { SidebarItem},
|
||||
computed: {
|
||||
...mapState(["settings"]),
|
||||
...mapGetters(["sidebarRouters", "sidebar"]),
|
||||
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 path;
|
||||
},
|
||||
showLogo() {
|
||||
return this.$store.state.settings.sidebarLogo;
|
||||
},
|
||||
variables() {
|
||||
return variables;
|
||||
},
|
||||
isCollapse() {
|
||||
return !this.sidebar.opened;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
|
||||
</style>
|
||||
94
src/layout/components/TagsView/ScrollPane.vue
Normal file
94
src/layout/components/TagsView/ScrollPane.vue
Normal file
@@ -0,0 +1,94 @@
|
||||
<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: 49px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
304
src/layout/components/TagsView/index.vue
Normal file
304
src/layout/components/TagsView/index.vue
Normal file
@@ -0,0 +1,304 @@
|
||||
<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 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"
|
||||
:style="activeStyle(tag)"
|
||||
@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>
|
||||
<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
|
||||
},
|
||||
theme() {
|
||||
return this.$store.state.settings.theme;
|
||||
}
|
||||
},
|
||||
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
|
||||
},
|
||||
activeStyle(tag) {
|
||||
if (!this.isActive(tag)) return {};
|
||||
return {
|
||||
"background-color": '#545c64',//原来是this.theme
|
||||
"border-color": '#50575f'
|
||||
};
|
||||
},
|
||||
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(view) {
|
||||
this.$store.dispatch('tagsView/delView', view).then(({ visitedViews }) => {
|
||||
if (this.isActive(view)) {
|
||||
this.toLastView(visitedViews, view)
|
||||
}
|
||||
})
|
||||
},
|
||||
closeOthersTags() {
|
||||
this.$router.push(this.selectedTag).catch(()=>{});
|
||||
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 === this.$route.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 = 30
|
||||
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: margin right
|
||||
|
||||
if (left > maxLeft) {
|
||||
this.left = maxLeft
|
||||
} else {
|
||||
this.left = left
|
||||
}
|
||||
|
||||
this.top = e.clientY-45
|
||||
this.visible = true
|
||||
this.selectedTag = tag
|
||||
},
|
||||
closeMenu() {
|
||||
this.visible = false
|
||||
},
|
||||
handleScroll() {
|
||||
this.closeMenu()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.tags-view-container {
|
||||
height: 34px;
|
||||
width: 100%;
|
||||
background: #fff;
|
||||
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 {
|
||||
.tags-view-item {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
height: 26px;
|
||||
line-height: 26px;
|
||||
border: 1px solid #d8dce5;
|
||||
color: #495060;
|
||||
background: #fff;
|
||||
padding: 0 8px;
|
||||
font-size: 12px;
|
||||
margin-left: 5px;
|
||||
margin-top: 4px;
|
||||
&:first-of-type {
|
||||
margin-left: 15px;
|
||||
}
|
||||
&:last-of-type {
|
||||
margin-right: 15px;
|
||||
}
|
||||
&.active {
|
||||
background-color: #42b983;
|
||||
color: #fff;
|
||||
border-color: #42b983;
|
||||
&::before {
|
||||
content: '';
|
||||
background: #fff;
|
||||
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: 2px;
|
||||
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: -3px;
|
||||
}
|
||||
&:hover {
|
||||
background-color: #b4bccc;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
510
src/layout/components/TopNav/Index.vue
Normal file
510
src/layout/components/TopNav/Index.vue
Normal file
@@ -0,0 +1,510 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="xtop">
|
||||
<div class="xtop-content xcontent">
|
||||
<div class="xtop-left">
|
||||
<!-- <div> -->
|
||||
<router-link class="routerLink" to="/index"><img src="../../../assets/logo/logo.png" style="width:240px;height: 30px;" /></router-link>
|
||||
<!-- </div> -->
|
||||
<div class="xtop-nav">
|
||||
<div><a :href="`${webBaseUrl}/index`">首页</a></div>
|
||||
<div><a :href="`${webBaseUrl}/course`">课程</a></div>
|
||||
<!-- <div><a :href="`${webBaseUrl}/case`" target="_blank">案例</a></div> -->
|
||||
<div><a :href="`${webBaseUrl}/article`">文章</a></div>
|
||||
<div><a :href="`${webBaseUrl}/qa`">问答</a></div>
|
||||
<div>
|
||||
<el-dropdown placement="bottom" @command="handleCommand">
|
||||
<span class="el-dropdown-link" style="color:#000;font-size:16px;cursor: pointer;">专区</span>
|
||||
<el-dropdown-menu slot="dropdown">
|
||||
<el-dropdown-item command='one'>BOE系列公开课</el-dropdown-item>
|
||||
<el-dropdown-item command='two' divided>Grow180</el-dropdown-item>
|
||||
<el-dropdown-item command='three' divided>管理者进阶</el-dropdown-item>
|
||||
<el-dropdown-item command='four' divided>U选小课堂</el-dropdown-item>
|
||||
<el-dropdown-item command='five' divided>社招新员工</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="xtop-right" style="display: flex;justify-content: flex-end;align-items: center;">
|
||||
<!-- <div>
|
||||
<el-badge :value="userMsg" :hidden="userMsg==0" class="message-count">
|
||||
<el-link type="primary" :href="`${webBaseUrl}/message`" target="_blank" icon="el-icon-message-solid" :underline="false"></el-link>
|
||||
</el-badge>
|
||||
</div>
|
||||
<div style="margin-left: 20px;"><el-avatar :src="userInfo.avatar" style="vertical-align: middle;width:28px;height:28px;margin-right:2px;"></el-avatar></div>
|
||||
<div style="margin-left: 5px;">
|
||||
<el-dropdown @command="handleUcCommand">
|
||||
<span class="el-dropdown-link">
|
||||
{{userInfo.name}}<i class="el-icon-arrow-down el-icon--right"></i>
|
||||
</span>
|
||||
<el-dropdown-menu slot="dropdown">
|
||||
<el-dropdown-item command="logout">退出</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
</div> -->
|
||||
<div class="person-action">
|
||||
<el-badge :value="userMsg" :hidden="userMsg == 0" class="message-count">
|
||||
<el-link type="primary" :href="`${webBaseUrl}/message`" icon="el-icon-bell" :underline="false"></el-link>
|
||||
</el-badge>
|
||||
<!-- <el-avatar :src="userInfo.avatar"></el-avatar> -->
|
||||
<!-- <el-link type="primary" :href="`${webBaseUrl}${isTiao ? '/uc/study/task' : '/uc/study/courses'}`" :underline="false">个人中心</el-link> -->
|
||||
<el-button @click="logout()" type="text" icon="el-icon-switch-button">退出</el-button>
|
||||
</div>
|
||||
<!-- <ul>
|
||||
<li @mouseover="mouseOver(1)" @mouseleave="mouseLeave(1)" :class="{ xactive: mouseIndex == 1 }">
|
||||
<el-badge :value="userMsg" :hidden="userMsg==0" style="margin-top: 10px;margin-right: -10px;">
|
||||
<el-link type="primary" :href="`${webBaseUrl}/message`" target="_blank" icon="el-icon-bell" style="margin-top: -10px;" :underline="false">消息</el-link>
|
||||
</el-badge>
|
||||
</li>
|
||||
<li @mouseover="mouseOver(9)" @mouseleave="mouseLeave(9)" :class="{ xactive: mouseIndex == 9 }" style="padding-right: 10px;">
|
||||
<el-button @click="logout()" type="text" icon="el-icon-switch-button">退出</el-button>
|
||||
</li>
|
||||
</ul> -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<el-dialog title="修改登录密码" :close-on-click-modal="false" :visible.sync="pwdDlg.show" width="600px" custom-class="g-dialog">
|
||||
<el-form :model="pwdDlg" size="medium" label-width="100px">
|
||||
<el-form-item label="当前密码"><el-input v-model="pwdDlg.nowPwd" type="password" placeholder="当前的登录密码" :style="{ width: '100%' }"></el-input></el-form-item>
|
||||
<el-form-item label="新密码">
|
||||
<el-input v-model="pwdDlg.newPwd" type="password" placeholder="新的密码" :maxlength="20" clearable :style="{ width: '100%' }"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="密码确认">
|
||||
<el-input v-model="pwdDlg.rePwd" type="password" placeholder="和上面新密码一致" :maxlength="20" clearable :style="{ width: '100%' }"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="pwdDlg.show = false">取 消</el-button>
|
||||
<el-button type="primary" @click="submitPwd">提交修改</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
<el-dialog
|
||||
class="dialog-signin"
|
||||
:show-close="false"
|
||||
:visible.sync="signInShow"
|
||||
:close-on-click-modal="false"
|
||||
width="30%">
|
||||
<!-- <span>这是一段信息</span> -->
|
||||
<div style="background-color: #99beff;padding-bottom: 20px;">
|
||||
<div class="signin-bg">
|
||||
<img style="width:100%" :src="`${this.webBaseUrl}/images/newtip/bg.png`" alt="" srcset="">
|
||||
<i @click="toExperience()" class="el-icon-close" style="cursor: pointer;"></i>
|
||||
</div>
|
||||
<!-- <div class="signin-box">
|
||||
<p class="signin-text"><span>更多彩蛋</span> <span class="ti-yan" @click="toExperience()">即刻体验>>> </span></p>
|
||||
<p class="signin-a"><span><a href="https://u.boe.com/upload/video/originfile/50/50d84b41d7e4c29b20e73215b5117fb5.mp4" target="_blank">点击小视频了解更多</a></span></p>
|
||||
<p class="signin-b"><el-checkbox v-model="checked"></el-checkbox> <span>一天之内不再提示</span></p>
|
||||
</div> -->
|
||||
<div class="signin-box2">
|
||||
<div class="signin-checkbox"><el-checkbox v-model="checked"></el-checkbox>一天之内不再提示</div>
|
||||
<!-- <div class="signin-text" @click="toExperience()">点击小视频了解更多</div> -->
|
||||
</div>
|
||||
</div>
|
||||
<div slot="footer" class="dialog-footer dialog-footer-signin">
|
||||
<!-- <el-checkbox v-model="checked">一天之内不在提示</el-checkbox> -->
|
||||
<!-- <el-button type="primary" @click="toExperience()">去体验</el-button> -->
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
import desk from '@/api/console.js';
|
||||
import Cookies from 'vue-cookies';
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
checked:true,
|
||||
signInShow: false,
|
||||
keyword: '',
|
||||
findType: '1',
|
||||
mouseIndex: 0,
|
||||
activeIndex: '',
|
||||
oneSignIn:'boe_new',
|
||||
msg: {
|
||||
num: 0
|
||||
},
|
||||
user: {
|
||||
name: ''
|
||||
},
|
||||
pwdDlg: { show: false, newPwd: '', nowPwd: '', rePwd: '' },
|
||||
current:1
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['userInfo', 'userMsg']),
|
||||
showName: function() {
|
||||
//console.log('name='+this.name);
|
||||
//console.log('loginName='+this.loginName);
|
||||
if (this.userInfo.name != '') {
|
||||
return this.userInfo.name;
|
||||
} else {
|
||||
return this.userInfo.userName;
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if(this.getCookies() == null) {
|
||||
this.signInShow = true;
|
||||
}
|
||||
this.$store.dispatch('refrashMsg');
|
||||
},
|
||||
methods: {
|
||||
getCookies() {
|
||||
return Cookies.get(this.oneSignIn)
|
||||
},
|
||||
setCookies(token,expiresTime) {
|
||||
//console.log(token,expiresTime,'token,expiresTime');
|
||||
return Cookies.set(this.oneSignIn, token,expiresTime)
|
||||
},
|
||||
removeCookies(){
|
||||
return Cookies.remove(this.oneSignIn)
|
||||
},
|
||||
toExperience() {
|
||||
this.signInShow = false;
|
||||
if(this.checked) {
|
||||
this.setCookies('new',60*60*24)
|
||||
} else {
|
||||
this.removeCookies();
|
||||
}
|
||||
},
|
||||
// searchJump() {
|
||||
// if(this.findType == '1') {// 课程
|
||||
// window.open(`/course?keyword=${this.keyword}`);
|
||||
// } else if(this.findType == '2'){ // 案例
|
||||
// window.open(`/case?keyword=${this.keyword}`);
|
||||
// } else if(this.findType == '3'){ //文章
|
||||
// window.open(`/article?keyword=${this.keyword}`);
|
||||
// } else if(this.findType == '4'){ // 问答
|
||||
// window.open(`/qa?keyword=${this.keyword}`);
|
||||
// }
|
||||
// },
|
||||
handleCommand(val) {
|
||||
let obj = {
|
||||
one: process.env.VUE_APP_BOE_WEB_URL+'/web/teacherLesson',
|
||||
two: process.env.VUE_APP_BOE_WEB_URL+'/grow180/login',
|
||||
three: this.webBaseUrl + '/study/index',
|
||||
four: 'https://m.qingxuetang.com/x/?appId=qxtcorp306130',
|
||||
five: process.env.VUE_APP_BOE_WEB_URL+'/boe/new-employee/index.html'
|
||||
};
|
||||
window.open(obj[val]);
|
||||
},
|
||||
handleUcCommand(val){
|
||||
if(val == 'logout'){
|
||||
this.logout();
|
||||
}
|
||||
},
|
||||
handleSelect(key, keyPath) {
|
||||
//console.log(key, keyPath);
|
||||
},
|
||||
showPwd() {
|
||||
this.pwdDlg.show = true;
|
||||
},
|
||||
submitPwd() {
|
||||
if (this.pwdDlg.nowPwd == '' || (this.pwdDlg.newPwd == '') | (this.pwdDlg.rePwd == '')) {
|
||||
return;
|
||||
}
|
||||
let params = {
|
||||
loginName: this.loginName,
|
||||
old: this.pwdDlg.nowPwd,
|
||||
newPassword: this.pwdDlg.newPwd,
|
||||
rePassword: this.pwdDlg.rePwd
|
||||
};
|
||||
desk.updatePassword(params).then(res => {
|
||||
if (res.status == 200) {
|
||||
this.$message({ message: '修改成功,请重新登录', type: 'success' });
|
||||
} else {
|
||||
this.$message({ message: '修改失败,请检查输入', type: 'error' });
|
||||
}
|
||||
});
|
||||
},
|
||||
logout() {
|
||||
this.$confirm('确定退出系统吗?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
this.$store.dispatch('LogOut').then(() => {
|
||||
//location.href = this.webBaseUrl + '/login';
|
||||
location.href =process.env.VUE_APP_LOGIN_URL;
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
::v-deep .dialog-signin{
|
||||
.el-dialog__header{
|
||||
padding: 0;
|
||||
}
|
||||
.el-dialog__body{
|
||||
padding: 0;
|
||||
}
|
||||
.el-dialog__footer {
|
||||
padding: 0;
|
||||
|
||||
}
|
||||
.signin-bg{
|
||||
position: relative;
|
||||
.el-icon-close{
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
right: 10px;
|
||||
color: #fff;
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
.signin-box2{
|
||||
margin-left: 100px;
|
||||
font-size: 12px;
|
||||
.signin-checkbox{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: #FFFFFF;
|
||||
margin-top: 10px;
|
||||
.el-checkbox{
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
.signin-text{
|
||||
font-family: Alibaba PuHuiTi;
|
||||
font-style:italic;
|
||||
cursor: pointer;
|
||||
margin-left: 20px;
|
||||
color:#003eb7;
|
||||
font-weight: bolder;
|
||||
}
|
||||
}
|
||||
.signin-box{
|
||||
margin: 0 70px;
|
||||
p{
|
||||
line-height: 28px;
|
||||
}
|
||||
.signin-text{
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
color: #FFFFFF;
|
||||
.ti-yan{
|
||||
border-bottom: 1px solid #FFFFFF;
|
||||
margin-left: 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
img{
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
margin-left: 6px;
|
||||
vertical-align: middle;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
}
|
||||
.signin-a{
|
||||
font-size: 12px;
|
||||
font-family: Alibaba PuHuiTi;
|
||||
font-weight: 600;
|
||||
color: #FFFFFF;
|
||||
span{
|
||||
border-bottom: 1px solid #FFFFFF;
|
||||
}
|
||||
}
|
||||
.signin-b{
|
||||
font-size: 12px;
|
||||
color:#FFFFFF;
|
||||
text-align: right;
|
||||
.el-checkbox__inner{
|
||||
//background-color: #588AFC;
|
||||
border-color: #FFFFFF;
|
||||
}
|
||||
.el-checkbox__input.is-checked .el-checkbox__inner{
|
||||
background-color: #588AFC;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.dialog-footer-signin{
|
||||
display: flex;
|
||||
justify-content: space-between
|
||||
}
|
||||
.xtop {
|
||||
height: 56px;
|
||||
line-height: 56px;
|
||||
background-color: #FFFFFF;
|
||||
position: fixed;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
border-bottom: 1px solid #e9e9e9;
|
||||
z-index: 9999;
|
||||
.xtop-content{
|
||||
//width: 1500px;
|
||||
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
.xtop .xtop-left {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
.routerLink{
|
||||
padding-right: 50px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
.xtop-nav {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
a{
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
.xtop-nav > div {
|
||||
line-height: 56px;
|
||||
padding: 0px 24px;
|
||||
}
|
||||
|
||||
.xtop .xtop-right {
|
||||
float: right;
|
||||
.person-action{
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
margin-left: 100px;
|
||||
::v-deep .message-count{
|
||||
margin-right: 30px;
|
||||
i{
|
||||
font-size: 26px;
|
||||
color:#409EFF;
|
||||
}
|
||||
}
|
||||
.el-avatar{
|
||||
margin-right: 8px;
|
||||
}
|
||||
.el-button{
|
||||
margin-top: 1px;
|
||||
// margin-left: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.xtop .xtop-right > ul {
|
||||
list-style: none;
|
||||
margin: 0px;
|
||||
}
|
||||
.xtop .xtop-right > ul > li {
|
||||
list-style: none;
|
||||
display: inline-block;
|
||||
margin: 0px 2px;
|
||||
padding: 0px 15px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.xtop .arrow-down {
|
||||
content: '';
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-style: solid dashed dashed;
|
||||
border-color: #000000 transparent transparent;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
-webkit-transition: all 0.2s;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
margin-top: -3px;
|
||||
border-width: 6px;
|
||||
border-top-color: #000000;
|
||||
}
|
||||
.xtop .arrow-up {
|
||||
margin-top: -9px;
|
||||
border-style: dashed dashed solid;
|
||||
border-color: transparent transparent #000000;
|
||||
}
|
||||
.xtop-user {
|
||||
width: 110px;
|
||||
}
|
||||
.xtop-user-img {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border: none;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
border-radius: 50%;
|
||||
}
|
||||
.xtop-user-menu {
|
||||
right: 0px;
|
||||
top: 40px;
|
||||
background-color: #f4f4f4;
|
||||
color: #202020;
|
||||
position: absolute;
|
||||
width: 140px;
|
||||
z-index: 1000;
|
||||
padding: 15px 0px;
|
||||
}
|
||||
.xtop-user-menu > ul {
|
||||
padding: 0px;
|
||||
list-style: none;
|
||||
}
|
||||
.xtop-user-menu > ul > li {
|
||||
display: block;
|
||||
text-align: left;
|
||||
}
|
||||
.xtop-user-menu > ul > li.divider {
|
||||
height: 1px;
|
||||
margin: 5px 0px;
|
||||
border-bottom: 1px solid #989898;
|
||||
}
|
||||
.xtop-user-menu > ul > li > a {
|
||||
display: block;
|
||||
padding-left: 30px;
|
||||
line-height: 30px;
|
||||
font-size: 14px;
|
||||
}
|
||||
.xtop-user-menu > ul > li > a:hover {
|
||||
background-color: #cccccc;
|
||||
}
|
||||
.xtop-find {
|
||||
border: 1px solid #c9c9c9;
|
||||
background-color: #f3f3f3;
|
||||
border-radius: 5px;
|
||||
line-height: 25px;
|
||||
height: 25px;
|
||||
display: inline-block;
|
||||
padding: 0px 5px;
|
||||
input {
|
||||
background-color: transparent;
|
||||
border: 0px;
|
||||
line-height: 25px;
|
||||
height: 25px;
|
||||
}
|
||||
input:focus {
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
.message-count a{
|
||||
color: #858D99;
|
||||
font-size: 28px;
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
::v-deep .el-badge{
|
||||
margin-top: 0 !important;
|
||||
.el-badge__content{
|
||||
top: 20px;
|
||||
}
|
||||
}
|
||||
::v-deep .el-link.el-link--primary:hover {
|
||||
color:#588AFC;
|
||||
}
|
||||
.el-dropdown-link{
|
||||
cursor: pointer;
|
||||
color: #666666;
|
||||
}
|
||||
</style>
|
||||
5
src/layout/components/index.js
Normal file
5
src/layout/components/index.js
Normal file
@@ -0,0 +1,5 @@
|
||||
export { default as AppMain } from './AppMain'
|
||||
export { default as Navbar } from './Navbar'
|
||||
export { default as Settings } from './Settings'
|
||||
export { default as Sidebar } from './Sidebar/index.vue'
|
||||
export { default as TagsView } from './TagsView/index.vue'
|
||||
156
src/layout/index.vue
Normal file
156
src/layout/index.vue
Normal file
@@ -0,0 +1,156 @@
|
||||
<template>
|
||||
<div class="uc-layout">
|
||||
<div style="height: 50px;"><top></top></div>
|
||||
<!-- <div style="position: fixed;left: 0px; top: 60px;" :style="{width:isCollapse? '54px':'200px'}">
|
||||
<div :style="{width:isCollapse? '64px':'200px'}">
|
||||
<div>
|
||||
<div class="el-aside-header">
|
||||
<span v-if="!isCollapse" style="padding: 0px 10px;color: #1EA0FA;">全部功能导航</span>
|
||||
<hamburger id="hamburger-container" :is-active="isCollapse" class="hamburger-container" @toggleClick="toggleSideBar" />
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<el-menu :default-active="activeMenu"
|
||||
:collapse="isCollapse"
|
||||
:unique-opened="true"
|
||||
active-text-color="#ffd04b"
|
||||
:collapse-transition="false"
|
||||
mode="vertical" >
|
||||
<sidebar-item v-for="(route, index) in sidebarRouters" :key="route.path + index" :item="route" :base-path="route.path" />
|
||||
</el-menu>
|
||||
</div>
|
||||
</div>
|
||||
</div> -->
|
||||
<div class="main-container">
|
||||
<uc-header></uc-header>
|
||||
<app-main />
|
||||
<right-panel v-if="showSettings">
|
||||
<settings />
|
||||
</right-panel>
|
||||
<portalFloatTools></portalFloatTools>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import top from './components/TopNav/Index.vue'
|
||||
import UcHeader from '@/components/UcHeader/Index.vue'
|
||||
import Hamburger from '@/components/Hamburger'
|
||||
import { AppMain, Navbar, Settings} from './components'
|
||||
import { mapGetters, mapState } from "vuex";
|
||||
import SidebarItem from "./components/Sidebar/SidebarItem";
|
||||
import portalFloatTools from '@/components/PortalFloatTools.vue';
|
||||
export default {
|
||||
name: 'Layout',
|
||||
data(){
|
||||
return {
|
||||
aside:{
|
||||
collapse:true,
|
||||
width:'54px'
|
||||
}
|
||||
}
|
||||
},
|
||||
components: {
|
||||
AppMain,
|
||||
Navbar,
|
||||
Settings,
|
||||
top,
|
||||
portalFloatTools,
|
||||
Hamburger,
|
||||
SidebarItem,
|
||||
UcHeader
|
||||
},
|
||||
mounted() {
|
||||
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
theme: state => state.settings.theme,
|
||||
showSettings: state => state.settings.showSettings
|
||||
}),
|
||||
...mapGetters(["sidebarRouters", "sidebar"]),
|
||||
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 path;
|
||||
},
|
||||
isCollapse() {
|
||||
return this.aside.collapse;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toggleSideBar(){
|
||||
console.log(this.aside.collapse);
|
||||
this.aside.collapse=!this.aside.collapse;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.uc-layout{
|
||||
height: 100%;
|
||||
// background-image:url(../assets/images/uc-bg.png);
|
||||
// background-repeat: no-repeat;
|
||||
//background-position: center;
|
||||
//background-color: #F4F4F4;
|
||||
|
||||
background-color: #F6F7FB;
|
||||
}
|
||||
.el-aside-header{
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
}
|
||||
.el-aside-menu{
|
||||
overflow: hidden;
|
||||
.scrollbar-wrapper {
|
||||
overflow-x: hidden !important;
|
||||
}
|
||||
.el-scrollbar__bar.is-vertical {
|
||||
right: 0px;
|
||||
}
|
||||
|
||||
.el-scrollbar {
|
||||
height: 100%;
|
||||
}
|
||||
.el-menu {
|
||||
border: none;
|
||||
height: 100%;
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
.el-menu-item, .el-submenu__title {
|
||||
overflow: hidden !important;
|
||||
text-overflow: ellipsis !important;
|
||||
white-space: nowrap !important;
|
||||
}
|
||||
|
||||
}
|
||||
.el-menu{
|
||||
border-right: solid 0px #e6e6e6;
|
||||
}
|
||||
.el-main{
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.hamburger-container {
|
||||
line-height: 30px;
|
||||
height: 100%;
|
||||
float: right;
|
||||
cursor: pointer;
|
||||
transition: background .3s;
|
||||
-webkit-tap-highlight-color:transparent;
|
||||
|
||||
&:hover {
|
||||
background: rgba(0, 0, 0, .025)
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
188
src/layout/index2.vue
Normal file
188
src/layout/index2.vue
Normal file
@@ -0,0 +1,188 @@
|
||||
<template>
|
||||
<el-container style="background-color: #f2f2f2;">
|
||||
<el-header>
|
||||
<top></top>
|
||||
</el-header>
|
||||
<el-container style="padding-top: 10px;">
|
||||
<el-aside :width="isCollapse? '54px':'200px'">
|
||||
<div class="el-aside-header">
|
||||
<span v-if="!isCollapse" style="padding: 0px 10px;">全部功能</span>
|
||||
<hamburger id="hamburger-container" :is-active="isCollapse" class="hamburger-container" @toggleClick="toggleSideBar" />
|
||||
</div>
|
||||
<div class="el-aside-menu" >
|
||||
<el-scrollbar class="theme-dark" wrap-class="scrollbar-wrapper">
|
||||
<el-menu :default-active="activeMenu"
|
||||
:collapse="isCollapse"
|
||||
:unique-opened="true"
|
||||
active-text-color="#ffd04b"
|
||||
:collapse-transition="false"
|
||||
mode="vertical" >
|
||||
<sidebar-item
|
||||
v-for="(route, index) in sidebarRouters"
|
||||
:key="route.path + index"
|
||||
:item="route"
|
||||
:base-path="route.path" />
|
||||
</el-menu>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
</el-aside>
|
||||
<el-main>
|
||||
<div class="main-container">
|
||||
<uc-header></uc-header>
|
||||
<app-main />
|
||||
<right-panel v-if="showSettings">
|
||||
<settings />
|
||||
</right-panel>
|
||||
</div>
|
||||
</el-main>
|
||||
</el-container>
|
||||
</el-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import top from './components/TopNav/Index.vue'
|
||||
import UcHeader from './components/UcHeader/Index.vue'
|
||||
import Hamburger from '@/components/Hamburger'
|
||||
import RightPanel from '@/components/RightPanel'
|
||||
import { AppMain, Navbar, Settings, Sidebar, TagsView } from './components'
|
||||
import ResizeMixin from './mixin/ResizeHandler'
|
||||
import { mapGetters, mapState } from "vuex";
|
||||
import SidebarItem from "./components/Sidebar/SidebarItem";
|
||||
import variables from "@/assets/styles/variables.scss";
|
||||
|
||||
export default {
|
||||
name: 'Layout',
|
||||
data(){
|
||||
return {
|
||||
aside:{
|
||||
collapse:false,
|
||||
width:'200px'
|
||||
}
|
||||
}
|
||||
},
|
||||
components: {
|
||||
AppMain,
|
||||
Navbar,
|
||||
RightPanel,
|
||||
Settings,
|
||||
Sidebar,
|
||||
TagsView,
|
||||
top,
|
||||
Hamburger,
|
||||
SidebarItem,
|
||||
UcHeader
|
||||
},
|
||||
mixins: [ResizeMixin],
|
||||
computed: {
|
||||
...mapState({
|
||||
theme: state => state.settings.theme,
|
||||
sideTheme: state => state.settings.sideTheme,
|
||||
sidebar: state => state.app.sidebar,
|
||||
device: state => state.app.device,
|
||||
showSettings: state => state.settings.showSettings,
|
||||
needTagsView: state => state.settings.tagsView,
|
||||
fixedHeader: state => state.settings.fixedHeader
|
||||
}),
|
||||
...mapGetters(["sidebarRouters", "sidebar"]),
|
||||
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 path;
|
||||
},
|
||||
showLogo() {
|
||||
return this.$store.state.settings.sidebarLogo;
|
||||
},
|
||||
isCollapse() {
|
||||
return !this.sidebar.opened;
|
||||
},
|
||||
variables() {
|
||||
return variables;
|
||||
},
|
||||
mainHeight(){
|
||||
let windowHeight=document.documentElement.clientHeight;
|
||||
return windowHeight-60;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toggleSideBar(){
|
||||
this.$store.dispatch('app/toggleSideBar')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "~@/assets/styles/mixin.scss";
|
||||
@import "~@/assets/styles/variables.scss";
|
||||
.el-container {
|
||||
height: 100%;
|
||||
// 不能通过css引用public下的图片,虚拟目录下会找不到
|
||||
//background: url($WEB_BASE_URL/images/center_bg.jpg);
|
||||
// background-size: cover;
|
||||
}
|
||||
.el-header {
|
||||
padding: 0px;
|
||||
height: 40px !important;
|
||||
}
|
||||
.el-aside{
|
||||
margin-bottom: 0px;
|
||||
padding: 0px;
|
||||
background-color: transparent;
|
||||
|
||||
}
|
||||
.el-aside-header{
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
}
|
||||
.el-aside-menu{
|
||||
overflow: hidden;
|
||||
.scrollbar-wrapper {
|
||||
overflow-x: hidden !important;
|
||||
}
|
||||
.el-scrollbar__bar.is-vertical {
|
||||
right: 0px;
|
||||
}
|
||||
|
||||
.el-scrollbar {
|
||||
height: 100%;
|
||||
}
|
||||
.el-menu {
|
||||
border: none;
|
||||
height: 100%;
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
.el-menu-item, .el-submenu__title {
|
||||
overflow: hidden !important;
|
||||
text-overflow: ellipsis !important;
|
||||
white-space: nowrap !important;
|
||||
}
|
||||
|
||||
}
|
||||
.el-menu{
|
||||
border-right: solid 0px #e6e6e6;
|
||||
}
|
||||
.el-main{
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.hamburger-container {
|
||||
line-height: 30px;
|
||||
height: 100%;
|
||||
float: right;
|
||||
cursor: pointer;
|
||||
transition: background .3s;
|
||||
-webkit-tap-highlight-color:transparent;
|
||||
|
||||
&:hover {
|
||||
background: rgba(0, 0, 0, .025)
|
||||
}
|
||||
}
|
||||
|
||||
</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 })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
44
src/layout/portal.vue
Normal file
44
src/layout/portal.vue
Normal file
@@ -0,0 +1,44 @@
|
||||
<template>
|
||||
<div>
|
||||
<portal-header></portal-header>
|
||||
<div>
|
||||
<transition name="fade-transform" mode="out-in">
|
||||
<router-view :key="key" />
|
||||
</transition>
|
||||
</div>
|
||||
<portal-footer></portal-footer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex'
|
||||
import portalHeader from '@/components/PortalHeader.vue'
|
||||
import portalFooter from '@/components/PortalFooter.vue'
|
||||
export default {
|
||||
name: "LayoutPortal",
|
||||
components:{portalHeader,portalFooter},
|
||||
computed:{
|
||||
...mapGetters(['userInfo']),
|
||||
key() {
|
||||
return this.$route.path
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 版本号
|
||||
version: "1.0.0"
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
|
||||
|
||||
},
|
||||
methods: {
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
</style>
|
||||
Reference in New Issue
Block a user