更新el-admin-layout版本 0.5.1 -> 0.8.2

master
toesbieya 5 years ago
parent 9ba53f7dbe
commit 21f31cfed1
  1. 6
      vue/full/package-lock.json
  2. 2
      vue/full/package.json
  3. 9
      vue/full/src/asset/style/cover/el-admin-layout.scss
  4. 25
      vue/full/src/layout/component/HeaderRight/index.vue
  5. 2
      vue/full/src/layout/component/NotifyBell/index.vue
  6. 258
      vue/full/src/layout/component/SettingDrawer/index.vue
  7. 2
      vue/full/src/layout/component/SettingDrawer/mixin/tagsViewPersistent.js
  8. 7
      vue/full/src/layout/component/SettingDrawer/mixin/tagsViewShortcut.js
  9. 21
      vue/full/src/layout/component/SettingDrawer/style.scss
  10. 143
      vue/full/src/layout/index.vue
  11. 117
      vue/full/src/store/module/setting.js

@ -4447,9 +4447,9 @@
"dev": true "dev": true
}, },
"el-admin-layout": { "el-admin-layout": {
"version": "0.5.1", "version": "0.8.2",
"resolved": "https://registry.npmjs.org/el-admin-layout/-/el-admin-layout-0.5.1.tgz", "resolved": "https://registry.npmjs.org/el-admin-layout/-/el-admin-layout-0.8.2.tgz",
"integrity": "sha512-nFtk2zrpJ6xsxJM3tAD7+qjHYvBA2MHcayEO6nU3kRpmeC/K0Zxw4WNEUlxbhqCTzziTIX6xl/0Hr325EorvKA==" "integrity": "sha512-6D5i70GqrPmw2AQo8ntLN1k1JWCYDdM6wNBX0errsJS9vDetxF3LuJHmqVQzZzm5t7RHH1FuOlQa8eKdHhCi4w=="
}, },
"electron-to-chromium": { "electron-to-chromium": {
"version": "1.3.681", "version": "1.3.681",

@ -10,7 +10,7 @@
"dependencies": { "dependencies": {
"axios": "^0.21.1", "axios": "^0.21.1",
"decimal.js": "^10.2.1", "decimal.js": "^10.2.1",
"el-admin-layout": "^0.5.1", "el-admin-layout": "^0.8.2",
"element-ui": "^2.15.1", "element-ui": "^2.15.1",
"file-saver": "^2.0.5", "file-saver": "^2.0.5",
"js-md5": "^0.7.3", "js-md5": "^0.7.3",

@ -2,3 +2,12 @@
.page-main > .scroll-container { .page-main > .scroll-container {
overflow: overlay; overflow: overlay;
} }
//TODO 升级el-admin-layout至0.8.3可解决
.right-out,
.left-out {
&-leave-active,
&-enter-active {
position: inherit;
}
}

@ -0,0 +1,25 @@
<script>
import NotifyBell from '../NotifyBell'
export default {
name: "HeaderRight",
functional: true,
props: {default: Array},
render(h, context) {
const custom = [
<NotifyBell class="header-item"/>,
<div
class="setting-btn header-item"
title="个性设置"
on-click={context.parent.openSettingDrawer}
>
<i class="el-icon-s-operation header-icon"/>
</div>
]
return custom.concat(context.props.default)
}
}
</script>

@ -1,6 +1,6 @@
<template> <template>
<el-badge :hidden="hidden" class="notify-bell-badge" is-dot title="消息提醒" @click.native="jump"> <el-badge :hidden="hidden" class="notify-bell-badge" is-dot title="消息提醒" @click.native="jump">
<i class="el-icon-bell navbar-icon"/> <i class="el-icon-bell header-icon"/>
</el-badge> </el-badge>
</template> </template>

@ -2,14 +2,14 @@
<el-drawer <el-drawer
:visible="visible" :visible="visible"
:with-header="false" :with-header="false"
custom-class="setting-drawer"
append-to-body append-to-body
size="288px" size="300px"
@close="close" @close="visible = false"
> >
<div class="drawer-container">
<el-divider>导航模式</el-divider> <el-divider>导航模式</el-divider>
<div class="drawer-item"> <div class="setting-drawer-item">
<checkbox-group v-model="setting.app.navMode"> <checkbox-group :value="setting.app.navMode" @input="v => onChange('app/navMode', v)">
<img-checkbox <img-checkbox
v-for="{label, value, img} in navModes" v-for="{label, value, img} in navModes"
:key="value" :key="value"
@ -20,13 +20,12 @@
</checkbox-group> </checkbox-group>
</div> </div>
<el-divider>导航栏设置</el-divider> <el-divider>栏设置</el-divider>
<div class="drawer-item"> <div class="setting-drawer-item">
<span>主题风格</span> <span>主题风格</span>
<el-select <el-select
v-model="setting.navbar.theme" :value="setting.header.theme"
size="mini" @input="v => onChange('header/theme', v)"
style="width: 80px"
> >
<el-option value="light" label="亮色"/> <el-option value="light" label="亮色"/>
<el-option value="dark" label="暗色"/> <el-option value="dark" label="暗色"/>
@ -34,96 +33,117 @@
</div> </div>
<el-divider>侧边栏设置</el-divider> <el-divider>侧边栏设置</el-divider>
<div class="drawer-item"> <div class="setting-drawer-item">
<span>主题风格</span> <span>主题风格</span>
<el-select <el-select
v-model="setting.aside.theme" :value="setting.aside.theme"
size="mini" @input="v => onChange('aside/theme', v)"
style="width: 80px"
> >
<el-option value="light" label="亮色"/> <el-option value="light" label="亮色"/>
<el-option value="dark" label="暗色"/> <el-option value="dark" label="暗色"/>
</el-select> </el-select>
</div> </div>
<div class="drawer-item"> <div class="setting-drawer-item">
<span>汉堡包位置</span>
<el-select
v-model="setting.aside.hamburgerPosition"
size="mini"
style="width: 90px"
>
<el-option value="aside" label="侧边栏"/>
<el-option value="head" label="导航栏"/>
</el-select>
</div>
<div class="drawer-item">
<span>手风琴效果</span> <span>手风琴效果</span>
<el-switch v-model="setting.aside.uniqueOpen"/> <el-switch
:value="setting.aside.uniqueOpen"
@input="v => onChange('aside/uniqueOpen', v)"
/>
</div> </div>
<div class="drawer-item"> <div class="setting-drawer-item">
<span>折叠</span> <span>折叠</span>
<el-switch v-model="setting.aside.collapse"/> <el-switch
:value="setting.aside.collapse"
@input="v => onChange('aside/collapse', v)"
/>
</div> </div>
<div class="drawer-item"> <div class="setting-drawer-item">
<span>折叠时显示上级</span> <span>折叠时显示上级</span>
<el-switch v-model="setting.aside.showParentOnCollapse"/> <el-switch
:value="setting.aside.showParentOnCollapse"
@input="v => onChange('aside/showParentOnCollapse', v)"
/>
</div> </div>
<div class="drawer-item"> <div class="setting-drawer-item">
<span>自动隐藏</span> <span>自动隐藏</span>
<el-switch v-model="setting.aside.autoHide"/> <el-switch
</div> :value="setting.aside.autoHide"
<div class="drawer-item"> @input="v => onChange('aside/autoHide', v)"
<span>显示搜索框</span> />
<el-switch v-model="setting.aside.search"/>
</div> </div>
<el-divider>页面设置</el-divider> <el-divider>页面设置</el-divider>
<div class="drawer-item"> <div class="setting-drawer-item">
<span>分层结构</span> <span>分层结构</span>
<el-select <el-select
v-model="setting.page.position" :value="setting.app.struct"
size="mini" @input="v => onChange('app/struct', v)"
style="width: 80px"
> >
<el-option value="top-bottom" label="上下"/> <el-option value="top-bottom" label="上下"/>
<el-option value="left-right" label="左右"/> <el-option value="left-right" label="左右"/>
</el-select> </el-select>
</div> </div>
<div class="drawer-item"> <div class="setting-drawer-item">
<span>显示logo</span> <span>显示logo</span>
<el-switch v-model="setting.page.showLogo"/> <el-switch
:value="setting.app.showLogo"
@input="v => onChange('app/showLogo', v)"
/>
</div> </div>
<div class="drawer-item"> <div class="setting-drawer-item">
<span>显示页头</span> <span>显示页头</span>
<el-switch v-model="setting.page.showHeader"/> <el-switch
:value="setting.page.showHeader"
@input="v => onChange('page/showHeader', v)"
/>
</div> </div>
<div class="drawer-item"> <div class="setting-drawer-item">
<span>显示页脚</span> <span>显示页脚</span>
<el-switch v-model="setting.page.showFooter"/> <el-switch
</div> :value="setting.page.showFooter"
<div class="drawer-item"> @input="v => onChange('page/showFooter', v)"
<span>显示返回顶部按钮</span> />
<el-switch v-model="setting.page.showBackToTop"/>
</div> </div>
<el-divider>多页签设置</el-divider> <el-divider>多页签设置</el-divider>
<div class="drawer-item"> <div class="setting-drawer-item">
<span>启用</span> <span>启用</span>
<el-switch v-model="setting.tagsView.enabled"/> <el-switch
:value="setting.tagsView.enabled"
@input="v => onChange('tagsView/enabled', v)"
/>
</div> </div>
<div class="drawer-item"> <div class="setting-drawer-item">
<span>启用缓存</span> <span>启用缓存</span>
<el-switch v-model="setting.tagsView.enableCache"/> <el-switch
:value="setting.tagsView.enableCache"
@input="v => onChange('tagsView/enableCache', v)"
/>
</div> </div>
<div class="drawer-item"> <div class="setting-drawer-item">
<span>启用快捷键切换</span> <span>启用快捷键切换</span>
<el-switch v-model="setting.tagsView.shortcut"/> <el-switch
:value="setting.tagsView.shortcut"
@input="v => onChange('tagsView/shortcut', v)"
/>
</div> </div>
<div class="drawer-item"> <div class="setting-drawer-item">
<span>持久化</span> <span>持久化</span>
<el-switch v-model="setting.tagsView.persistent"/> <el-switch
</div> :value="setting.tagsView.persistent"
@input="v => onChange('tagsView/persistent', v)"
/>
</div> </div>
<el-divider/>
<el-button
type="primary"
size="medium"
icon="el-icon-delete"
@click="clearCacheAndReload"
>
清除设置缓存并刷新
</el-button>
</el-drawer> </el-drawer>
</template> </template>
@ -133,24 +153,21 @@ import tagsViewShortcutMixin from "./mixin/tagsViewShortcut"
import CheckboxGroup from "./component/checkbox/Group" import CheckboxGroup from "./component/checkbox/Group"
import ColorCheckbox from "./component/checkbox/ColorCheckbox" import ColorCheckbox from "./component/checkbox/ColorCheckbox"
import ImgCheckbox from "./component/checkbox/ImgCheckbox" import ImgCheckbox from "./component/checkbox/ImgCheckbox"
import {appMutations, asideMutations, navbarMutations, pageMutations, tagsViewMutations} from "el-admin-layout" import {setLocalPersonalSettings} from "@/util/storage"
import {mergeObj} from "@/util"
import {getLocalPersonalSettings, setLocalPersonalSettings} from "@/util/storage"
export default { export default {
name: "SettingDrawer", name: "SettingDrawer",
mixins: [tagsViewPersistentMixin, tagsViewShortcutMixin], mixins: [tagsViewPersistentMixin, tagsViewShortcutMixin],
//el-selectsizemini
provide: () => ({elFormItem: {elFormItemSize: 'mini'}}),
components: {CheckboxGroup, ColorCheckbox, ImgCheckbox}, components: {CheckboxGroup, ColorCheckbox, ImgCheckbox},
data() { data() {
return { return {
//vue
getRoot: () => undefined,
visible: false, visible: false,
navModes: [ navModes: [
{ {
label: '侧边栏导航', label: '侧边栏导航',
@ -166,111 +183,28 @@ export default {
label: '混合导航', label: '混合导航',
value: 'mix', value: 'mix',
img: 'https://gw.alipayobjects.com/zos/antfincdn/x8Ob%26B8cy8/LCkqqYNmvBEbokSDscrm.svg' img: 'https://gw.alipayobjects.com/zos/antfincdn/x8Ob%26B8cy8/LCkqqYNmvBEbokSDscrm.svg'
},
{
label: '双层侧边栏导航',
value: 'aside-two-part',
img: 'https://gw.alipayobjects.com/zos/antfincdn/XwFOFbLkSM/LCkqqYNmvBEbokSDscrm.svg'
}
],
setting: {
app: {
navMode: 'mix'
},
page: {
position: 'left-right',
showLogo: true,
showHeader: true,
showFooter: true,
showBackToTop: true
},
aside: {
theme: 'dark',
hamburgerPosition: 'aside',
uniqueOpen: true,
collapse: false,
showParentOnCollapse: false,
autoHide: false,
search: true
},
navbar: {
theme: 'dark'
},
tagsView: {
enabled: true,
enableCache: true,
shortcut: true,
persistent: true
} }
]
} }
}
},
methods: {
close() {
this.visible = false
}, },
getMutationsByType(type) { computed: {
switch (type) { setting() {
case 'app': return this.$store.state.setting
return appMutations
case 'aside':
return asideMutations
case 'navbar':
return navbarMutations
case 'page':
return pageMutations
case 'tagsView':
return tagsViewMutations
} }
}, },
//layoutstore methods: {
syncLayoutStore() { //vuex
const {app, page, aside, navbar, tagsView} = this.setting onChange(type, val) {
this.$store.commit(`setting/${type}`, val)
Object.entries(app).forEach(([k, v]) => appMutations[k](v))
Object.entries(page).forEach(([k, v]) => pageMutations[k](v))
Object.entries(aside).forEach(([k, v]) => asideMutations[k](v))
Object.entries(navbar).forEach(([k, v]) => navbarMutations[k](v))
tagsViewMutations.enabled(tagsView.enabled)
tagsViewMutations.enableCache(tagsView.enableCache)
}
}, },
created() { //layout
// clearCacheAndReload() {
mergeObj(this.setting, getLocalPersonalSettings()) setLocalPersonalSettings()
window.location.reload()
//
setLocalPersonalSettings(this.setting)
this.syncLayoutStore()
//
const noop = () => undefined
Object.entries(this.setting).forEach(([type, v]) => {
const mutations = this.getMutationsByType(type)
Object.keys(v).forEach(key => {
const mutation = (() => {
const fun = mutations[key]
//tagsView
return fun ? newVal => fun(newVal) : noop
})()
this.$watch(
`setting.${type}.${key}`,
v => {
mutation(v)
setLocalPersonalSettings(this.setting)
} }
)
})
})
} }
} }
</script> </script>

@ -45,7 +45,7 @@ export default {
const tags = getTagsView() const tags = getTagsView()
Array.isArray(tags) && tags.forEach(({fullPath, meta}) => { Array.isArray(tags) && tags.forEach(({fullPath, meta}) => {
const {route} = this.getRoot().$router.resolve(fullPath) const {route} = this.$router.resolve(fullPath)
route && tagsViewMutations.addTagOnly({...route, meta: {...route.meta, ...meta}}) route && tagsViewMutations.addTagOnly({...route, meta: {...route.meta, ...meta}})
}) })
} }

@ -22,13 +22,10 @@ export default {
methods: { methods: {
gotoViewByDirection(direction) { gotoViewByDirection(direction) {
const root = this.getRoot()
if (!root) return
const views = tagsViewGetters.visitedViews const views = tagsViewGetters.visitedViews
if (views.length <= 1) return if (views.length <= 1) return
const key = getRouterKey(root.$route) const key = getRouterKey(this.$route)
let index = views.findIndex(view => view.key === key) let index = views.findIndex(view => view.key === key)
if (index < 0) return if (index < 0) return
@ -41,7 +38,7 @@ export default {
index = index > views.length - 2 ? 0 : index + 1 index = index > views.length - 2 ? 0 : index + 1
} }
return root.$router.push(views[index]) return this.$router.push(views[index])
}, },
//快捷键监听 //快捷键监听

@ -1,17 +1,26 @@
@import "~@/asset/style/var"; @import "~@/asset/style/var";
@import "./component/checkbox/style"; @import "./component/checkbox/style";
.drawer-container { .setting-drawer {
padding: 24px; overflow-y: auto;
font-size: 14px;
line-height: 1.5; .el-drawer__body {
word-wrap: break-word; padding: $--dialog-padding-primary;
}
.drawer-item { &-item {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
color: $--color-text-regular; color: $--color-text-regular;
font-size: 14px; font-size: 14px;
padding: 12px 0; padding: 12px 0;
} }
.el-select {
width: 80px;
}
.el-button {
width: 100%;
}
} }

@ -1,13 +1,34 @@
<template> <template>
<el-admin-layout :navbar-props="navbarProps" :page-props="pageProps"/> <div style="height: 100%">
<el-admin-layout>
<!--设置icon渲染-->
<template v-slot:aside-menu-icon="{menu}">
<v-icon :icon="menu.meta.icon" class="menu-icon"/>
</template>
<template v-slot:header-menu-icon="{menu}">
<v-icon :icon="menu.meta.icon" class="menu-icon"/>
</template>
<!--自定义顶栏右侧元素-->
<template v-slot:header-right="defaultContent">
<header-right :default="defaultContent"/>
</template>
<!--页脚-->
<template v-slot:page-footer>
<v-footer/>
</template>
</el-admin-layout>
<setting-drawer ref="setting-drawer"/>
</div>
</template> </template>
<script type="text/jsx"> <script type="text/jsx">
import Vue from 'vue'
import config from "@/config" import config from "@/config"
import ElAdminLayout, {Const, appMutations} from 'el-admin-layout' import ElAdminLayout, {appMutations, headerMutations} from 'el-admin-layout'
import Footer from './component/Footer' import HeaderRight from './component/HeaderRight'
import NotifyBell from './component/NotifyBell' import VFooter from './component/Footer'
import SettingDrawer from './component/SettingDrawer' import SettingDrawer from './component/SettingDrawer'
import offlineMixin from './mixin/offline' import offlineMixin from './mixin/offline'
import {elConfirm} from "@/util/message" import {elConfirm} from "@/util/message"
@ -16,25 +37,22 @@ import {elConfirm} from "@/util/message"
appMutations.title(config.title) appMutations.title(config.title)
appMutations.logo(config.logo) appMutations.logo(config.logo)
//
Const.iconRenderer = (h, icon) => <v-icon icon={icon}/>
export default { export default {
name: "Layout", name: "Layout",
mixins: [offlineMixin], mixins: [offlineMixin],
components: {ElAdminLayout, NotifyBell, SettingDrawer}, components: {ElAdminLayout, HeaderRight, VFooter, SettingDrawer},
data() { data() {
return { return {
guideSteps: [ guideSteps: [
{ {
element: '.setting-btn.navbar-item', element: '.setting-btn.header-item',
content: '这是个性设置按钮,可以根据自己喜好进行一些设置', content: '这是个性设置按钮,可以根据自己喜好进行一些设置',
}, },
{ {
element: '.navbar .el-dropdown.navbar-item', element: '.header .el-dropdown.header-item',
content: '这是用户中心', content: '这是用户中心',
}, },
{ {
@ -48,13 +66,44 @@ export default {
} }
}, },
computed: { methods: {
navbarProps() { toUserCenter() {
this.$router.push('/user', () => undefined)
},
startGuide() {
this.$guide(this.guideSteps)
},
logout() {
if (this.$store.state.user.prepareLogout) {
return
}
elConfirm('确认退出?').then(() => this.$store.dispatch('user/logout'))
},
openSettingDrawer() {
this.$refs['setting-drawer'].visible = true
}
},
created() {
//
this.$watch(
() => {
const userInfo = this.$store.state.user const userInfo = this.$store.state.user
return { return {
avatar: userInfo.avatar, avatar: userInfo.avatar,
username: userInfo.name, username: userInfo.name
userDropdownItems: [ }
},
({avatar, username}) => {
headerMutations.avatar(avatar)
headerMutations.username(username)
},
{immediate: true}
)
//
headerMutations.dropdownItems([
{ {
icon: 'el-icon-user', icon: 'el-icon-user',
command: 'user-center', command: 'user-center',
@ -74,69 +123,7 @@ export default {
content: '退出登录', content: '退出登录',
handler: this.logout handler: this.logout
} }
], ])
renderCustomActions: this.renderNavbarActions
}
},
pageProps() {
return {
renderFooter: () => <Footer/>
}
}
},
methods: {
toUserCenter() {
const path = '/user'
this.$route.path !== path && this.$router.push(path)
},
startGuide() {
this.$guide(this.guideSteps)
},
logout() {
if (this.$store.state.user.prepareLogout) {
return
}
elConfirm('确认退出?').then(() => this.$store.dispatch('user/logout'))
},
openSettingDrawer() {
this.$_settingDrawerInstance.visible = true
},
renderNavbarActions(defaultActions) {
const customActions = [
<notify-bell class="navbar-item"/>,
<div
class="setting-btn navbar-item"
title="个性设置"
on-click={this.openSettingDrawer}
>
<i class="el-icon-s-operation navbar-icon"/>
</div>
]
return customActions.concat(defaultActions.map(f => f()))
}
},
//layout
beforeCreate() {
const Drawer = Vue.extend(SettingDrawer)
const instance = new Drawer({data: {getRoot: () => this}}).$mount()
document.body.appendChild(instance.$el)
this.$_settingDrawerInstance = instance
},
//
beforeDestroy() {
if (this.$_settingDrawerInstance) {
this.$_settingDrawerInstance.$destroy()
this.$_settingDrawerInstance.$el.remove()
delete this.$_settingDrawerInstance
} }
},
} }
</script> </script>

@ -0,0 +1,117 @@
import {mergeObj} from "@/util"
import {getLocalPersonalSettings, setLocalPersonalSettings} from '@/util/storage'
import {
appMutations,
asideMutations,
headerMutations,
pageMutations,
tagsViewMutations
} from "el-admin-layout"
const noop = () => undefined
function getLayoutMutationsByType(type) {
switch (type) {
case 'app':
return appMutations
case 'aside':
return asideMutations
case 'header':
return headerMutations
case 'page':
return pageMutations
case 'tagsView':
return tagsViewMutations
}
}
//app.navMode -> commit('setting/app/navMode')
function createMutations(state, mutations = Object.create(null), parentType = '') {
Object.entries(state).forEach(([k, v]) => {
const type = parentType ? `${parentType}/${k}` : k
if (v !== null && typeof v === 'object') {
return createMutations(v, mutations, type)
}
//反正只有两项,偷个懒
const [mutationType, mutationProp] = type.split('/')
const layoutMutation = (() => {
const fun = getLayoutMutationsByType(mutationType)[mutationProp]
//像tagsView中就有两项是没有对应的修改方法的
return fun ? newVal => fun(newVal) : noop
})()
mutations[type] = (s, v) => {
const val = s[mutationType]
if (val[mutationProp] === v) return
val[mutationProp] = v
layoutMutation(v)
setLocalPersonalSettings(s)
}
})
return mutations
}
//将此处的设置项数据同步到layout中的store
function syncLayoutStore(state) {
const {app, page, aside, header, tagsView} = state
Object.entries(app).forEach(([k, v]) => appMutations[k](v))
Object.entries(page).forEach(([k, v]) => pageMutations[k](v))
Object.entries(aside).forEach(([k, v]) => asideMutations[k](v))
Object.entries(header).forEach(([k, v]) => headerMutations[k](v))
tagsViewMutations.enabled(tagsView.enabled)
tagsViewMutations.enableCache(tagsView.enableCache)
}
const state = {
app: {
showLogo: true,
struct: 'left-right',
navMode: 'mix'
},
page: {
showHeader: true,
showFooter: true
},
aside: {
theme: 'dark',
uniqueOpen: true,
collapse: false,
showParentOnCollapse: false,
autoHide: false
},
header: {
theme: 'dark'
},
tagsView: {
enabled: true,
enableCache: true,
shortcut: true,
persistent: true
}
}
const mutations = createMutations(state)
//将本地存储的数据合并到此处
mergeObj(state, getLocalPersonalSettings())
//由于数据结构可能发生变化,所以在合并后覆盖本地数据
setLocalPersonalSettings(state)
syncLayoutStore(state)
export default {
namespaced: true,
state,
mutations
}
Loading…
Cancel
Save