NEZ-2741 feat:playlist页面开发

This commit is contained in:
zyh
2023-04-03 10:03:21 +08:00
parent 099859d736
commit 1cea6a1e18
19 changed files with 758 additions and 7853 deletions

View File

@@ -66,21 +66,34 @@
} }
.top-tool-btn-group { .top-tool-btn-group {
display: flex; display: flex;
.top-tool-btn:not(:last-of-type):not(:first-of-type) {
border-left: none;
border-radius: 0;
}
.top-tool-btn:first-of-type:not(:last-of-type) { .top-tool-btn:first-of-type:not(:last-of-type) {
border-right-color: transparent;
border-radius: $--button-border-radius 0 0 $--button-border-radius; border-radius: $--button-border-radius 0 0 $--button-border-radius;
&:focus+.top-tool-btn{
border-left-color: transparent !important;
}
}
.top-tool-btn:not(:last-of-type):not(:first-of-type) {
border-right-color: transparent;
border-radius: 0;
&:focus+.top-tool-btn{
border-left-color: transparent !important;
}
} }
.top-tool-btn:last-of-type:not(:first-of-type) { .top-tool-btn:last-of-type:not(:first-of-type) {
border-radius: 0 $--button-border-radius $--button-border-radius 0; border-radius: 0 $--button-border-radius $--button-border-radius 0;
border-left: none;
} }
.top-tool-btn { .top-tool-btn {
background-color: $--background-color-empty; background-color: $--background-color-empty;
} }
} }
.top-tool-btn-group.playlist{
margin-right: 10px;
.top-tool-btn.stopPlaylist{
width: 92px;
padding: 0 5px;
}
}
.top-tool-btn { .top-tool-btn {
height: 32px; height: 32px;
width: 36px; width: 36px;

View File

@@ -24,22 +24,28 @@
.tree--node > span:last-of-type > span > i { .tree--node > span:last-of-type > span > i {
font-weight: normal !important; font-weight: normal !important;
} }
.select-panel-tree { .select-dashboard-tree {
height: 350px; height: 350px;
overflow: auto; overflow: auto;
} }
.select-panel-tree .el-tree-node__content { .select-dashboard-tree .el-tree-node__content {
height: 34px; height: 34px;
line-height: 34px; line-height: 34px;
} }
.select-panel-tree .el-tree-node__content:hover { .select-dashboard-tree .el-tree-node__content:hover {
color: $--color-primary; color: $--color-primary;
} }
.select-panel-tree .el-tree--highlight-current .el-tree-node.is-current > .el-tree-node__content { .select-dashboard-tree .el-tree--highlight-current .el-tree-node.is-current > .el-tree-node__content {
background-color: $--background-color-base; background-color: $--background-color-base;
font-weight: bold; font-weight: bold;
color: $--color-primary; color: $--color-primary;
} }
.select-dashboard-tree.playlistTree .el-tree-node:focus>.el-tree-node__content{
background-color: transparent;
}
.select-dashboard-tree.playlistTree .el-tree-node>.el-tree-node__content:hover{
background-color: $--background-color-base;
}
.tree--node { .tree--node {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
@@ -71,12 +77,12 @@
color: #D96D7A; color: #D96D7A;
} }
.panel-select-wrap{ .dashboard-select-wrap{
width: 100%; width: 100%;
height: 402px; height: 402px;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
.panel-select-left{ .dashboard-select-left{
width: 196px; width: 196px;
height: 100%; height: 100%;
box-sizing: border-box; box-sizing: border-box;
@@ -85,9 +91,9 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: space-between; justify-content: space-between;
.panel-select-list{ .dashboard-select-list{
width: 100%; width: 100%;
.panel-select-item{ .dashboard-select-item{
font-family: Roboto-Regular; font-family: Roboto-Regular;
font-size: 14px; font-size: 14px;
font-weight: 400; font-weight: 400;
@@ -106,14 +112,14 @@
color: $--color-text-regular; color: $--color-text-regular;
} }
} }
.panel-select-item:hover{ .dashboard-select-item:hover{
color: $--color-primary; color: $--color-primary;
background: $--background-color-base; background: $--background-color-base;
i{ i{
color: $--color-primary; color: $--color-primary;
} }
} }
.panel-select-item.active{ .dashboard-select-item.active{
color: $--color-primary; color: $--color-primary;
background: $--background-color-base; background: $--background-color-base;
i{ i{
@@ -167,9 +173,60 @@
flex: 1; flex: 1;
width: calc(100% - 196px); width: calc(100% - 196px);
padding-top: 0; padding-top: 0;
.panel-select-header{ .dashboard-select-header{
margin-top: 12px; margin-top: 12px;
margin-bottom: 8px; margin-bottom: 8px;
box-sizing: border-box;
padding: 0 12px;
display: flex;
.el-input{
flex: 1;
.el-input__inner {
border: 1px solid $--button-icon-border-color;
}
.el-input__inner:hover {
border: 1px solid $--button-icon-hover-border-color;
}
.el-input__inner:focus {
border: 1px solid $--button-icon-active-border-color;
}
}
.top-tool-btn {
height: 32px;
width: 36px;
cursor: pointer;
border: 1px solid $--button-icon-border-color;
outline: none;
border-radius: $--button-border-radius;
background-color: $--background-color-empty;
transition:all .2s;
color: $--button-icon-color;
i {
font-size: 14px;
color: $--button-icon-color;
}
}
.top-tool-btn.top-tool-btn--text {
padding: 0 8px;
width: unset;
color: $--color-text-regular;
}
.top-tool-btn:hover:not(.nz-btn-disabled) {
background-color: $--button-icon-hover-background-color;
border: 1px solid $--button-icon-hover-border-color;
color: $--button-icon-hover-color;
i {
color: $--button-icon-hover-color;
}
}
.top-tool-btn:focus:not(.nz-btn-disabled), .top-tool-btn.is-focus {
background-color: $--button-icon-active-background-color;
border: 1px solid $--button-icon-active-border-color !important;
color: $--button-icon-active-color;
i {
color: $--button-icon-active-color;
}
}
} }
} }
.nz-icon-xingzhuang{ .nz-icon-xingzhuang{
@@ -185,4 +242,15 @@
color:$--color-primary; color:$--color-primary;
background: none; background: none;
} }
.nz-icon-bofang{
color: $--color-text-regular;
}
}
.right-box-playlist{
.el-input-group__append{
background-color: $--right-box-sub-title-background-color;
border: 1px solid $--border-color-light;
border-left: none;
}
} }

View File

@@ -51,6 +51,10 @@
top: 0px; top: 0px;
height: 100%; height: 100%;
} }
.panel-loading{
left: 0;
top: 0;
}
} }
} }
.home.se{ .home.se{

View File

@@ -136,7 +136,7 @@
height: 100%; height: 100%;
width: 100%; width: 100%;
background: center center no-repeat $--background-color-empty; background: center center no-repeat $--background-color-empty;
z-index: 1010; z-index: 10;
} }
.show-panel-name{ .show-panel-name{
display: inline-block; display: inline-block;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -5,6 +5,41 @@
"css_prefix_text": "nz-icon-", "css_prefix_text": "nz-icon-",
"description": "", "description": "",
"glyphs": [ "glyphs": [
{
"icon_id": "34816567",
"name": "下一播放",
"font_class": "xiayibofang",
"unicode": "e7dc",
"unicode_decimal": 59356
},
{
"icon_id": "34816568",
"name": "上一播放",
"font_class": "shangyibofang",
"unicode": "e7dd",
"unicode_decimal": 59357
},
{
"icon_id": "34801441",
"name": "播放",
"font_class": "bofang",
"unicode": "e7da",
"unicode_decimal": 59354
},
{
"icon_id": "34801442",
"name": "Playlists",
"font_class": "Playlists",
"unicode": "e7db",
"unicode_decimal": 59355
},
{
"icon_id": "34764401",
"name": "edit",
"font_class": "edit1",
"unicode": "e7d9",
"unicode_decimal": 59353
},
{ {
"icon_id": "34724146", "icon_id": "34724146",
"name": "全部展开", "name": "全部展开",

File diff suppressed because one or more lines are too long

View File

@@ -3,6 +3,7 @@ import MessageBox from 'element-ui/packages/message-box/src/main'
import i18n from '../i18n' import i18n from '../i18n'
import bus from '@/libs/bus' import bus from '@/libs/bus'
import moment from 'moment-timezone' import moment from 'moment-timezone'
import loadsh from 'lodash'
/* 弹窗点击外部后关闭 */ /* 弹窗点击外部后关闭 */
const exceptClassName = ['prevent-clickoutside', 'config-dropdown', 'nz-pop', 'el-picker', 'chart-box-dropdown', 'metric-dropdown', 'el-cascader__dropdown', 'no-style-class', 'el-message-box', 'nz-dashboard-dropdown', 'el-autocomplete-suggestion', 'nz-temp-box', 'el-time-panel', 'el-dropdown-menu', 'el-select-dropdown', 'no-close'] // clickoutside排除的class(白名单) no-style-class没有任何样式的class const exceptClassName = ['prevent-clickoutside', 'config-dropdown', 'nz-pop', 'el-picker', 'chart-box-dropdown', 'metric-dropdown', 'el-cascader__dropdown', 'no-style-class', 'el-message-box', 'nz-dashboard-dropdown', 'el-autocomplete-suggestion', 'nz-temp-box', 'el-time-panel', 'el-dropdown-menu', 'el-select-dropdown', 'no-close'] // clickoutside排除的class(白名单) no-style-class没有任何样式的class
export const clickoutside = { export const clickoutside = {
@@ -12,9 +13,9 @@ export const clickoutside = {
if (!binding.expression) return if (!binding.expression) return
const unsavedChange = localStorage.getItem('nz-unsaved-change') const unsavedChange = localStorage.getItem('nz-unsaved-change')
try { try {
el.__oldValue__ = JSON.parse(JSON.stringify(binding.value.obj)) el.__oldValue__ = loadsh.cloneDeep(binding.value.obj)
el.__oldData__ = JSON.parse(JSON.stringify(binding.value.oldData))
el.__newValue__ = el.__oldValue__ el.__newValue__ = el.__oldValue__
el.__oldData__ = loadsh.cloneDeep(binding.value.oldData)
} catch (e) { } catch (e) {
} }
@@ -38,7 +39,7 @@ export const clickoutside = {
return false return false
} }
if (el.__oldValue__) { if (el.__oldValue__) {
// const newValue = JSON.parse(JSON.stringify(binding.value.obj)) // const newValue = loadsh.cloneDeep(binding.value.obj)
const oldData = el.__oldData__ || el.__oldValue__ const oldData = el.__oldData__ || el.__oldValue__
if (unsavedChange == 'on' && !isEqual(oldData, el.__newValue__) && !el.isShow) { if (unsavedChange == 'on' && !isEqual(oldData, el.__newValue__) && !el.isShow) {
el.isShow = true el.isShow = true
@@ -77,11 +78,11 @@ export const clickoutside = {
update (el, binding, vnode) { update (el, binding, vnode) {
if (binding.arg && binding.arg != 'stable') { if (binding.arg && binding.arg != 'stable') {
if (binding.value.obj.datasource !== '0') { if (binding.value.obj.datasource !== '0') {
el.__oldValue__ = JSON.parse(JSON.stringify(binding.value.obj)) el.__oldValue__ = loadsh.cloneDeep(binding.value.obj)
} }
} }
el.__newValue__ = binding.value.obj el.__newValue__ = binding.value.obj
el.__oldData__ = binding.value.oldData el.__oldData__ = binding.value.oldData
}, },
unbind (el, binding) { unbind (el, binding) {
// 解除事件监听 // 解除事件监听
@@ -219,7 +220,7 @@ export const cancelWithChange = {
setTimeout(() => { setTimeout(() => {
if (!binding.value || !binding.value.obj) return if (!binding.value || !binding.value.obj) return
const unsavedChange = localStorage.getItem('nz-unsaved-change') const unsavedChange = localStorage.getItem('nz-unsaved-change')
el.__oldValue__ = JSON.parse(JSON.stringify(binding.value.obj)) el.__oldValue__ = loadsh.cloneDeep(binding.value.obj)
el.__newValue__ = el.__oldValue__ el.__newValue__ = el.__oldValue__
function domClick (e) { function domClick (e) {
if (unsavedChange == 'on' && !isEqual(el.__oldValue__, el.__newValue__)) { if (unsavedChange == 'on' && !isEqual(el.__oldValue__, el.__newValue__)) {
@@ -242,7 +243,7 @@ export const cancelWithChange = {
}, },
update (el, binding, vnode) { update (el, binding, vnode) {
if (binding.arg && binding.arg != 'stable') { if (binding.arg && binding.arg != 'stable') {
el.__oldValue__ = JSON.parse(JSON.stringify(binding.value.obj)) el.__oldValue__ = loadsh.cloneDeep(binding.value.obj)
} }
el.__newValue__ = binding.value.obj el.__newValue__ = binding.value.obj
}, },

View File

@@ -12,7 +12,7 @@
<span class="select-refresh-time-label" v-if="interval">{{interLabel}}</span> <span class="select-refresh-time-label" v-if="interval">{{interLabel}}</span>
<i class="nz-icon nz-icon-arrow-down" style="font-size: 12px;"></i> <i class="nz-icon nz-icon-arrow-down" style="font-size: 12px;"></i>
<transition name="el-zoom-in-top"> <transition name="el-zoom-in-top">
<ul v-show="dropdownShow" class="el-dropdown-menu el-popper el-dropdown-menu--mini nz-dropdown" v-clickoutside="dropdownHandler"> <ul v-show="dropdownShow" class="el-dropdown-menu el-popper el-dropdown-menu--mini nz-dropdown popper-z-index" v-clickoutside="dropdownHandler">
<li v-for="i in $CONSTANTS.intervalList" :key="i.value + i.label" :style="{color:interval === i.value || interval.value === i.value ? theme.themeColor : ''}" class="el-dropdown-menu__item dropdown-content" @click="selectInterval(i,true)"> <li v-for="i in $CONSTANTS.intervalList" :key="i.value + i.label" :style="{color:interval === i.value || interval.value === i.value ? theme.themeColor : ''}" class="el-dropdown-menu__item dropdown-content" @click="selectInterval(i,true)">
{{$t(i.label)}} {{$t(i.label)}}
</li> </li>

View File

@@ -0,0 +1,121 @@
<template>
<div class="top-tool-btn-group playlist">
<el-tooltip
effect="light"
placement="bottom"
:content="$t('dashboard.previous')">
<button class="top-tool-btn previous" @click="goPrevious">
<i class="nz-icon nz-icon-shangyibofang"></i>
</button>
</el-tooltip>
<button class="top-tool-btn stopPlaylist" @click="stopPlaylist">{{$t('dashboard.stopPlaylist')}}</button>
<el-tooltip
effect="light"
placement="bottom"
:content="$t('dashboard.next')">
<button class="top-tool-btn next" @click="goNext">
<i class="nz-icon nz-icon-xiayibofang"></i>
</button>
</el-tooltip>
</div>
</template>
<script>
export default {
name: 'playlist',
props: {
playlistObj: {
type: Object
}
},
data () {
return {
dashboardList: [], // 轮播仪表盘列表
timer: null,
currentIndex: 0
}
},
watch: {
playlistObj: {
immediate: true,
async handler () {
this.currentIndex = 0
if (this.timer) {
clearInterval(this.timer)
this.timer = null
}
await this.getDashboard()
this.startPlay()
}
}
},
methods: {
// 开始轮播
async startPlay () {
if (this.timer) {
clearInterval(this.timer)
this.timer = null
}
this.changePlay()
const interval = this.playlistObj.intvl * 60 * 1000
this.timer = setInterval(() => {
this.currentIndex++
if (this.currentIndex === this.playlistObj.dashboardIds.length) {
this.currentIndex = 0
}
this.changePlay()
}, interval)
},
// 上一个
goPrevious () {
this.currentIndex--
if (this.currentIndex === -1) {
this.currentIndex = this.playlistObj.dashboardIds.length - 1
}
this.startPlay()
},
// 下一个
goNext () {
this.currentIndex++
if (this.currentIndex === this.playlistObj.dashboardIds.length) {
this.currentIndex = 0
}
this.startPlay()
},
// 停止轮播
stopPlaylist () {
if (this.timer) {
clearInterval(this.timer)
this.timer = null
}
this.$emit('stopPlaylist')
},
changePlay () {
let data = this.dashboardList[this.currentIndex]
if (!data) {
data = {
id: this.playlistObj.dashboardIds[this.currentIndex],
name: ''
}
}
this.$emit('changePlay', data)
},
async getDashboard () {
this.dashboardList = []
const ids = this.playlistObj.dashboardIds.join(',')
const res = await this.$get('visual/dashboard?ids=' + ids)
this.playlistObj.dashboardIds.forEach(id => {
const findItem = res.data.list.find(item => item.id == id)
this.dashboardList.push(findItem)
})
}
},
beforeDestroy () {
if (this.timer) {
clearInterval(this.timer)
this.timer = null
}
}
}
</script>

View File

@@ -1,114 +1,146 @@
<template> <template>
<el-popover :placement="placement" popper-class="'nz-pop nz-pop-select-panel right-box-select-top right-public-box-dropdown-top nz-pop-select-panel__dropdown'" transition="slide" v-model="popBox.show" :width="536" :disabled="disabled"> <div>
<div class="panel-select-wrap"> <el-popover :placement="placement" popper-class="'nz-pop nz-pop-select-panel right-box-select-top right-public-box-dropdown-top nz-pop-select-panel__dropdown'" transition="slide" v-model="popBox.show" :width="536" :disabled="disabled">
<div class="panel-select-left"> <div class="dashboard-select-wrap">
<ul class="panel-select-list"> <div class="dashboard-select-left">
<li class="panel-select-item" :class="{active:currentTab===item.value}" v-for="item in tabList" :key="item.value" @click="tabChange(item.value)"> <ul class="dashboard-select-list">
<i class="nz-icon" :class="item.icon"></i> <li class="dashboard-select-item" :class="{active:currentTab===item.value}" v-for="item in tabList" :key="item.value" @click="tabChange(item.value)">
<span>{{item.name}}</span> <i class="nz-icon" :class="item.icon"></i>
</li> <span>{{item.name}}</span>
</ul> </li>
<div class="dashboard-select-tail"> </ul>
<slot name="button"></slot> <div class="dashboard-select-tail">
<slot name="button"></slot>
</div>
</div>
<div class="pop-item-wider">
<div class="dashboard-select-header">
<el-input v-model="filterPanel" :placeholder="$t('overall.search')" clearable size="small"></el-input>
<button v-has="'main_add'" :title="$t('overall.createChart')" class="top-tool-btn margin-l-10" type="button" @click="addPlaylist" v-if="currentTab==='playlist'">
<i class="nz-icon-create-square nz-icon"></i>
</button>
</div>
<!-- 全部仪表盘数据树形结构-->
<div :class="{'movable': !panelLock}" class="select-dashboard-tree" v-if="currentTab==='all'">
<el-tree
:data="panelData"
:draggable="!panelLock"
:expand-on-click-node="false"
:filter-node-method="filterNode"
:props="{label: 'name', children: 'children'}"
@node-click="selectDashboard"
@node-drop="nodeDrop"
check-on-click-node
check-strictly
default-expand-all
:highlight-current="true"
node-key="id"
ref="panelTree">
<div class="tree--node" slot-scope="{ node, data }">
<HighlightText :queries="filterPanel" :highlightClass="'highlight-keyword'" style="vertical-align: middle" :title="node.label + ' (' + data.chartNum +' charts' ">{{node.label}}</HighlightText>
<el-row class="block-col-2" style="margin-left:10px;margin-right:8px">
<el-col>
<el-dropdown placement="bottom-end" trigger="click" style="margin-right:10px" v-has="['main_edit', 'main_delete']">
<span class="el-dropdown-link tree--operation" @click.stop><i class="nz-icon nz-icon-more1"></i></span>
<el-dropdown-menu class="right-box-select-top" slot="dropdown">
<el-dropdown-item>
<div @click="editPanel(data)" v-has="'main_edit'"><i class="nz-icon nz-icon-edit"></i>{{$t('overall.edit')}}</div>
</el-dropdown-item>
<el-dropdown-item>
<div @click="deletePanel(data)" v-has="'main_delete'"><i class="nz-icon nz-icon-delete"></i>{{$t('overall.delete')}}</div>
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<template>
<i v-if="data.starred===1" class="nz-icon nz-icon-a-xingzhuang2" @click.stop="delStarred(data)" :title ="$t('overall.starred')"></i>
<i v-else class="nz-icon nz-icon-xingzhuang" @click.stop="addStarred(data)" :title ="$t('overall.unstarred')"></i>
</template>
</el-col>
</el-row>
</div>
</el-tree>
</div>
<!-- 我的收藏我的创建最近浏览数据轮播列表无层级关系 -->
<div class="select-dashboard-tree" :class="{'playlistTree':currentTab==='playlist'}" v-else>
<el-tree
:data="otherData"
:expand-on-click-node="false"
:filter-node-method="filterNode"
:props="{label: 'name', children: 'children'}"
@node-click="selectDashboard"
@node-drop="nodeDrop"
check-on-click-node
check-strictly
default-expand-all
:highlight-current="currentTab!=='playlist'"
node-key="id"
ref="otherTree">
<div class="tree--node" slot-scope="{ node, data }" v-if="currentTab!=='playlist'">
<HighlightText :queries="filterPanel" :highlightClass="'highlight-keyword'" style="vertical-align: middle" :title="node.label + ' (' + data.chartNum +' charts' ">{{node.label}}</HighlightText>
<el-row class="block-col-2" style="margin-left:10px;margin-right:8px">
<el-col>
<el-dropdown placement="bottom-end" trigger="click" style="margin-right:10px" v-has="['main_edit', 'main_delete']">
<span class="el-dropdown-link tree--operation" @click.stop><i class="nz-icon nz-icon-more1"></i></span>
<el-dropdown-menu class="right-box-select-top nz-el-dropdown-menu" slot="dropdown">
<el-dropdown-item>
<div @click="editPanel(data)" v-has="'main_edit'"><i class="nz-icon nz-icon-edit"></i>{{$t('overall.edit')}}</div>
</el-dropdown-item>
<el-dropdown-item>
<div @click="deletePanel(data)" v-has="'main_delete'"><i class="nz-icon nz-icon-delete"></i>{{$t('overall.delete')}}</div>
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<template>
<i v-if="data.starred===1" class="nz-icon nz-icon-a-xingzhuang2" @click.stop="delStarred(data)" :title ="$t('overall.starred')"></i>
<i v-else class="nz-icon nz-icon-xingzhuang" @click.stop="addStarred(data)" :title ="$t('overall.unstarred')"></i>
</template>
</el-col>
</el-row>
</div>
<!-- 轮播列表 -->
<div class="tree--node" slot-scope="{ node, data }" v-else>
<HighlightText :queries="filterPanel" :highlightClass="'highlight-keyword'" style="vertical-align: middle">{{node.label}}</HighlightText>
<el-row class="block-col-2" style="margin-left:10px;margin-right:8px">
<el-col>
<el-dropdown placement="bottom-end" trigger="click" style="margin-right:10px" v-has="['main_edit', 'main_delete']">
<span class="el-dropdown-link tree--operation" @click.stop><i class="nz-icon nz-icon-more1"></i></span>
<el-dropdown-menu class="right-box-select-top nz-el-dropdown-menu" slot="dropdown">
<el-dropdown-item>
<div @click="editPlaylist(data)" v-has="'main_edit'"><i class="nz-icon nz-icon-edit"></i>{{$t('overall.edit')}}</div>
</el-dropdown-item>
<el-dropdown-item>
<div @click="deletePlaylist(data)" v-has="'main_delete'"><i class="nz-icon nz-icon-delete"></i>{{$t('overall.delete')}}</div>
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<template>
<i class="nz-icon nz-icon-bofang" @click.stop="startPlay(data)" :title ="$t('dashboard.startPlaylist')"></i>
</template>
</el-col>
</el-row>
</div>
</el-tree>
</div>
</div> </div>
</div> </div>
<div class="pop-item-wider"> <div slot="reference">
<div class="panel-select-header"> <slot name="trigger"></slot>
<el-input id="panel-list-search" v-model="filterPanel" :placeholder="$t('overall.search')" clearable size="small" style="width:316px"></el-input>
</div>
<!-- 全部仪表盘 数据 -->
<div :class="{'movable': !panelLock}" class="select-panel-tree" v-if="currentTab==='all'">
<el-tree
:data="panelData"
:draggable="!panelLock"
:expand-on-click-node="false"
:filter-node-method="filterNode"
:props="{label: 'name', children: 'children'}"
@node-click="selectDashboard"
@node-drop="nodeDrop"
check-on-click-node
check-strictly
default-expand-all
:highlight-current="true"
node-key="id"
ref="panelTree">
<div class="tree--node" slot-scope="{ node, data }">
<HighlightText :queries="filterPanel" :highlightClass="'highlight-keyword'" style="vertical-align: middle" :title="node.label + ' (' + data.chartNum +' charts' ">{{node.label}}</HighlightText>
<el-row class="block-col-2" style="margin-left:10px;margin-right:8px">
<el-col>
<el-dropdown placement="bottom-end" trigger="click" style="margin-right:10px" v-has="['main_edit', 'main_delete']">
<span class="el-dropdown-link tree--operation" @click.stop><i class="nz-icon nz-icon-more1"></i></span>
<el-dropdown-menu class="right-box-select-top" slot="dropdown">
<el-dropdown-item>
<div @click="editPanel(data)" v-has="'main_edit'"><i class="nz-icon nz-icon-edit"></i>{{$t('overall.edit')}}</div>
</el-dropdown-item>
<el-dropdown-item>
<div @click="deletePanel(data)" v-has="'main_delete'"><i class="nz-icon nz-icon-delete"></i>{{$t('overall.delete')}}</div>
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<template>
<i v-if="data.starred===1" class="nz-icon nz-icon-a-xingzhuang2" @click.stop="delStarred(data)" :title ="$t('overall.starred')"></i>
<i v-else class="nz-icon nz-icon-xingzhuang" @click.stop="addStarred(data)" :title ="$t('overall.unstarred')"></i>
</template>
</el-col>
</el-row>
</div>
</el-tree>
</div>
<!-- 我的收藏我的创建最近浏览数据 -->
<div class="select-panel-tree" v-else>
<el-tree
:data="otherData"
:expand-on-click-node="false"
:filter-node-method="filterNode"
:props="{label: 'name', children: 'children'}"
@node-click="selectDashboard"
@node-drop="nodeDrop"
check-on-click-node
check-strictly
default-expand-all
:highlight-current="true"
node-key="id"
ref="otherTree">
<div class="tree--node" slot-scope="{ node, data }">
<HighlightText :queries="filterPanel" :highlightClass="'highlight-keyword'" style="vertical-align: middle" :title="node.label + ' (' + data.chartNum +' charts' ">{{node.label}}</HighlightText>
<el-row class="block-col-2" style="margin-left:10px;margin-right:8px">
<el-col>
<el-dropdown placement="bottom-end" trigger="click" style="margin-right:10px" v-has="['main_edit', 'main_delete']">
<span class="el-dropdown-link tree--operation" @click.stop><i class="nz-icon nz-icon-more1"></i></span>
<el-dropdown-menu class="right-box-select-top nz-el-dropdown-menu" slot="dropdown">
<el-dropdown-item>
<div @click="editPanel(data)" v-has="'main_edit'"><i class="nz-icon nz-icon-edit"></i>{{$t('overall.edit')}}</div>
</el-dropdown-item>
<el-dropdown-item>
<div @click="deletePanel(data)" v-has="'main_delete'"><i class="nz-icon nz-icon-delete"></i>{{$t('overall.delete')}}</div>
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<template>
<i v-if="data.starred===1" class="nz-icon nz-icon-a-xingzhuang2" @click.stop="delStarred(data)" :title ="$t('overall.starred')"></i>
<i v-else class="nz-icon nz-icon-xingzhuang" @click.stop="addStarred(data)" :title ="$t('overall.unstarred')"></i>
</template>
</el-col>
</el-row>
</div>
</el-tree>
</div>
</div> </div>
</div> </el-popover>
<div slot="reference"> <transition name="right-box">
<slot name="trigger"></slot> <playlistBox v-if="playlistVisible" @close="closePlaylist" :obj="playlistObj"></playlistBox>
</div> </transition>
</el-popover> </div>
</template> </template>
<script> <script>
import bus from '@/libs/bus' import bus from '@/libs/bus'
import HighlightText from 'vue-text-highlight' import HighlightText from 'vue-text-highlight'
import playlistBox from '@/components/common/rightBox/playlistBox'
export default { export default {
name: 'selectDashboard', name: 'selectDashboard',
components: { components: {
HighlightText HighlightText,
playlistBox
}, },
props: { props: {
placement: { type: String }, placement: { type: String },
@@ -155,7 +187,8 @@ export default {
{ name: this.$t('dashboard.allDashboards'), icon: 'nz-icon-a-leimucuquanbu', value: 'all' }, { name: this.$t('dashboard.allDashboards'), icon: 'nz-icon-a-leimucuquanbu', value: 'all' },
{ name: this.$t('dashboard.starredDashboards'), icon: 'nz-icon-xingzhuang', value: 'starred' }, { name: this.$t('dashboard.starredDashboards'), icon: 'nz-icon-xingzhuang', value: 'starred' },
{ name: this.$t('dashboard.createdByYou'), icon: 'nz-icon-wodechuangjian', value: 'create' }, { name: this.$t('dashboard.createdByYou'), icon: 'nz-icon-wodechuangjian', value: 'create' },
{ name: this.$t('dashboard.recentlyViewed'), icon: 'nz-icon-liulanlishi', value: 'browse' } { name: this.$t('dashboard.recentlyViewed'), icon: 'nz-icon-liulanlishi', value: 'browse' },
{ name: this.$t('dashboard.playlist'), icon: 'nz-icon-Playlists', value: 'playlist' }
], ],
currentTab: 'all', currentTab: 'all',
// 过滤值 // 过滤值
@@ -163,9 +196,15 @@ export default {
// 其他tab的数据我的收藏、我的创建、最近浏览数据 // 其他tab的数据我的收藏、我的创建、最近浏览数据
otherData: [], otherData: [],
// 收藏列表 // 收藏列表
starredList: [] starredList: [],
playlist: [],
playlistVisible: false,
playlistObj: {}
} }
}, },
created () {
this.getPlaylist()
},
methods: { methods: {
// 左侧tab点击 // 左侧tab点击
tabChange (value) { tabChange (value) {
@@ -178,24 +217,35 @@ export default {
// 设置树形菜单数据 // 设置树形菜单数据
setData (type = this.currentTab) { setData (type = this.currentTab) {
const userId = localStorage.getItem('nz-user-id') const userId = localStorage.getItem('nz-user-id')
if (type === 'starred') { // 我的收藏 switch (type) {
this.otherData = JSON.parse(JSON.stringify(this.starredList)) case 'starred': { // 我的收藏
} else if (type === 'create') { // 我的创建 this.otherData = JSON.parse(JSON.stringify(this.starredList))
const flatArr = this.flatten(this.panelData) break
this.otherData = flatArr.filter(item => item.createBy == userId) }
} else if (type === 'browse') { // 最近浏览 case 'create': { // 我的创建
const browseArr = JSON.parse(localStorage.getItem(`nz-view-dashboard-${userId}`) || '[]') const flatArr = this.flatten(this.panelData)
const flatArr = this.flatten(this.panelData) this.otherData = flatArr.filter(item => item.createBy == userId)
const tempArr = [] break
// 比对id获取最近浏览的数据 }
browseArr.forEach(item => { case 'browse': { // 最近浏览
flatArr.forEach(subItem => { const browseArr = JSON.parse(localStorage.getItem(`nz-view-dashboard-${userId}`) || '[]')
if (item.id === subItem.id) { const flatArr = this.flatten(this.panelData)
tempArr.push(subItem) const tempArr = []
} // 比对id获取最近浏览的数据
browseArr.forEach(item => {
flatArr.forEach(subItem => {
if (item.id === subItem.id) {
tempArr.push(subItem)
}
})
}) })
}) this.otherData = JSON.parse(JSON.stringify(tempArr))
this.otherData = JSON.parse(JSON.stringify(tempArr)) break
}
case 'playlist': {
this.otherData = JSON.parse(JSON.stringify(this.playlist))
break
}
} }
// 设置当前面板高亮 以及保持搜索状态 // 设置当前面板高亮 以及保持搜索状态
this.$nextTick(() => { this.$nextTick(() => {
@@ -208,6 +258,68 @@ export default {
} }
}) })
}, },
startPlay (val) {
const data = this.$loadsh.cloneDeep(val)
data.dashboardIds = JSON.parse(data.dashboardIds)
if (data.dashboardIds.length) {
this.esc()
this.$emit('startPlay', data)
} else {
this.$message.error(this.$t('PLAYLIST_DASHBOARD_IDS_ISNULL'))
}
},
async getPlaylist () {
const res = await this.$get('/visual/playlist', { pageSize: -1 })
this.playlist = res.data.list
this.setData()
},
addPlaylist () {
this.esc()
this.playlistObj = {
name: '',
intvl: undefined,
dashboardIds: []
}
this.playlistVisible = true
},
async editPlaylist (data) {
this.esc()
const res = await this.$get('/visual/playlist/' + data.id)
this.playlistObj = {
id: res.data.id,
name: res.data.name,
intvl: res.data.intvl,
dashboardIds: res.data.dashboardIds
}
this.playlistObj.dashboardIds = JSON.parse(this.playlistObj.dashboardIds)
this.playlistVisible = true
},
async deletePlaylist (data) {
this.$confirm(this.$t('tip.confirmDelete'), {
confirmButtonText: this.$t('tip.yes'),
cancelButtonText: this.$t('tip.no'),
type: 'warning'
}).then(() => {
this.$delete('/visual/playlist?ids=' + data.id).then((response) => {
if (response.code === 200) {
this.$message({
duration: 1000,
type: 'success',
message: this.$t('tip.deleteSuccess')
})
this.getPlaylist(true)
} else {
this.$message.error(response.msg)
}
})
})
},
closePlaylist (refresh) {
this.playlistVisible = false
if (refresh) {
this.getPlaylist()
}
},
// 获取收藏的列表 // 获取收藏的列表
async getStarred () { async getStarred () {
// 1: 已收藏 0未收藏 // 1: 已收藏 0未收藏
@@ -359,7 +471,8 @@ export default {
}, },
// 确认选择某个节点,与父组件交互 // 确认选择某个节点,与父组件交互
selectDashboard (data, checked, child) { selectDashboard (data, checked, child) {
this.$emit('selectDashboard', data) if (this.currentTab === 'playlist') return
this.$emit('selectDashboard', data, 'select')
if (this.currentTab === 'all') { if (this.currentTab === 'all') {
this.$refs.panelTree && this.$refs.panelTree.setCurrentKey(data) this.$refs.panelTree && this.$refs.panelTree.setCurrentKey(data)
} else { } else {

View File

@@ -0,0 +1,181 @@
<template>
<div v-clickoutside="{obj: editPlaylist, func: esc}" class="right-box right-box-playlist">
<div class="right-box__header">
<div class="header__title">{{editPlaylist.id ? $t('dashboard.editPlaylist') : $t('dashboard.createPlaylist')}}</div>
<div class="header__operation">
<span v-cancel="{obj: editPlaylist, func: esc}"><i class="nz-icon nz-icon-close" :title="$t('overall.close')"></i></span>
</div>
</div>
<div class="right-box__container">
<div class="container__form">
<el-form ref="form" :model="editPlaylist" :rules="rules" label-position="top" label-width="120px">
<!--name-->
<el-form-item :label="$t('overall.name')" prop="name">
<el-input maxlength="64" show-word-limit v-model="editPlaylist.name" size="small" type="text"></el-input>
</el-form-item>
<!-- interval -->
<el-form-item
:label="$t('dashboard.interval')"
prop="intvl"
>
<div class="el-input-group el-input-group--append">
<el-input-number
style="width:100%"
size="small"
:controls="false"
:min="1"
v-model="editPlaylist.intvl">
</el-input-number>
<div class="el-input-group__append" style="text-transform:capitalize;">{{$t('config.system.basic.minute')}}</div>
</div>
</el-form-item>
<!-- dashboardIds -->
<el-form-item
:label="$t('dashboard.title')"
prop="dashboardIds"
>
<el-select
v-model="editPlaylist.dashboardIds"
multiple
:placeholder="$t('el.select.placeholder')"
popper-class="right-box-select-top prevent-clickoutside"
size="small"
style="width:100%"
>
<el-option
v-for="item in dashboardList"
:key="item.id"
:label="$t(item.name)"
:value="item.id"
>
</el-option>
</el-select>
</el-form-item>
</el-form>
</div>
</div>
<div class="right-box__footer">
<button id="asset-edit-cancel" v-cancel="{obj: editPlaylist, func: esc}" class="footer__btn footer__btn--light">
<span>{{$t('overall.cancel')}}</span>
</button>
<button id="asset-edit-save" :class="{'footer__btn--disabled': prevent_opt.save}" :disabled="prevent_opt.save" class="footer__btn" @click="save">
<span>{{$t('overall.save')}}</span>
</button>
</div>
</div>
</template>
<script>
import editRigthBox from '../mixin/editRigthBox'
export default {
name: 'playlistBox',
props: {
obj: {
type: Object
}
},
mixins: [editRigthBox],
data () {
return {
url: '/visual/playlist',
editPlaylist: {
name: '',
intvl: undefined,
dashboardIds: []
},
rules: {
name: [
{ required: true, message: this.$t('validate.required'), trigger: 'change' }
],
intvl: [
{ required: true, message: this.$t('validate.required'), trigger: 'blur' }
],
dashboardIds: [
{ required: true, message: this.$t('validate.required'), trigger: 'change' }
]
},
dashboardList: []
}
},
created () {
this.getDashboard()
},
methods: {
clickOutside () {
this.esc(false)
},
/* 关闭弹框 */
esc (refresh) {
this.prevent_opt.save = false
this.$emit('close', refresh)
},
async getDashboard () {
const res = await this.$get('visual/dashboard?type=dashboard&pageSize=-1')
this.dashboardList = this.flatten(res.data.list)
},
// 数组对象扁平化
flatten (arr) {
const tempArr = this.$loadsh.cloneDeep(arr)
// 递归调用
function handler (tempArr) {
const newArr = []
tempArr.forEach(element => {
newArr.push(element)
if (element.children) {
newArr.push.apply(newArr, handler(element.children))
delete element.children
}
})
return newArr
}
return handler(tempArr)
},
save () {
if (this.prevent_opt.save) {
return
}
this.prevent_opt.save = true
this.$refs.form.validate((valid) => {
if (valid) {
const params = {
...this.editPlaylist
}
if (this.editPlaylist.id) {
this.$put(this.url, params).then(res => {
this.prevent_opt.save = false
if (res.code === 200) {
this.$message({ duration: 2000, type: 'success', message: this.$t('tip.saveSuccess') })
this.esc(true)
} else {
this.$message.error(res.msg)
}
})
} else {
this.$post(this.url, params).then(res => {
this.prevent_opt.save = false
if (res.code === 200) {
this.$message({ duration: 2000, type: 'success', message: this.$t('tip.saveSuccess') })
this.esc(true)
} else {
this.$message.error(res.msg)
}
})
}
} else {
this.prevent_opt.save = false
}
})
}
},
watch: {
obj: {
immediate: true,
deep: true,
handler (n) {
this.isEdit = true
this.editPlaylist = this.$loadsh.cloneDeep(n)
}
}
}
}
</script>

View File

@@ -7,7 +7,7 @@
</transition> </transition>
</div> </div>
<div class="main-container"> <div class="main-container">
<div class="top-tools panel-top-tools" :class="showTopLine? 'panel-top-tools-bottom' : ''" style="z-index: 1001;"> <div class="top-tools panel-top-tools" :class="showTopLine? 'panel-top-tools-bottom' : ''">
<div v-if="panelData.length === 0" class="top-tool-left" style="margin-left: 10px;"> <div v-if="panelData.length === 0" class="top-tool-left" style="margin-left: 10px;">
<button id="dashboard-add-panel" class="nz-btn nz-btn-style-light nz-btn-size-small" v-has="'main_add'" @click="toAdd"><i class="nz-icon nz-icon-create-square"></i>&nbsp;&nbsp;{{$t("overall.addDashboard")}}</button> <button id="dashboard-add-panel" class="nz-btn nz-btn-style-light nz-btn-size-small" v-has="'main_add'" @click="toAdd"><i class="nz-icon nz-icon-create-square"></i>&nbsp;&nbsp;{{$t("overall.addDashboard")}}</button>
</div> </div>
@@ -22,10 +22,12 @@
style="display: inline-block;padding: 0" style="display: inline-block;padding: 0"
@deletePanel="del" @deletePanel="del"
@editPanel="edit" @editPanel="edit"
@selectDashboard="panelChange"> @selectDashboard="panelChange"
@startPlay="startPlay"
>
<template v-slot:trigger> <template v-slot:trigger>
<i style="color: #BEBEBE" class="el-icon-menu"></i> <i style="color: #BEBEBE" class="el-icon-menu"></i>
<span :title="showPanel.name + ' (' + showPanel.chartNum +' charts)' " class="show-panel-name">{{showPanel.name}}</span> <span :title="showPanel.name + ' (' + (showPanel.chartNum || 0) +' charts)' " class="show-panel-name">{{showPanel.name||$t('overall.notFound')}}</span>
<i @click.stop="delStarred(showPanel)" v-if="showPanel.starred===1" class="nz-icon nz-icon-a-xingzhuang2" :title ="$t('overall.starred')"></i> <i @click.stop="delStarred(showPanel)" v-if="showPanel.starred===1" class="nz-icon nz-icon-a-xingzhuang2" :title ="$t('overall.starred')"></i>
<i @click.stop="addStarred(showPanel)" v-else class="nz-icon nz-icon-xingzhuang" :title ="$t('overall.unstarred')"></i> <i @click.stop="addStarred(showPanel)" v-else class="nz-icon nz-icon-xingzhuang" :title ="$t('overall.unstarred')"></i>
</template> </template>
@@ -43,6 +45,8 @@
</div> </div>
<div class="top-tool-right"> <div class="top-tool-right">
<!-- 仪表盘轮播 -->
<playlist v-if="playListControls" :playlistObj="playlistObj" @stopPlaylist="stopPlaylist" @changePlay="panelChange"></playlist>
<pick-time id="panel" ref="pickTime" v-model="searchTime" :refresh-data-func="dateChange" :use-chart-unit="false" class="margin-r-10" :sign="showPanel.id" :from="fromRoute.dashboard"></pick-time> <pick-time id="panel" ref="pickTime" v-model="searchTime" :refresh-data-func="dateChange" :use-chart-unit="false" class="margin-r-10" :sign="showPanel.id" :from="fromRoute.dashboard"></pick-time>
@@ -79,12 +83,6 @@
</el-dropdown-item> </el-dropdown-item>
</template> </template>
<template v-slot:after> <template v-slot:after>
<!-- <el-dropdown-item v-has="'main_add'">
<div id="chart-temp-add" @click="addChartByTemp"><i class="nz-icon nz-icon-add"></i>{{$t('overall.AddByTemplate')}}</div>
</el-dropdown-item>
<el-dropdown-item v-has="'main_edit'">
<div id="chart-temp-sync" @click="chartBySync"><i class="nz-icon nz-icon-sync"></i>{{ $t('overall.syncChart') }}</div>
</el-dropdown-item> -->
<el-dropdown-item v-has="'dashboard_view'"> <el-dropdown-item v-has="'dashboard_view'">
<div id="chart-export-html" @click="exportType"><i class="nz-icon nz-icon-kuaizhao"></i>{{ $t('overall.snapshoot') }}</div> <div id="chart-export-html" @click="exportType"><i class="nz-icon nz-icon-kuaizhao"></i>{{ $t('overall.snapshoot') }}</div>
</el-dropdown-item> </el-dropdown-item>
@@ -172,6 +170,7 @@ import exportHtmlMixin from '@/components/common/mixin/exportHtml'
import panelVariables from '@/components/common/panel/panelVariables' import panelVariables from '@/components/common/panel/panelVariables'
import snapshotProgress from '@/components/common/snapshotProgress/snapshotProgress.vue' import snapshotProgress from '@/components/common/snapshotProgress/snapshotProgress.vue'
import dashboardTempBox from '@/components/common/rightBox/dashboardTempBox' import dashboardTempBox from '@/components/common/rightBox/dashboardTempBox'
import playlist from '@/components/common/playlist'
// import FileSaver from 'file-saver' // import FileSaver from 'file-saver'
// import chartData from './testData' // import chartData from './testData'
export default { export default {
@@ -347,7 +346,9 @@ export default {
{ value: 300, label: '5m' }, { value: 300, label: '5m' },
{ value: 900, label: '15m' }, { value: 900, label: '15m' },
{ value: 1800, label: '30m' } { value: 1800, label: '30m' }
] ],
playListControls: false, // 显示隐藏轮播按钮
playlistObj: {} // 轮播仪表盘配置
} }
}, },
components: { components: {
@@ -359,7 +360,8 @@ export default {
chartRightBox, chartRightBox,
panelVariables, // 处理panel变量的组件 panelVariables, // 处理panel变量的组件
snapshotProgress, // 快照进度 snapshotProgress, // 快照进度
dashboardTempBox // dashboard模板 dashboardTempBox, // dashboard模板
playlist
}, },
computed: { computed: {
chartRightBoxShow () { chartRightBoxShow () {
@@ -373,6 +375,16 @@ export default {
} }
}, },
methods: { methods: {
// 开始轮播列表
startPlay (data) {
this.playListControls = true
this.playlistObj = data
},
// 结束轮播列表
stopPlaylist () {
this.playListControls = false
this.playlistObj = {}
},
closeDashboardTempBox (refresh) { closeDashboardTempBox (refresh) {
this.rightBox.dashboardTemp.show = false this.rightBox.dashboardTemp.show = false
if (refresh) { if (refresh) {
@@ -404,7 +416,7 @@ export default {
cancelButtonText: this.$t('tip.no'), cancelButtonText: this.$t('tip.no'),
type: 'warning' type: 'warning'
}).then(() => { }).then(() => {
this.$delete('visual/dashboard?ids=' + u.id).then(async (response) => { this.$delete('visual/dashboard?ids=' + u.id).then((response) => {
if (response.code === 200) { if (response.code === 200) {
this.$message({ this.$message({
duration: 1000, duration: 1000,
@@ -416,6 +428,7 @@ export default {
const param = { t: +new Date() } const param = { t: +new Date() }
const path = this.fromRoute.dashboard const path = this.fromRoute.dashboard
this.updatePath(param, path) this.updatePath(param, path)
this.stopPlaylist()
this.getTableData(true) this.getTableData(true)
} else { } else {
this.getTableData(false) this.getTableData(false)
@@ -709,10 +722,13 @@ export default {
}, },
// 面板相关操作 // 面板相关操作
panelChange (val) { panelChange (val, type) {
if (!val) { if (!val) {
return false return false
} }
if (type === 'select') { // 选择面板 则停止仪表盘轮播
this.stopPlaylist()
}
// 切换面板 重置参数 // 切换面板 重置参数
const param = { const param = {
dashboardId: val.id dashboardId: val.id