2022年5月29日从svn移到git

This commit is contained in:
daihh
2022-05-29 18:56:34 +08:00
commit b050613020
488 changed files with 68444 additions and 0 deletions

View 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>

View 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>

View 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>

View 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)
}
}
}
}
}

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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
View 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
View 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>

View 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
View 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>