add settings (#1707)
This commit is contained in:
parent
537ecf9990
commit
e855f6a121
|
@ -0,0 +1,140 @@
|
||||||
|
<template>
|
||||||
|
<div ref="rightPanel" :class="{show:show}" class="rightPanel-container">
|
||||||
|
<div class="rightPanel-background" />
|
||||||
|
<div class="rightPanel">
|
||||||
|
<div class="handle-button" :style="{'top':buttonTop+'px'}" type="primary" circle @click="show=!show">
|
||||||
|
<i :class="show?'el-icon-close':'el-icon-setting'" />
|
||||||
|
</div>
|
||||||
|
<div class="rightPanel-items">
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { addClass, removeClass } from '@/utils'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'RightPanel',
|
||||||
|
props: {
|
||||||
|
clickNotClose: {
|
||||||
|
default: false,
|
||||||
|
type: Boolean
|
||||||
|
},
|
||||||
|
buttonTop: {
|
||||||
|
default: 240,
|
||||||
|
type: Number
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
show: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
show(value) {
|
||||||
|
if (value && !this.clickNotClose) {
|
||||||
|
this.addEventClick()
|
||||||
|
}
|
||||||
|
if (value) {
|
||||||
|
addClass(document.body, 'showRightPanel')
|
||||||
|
} else {
|
||||||
|
removeClass(document.body, 'showRightPanel')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.insertToBody()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
addEventClick() {
|
||||||
|
window.addEventListener('click', this.closeSidebar)
|
||||||
|
},
|
||||||
|
closeSidebar(evt) {
|
||||||
|
const parent = evt.target.closest('.rightPanel')
|
||||||
|
if (!parent) {
|
||||||
|
this.show = false
|
||||||
|
window.removeEventListener('click', this.closeSidebar)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
insertToBody() {
|
||||||
|
const elx = this.$refs.rightPanel
|
||||||
|
const body = document.querySelector('body')
|
||||||
|
body.insertBefore(elx, body.firstChild)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.showRightPanel {
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
|
width: calc(100% - 15px);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style rel="stylesheet/scss" lang="scss" scoped>
|
||||||
|
.rightPanel-background {
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity .3s cubic-bezier(.7,.3,.1,1);
|
||||||
|
background: rgba(0, 0, 0, .2);
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
position: fixed;
|
||||||
|
z-index: -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rightPanel {
|
||||||
|
background: #fff;
|
||||||
|
z-index: 3000;
|
||||||
|
position: fixed;
|
||||||
|
height: 100vh;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 260px;
|
||||||
|
top: 0px;
|
||||||
|
left: 0px;
|
||||||
|
box-shadow: 0px 0px 15px 0px rgba(0, 0, 0, .05);
|
||||||
|
transition: all .25s cubic-bezier(.7,.3,.1,1);
|
||||||
|
transform: translate(100%);
|
||||||
|
z-index: 40000;
|
||||||
|
left: auto;
|
||||||
|
right: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.show {
|
||||||
|
|
||||||
|
transition: all .3s cubic-bezier(.7,.3,.1,1);
|
||||||
|
.rightPanel-background {
|
||||||
|
z-index: 20000;
|
||||||
|
opacity: 1;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rightPanel {
|
||||||
|
transform: translate(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.handle-button {
|
||||||
|
position: absolute;
|
||||||
|
left: -48px;
|
||||||
|
border-radius: 4px 0 0 4px !important;
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
background: #1890ff;
|
||||||
|
cursor: pointer;
|
||||||
|
pointer-events: auto;
|
||||||
|
z-index: 0;
|
||||||
|
text-align: center;
|
||||||
|
color: #fff;
|
||||||
|
line-height: 48px;
|
||||||
|
|
||||||
|
i {
|
||||||
|
font-size: 24px;
|
||||||
|
line-height: 48px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -2,34 +2,41 @@
|
||||||
<div :class="classObj" class="app-wrapper">
|
<div :class="classObj" class="app-wrapper">
|
||||||
<div v-if="device==='mobile'&&sidebar.opened" class="drawer-bg" @click="handleClickOutside" />
|
<div v-if="device==='mobile'&&sidebar.opened" class="drawer-bg" @click="handleClickOutside" />
|
||||||
<sidebar class="sidebar-container" />
|
<sidebar class="sidebar-container" />
|
||||||
<div class="main-container">
|
<div :class="{hasTagsView:needTagsView}" class="main-container">
|
||||||
<navbar />
|
<navbar />
|
||||||
<tags-view />
|
<tags-view v-if="needTagsView" />
|
||||||
<app-main />
|
<app-main />
|
||||||
|
<right-panel v-if="showSettings">
|
||||||
|
<settings />
|
||||||
|
</right-panel>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { Navbar, Sidebar, AppMain, TagsView } from './components'
|
import RightPanel from '@/components/RightPanel'
|
||||||
|
import { Navbar, Sidebar, AppMain, TagsView, Settings } from './components'
|
||||||
import ResizeMixin from './mixin/ResizeHandler'
|
import ResizeMixin from './mixin/ResizeHandler'
|
||||||
|
import { mapState } from 'vuex'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Layout',
|
name: 'Layout',
|
||||||
components: {
|
components: {
|
||||||
|
RightPanel,
|
||||||
Navbar,
|
Navbar,
|
||||||
Sidebar,
|
Sidebar,
|
||||||
AppMain,
|
AppMain,
|
||||||
TagsView
|
TagsView,
|
||||||
|
Settings
|
||||||
},
|
},
|
||||||
mixins: [ResizeMixin],
|
mixins: [ResizeMixin],
|
||||||
computed: {
|
computed: {
|
||||||
sidebar() {
|
...mapState({
|
||||||
return this.$store.state.app.sidebar
|
sidebar: state => state.app.sidebar,
|
||||||
},
|
device: state => state.app.device,
|
||||||
device() {
|
showSettings: state => state.settings.showSettings,
|
||||||
return this.$store.state.app.device
|
needTagsView: state => state.settings.tagsView
|
||||||
},
|
}),
|
||||||
classObj() {
|
classObj() {
|
||||||
return {
|
return {
|
||||||
hideSidebar: !this.sidebar.opened,
|
hideSidebar: !this.sidebar.opened,
|
||||||
|
|
|
@ -24,11 +24,16 @@ export default {
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.app-main {
|
.app-main {
|
||||||
/*84 = navbar + tags-view = 50 +34 */
|
/*50= navbar 50 */
|
||||||
min-height: calc(100vh - 84px);
|
min-height: calc(100vh - 50px);
|
||||||
width: 100%;
|
width: 100%;
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.hasTagsView .app-main {
|
||||||
|
/*84 = navbar + tags-view = 50 + 34 */
|
||||||
|
min-height: calc(100vh - 84px);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|
|
@ -92,9 +92,16 @@ export default {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style rel="stylesheet/scss" lang="scss" scoped>
|
<style rel="stylesheet/scss" lang="scss" scoped>
|
||||||
|
.hasTagsView {
|
||||||
|
.navbar {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.navbar {
|
.navbar {
|
||||||
height: 50px;
|
height: 50px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
box-shadow: 0 1px 4px rgba(0,21,41,.08);
|
||||||
|
|
||||||
.hamburger-container {
|
.hamburger-container {
|
||||||
line-height: 46px;
|
line-height: 46px;
|
||||||
|
@ -150,6 +157,7 @@ export default {
|
||||||
.avatar-wrapper {
|
.avatar-wrapper {
|
||||||
margin-top: 5px;
|
margin-top: 5px;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
.user-avatar {
|
.user-avatar {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
width: 40px;
|
width: 40px;
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
<template>
|
||||||
|
<div class="drawer-container">
|
||||||
|
<div>
|
||||||
|
<h3 class="drawer-title">
|
||||||
|
系统布局配置
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
<div class="drawer-item">
|
||||||
|
<span>开启 Tags-View</span>
|
||||||
|
<el-switch v-model="tagsView" class="drawer-switch" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- <div class="drawer-item">
|
||||||
|
<span>显示 Logo</span>
|
||||||
|
<el-switch v-model="sidebarLogo" class="drawer-switch" />
|
||||||
|
</div> -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
sidebarLogo: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
tagsView: {
|
||||||
|
get() {
|
||||||
|
return this.$store.state.settings.tagsView
|
||||||
|
},
|
||||||
|
set(val) {
|
||||||
|
this.$store.dispatch('changeSetting', {
|
||||||
|
key: 'tagsView',
|
||||||
|
value: val
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style rel="stylesheet/scss" lang="scss" scoped>
|
||||||
|
.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>
|
|
@ -2,3 +2,4 @@ export { default as Navbar } from './Navbar'
|
||||||
export { default as Sidebar } from './Sidebar/index.vue'
|
export { default as Sidebar } from './Sidebar/index.vue'
|
||||||
export { default as TagsView } from './TagsView/index.vue'
|
export { default as TagsView } from './TagsView/index.vue'
|
||||||
export { default as AppMain } from './AppMain'
|
export { default as AppMain } from './AppMain'
|
||||||
|
export { default as Settings } from './Settings'
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
export default {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {boolean} true | false
|
||||||
|
* @description Whether show the settings right-panel
|
||||||
|
*/
|
||||||
|
showSettings: true,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {boolean} true | false
|
||||||
|
* @description Whether need tagsView
|
||||||
|
*/
|
||||||
|
tagsView: true,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {string | array} 'production' | ['production','development']
|
||||||
|
* @description Need show err logs component.
|
||||||
|
* The default is only used in the production env
|
||||||
|
* If you want to use it in dev, you can pass ['production','development']
|
||||||
|
*/
|
||||||
|
errorLog: 'production'
|
||||||
|
}
|
|
@ -4,6 +4,7 @@ import app from './modules/app'
|
||||||
import errorLog from './modules/errorLog'
|
import errorLog from './modules/errorLog'
|
||||||
import permission from './modules/permission'
|
import permission from './modules/permission'
|
||||||
import tagsView from './modules/tagsView'
|
import tagsView from './modules/tagsView'
|
||||||
|
import settings from './modules/settings'
|
||||||
import user from './modules/user'
|
import user from './modules/user'
|
||||||
import getters from './getters'
|
import getters from './getters'
|
||||||
|
|
||||||
|
@ -15,6 +16,7 @@ const store = new Vuex.Store({
|
||||||
errorLog,
|
errorLog,
|
||||||
permission,
|
permission,
|
||||||
tagsView,
|
tagsView,
|
||||||
|
settings,
|
||||||
user
|
user
|
||||||
},
|
},
|
||||||
getters
|
getters
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
import defaultSettings from '@/settings'
|
||||||
|
const { showSettings, tagsView } = defaultSettings
|
||||||
|
|
||||||
|
const settings = {
|
||||||
|
state: {
|
||||||
|
showSettings: showSettings,
|
||||||
|
tagsView: tagsView
|
||||||
|
},
|
||||||
|
mutations: {
|
||||||
|
CHANGE_SETTING: (state, { key, value }) => {
|
||||||
|
if (state.hasOwnProperty(key)) {
|
||||||
|
state[key] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
changeSetting({ commit }, data) {
|
||||||
|
commit('CHANGE_SETTING', data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default settings
|
|
@ -299,3 +299,16 @@ export function createUniqueString() {
|
||||||
const randomNum = parseInt((1 + Math.random()) * 65536) + ''
|
const randomNum = parseInt((1 + Math.random()) * 65536) + ''
|
||||||
return (+(randomNum + timestamp)).toString(32)
|
return (+(randomNum + timestamp)).toString(32)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function hasClass(ele, cls) {
|
||||||
|
return !!ele.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)'))
|
||||||
|
}
|
||||||
|
export function addClass(ele, cls) {
|
||||||
|
if (!hasClass(ele, cls)) ele.className += ' ' + cls
|
||||||
|
}
|
||||||
|
export function removeClass(ele, cls) {
|
||||||
|
if (hasClass(ele, cls)) {
|
||||||
|
const reg = new RegExp('(\\s|^)' + cls + '(\\s|$)')
|
||||||
|
ele.className = ele.className.replace(reg, ' ')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue