新版文件
Former-commit-id: f8cb004bc9c5fe881993aec4bc46f696bbc5a2c8
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
<template>
|
||||
<el-menu-item :index="menu.path || uniqueId">
|
||||
<i v-if="menu.icon" :class="`fa fa-${menu.icon}`"></i>
|
||||
<i v-else-if="menu.iconSvg">
|
||||
<d2-icon-svg :name="menu.iconSvg"/>
|
||||
</i>
|
||||
<i v-else class="fa fa-file-o"></i>
|
||||
<span slot="title">{{menu.title || '未命名菜单'}}</span>
|
||||
</el-menu-item>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { uniqueId } from 'lodash'
|
||||
export default {
|
||||
name: 'd2-layout-header-aside-menu-item',
|
||||
props: {
|
||||
menu: {
|
||||
type: Object,
|
||||
required: false,
|
||||
default: () => {}
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
uniqueId: uniqueId('d2-menu-empty-')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,41 @@
|
||||
<template>
|
||||
<el-submenu :index="menu.path || uniqueId">
|
||||
<template slot="title">
|
||||
<i v-if="menu.icon" :class="`fa fa-${menu.icon}`"></i>
|
||||
<i v-else-if="menu.iconSvg">
|
||||
<d2-icon-svg :name="menu.iconSvg"/>
|
||||
</i>
|
||||
<i v-else class="fa fa-folder-o"></i>
|
||||
<span slot="title">{{menu.title}}</span>
|
||||
</template>
|
||||
<template v-for="(child, childIndex) in menu.children">
|
||||
<d2-layout-header-aside-menu-item v-if="child.children === undefined" :menu="child" :key="childIndex"/>
|
||||
<d2-layout-header-aside-menu-sub v-else :menu="child" :key="childIndex"/>
|
||||
</template>
|
||||
</el-submenu>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { uniqueId } from 'lodash'
|
||||
// 组件
|
||||
import d2LayoutMainMenuItem from '../menu-item'
|
||||
|
||||
export default {
|
||||
name: 'd2-layout-header-aside-menu-sub',
|
||||
components: {
|
||||
'd2-layout-header-aside-menu-item': d2LayoutMainMenuItem
|
||||
},
|
||||
props: {
|
||||
menu: {
|
||||
type: Object,
|
||||
required: false,
|
||||
default: () => {}
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
uniqueId: uniqueId('d2-menu-empty-')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,61 @@
|
||||
<template>
|
||||
<div
|
||||
class="d2-contentmenu-list"
|
||||
@click="rowClick">
|
||||
<div
|
||||
v-for="item in menulist"
|
||||
:key="item.value"
|
||||
:data-value="item.value"
|
||||
class="d2-contentmenu-item"
|
||||
flex="cross:center main:center">
|
||||
<d2-icon
|
||||
v-if="item.icon"
|
||||
:name="item.icon"/>
|
||||
<div
|
||||
class="d2-contentmenu-item-title"
|
||||
flex-box="1">
|
||||
{{item.title}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'd2-contextmenu-list',
|
||||
props: {
|
||||
menulist: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
rowClick (event) {
|
||||
let target = event.target
|
||||
while (!target.dataset.value) {
|
||||
target = target.parentNode
|
||||
}
|
||||
this.$emit('rowClick', target.dataset.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.d2-contentmenu-list {
|
||||
.d2-contentmenu-item {
|
||||
padding: 8px 20px 8px 15px;
|
||||
margin: 0;
|
||||
font-size: 14px;
|
||||
color: #606266;
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
background: #ecf5ff;
|
||||
color: #66b1ff;
|
||||
}
|
||||
.d2-contentmenu-item-title {
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,71 @@
|
||||
<template>
|
||||
<div
|
||||
class="d2-contextmenu"
|
||||
v-show="flag"
|
||||
:style="style">
|
||||
<slot/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'd2-contextmenu',
|
||||
props: {
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
x: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
y: {
|
||||
type: Number,
|
||||
default: 0
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
flag: {
|
||||
get () {
|
||||
if (this.visible) {
|
||||
// 注册全局监听事件 [ 目前只考虑鼠标解除触发 ]
|
||||
window.addEventListener('mousedown', this.watchContextmenu)
|
||||
}
|
||||
return this.visible
|
||||
},
|
||||
set (newVal) {
|
||||
this.$emit('update:visible', newVal)
|
||||
}
|
||||
},
|
||||
style () {
|
||||
return {
|
||||
left: this.x + 'px',
|
||||
top: this.y + 'px',
|
||||
display: this.visible ? 'block' : 'none '
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
watchContextmenu (event) {
|
||||
if (!this.$el.contains(event.target) || event.button !== 0) this.flag = false
|
||||
window.removeEventListener('mousedown', this.watchContextmenu)
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
// 将菜单放置到body下
|
||||
document.querySelector('body').appendChild(this.$el)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.d2-contextmenu {
|
||||
position: absolute;
|
||||
padding: 5px 0;
|
||||
z-index: 2018;
|
||||
background: #FFF;
|
||||
border: 1px solid #cfd7e5;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 2px 12px 0 rgba(0,0,0,.1);
|
||||
}
|
||||
</style>
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
<template>
|
||||
<div
|
||||
class="d2-error-log-list__expand"
|
||||
:class="className">
|
||||
<p class="d2-error-log-list__expand-title">{{title}}</p>
|
||||
<p class="d2-error-log-list__expand-value">{{value === '' ? '无数据' : value}}</p>
|
||||
<slot/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
type: {
|
||||
default: 'log'
|
||||
},
|
||||
title: {
|
||||
default: ''
|
||||
},
|
||||
value: {
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
className () {
|
||||
return this.type === 'log' ? 'd2-error-log-list__expand--log' : 'd2-error-log-list__expand--error'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,195 @@
|
||||
<template>
|
||||
<el-table
|
||||
:data="logReverse"
|
||||
border
|
||||
stripe
|
||||
style="width: 100%"
|
||||
size="mini">
|
||||
|
||||
<el-table-column type="expand">
|
||||
<div slot-scope="props" class="d2-error-log-list__expand-group">
|
||||
<expand-item
|
||||
:type="props.row.type"
|
||||
title="类型"
|
||||
:value="props.row.type === 'log' ? '日志' : '异常'"/>
|
||||
<expand-item
|
||||
:type="props.row.type"
|
||||
title="内容"
|
||||
:value="props.row.info"/>
|
||||
<expand-item
|
||||
v-if="props.row.type === 'error'"
|
||||
type="error"
|
||||
title="报错组件"
|
||||
:value="get(props.row.vm, '$vnode.tag', '')"/>
|
||||
<expand-item
|
||||
v-if="props.row.type === 'error'"
|
||||
type="error"
|
||||
title="错误名称"
|
||||
:value="get(props.row.err, 'name', '')"/>
|
||||
<expand-item
|
||||
v-if="props.row.type === 'error'"
|
||||
type="error"
|
||||
title="错误信息"
|
||||
:value="get(props.row.err, 'message', '')"/>
|
||||
<expand-item
|
||||
v-if="props.row.type === 'error'"
|
||||
type="error"
|
||||
title="错误堆栈"
|
||||
value="见下">
|
||||
<div style="overflow: auto;">
|
||||
<pre>{{stackBeautify(props.row.err)}}</pre>
|
||||
</div>
|
||||
</expand-item>
|
||||
<expand-item
|
||||
:type="props.row.type"
|
||||
title="用户名"
|
||||
:value="get(props.row.user, 'name', '')"/>
|
||||
<expand-item
|
||||
:type="props.row.type"
|
||||
title="uuid"
|
||||
:value="props.row.uuid"/>
|
||||
<expand-item
|
||||
:type="props.row.type"
|
||||
title="token"
|
||||
:value="props.row.token"/>
|
||||
<expand-item
|
||||
:type="props.row.type"
|
||||
title="页面地址"
|
||||
:value="props.row.url"/>
|
||||
<expand-item
|
||||
:type="props.row.type"
|
||||
title="时间"
|
||||
:value="props.row.time"/>
|
||||
</div>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
prop="type"
|
||||
label="类型"
|
||||
width="80px"
|
||||
align="center"
|
||||
:filters="[
|
||||
{ text: '日志', value: 'log' },
|
||||
{ text: '异常', value: 'error' }
|
||||
]"
|
||||
:filter-multiple="false"
|
||||
:filter-method="filterType"
|
||||
filter-placement="bottom">
|
||||
<template slot-scope="scope">
|
||||
<el-tag
|
||||
v-if="scope.row.type === 'error'"
|
||||
size="mini"
|
||||
type="danger">
|
||||
<d2-icon name="bug"/> Bug
|
||||
</el-tag>
|
||||
<el-tag
|
||||
v-else
|
||||
size="mini"
|
||||
type="info">
|
||||
<d2-icon name="dot-circle-o"/> Log
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
label="地址"
|
||||
prop="url"
|
||||
width="140px"
|
||||
:show-overflow-tooltip="true">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
label="内容"
|
||||
prop="info"
|
||||
:show-overflow-tooltip="true">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
label="错误类型"
|
||||
width="140px"
|
||||
:show-overflow-tooltip="true">
|
||||
<template
|
||||
slot-scope="scope">
|
||||
{{get(scope.row.err, 'name', '')}}
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
label="错误信息"
|
||||
width="300px">
|
||||
<template
|
||||
slot-scope="scope">
|
||||
{{get(scope.row.err, 'message', '')}}
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
</el-table>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
import { get } from 'lodash'
|
||||
import ExpandItem from './components/ExpandItem'
|
||||
export default {
|
||||
name: 'd2-error-log-list',
|
||||
components: {
|
||||
ExpandItem
|
||||
},
|
||||
computed: {
|
||||
...mapState('d2admin', {
|
||||
logList: state => state.log.list
|
||||
}),
|
||||
logReverse () {
|
||||
// 直接 reverse 的话有点问题
|
||||
const res = []
|
||||
const loglength = this.logList.length
|
||||
this.logList.forEach((log, index) => {
|
||||
res.push(this.logList[loglength - 1 - index])
|
||||
})
|
||||
return res
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
get,
|
||||
filterType (value, row) {
|
||||
return row.type === value
|
||||
},
|
||||
stackBeautify (err) {
|
||||
if (!err) {
|
||||
return ''
|
||||
}
|
||||
return err.stack
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import '~@/assets/style/public.scss';
|
||||
.d2-error-log-list__expand-group {
|
||||
.d2-error-log-list__expand {
|
||||
padding-left: 20px;
|
||||
margin-bottom: 10px;
|
||||
&:last-child {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
.d2-error-log-list__expand-title {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
margin-top: 0px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.d2-error-log-list__expand-value {
|
||||
font-size: 12px;
|
||||
margin-top: 0px;
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
}
|
||||
.d2-error-log-list__expand--log {
|
||||
border-left: 4px solid $color-info;
|
||||
}
|
||||
.d2-error-log-list__expand--error {
|
||||
border-left: 4px solid $color-danger;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,82 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-tooltip
|
||||
effect="dark"
|
||||
:content="tooltipContent"
|
||||
placement="bottom">
|
||||
<el-button
|
||||
class="d2-ml-0 d2-mr btn-text can-hover"
|
||||
type="text"
|
||||
@click="handleClick">
|
||||
<el-badge
|
||||
v-if="logLength > 0"
|
||||
:max="99"
|
||||
:value="logLengthError"
|
||||
:is-dot="logLengthError === 0">
|
||||
<d2-icon
|
||||
:name="logLengthError === 0 ? 'dot-circle-o' : 'bug'"
|
||||
style="font-size: 20px"/>
|
||||
</el-badge>
|
||||
<d2-icon
|
||||
v-else
|
||||
name="dot-circle-o"
|
||||
style="font-size: 20px"/>
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
<el-dialog
|
||||
:title="tooltipContent"
|
||||
:fullscreen="true"
|
||||
:visible.sync="dialogVisible"
|
||||
:append-to-body="true">
|
||||
<div class="d2-mb-10">
|
||||
<el-button type="danger" size="mini" @click="handleLogClean">
|
||||
<d2-icon name="trash-o"/>
|
||||
清空
|
||||
</el-button>
|
||||
</div>
|
||||
<d2-error-log-list/>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapMutations } from 'vuex'
|
||||
import D2ErrorLogList from './components/list'
|
||||
export default {
|
||||
components: {
|
||||
D2ErrorLogList
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
dialogVisible: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters('d2admin', {
|
||||
logLength: 'log/length',
|
||||
logLengthError: 'log/lengthError'
|
||||
}),
|
||||
tooltipContent () {
|
||||
return this.logLength === 0
|
||||
? '没有日志或异常'
|
||||
: `${this.logLength} 条日志${this.logLengthError > 0
|
||||
? ` | 包含 ${this.logLengthError} 个异常`
|
||||
: ''}`
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapMutations('d2admin/log', [
|
||||
'clean'
|
||||
]),
|
||||
handleClick () {
|
||||
if (this.logLength > 0) {
|
||||
this.dialogVisible = true
|
||||
}
|
||||
},
|
||||
handleLogClean () {
|
||||
this.dialogVisible = false
|
||||
this.clean()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,27 @@
|
||||
<template>
|
||||
<el-tooltip
|
||||
effect="dark"
|
||||
:content="active ? '退出全屏' : '全屏'"
|
||||
placement="bottom">
|
||||
<el-button class="d2-mr btn-text can-hover" type="text" @click="toggle">
|
||||
<d2-icon v-if="active" name="compress"/>
|
||||
<d2-icon v-else name="arrows-alt" style="font-size: 16px"/>
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState, mapMutations } from 'vuex'
|
||||
export default {
|
||||
computed: {
|
||||
...mapState('d2admin/fullscreen', [
|
||||
'active'
|
||||
])
|
||||
},
|
||||
methods: {
|
||||
...mapMutations('d2admin/fullscreen', [
|
||||
'toggle'
|
||||
])
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,58 @@
|
||||
<template>
|
||||
<el-table :data="list" v-bind="table">
|
||||
<el-table-column prop="title" align="center" width="160"/>
|
||||
<el-table-column label="预览" width="120">
|
||||
<div
|
||||
slot-scope="scope"
|
||||
class="theme-preview"
|
||||
:style="{'backgroundImage': `url(${$baseUrl}${scope.row.preview})`}">
|
||||
</div>
|
||||
</el-table-column>
|
||||
<el-table-column prop="address" align="center">
|
||||
<template slot-scope="scope">
|
||||
<el-button v-if="activeName === scope.row.name" type="success" icon="el-icon-check" round>已激活</el-button>
|
||||
<el-button v-else round @click="handleSelectTheme(scope.row.name)">使用</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState, mapMutations } from 'vuex'
|
||||
export default {
|
||||
name: 'd2-theme-list',
|
||||
data () {
|
||||
return {
|
||||
table: {
|
||||
showHeader: false,
|
||||
border: true
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState('d2admin/theme', [
|
||||
'list',
|
||||
'activeName'
|
||||
])
|
||||
},
|
||||
methods: {
|
||||
...mapMutations('d2admin/theme', [
|
||||
'set'
|
||||
]),
|
||||
handleSelectTheme (name) {
|
||||
this.set(name)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '~@/assets/style/public.scss';
|
||||
.theme-preview {
|
||||
height: 50px;
|
||||
width: 100px;
|
||||
border-radius: 4px;
|
||||
background-size: cover;
|
||||
border: 1px solid $color-border-1;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,26 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-tooltip effect="dark" content="主题" placement="bottom">
|
||||
<el-button class="d2-ml-0 d2-mr btn-text can-hover" type="text" @click="dialogVisible = true">
|
||||
<d2-icon name="diamond" style="font-size: 16px"/>
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
<el-dialog title="主题" width="600px" :visible.sync="dialogVisible" :append-to-body="true">
|
||||
<d2-theme-list style="margin-top: -25px;"/>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import themeList from './components/d2-theme-list'
|
||||
export default {
|
||||
components: {
|
||||
'd2-theme-list': themeList
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
dialogVisible: false
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,36 @@
|
||||
<template>
|
||||
<el-dropdown class="d2-mr">
|
||||
<span class="btn-text">你好 {{info.name}}</span>
|
||||
<el-dropdown-menu slot="dropdown">
|
||||
<el-dropdown-item @click.native="logOff">
|
||||
<d2-icon name="power-off" class="d2-mr-5"/>
|
||||
注销
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState, mapActions } from 'vuex'
|
||||
export default {
|
||||
computed: {
|
||||
...mapState('d2admin/user', [
|
||||
'info'
|
||||
])
|
||||
},
|
||||
methods: {
|
||||
...mapActions('d2admin/account', [
|
||||
'logout'
|
||||
]),
|
||||
/**
|
||||
* @description 登出
|
||||
*/
|
||||
logOff () {
|
||||
this.logout({
|
||||
vm: this,
|
||||
confirm: true
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,30 @@
|
||||
<template>
|
||||
<el-menu mode="horizontal" @select="handleMenuSelect">
|
||||
<template v-for="(menu, menuIndex) in header">
|
||||
<d2-layout-header-aside-menu-item v-if="menu.children === undefined" :menu="menu" :key="menuIndex"/>
|
||||
<d2-layout-header-aside-menu-sub v-else :menu="menu" :key="menuIndex"/>
|
||||
</template>
|
||||
</el-menu>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
import menuMixin from '../mixin/menu'
|
||||
import d2LayoutMainMenuItem from '../components/menu-item/index.vue'
|
||||
import d2LayoutMainMenuSub from '../components/menu-sub/index.vue'
|
||||
export default {
|
||||
name: 'd2-layout-header-aside-menu-header',
|
||||
mixins: [
|
||||
menuMixin
|
||||
],
|
||||
components: {
|
||||
'd2-layout-header-aside-menu-item': d2LayoutMainMenuItem,
|
||||
'd2-layout-header-aside-menu-sub': d2LayoutMainMenuSub
|
||||
},
|
||||
computed: {
|
||||
...mapState('d2admin/menu', [
|
||||
'header'
|
||||
])
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,98 @@
|
||||
<template>
|
||||
<div class="d2-layout-header-aside-menu-side">
|
||||
<el-menu
|
||||
:collapse="asideCollapse"
|
||||
:unique-opened="true"
|
||||
:default-active="active"
|
||||
ref="menu"
|
||||
@select="handleMenuSelect">
|
||||
<template v-for="(menu, menuIndex) in aside">
|
||||
<d2-layout-header-aside-menu-item v-if="menu.children === undefined" :menu="menu" :key="menuIndex"/>
|
||||
<d2-layout-header-aside-menu-sub v-else :menu="menu" :key="menuIndex"/>
|
||||
</template>
|
||||
</el-menu>
|
||||
<div v-if="aside.length === 0 && !asideCollapse" class="d2-layout-header-aside-menu-empty" flex="dir:top main:center cross:center">
|
||||
<d2-icon name="inbox"/>
|
||||
<span>没有侧栏菜单</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
import menuMixin from '../mixin/menu'
|
||||
import d2LayoutMainMenuItem from '../components/menu-item/index.vue'
|
||||
import d2LayoutMainMenuSub from '../components/menu-sub/index.vue'
|
||||
import BScroll from 'better-scroll'
|
||||
export default {
|
||||
name: 'd2-layout-header-aside-menu-side',
|
||||
mixins: [
|
||||
menuMixin
|
||||
],
|
||||
components: {
|
||||
'd2-layout-header-aside-menu-item': d2LayoutMainMenuItem,
|
||||
'd2-layout-header-aside-menu-sub': d2LayoutMainMenuSub
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
active: '',
|
||||
asideHeight: 300,
|
||||
BS: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState('d2admin/menu', [
|
||||
'aside',
|
||||
'asideCollapse'
|
||||
])
|
||||
},
|
||||
watch: {
|
||||
// 折叠和展开菜单的时候销毁 better scroll
|
||||
asideCollapse (val) {
|
||||
this.scrollDestroy()
|
||||
setTimeout(() => {
|
||||
this.scrollInit()
|
||||
}, 500)
|
||||
},
|
||||
// 监听路由 控制侧边栏激活状态
|
||||
'$route.matched': {
|
||||
handler (val) {
|
||||
this.active = val[val.length - 1].path
|
||||
this.$nextTick(() => {
|
||||
if (this.aside.length > 0) {
|
||||
this.$refs.menu.activeIndex = this.active
|
||||
}
|
||||
})
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.scrollInit()
|
||||
},
|
||||
beforeDestroy () {
|
||||
this.scrollDestroy()
|
||||
},
|
||||
methods: {
|
||||
scrollInit () {
|
||||
this.BS = new BScroll(this.$el, {
|
||||
mouseWheel: true
|
||||
// 如果你愿意可以打开显示滚动条
|
||||
// scrollbar: {
|
||||
// fade: true,
|
||||
// interactive: false
|
||||
// }
|
||||
})
|
||||
},
|
||||
scrollDestroy () {
|
||||
// https://github.com/d2-projects/d2-admin/issues/75
|
||||
try {
|
||||
this.BS.destroy()
|
||||
} catch (e) {
|
||||
delete this.BS
|
||||
this.BS = null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,17 @@
|
||||
import util from '@/libs/util.js'
|
||||
|
||||
export default {
|
||||
methods: {
|
||||
handleMenuSelect (index, indexPath) {
|
||||
if (/^d2-menu-empty-\d+$/.test(index)) {
|
||||
this.$message.warning('临时菜单')
|
||||
} else if (/^https:\/\/|http:\/\//.test(index)) {
|
||||
util.open(index)
|
||||
} else {
|
||||
this.$router.push({
|
||||
path: index
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
<template>
|
||||
<div class="d2-multiple-page-control-group" flex>
|
||||
<div class="d2-multiple-page-control-content" flex-box="1">
|
||||
<div class="d2-multiple-page-control-content-inner">
|
||||
<d2-contextmenu
|
||||
:visible.sync="contextmenuFlag"
|
||||
:x="contentmenuX"
|
||||
:y="contentmenuY">
|
||||
<d2-contextmenu-list
|
||||
:menulist="tagName === 'index' ? contextmenuListIndex : contextmenuList"
|
||||
@rowClick="contextmenuClick"/>
|
||||
</d2-contextmenu>
|
||||
<el-tabs
|
||||
class="d2-multiple-page-control"
|
||||
:value="current"
|
||||
type="card"
|
||||
:closable="true"
|
||||
@tab-click="handleClick"
|
||||
@edit="handleTabsEdit"
|
||||
@contextmenu.native="handleContextmenu">
|
||||
<el-tab-pane
|
||||
v-for="(page, index) in opened"
|
||||
:key="index"
|
||||
:label="page.meta.title || '未命名'"
|
||||
:name="page.name"/>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="d2-multiple-page-control-btn"
|
||||
flex-box="0">
|
||||
<el-dropdown
|
||||
split-button
|
||||
@click="handleControlBtnClick"
|
||||
@command="command => handleControlItemClick(command)">
|
||||
<d2-icon name="times-circle"/>
|
||||
<el-dropdown-menu slot="dropdown">
|
||||
<el-dropdown-item command="left">
|
||||
<d2-icon name="arrow-left" class="d2-mr-10"/>
|
||||
关闭左侧
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item command="right">
|
||||
<d2-icon name="arrow-right" class="d2-mr-10"/>
|
||||
关闭右侧
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item command="other">
|
||||
<d2-icon name="times" class="d2-mr-10"/>
|
||||
关闭其它
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item command="all">
|
||||
<d2-icon name="times-circle" class="d2-mr-10"/>
|
||||
全部关闭
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState, mapMutations } from 'vuex'
|
||||
export default {
|
||||
components: {
|
||||
D2Contextmenu: () => import('../contextmenu'),
|
||||
D2ContextmenuList: () => import('../contextmenu/components/contentmenuList')
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
contextmenuFlag: false,
|
||||
contentmenuX: 0,
|
||||
contentmenuY: 0,
|
||||
contextmenuListIndex: [
|
||||
{ icon: 'times-circle', title: '关闭全部', value: 'all' }
|
||||
],
|
||||
contextmenuList: [
|
||||
{ icon: 'arrow-left', title: '关闭左侧', value: 'left' },
|
||||
{ icon: 'arrow-right', title: '关闭右侧', value: 'right' },
|
||||
{ icon: 'times', title: '关闭其它', value: 'other' },
|
||||
{ icon: 'times-circle', title: '关闭全部', value: 'all' }
|
||||
],
|
||||
tagName: 'index'
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState('d2admin/page', [
|
||||
'opened',
|
||||
'current'
|
||||
])
|
||||
},
|
||||
methods: {
|
||||
...mapMutations('d2admin/page', [
|
||||
'close',
|
||||
'closeLeft',
|
||||
'closeRight',
|
||||
'closeOther',
|
||||
'closeAll'
|
||||
]),
|
||||
/**
|
||||
* @description 右键菜单功能点击
|
||||
*/
|
||||
handleContextmenu (event) {
|
||||
let target = event.target
|
||||
|
||||
// 解决 https://github.com/d2-projects/d2-admin/issues/54
|
||||
let flag = false
|
||||
if (target.className.indexOf('el-tabs__item') > -1) flag = true
|
||||
else if (target.parentNode.className.indexOf('el-tabs__item') > -1) {
|
||||
target = target.parentNode
|
||||
flag = true
|
||||
}
|
||||
|
||||
if (flag) {
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
this.contentmenuX = event.clientX
|
||||
this.contentmenuY = event.clientY
|
||||
this.tagName = target.getAttribute('aria-controls').slice(5)
|
||||
this.contextmenuFlag = true
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @description 右键菜单的row-click事件
|
||||
*/
|
||||
contextmenuClick (command) {
|
||||
this.handleControlItemClick(command, this.tagName)
|
||||
},
|
||||
/**
|
||||
* @description 接收点击关闭控制上选项的事件
|
||||
*/
|
||||
handleControlItemClick (command, tagName = null) {
|
||||
if (tagName) {
|
||||
this.contextmenuFlag = false
|
||||
}
|
||||
const params = {
|
||||
pageSelect: tagName,
|
||||
vm: this
|
||||
}
|
||||
switch (command) {
|
||||
case 'left':
|
||||
this.closeLeft(params)
|
||||
break
|
||||
case 'right':
|
||||
this.closeRight(params)
|
||||
break
|
||||
case 'other':
|
||||
this.closeOther(params)
|
||||
break
|
||||
case 'all':
|
||||
this.closeAll(this)
|
||||
break
|
||||
default:
|
||||
this.$message.error('无效的操作')
|
||||
break
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @description 接收点击关闭控制上按钮的事件
|
||||
*/
|
||||
handleControlBtnClick () {
|
||||
this.closeAll(this)
|
||||
},
|
||||
/**
|
||||
* @description 接收点击 tab 标签的事件
|
||||
*/
|
||||
handleClick (tab, event) {
|
||||
// 找到点击的页面在 tag 列表里是哪个
|
||||
const page = this.opened.find(page => page.name === tab.name)
|
||||
const { name, params, query } = page
|
||||
if (page) {
|
||||
this.$router.push({ name, params, query })
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @description 点击 tab 上的删除按钮触发这里 首页的删除按钮已经隐藏 因此这里不用判断是 index
|
||||
*/
|
||||
handleTabsEdit (tagName, action) {
|
||||
if (action === 'remove') {
|
||||
this.close({
|
||||
tagName,
|
||||
vm: this
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,3 @@
|
||||
import layout from './layout'
|
||||
|
||||
export default layout
|
||||
@@ -0,0 +1,116 @@
|
||||
<template>
|
||||
<div
|
||||
class="d2-layout-header-aside-group"
|
||||
:style="styleLayoutMainGroup"
|
||||
:class="{grayMode: grayActive}">
|
||||
<!-- 半透明遮罩 -->
|
||||
<div class="d2-layout-header-aside-mask"></div>
|
||||
<!-- 主体内容 -->
|
||||
<div class="d2-layout-header-aside-content" flex="dir:top">
|
||||
<!-- 顶栏 -->
|
||||
<div class="d2-theme-header" flex-box="0">
|
||||
<div class="logo-group" :style="{width: asideCollapse ? asideWidthCollapse : asideWidth}">
|
||||
<img v-if="asideCollapse" :src="`${$baseUrl}image/theme/${themeActiveSetting.name}/logo/icon-only.png`">
|
||||
<img v-else :src="`${$baseUrl}image/theme/${themeActiveSetting.name}/logo/all.png`">
|
||||
</div>
|
||||
<div class="toggle-aside-btn" @click="handleToggleAside">
|
||||
<d2-icon name="bars"/>
|
||||
</div>
|
||||
<d2-menu-header/>
|
||||
<!-- 顶栏右侧 -->
|
||||
<div class="d2-header-right">
|
||||
<!-- 如果你只想在开发环境显示这个按钮请添加 v-if="$env === 'development'" -->
|
||||
<d2-header-error-log/>
|
||||
<d2-header-fullscreen/>
|
||||
<d2-header-theme/>
|
||||
<d2-header-user/>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 下面 主体 -->
|
||||
<div class="d2-theme-container" flex-box="1" flex>
|
||||
<!-- 主体 侧边栏 -->
|
||||
<div
|
||||
flex-box="0"
|
||||
ref="aside"
|
||||
class="d2-theme-container-aside"
|
||||
:style="{width: asideCollapse ? asideWidthCollapse : asideWidth}">
|
||||
<d2-menu-side/>
|
||||
</div>
|
||||
<!-- 主体 -->
|
||||
<div class="d2-theme-container-main" flex-box="1" flex="dir:top">
|
||||
<div class="d2-theme-container-main-header" flex-box="0">
|
||||
<d2-tabs/>
|
||||
</div>
|
||||
<div class="d2-theme-container-main-body" flex-box="1">
|
||||
<transition :name="transitionActive ? 'fade-transverse' : ''">
|
||||
<keep-alive :include="keepAlive">
|
||||
<router-view/>
|
||||
</keep-alive>
|
||||
</transition>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState, mapGetters, mapMutations } from 'vuex'
|
||||
export default {
|
||||
name: 'd2-layout-header-aside',
|
||||
components: {
|
||||
'd2-menu-side': () => import('./components/menu-side'),
|
||||
'd2-menu-header': () => import('./components/menu-header'),
|
||||
'd2-tabs': () => import('./components/tabs'),
|
||||
'd2-header-fullscreen': () => import('./components/header-fullscreen'),
|
||||
'd2-header-theme': () => import('./components/header-theme'),
|
||||
'd2-header-user': () => import('./components/header-user'),
|
||||
'd2-header-error-log': () => import('./components/header-error-log')
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// [侧边栏宽度] 正常状态
|
||||
asideWidth: '200px',
|
||||
// [侧边栏宽度] 折叠状态
|
||||
asideWidthCollapse: '65px'
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState('d2admin', {
|
||||
grayActive: state => state.gray.active,
|
||||
transitionActive: state => state.transition.active,
|
||||
asideCollapse: state => state.menu.asideCollapse
|
||||
}),
|
||||
...mapGetters('d2admin', {
|
||||
keepAlive: 'page/keepAlive',
|
||||
themeActiveSetting: 'theme/activeSetting'
|
||||
}),
|
||||
/**
|
||||
* @description 最外层容器的背景图片样式
|
||||
*/
|
||||
styleLayoutMainGroup () {
|
||||
return {
|
||||
...this.themeActiveSetting.backgroundImage ? {
|
||||
backgroundImage: `url('${this.$baseUrl}${this.themeActiveSetting.backgroundImage}')`
|
||||
} : {}
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapMutations('d2admin/menu', [
|
||||
'asideCollapseToggle'
|
||||
]),
|
||||
/**
|
||||
* 接收点击切换侧边栏的按钮
|
||||
*/
|
||||
handleToggleAside () {
|
||||
this.asideCollapseToggle()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
// 注册主题
|
||||
@import '~@/assets/style/theme/register.scss';
|
||||
</style>
|
||||
Reference in New Issue
Block a user