This repository has been archived on 2025-09-14. You can view files and clone it, but cannot push or open issues or pull requests.
Files
nezha-nezha-fronted/nezha-fronted/src/components/common/popBox/selectDashboard.vue

471 lines
18 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div>
<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="dashboard-select-wrap">
<div class="dashboard-select-left">
<ul class="dashboard-select-list">
<li class="dashboard-select-item" :class="{active:currentTab===item.value}" v-for="item in tabList" :key="item.value" @click="tabChange(item.value)">
<i class="nz-icon" :class="item.icon"></i>
<span>{{item.name}}</span>
</li>
</ul>
<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('dashboard.createPlaylist')" 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 slot="reference">
<slot name="trigger"></slot>
</div>
</el-popover>
<transition name="right-box">
<playlistBox v-if="playlistVisible" @close="closePlaylist" :obj="playlistObj"></playlistBox>
</transition>
</div>
</template>
<script>
import bus from '@/libs/bus'
import HighlightText from 'vue-text-highlight'
import playlistBox from '@/components/common/rightBox/playlistBox'
export default {
name: 'selectDashboard',
components: {
HighlightText,
playlistBox
},
props: {
placement: { type: String },
panelData: { type: Array },
showPanel: { type: Object },
panelLock: { type: Boolean, default: true },
disabled: { type: Boolean, default: false }
},
watch: {
filterPanel: {
handler (n) {
if (this.currentTab === 'all') {
this.$refs.panelTree && this.$refs.panelTree.filter(n)
} else {
this.$refs.otherTree && this.$refs.otherTree.filter(n)
}
}
},
showPanel: {
immediate: true,
handler (n) {
if (n) {
this.panel = JSON.parse(JSON.stringify(n))
// 设置最近浏览数据
this.setBrowse()
this.setData()
}
}
},
panelData: {
immediate: true,
async handler () {
// 获取收藏列表
this.getStarred()
this.setData()
}
}
},
data () {
return {
popBox: { show: false },
panel: { id: 0, name: '' },
tabList: [
{ 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.createdByYou'), icon: 'nz-icon-wodechuangjian', value: 'create' },
{ name: this.$t('dashboard.recentlyViewed'), icon: 'nz-icon-liulanlishi', value: 'browse' },
{ name: this.$t('dashboard.playlist'), icon: 'nz-icon-Playlists', value: 'playlist' }
],
currentTab: 'all',
// 过滤值
filterPanel: '',
// 其他tab的数据我的收藏、我的创建、最近浏览数据
otherData: [],
// 收藏列表
starredList: [],
playlist: [],
playlistVisible: false,
playlistObj: {}
}
},
created () {
this.getPlaylist()
},
methods: {
// 左侧tab点击
tabChange (value) {
if (this.currentTab !== value) {
this.currentTab = value
this.filterPanel = ''
}
this.setData()
},
// 设置树形菜单数据
setData (type = this.currentTab) {
const userId = localStorage.getItem('nz-user-id')
switch (type) {
case 'starred': { // 我的收藏
this.otherData = JSON.parse(JSON.stringify(this.starredList))
break
}
case 'create': { // 我的创建
const flatArr = bus.flatten(this.panelData)
this.otherData = flatArr.filter(item => item.createBy == userId)
break
}
case 'browse': { // 最近浏览
const browseArr = JSON.parse(localStorage.getItem(`nz-view-dashboard-${userId}`) || '[]')
const flatArr = bus.flatten(this.panelData)
const tempArr = []
// 比对id获取最近浏览的数据
browseArr.forEach(item => {
flatArr.forEach(subItem => {
if (item.id === subItem.id) {
tempArr.push(subItem)
}
})
})
this.otherData = JSON.parse(JSON.stringify(tempArr))
break
}
case 'playlist': {
this.otherData = JSON.parse(JSON.stringify(this.playlist))
break
}
}
// 设置当前面板高亮 以及保持搜索状态
this.$nextTick(() => {
if (this.currentTab === 'all') {
this.$refs.panelTree && this.$refs.panelTree.setCurrentKey(this.showPanel)
this.$refs.panelTree && this.$refs.panelTree.filter(this.filterPanel)
} else {
this.$refs.otherTree && this.$refs.otherTree.setCurrentKey(this.showPanel)
this.$refs.otherTree && this.$refs.otherTree.filter(this.filterPanel)
}
})
},
startPlay (val) {
const data = this.$lodash.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: [],
mode: 'normal'
}
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,
mode: res.data.mode || 'normal'
}
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 () {
// 1: 已收藏 0未收藏
const flatArr = bus.flatten(this.panelData) // 数组对象扁平化
this.starredList = flatArr.filter(item => {
return item.starred === 1
})
},
// 存储最近浏览的面板
setBrowse () {
const userId = localStorage.getItem('nz-user-id')
// 获取最近浏览id数组
let browseArr = JSON.parse(localStorage.getItem(`nz-view-dashboard-${userId}`) || '[]')
const flatArr = bus.flatten(this.panelData)
// 若最近浏览的数据已被删除 则截取掉
for (let i = 0; i < browseArr.length; i++) {
const flag = flatArr.some(item => {
return item.id === browseArr[i].id
})
if (flag === false) {
browseArr.splice(i, 1)
i--
}
}
// 若已经存在 则先删除
const value = browseArr.find(item => item.id === this.panel.id)
if (value) {
browseArr = browseArr.filter(item => item.id !== value.id)
}
// 追加到数组前边
browseArr.unshift({ id: this.panel.id })
// 如果数组长度大于10则截取
browseArr.splice(10)
localStorage.setItem(`nz-view-dashboard-${userId}`, JSON.stringify(browseArr))
},
// 新增收藏
addStarred: bus.debounceFn(function (data) {
const params = {
type: 'dashboard',
tid: data.id
}
this.$post('/sys/user/starred', params).then(async response => {
if (response.code === 200) {
data.starred = 1
// 更新panelData收藏状态
handler(this.panelData)
function handler (list) {
list.forEach(item => {
if (item.id === data.id) {
item.starred = 1
} else if (item.children && item.children.length > 0) {
handler(item.children)
}
})
}
this.getStarred()
this.setData()
// 更新父组件面板收藏状态
this.$set(this.$parent.showPanel, 'starred', this.starredList.some(item => item.id === this.showPanel.id) ? 1 : 0)
}
})
},
300, true),
// 删除收藏
delStarred: bus.debounceFn(function (data) {
this.$delete('/sys/user/starred?type=dashboard&tid=' + data.id).then(async response => {
if (response.code === 200) {
data.starred = 0
// 更新panelData收藏状态
handler(this.panelData)
function handler (list) {
list.forEach(item => {
if (item.id === data.id) {
item.starred = 0
} else if (item.children && item.children.length > 0) {
handler(item.children)
}
})
}
this.getStarred()
this.setData()
// 更新父组件面板收藏状态
this.$set(this.$parent.showPanel, 'starred', this.starredList.some(item => item.id === this.showPanel.id) ? 1 : 0)
}
})
},
300, true),
/*
* node: 被拖的节点
* relative: 发生关系的节点
* position: ['before', 'after', 'inner'] 与relative节点的关系
* */
nodeDrop (node, relative, position, event) {
if (position === 'inner') {
node.data.pid = relative.data.id
} else {
node.data.pid = relative.data.pid
}
this.updateWeight()
},
filterNode (value, data) {
if (!value) return true
// 不区分大小写
return data.name.toLowerCase().indexOf(value.toLowerCase()) !== -1
},
updateWeight (data) {
const toUpdate = []
let count = 0
handler(this.panelData)
function handler (panelData) {
panelData.forEach(panel => {
panel.weight = count++
toUpdate.push({ id: panel.id, pid: panel.pid, weight: panel.weight })
if (panel.children && panel.children.length > 0) {
handler(panel.children)
}
})
}
this.$put('visual/dashboard/tree', toUpdate)
},
deletePanel (data) {
this.$emit('deletePanel', data)
},
editPanel (data) {
this.$emit('editPanel', data)
this.esc()
},
esc () {
this.popBox.show = false
},
// 确认选择某个节点,与父组件交互
selectDashboard (data, checked, child) {
if (this.currentTab === 'all') {
this.$refs.panelTree && this.$refs.panelTree.setCurrentKey(data)
} else {
this.$refs.otherTree && this.$refs.otherTree.setCurrentKey(data)
}
if (this.currentTab === 'playlist') return
this.$emit('selectDashboard', data, 'select')
this.esc()
}
}
}
</script>