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 Normal View History

<template>
2023-04-03 10:03:21 +08:00
<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>
2023-04-03 10:03:21 +08:00
<div class="pop-item-wider">
<div class="dashboard-select-header">
<el-input v-model="filterPanel" :placeholder="$t('overall.search')" clearable size="small"></el-input>
2023-05-08 16:56:08 +08:00
<button v-has="'main_add'" :title="$t('dashboard.createPlaylist')" class="top-tool-btn margin-l-10" type="button" @click="addPlaylist" v-if="currentTab==='playlist'">
2023-04-03 10:03:21 +08:00
<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>
2023-04-03 10:03:21 +08:00
<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'
2023-04-03 10:03:21 +08:00
import playlistBox from '@/components/common/rightBox/playlistBox'
export default {
name: 'selectDashboard',
components: {
2023-04-03 10:03:21 +08:00
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' },
2023-04-03 10:03:21 +08:00
{ 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: [],
// 收藏列表
2023-04-03 10:03:21 +08:00
starredList: [],
playlist: [],
playlistVisible: false,
playlistObj: {}
}
},
2023-04-03 10:03:21 +08:00
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')
2023-04-03 10:03:21 +08:00
switch (type) {
case 'starred': { // 我的收藏
this.otherData = JSON.parse(JSON.stringify(this.starredList))
break
}
case 'create': { // 我的创建
const flatArr = bus.flatten(this.panelData)
2023-04-03 10:03:21 +08:00
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)
2023-04-03 10:03:21 +08:00
const tempArr = []
// 比对id获取最近浏览的数据
browseArr.forEach(item => {
flatArr.forEach(subItem => {
if (item.id === subItem.id) {
tempArr.push(subItem)
}
})
})
2023-04-03 10:03:21 +08:00
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)
}
})
},
2023-04-03 10:03:21 +08:00
startPlay (val) {
const data = this.$lodash.cloneDeep(val)
2023-04-03 10:03:21 +08:00
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'
2023-04-03 10:03:21 +08:00
}
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'
2023-04-03 10:03:21 +08:00
}
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 = {
2023-03-15 15:39:06 +08:00
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) {
2023-03-15 15:39:06 +08:00
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)
}
})
}
2023-03-15 15:39:06 +08:00
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>