clean
Former-commit-id: 6d7a4adb3f160ed8ecc06ea9b3f566bffdcc086b
This commit is contained in:
@@ -1,27 +0,0 @@
|
||||
<template>
|
||||
<el-menu-item :index="menu.path || uniqueId">
|
||||
<i v-if="menu.icon" :class="`fa fa-${menu.icon}`"></i>
|
||||
<d2-icon-svg v-else-if="menu.iconSvg" :name="menu.iconSvg"/>
|
||||
<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>
|
||||
@@ -1,39 +0,0 @@
|
||||
<template>
|
||||
<el-submenu :index="menu.path || uniqueId">
|
||||
<template slot="title">
|
||||
<i v-if="menu.icon" :class="`fa fa-${menu.icon}`"></i>
|
||||
<d2-icon-svg v-else-if="menu.iconSvg" :name="menu.iconSvg"/>
|
||||
<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>
|
||||
@@ -1,61 +0,0 @@
|
||||
<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>
|
||||
@@ -1,71 +0,0 @@
|
||||
<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
@@ -1,30 +0,0 @@
|
||||
<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>
|
||||
@@ -1,195 +0,0 @@
|
||||
<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>
|
||||
@@ -1,82 +0,0 @@
|
||||
<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>
|
||||
@@ -1,27 +0,0 @@
|
||||
<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, mapActions } from 'vuex'
|
||||
export default {
|
||||
computed: {
|
||||
...mapState('d2admin/fullscreen', [
|
||||
'active'
|
||||
])
|
||||
},
|
||||
methods: {
|
||||
...mapActions('d2admin/fullscreen', [
|
||||
'toggle'
|
||||
])
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,15 +0,0 @@
|
||||
<template>
|
||||
<el-button class="d2-mr btn-text can-hover" type="text" @click="handleClick">
|
||||
<d2-icon name="search" style="font-size: 18px;"/>
|
||||
</el-button>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
methods: {
|
||||
handleClick () {
|
||||
this.$emit('click')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,68 +0,0 @@
|
||||
<template>
|
||||
<el-dropdown placement="bottom" size="small" @command="handleChange">
|
||||
<el-button class="d2-mr btn-text can-hover" type="text">
|
||||
<d2-icon name="font" style="font-size: 16px;"/>
|
||||
</el-button>
|
||||
<el-dropdown-menu slot="dropdown">
|
||||
<el-dropdown-item command="default">
|
||||
<d2-icon :name="iconName('default')" class="d2-mr-5"/>默认
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item command="medium">
|
||||
<d2-icon :name="iconName('medium')" class="d2-mr-5"/>中
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item command="small">
|
||||
<d2-icon :name="iconName('small')" class="d2-mr-5"/>小
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item command="mini">
|
||||
<d2-icon :name="iconName('mini')" class="d2-mr-5"/>最小
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState, mapMutations, mapActions } from 'vuex'
|
||||
export default {
|
||||
name: 'd2-header-size',
|
||||
computed: {
|
||||
...mapState('d2admin/size', [
|
||||
'value'
|
||||
])
|
||||
},
|
||||
watch: {
|
||||
// 注意 这里是关键
|
||||
// 因为需要访问 this.$ELEMENT 所以只能在这里使用这种方式
|
||||
value: {
|
||||
handler (val, oldVal) {
|
||||
// https://github.com/d2-projects/d2-admin/pull/129
|
||||
if (oldVal) {
|
||||
// 这个情况在已经加载完页面 用户改变了尺寸时触发
|
||||
this.$ELEMENT.size = val
|
||||
// 由于已经加载过设置 需要清空缓存设置
|
||||
this.pageKeepAliveClean()
|
||||
// 由于已经加载过设置 需要刷新此页面
|
||||
this.$router.replace('/refresh')
|
||||
} else {
|
||||
// 这个情况在刷新页面时触发
|
||||
this.$ELEMENT.size = val
|
||||
}
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapMutations({
|
||||
pageKeepAliveClean: 'd2admin/page/keepAliveClean'
|
||||
}),
|
||||
...mapActions({
|
||||
sizeSet: 'd2admin/size/set'
|
||||
}),
|
||||
handleChange (value) {
|
||||
this.sizeSet(value)
|
||||
},
|
||||
iconName (name) {
|
||||
return name === this.value ? 'dot-circle-o' : 'circle-o'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,80 +0,0 @@
|
||||
<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, mapActions } from 'vuex'
|
||||
export default {
|
||||
name: 'd2-theme-list',
|
||||
data () {
|
||||
return {
|
||||
table: {
|
||||
showHeader: false,
|
||||
border: true
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState('d2admin/theme', [
|
||||
'list',
|
||||
'activeName'
|
||||
])
|
||||
},
|
||||
methods: {
|
||||
...mapActions('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>
|
||||
@@ -1,38 +0,0 @@
|
||||
<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>
|
||||
@@ -1,36 +0,0 @@
|
||||
<template>
|
||||
<el-dropdown size="small" 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>
|
||||
@@ -1,122 +0,0 @@
|
||||
<template>
|
||||
<div class="d2-theme-header-menu" ref="page" :class="{'is-scrollable': isScroll}" flex="cross:center">
|
||||
<div class="d2-theme-header-menu__content" ref="content" flex-box="1" flex>
|
||||
<div class="d2-theme-header-menu__scroll" ref="scroll" flex-box="0" :style="'transform: translateX(' + currentTranslateX + 'px);'">
|
||||
<el-menu mode="horizontal" :default-active="active" @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>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="isScroll" class="d2-theme-header-menu__prev" flex-box="0" @click="scroll('left')" flex="main:center cross:center">
|
||||
<i class="el-icon-arrow-left"></i>
|
||||
</div>
|
||||
<div v-if="isScroll" class="d2-theme-header-menu__next" flex-box="0" @click="scroll('right')" flex="cross:center">
|
||||
<i class="el-icon-arrow-right"></i>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { throttle } from 'lodash'
|
||||
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'
|
||||
])
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
active: '',
|
||||
isScroll: false,
|
||||
scrollWidth: 0,
|
||||
contentWidth: 0,
|
||||
currentTranslateX: 0,
|
||||
throttledCheckScroll: null
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
'$route.matched': {
|
||||
handler (val) {
|
||||
this.active = val[val.length - 1].path
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
scroll (direction) {
|
||||
if (direction === 'left') {
|
||||
// 向右滚动
|
||||
this.currentTranslateX = 0
|
||||
} else {
|
||||
// 向左滚动
|
||||
if (this.contentWidth * 2 - this.currentTranslateX <= this.scrollWidth) {
|
||||
this.currentTranslateX -= this.contentWidth
|
||||
} else {
|
||||
this.currentTranslateX = this.contentWidth - this.scrollWidth
|
||||
}
|
||||
}
|
||||
},
|
||||
checkScroll () {
|
||||
let contentWidth = this.$refs.content.clientWidth
|
||||
let scrollWidth = this.$refs.scroll.clientWidth
|
||||
if (this.isScroll) {
|
||||
// 页面依旧允许滚动的情况,需要更新width
|
||||
if (this.contentWidth - this.scrollWidth === this.currentTranslateX) {
|
||||
// currentTranslateX 也需要相应变化【在右端到头的情况时】
|
||||
this.currentTranslateX = contentWidth - scrollWidth
|
||||
// 快速的滑动依旧存在判断和计算时对应的contentWidth变成正数,所以需要限制一下
|
||||
if (this.currentTranslateX > 0) {
|
||||
this.currentTranslateX = 0
|
||||
}
|
||||
}
|
||||
// 更新元素数据
|
||||
this.contentWidth = contentWidth
|
||||
this.scrollWidth = scrollWidth
|
||||
// 判断何时滚动消失: 当scroll > content
|
||||
if (contentWidth > scrollWidth) {
|
||||
this.isScroll = false
|
||||
}
|
||||
}
|
||||
// 判断何时滚动出现: 当scroll < content
|
||||
if (!this.isScroll && contentWidth < scrollWidth) {
|
||||
this.isScroll = true
|
||||
// 注意,当isScroll变为true,对应的元素盒子大小会发生变化
|
||||
this.$nextTick(() => {
|
||||
contentWidth = this.$refs.content.clientWidth
|
||||
scrollWidth = this.$refs.scroll.clientWidth
|
||||
this.contentWidth = contentWidth
|
||||
this.scrollWidth = scrollWidth
|
||||
this.currentTranslateX = 0
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
// 初始化判断
|
||||
// 默认判断父元素和子元素的大小,以确定初始情况是否显示滚动
|
||||
this.checkScroll()
|
||||
// 全局窗口变化监听,判断父元素和子元素的大小,从而控制isScroll的开关
|
||||
this.throttledCheckScroll = throttle(this.checkScroll, 300)
|
||||
window.addEventListener('resize', this.throttledCheckScroll)
|
||||
},
|
||||
beforeDestroy () {
|
||||
// 取消监听
|
||||
window.removeEventListener('resize', this.throttledCheckScroll)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,98 +0,0 @@
|
||||
<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) {
|
||||
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>
|
||||
@@ -1,17 +0,0 @@
|
||||
import util from '@/libs/util.js'
|
||||
|
||||
export default {
|
||||
methods: {
|
||||
handleMenuSelect (index, indexPath) {
|
||||
if (/^d2-menu-empty-\d+$/.test(index) || index === undefined) {
|
||||
this.$message.warning('临时菜单')
|
||||
} else if (/^https:\/\/|http:\/\//.test(index)) {
|
||||
util.open(index)
|
||||
} else {
|
||||
this.$router.push({
|
||||
path: index
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
-105
@@ -1,105 +0,0 @@
|
||||
<template>
|
||||
<div class="d2-panel-search-item" :class="hoverMode ? 'can-hover' : ''" flex>
|
||||
<div class="d2-panel-search-item__icon" flex-box="0">
|
||||
<div class="d2-panel-search-item__icon-box" flex="main:center cross:center">
|
||||
<d2-icon v-if="item.icon" :name="item.icon"/>
|
||||
<d2-icon-svg v-else-if="item.iconSvg" :name="item.iconSvg"/>
|
||||
<d2-icon v-else name="file-o"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d2-panel-search-item__info" flex-box="1" flex="dir:top">
|
||||
<div class="d2-panel-search-item__info-title" flex-box="1" flex="cross:center">
|
||||
<span>{{item.title}}</span>
|
||||
</div>
|
||||
<div class="d2-panel-search-item__info-fullTitle" flex-box="0">
|
||||
<span>{{item.fullTitle}}</span>
|
||||
</div>
|
||||
<div class="d2-panel-search-item__info-path" flex-box="0">
|
||||
<span>{{item.path}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
item: {
|
||||
default: () => ({})
|
||||
},
|
||||
hoverMode: {
|
||||
default: false
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '~@/assets/style/public.scss';
|
||||
.d2-panel-search-item {
|
||||
height: 64px;
|
||||
margin: 0px -20px;
|
||||
&.can-hover {
|
||||
@extend %unable-select;
|
||||
margin: 0px;
|
||||
&:hover {
|
||||
background-color: #F5F7FA;
|
||||
.d2-panel-search-item__icon {
|
||||
.d2-panel-search-item__icon-box {
|
||||
i {
|
||||
font-size: 24px;
|
||||
color: $color-primary;
|
||||
}
|
||||
}
|
||||
}
|
||||
.d2-panel-search-item__info {
|
||||
.d2-panel-search-item__info-title {
|
||||
color: $color-text-main;
|
||||
}
|
||||
.d2-panel-search-item__info-fullTitle {
|
||||
color: $color-text-normal;
|
||||
}
|
||||
.d2-panel-search-item__info-path {
|
||||
color: $color-text-normal;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.d2-panel-search-item__icon {
|
||||
width: 64px;
|
||||
.d2-panel-search-item__icon-box {
|
||||
height: 64px;
|
||||
width: 64px;
|
||||
border-right: 1px solid $color-border-3;
|
||||
i {
|
||||
font-size: 20px;
|
||||
color: $color-text-sub;
|
||||
}
|
||||
svg {
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.d2-panel-search-item__info {
|
||||
margin-left: 10px;
|
||||
.d2-panel-search-item__info-title {
|
||||
font-size: 16px;
|
||||
line-height: 16px;
|
||||
font-weight: bold;
|
||||
color: $color-text-normal;
|
||||
}
|
||||
.d2-panel-search-item__info-fullTitle {
|
||||
font-size: 10px;
|
||||
line-height: 14px;
|
||||
color: $color-text-placehoder;
|
||||
}
|
||||
.d2-panel-search-item__info-path {
|
||||
margin-bottom: 4px;
|
||||
font-size: 10px;
|
||||
line-height: 14px;
|
||||
color: $color-text-placehoder;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,221 +0,0 @@
|
||||
<template>
|
||||
<div
|
||||
class="panel-search"
|
||||
flex="dir:top">
|
||||
<div
|
||||
class="panel-search__input-group"
|
||||
flex-box="0"
|
||||
flex="dir:top main:center cross:center"
|
||||
@click.self="handlePanelClick">
|
||||
<d2-icon-svg
|
||||
class="panel-search__logo"
|
||||
name="d2-admin-text"/>
|
||||
<el-autocomplete
|
||||
class="panel-search__input"
|
||||
ref="input"
|
||||
v-model="searchText"
|
||||
suffix-icon="el-icon-search"
|
||||
placeholder="搜索页面"
|
||||
:fetch-suggestions="querySearch"
|
||||
:trigger-on-focus="false"
|
||||
:clearable="true"
|
||||
@keydown.esc.native="handleEsc"
|
||||
@select="handleSelect">
|
||||
<d2-panel-search-item
|
||||
slot-scope="{ item }"
|
||||
:item="item"/>
|
||||
</el-autocomplete>
|
||||
<div class="panel-search__tip">
|
||||
您可以使用快捷键
|
||||
<span class="panel-search__key">{{hotkey.open}}</span>
|
||||
唤醒搜索面板,按
|
||||
<span class="panel-search__key">{{hotkey.close}}</span>
|
||||
关闭
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="resultsList.length > 0"
|
||||
class="panel-search__results-group"
|
||||
flex-box="1">
|
||||
<el-card>
|
||||
<div class="panel-search__results-group-inner">
|
||||
<d2-panel-search-item
|
||||
v-for="(item, index) in resultsList"
|
||||
:key="index"
|
||||
:item="item"
|
||||
:hover-mode="true"
|
||||
@click.native="handleResultsGroupItemClick(item.path)"/>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Fuse from 'fuse.js'
|
||||
import { mapState } from 'vuex'
|
||||
import mixin from '../mixin/menu'
|
||||
export default {
|
||||
mixins: [
|
||||
mixin
|
||||
],
|
||||
components: {
|
||||
'd2-panel-search-item': () => import('./components/panel-search-item/index.vue')
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
searchText: '',
|
||||
results: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState('d2admin/search', [
|
||||
'hotkey',
|
||||
'pool'
|
||||
]),
|
||||
// 这份数据是展示在搜索面板下面的
|
||||
resultsList () {
|
||||
return (this.results.length === 0 && this.searchText === '') ? this.pool.map(e => ({
|
||||
value: e.fullTitle,
|
||||
...e
|
||||
})) : this.results
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* @description 过滤选项 这个方法在每次输入框的值发生变化时会触发
|
||||
*/
|
||||
querySearch (queryString, callback) {
|
||||
var pool = this.pool
|
||||
const results = this.query(queryString ? pool : [], queryString)
|
||||
this.results = results
|
||||
callback(results)
|
||||
},
|
||||
/**
|
||||
* @description 指定的数据源中根据指定的查询字符串过滤数据
|
||||
* @param {Object} pool 需要过滤的数据
|
||||
* @param {String} queryString 查询字符串
|
||||
*/
|
||||
query (pool, queryString) {
|
||||
return new Fuse(pool, {
|
||||
shouldSort: true,
|
||||
tokenize: true,
|
||||
threshold: 0.6,
|
||||
location: 0,
|
||||
distance: 100,
|
||||
maxPatternLength: 32,
|
||||
minMatchCharLength: 1,
|
||||
keys: [
|
||||
'fullTitle',
|
||||
'path'
|
||||
]
|
||||
})
|
||||
.search(queryString)
|
||||
.map(e => ({
|
||||
value: e.fullTitle,
|
||||
...e
|
||||
}))
|
||||
},
|
||||
/**
|
||||
* @description 聚焦输入框
|
||||
*/
|
||||
focus () {
|
||||
this.input = ''
|
||||
setTimeout(() => {
|
||||
this.$refs.input.focus()
|
||||
// 还原
|
||||
this.searchText = ''
|
||||
this.results = []
|
||||
}, 500)
|
||||
},
|
||||
/**
|
||||
* @description 接收用户在列表中选择项目的事件
|
||||
*/
|
||||
handleResultsGroupItemClick (path) {
|
||||
// 如果用户选择的就是当前页面 就直接关闭搜索面板
|
||||
if (path === this.$route.path) {
|
||||
this.handleEsc()
|
||||
return
|
||||
}
|
||||
// 用户选择的是其它页面
|
||||
this.handleMenuSelect(path)
|
||||
},
|
||||
/**
|
||||
* @description 接收用户在下拉菜单中选中事件
|
||||
*/
|
||||
handleSelect ({ path }) {
|
||||
// 如果用户选择的就是当前页面 就直接关闭搜索面板
|
||||
if (path === this.$route.path) {
|
||||
this.handleEsc()
|
||||
return
|
||||
}
|
||||
// 用户选择的是其它页面
|
||||
this.$nextTick(() => {
|
||||
this.handleMenuSelect(path)
|
||||
})
|
||||
},
|
||||
/**
|
||||
* @augments 关闭输入框的下拉菜单
|
||||
*/
|
||||
closeSuggestion () {
|
||||
if (this.$refs.input.activated) {
|
||||
this.$refs.input.suggestions = []
|
||||
this.$refs.input.activated = false
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @augments 接收用户点击空白区域的关闭
|
||||
*/
|
||||
handlePanelClick () {
|
||||
this.handleEsc()
|
||||
},
|
||||
/**
|
||||
* @augments 接收用户触发的关闭
|
||||
*/
|
||||
handleEsc () {
|
||||
this.closeSuggestion()
|
||||
this.$nextTick(() => {
|
||||
this.$emit('close')
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '~@/assets/style/public.scss';
|
||||
.panel-search {
|
||||
margin: 20px;
|
||||
.panel-search__input-group {
|
||||
height: 240px;
|
||||
.panel-search__logo {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.panel-search__input {
|
||||
width: 500px;
|
||||
}
|
||||
.panel-search__tip {
|
||||
@extend %unable-select;
|
||||
margin-top: 20px;
|
||||
margin-bottom: 40px;
|
||||
font-size: 12px;
|
||||
color: $color-text-sub;
|
||||
.panel-search__key {
|
||||
padding: 1px 5px;
|
||||
margin: 0px 2px;
|
||||
border-radius: 2px;
|
||||
background-color: $color-text-normal;
|
||||
color: $color-bg;
|
||||
}
|
||||
}
|
||||
}
|
||||
.panel-search__results-group {
|
||||
overflow: auto;
|
||||
.panel-search__results-group-inner {
|
||||
margin: -20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,185 +0,0 @@
|
||||
<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
|
||||
size="default"
|
||||
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, mapActions } 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: {
|
||||
...mapActions('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>
|
||||
@@ -1,3 +0,0 @@
|
||||
import layout from './layout'
|
||||
|
||||
export default layout
|
||||
@@ -1,148 +0,0 @@
|
||||
<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"
|
||||
:style="{
|
||||
opacity: this.searchActive ? 0.5 : 1
|
||||
}"
|
||||
flex-box="0"
|
||||
flex>
|
||||
<div class="logo-group" :style="{width: asideCollapse ? asideWidthCollapse : asideWidth}" flex-box="0">
|
||||
<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" flex-box="0">
|
||||
<d2-icon name="bars"/>
|
||||
</div>
|
||||
<d2-menu-header flex-box="1"/>
|
||||
<!-- 顶栏右侧 -->
|
||||
<div class="d2-header-right" flex-box="0">
|
||||
<!-- 如果你只想在开发环境显示这个按钮请添加 v-if="$env === 'development'" -->
|
||||
<d2-header-search @click="handleSearchClick"/>
|
||||
<d2-header-error-log/>
|
||||
<d2-header-fullscreen/>
|
||||
<d2-header-theme/>
|
||||
<d2-header-size/>
|
||||
<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,
|
||||
opacity: this.searchActive ? 0.5 : 1
|
||||
}">
|
||||
<d2-menu-side/>
|
||||
</div>
|
||||
<!-- 主体 -->
|
||||
<div class="d2-theme-container-main" flex-box="1" flex>
|
||||
<!-- 搜索 -->
|
||||
<transition name="fade-scale">
|
||||
<div v-show="searchActive" class="d2-theme-container-main-layer" flex="dir:top">
|
||||
<d2-panel-search
|
||||
ref="panelSearch"
|
||||
@close="searchPanelClose"/>
|
||||
</div>
|
||||
</transition>
|
||||
<!-- 内容 -->
|
||||
<transition name="fade-scale">
|
||||
<div v-show="!searchActive" class="d2-theme-container-main-layer" flex="dir:top">
|
||||
<!-- tab -->
|
||||
<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>
|
||||
</transition>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState, mapGetters, mapActions } from 'vuex'
|
||||
import mixinSearch from './mixins/search'
|
||||
export default {
|
||||
name: 'd2-layout-header-aside',
|
||||
mixins: [
|
||||
mixinSearch
|
||||
],
|
||||
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-search': () => import('./components/header-search'),
|
||||
'd2-header-size': () => import('./components/header-size'),
|
||||
'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', {
|
||||
keepAlive: state => state.page.keepAlive,
|
||||
grayActive: state => state.gray.active,
|
||||
transitionActive: state => state.transition.active,
|
||||
asideCollapse: state => state.menu.asideCollapse
|
||||
}),
|
||||
...mapGetters('d2admin', {
|
||||
themeActiveSetting: 'theme/activeSetting'
|
||||
}),
|
||||
/**
|
||||
* @description 最外层容器的背景图片样式
|
||||
*/
|
||||
styleLayoutMainGroup () {
|
||||
return {
|
||||
...this.themeActiveSetting.backgroundImage ? {
|
||||
backgroundImage: `url('${this.$baseUrl}${this.themeActiveSetting.backgroundImage}')`
|
||||
} : {}
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapActions('d2admin/menu', [
|
||||
'asideCollapseToggle'
|
||||
]),
|
||||
/**
|
||||
* 接收点击切换侧边栏的按钮
|
||||
*/
|
||||
handleToggleAside () {
|
||||
this.asideCollapseToggle()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
// 注册主题
|
||||
@import '~@/assets/style/theme/register.scss';
|
||||
</style>
|
||||
@@ -1,58 +0,0 @@
|
||||
import { mapState, mapMutations } from 'vuex'
|
||||
|
||||
import hotkeys from 'hotkeys-js'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
'd2-panel-search': () => import('../components/panel-search')
|
||||
},
|
||||
mounted () {
|
||||
// 绑定搜索功能快捷键 [ 打开 ]
|
||||
hotkeys(this.searchHotkey.open, event => {
|
||||
event.preventDefault()
|
||||
this.searchPanelOpen()
|
||||
})
|
||||
// 绑定搜索功能快捷键 [ 关闭 ]
|
||||
hotkeys(this.searchHotkey.close, event => {
|
||||
event.preventDefault()
|
||||
this.searchPanelClose()
|
||||
})
|
||||
},
|
||||
beforeDestroy () {
|
||||
hotkeys.unbind(this.searchHotkey.open)
|
||||
hotkeys.unbind(this.searchHotkey.close)
|
||||
},
|
||||
computed: {
|
||||
...mapState('d2admin', {
|
||||
searchActive: state => state.search.active,
|
||||
searchHotkey: state => state.search.hotkey
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
...mapMutations({
|
||||
searchToggle: 'd2admin/search/toggle',
|
||||
searchSet: 'd2admin/search/set'
|
||||
}),
|
||||
/**
|
||||
* 接收点击搜索按钮
|
||||
*/
|
||||
handleSearchClick () {
|
||||
this.searchToggle()
|
||||
if (this.searchActive) {
|
||||
this.$refs.panelSearch.focus()
|
||||
}
|
||||
},
|
||||
searchPanelOpen () {
|
||||
if (!this.searchActive) {
|
||||
this.searchSet(true)
|
||||
this.$refs.panelSearch.focus()
|
||||
}
|
||||
},
|
||||
// 关闭搜索面板
|
||||
searchPanelClose () {
|
||||
if (this.searchActive) {
|
||||
this.searchSet(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user