Files
wvp-platform/web/src/views/common/RegionTree.vue

559 lines
17 KiB
Vue
Raw Normal View History

2025-04-28 15:04:06 +08:00
<template>
<div id="regionTree" style="border-right: 1px solid #EBEEF5; height: 100%">
<div style="padding: 0 20px 0 10px;">
<el-input size="small" v-model="searchStr" @input="searchChange" suffix-icon="el-icon-search" placeholder="请输入搜索内容" clearable>
<!-- <el-select v-model="searchType" slot="prepend" placeholder="搜索类型" style="width: 80px">-->
<!-- <el-option label="目录" :value="0"></el-option>-->
<!-- <el-option label="通道" :value="1"></el-option>-->
<!-- </el-select>-->
</el-input>
2025-04-28 15:04:06 +08:00
</div>
<div v-if="!searchStr">
2025-04-28 15:04:06 +08:00
<el-alert
v-if="showAlert && edit"
title="操作提示"
description="你可以使用右键菜单管理节点"
type="info"
style="text-align: left"
/>
2025-10-10 18:42:44 +08:00
<div v-if="edit" style="margin-top: 18px;font-size: 14px;position: absolute;left: 309px;z-index: 100;" >
显示编号 <el-checkbox v-model="showCode" />
</div>
2025-04-28 15:04:06 +08:00
<vue-easy-tree
ref="veTree"
class="flow-tree"
node-key="treeId"
:height="treeHeight?treeHeight:'78vh'"
lazy
:load="loadNode"
:data="treeData"
:props="props"
:default-expanded-keys="['']"
@node-contextmenu="contextmenuEventHandler"
@node-click="nodeClickHandler"
>
<template v-slot:default="{ node, data }" class="custom-tree-node">
<span class="custom-tree-node">
<span
v-if="node.data.type === 0 && chooseId !== node.data.deviceId"
style="color: #409EFF"
class="iconfont icon-bianzubeifen3"
/>
<span
v-if="node.data.type === 0 && chooseId === node.data.deviceId"
style="color: #c60135;"
class="iconfont icon-bianzubeifen3"
/>
<span
v-if="node.data.type === 1 && node.data.status === 'ON'"
style="color: #409EFF"
class="iconfont icon-shexiangtou2"
/>
<span
v-if="node.data.type === 1 && node.data.status !== 'ON'"
style="color: #808181"
class="iconfont icon-shexiangtou2"
/>
<span
style=" padding-left: 1px"
:title="node.data.deviceId"
>{{ node.label }}</span>
<span v-if="node.data.deviceId !=='' && showCode">编号{{ node.data.deviceId }}</span>
<span v-if="node.data.longitude && showPosition" class="iconfont icon-gps"></span>
2025-04-28 15:04:06 +08:00
</span>
</template>
</vue-easy-tree>
</div>
<div v-if="searchStr" style="color: #606266; height: calc(100% - 32px); overflow: auto !important;">
<ul v-if="regionList.length > 0" style="list-style: none; margin: 0; padding: 10px">
<li v-for="item in regionList" :key="item.id" class="channel-list-li" style="height: 26px; align-items: center;cursor: pointer;" @click="listClickHandler(item)">
<span
v-if="chooseId !== item.deviceId"
style="color: #409EFF; font-size: 20px"
class="iconfont icon-bianzubeifen3"
/>
<span
v-if="chooseId === item.deviceId"
style="color: #c60135; font-size: 20px"
class="iconfont icon-bianzubeifen3"
/>
<div>
<div style="margin-left: 4px; margin-bottom: 3px; font-size: 15px">{{item.name}}</div>
<div style="margin-left: 4px; font-size: 13px; color: #808181">{{item.deviceId}}</div>
</div>
</li>
</ul>
<ul v-if="channelList.length > 0" style="list-style: none; margin: 0; padding: 10px; overflow: auto">
<li v-for="item in channelList" :key="item.id" class="channel-list-li" @click="channelLstClickHandler(item)" @contextmenu.prevent="contextmenuEventHandlerForLi($event, item)">
<span
v-if="item.gbStatus === 'ON'"
style="color: #409EFF; font-size: 20px"
class="iconfont icon-shexiangtou2"
/>
<span
v-if="item.gbStatus !== 'ON'"
style="color: #808181; font-size: 20px"
class="iconfont icon-shexiangtou2"
/>
<div>
<div style="margin-left: 4px; margin-bottom: 3px; font-size: 15px">{{item.gbName}}</div>
<div style="margin-left: 4px; font-size: 13px; color: #808181">{{item.gbDeviceId}}</div>
</div>
</li>
</ul>
<div v-if="this.currentPage * this.count < this.total" style="text-align: center;">
<el-button type="text" @click="loadListMore">加载更多</el-button>
</div>
</div>
2025-04-28 15:04:06 +08:00
<regionEdit ref="regionEdit" />
<gbDeviceSelect ref="gbDeviceSelect" />
<GbChannelSelect ref="gbChannelSelect" data-type="civilCode" />
</div>
</template>
<script>
import VueEasyTree from '@wchbrad/vue-easy-tree'
import regionEdit from './../dialog/regionEdit'
import gbDeviceSelect from './../dialog/GbDeviceSelect'
import GbChannelSelect from '../dialog/GbChannelSelect.vue'
import chooseCivilCode from '@/views/dialog/chooseCivilCode.vue'
2025-04-28 15:04:06 +08:00
export default {
name: 'DeviceTree',
components: {
GbChannelSelect,
VueEasyTree, regionEdit, gbDeviceSelect
},
props: ['edit', 'enableAddChannel', 'onChannelChange', 'showHeader', 'hasChannel', 'addChannelToCivilCode', 'treeHeight', 'showPosition', 'contextmenu'],
2025-04-28 15:04:06 +08:00
data() {
return {
props: {
label: 'name',
children: 'children'
2025-04-28 15:04:06 +08:00
},
searchType: 0,
2025-04-28 15:04:06 +08:00
showCode: false,
showAlert: true,
2025-11-11 14:23:45 +08:00
treeLimit: 50,
searchStr: '',
2025-04-28 15:04:06 +08:00
chooseId: '',
treeData: [],
currentPage: this.defaultPage | 1,
count: this.defaultCount | 15,
total: 0,
regionList: [],
channelList: []
2025-04-28 15:04:06 +08:00
}
},
created() {
},
destroyed() {
// if (this.jessibuca) {
// this.jessibuca.destroy();
// }
// this.playing = false;
// this.loaded = false;
// this.performance = "";
},
methods: {
searchChange() {
this.currentPage = 1
this.total = 0
if (this.edit) {
this.regionList = []
this.queryRegion()
}else {
this.channelList = []
this.queryChannelList()
}
},
loadListMore: function() {
this.currentPage += 1
if (this.edit) {
this.queryRegion()
}else {
this.queryChannelList()
}
},
queryRegion: function() {
this.$store.dispatch('region/queryTree', {
query: this.searchStr,
page: this.currentPage,
count: this.count
}).then(data => {
this.total = data.total
this.regionList = this.regionList.concat(data.list)
})
},
queryChannelList: function() {
this.$store.dispatch('commonChanel/getList', {
page: this.currentPage,
count: this.count,
query: this.searchStr
}).then(data => {
this.total = data.total
this.channelList = this.channelList.concat(data.list)
})
2025-04-28 15:04:06 +08:00
},
loadNode: function(node, resolve) {
if (node.level === 0) {
resolve([{
treeId: '',
deviceId: '',
name: '根资源组',
isLeaf: false,
type: 0
}])
} else if (node.data.deviceId.length <= 8) {
if (node.data.leaf) {
resolve([])
return
}
this.$store.dispatch('region/getTreeList', {
query: this.searchStr,
2025-04-28 15:04:06 +08:00
parent: node.data.id,
hasChannel: this.hasChannel
})
.then(data => {
if (data.length > 0) {
this.showAlert = false
}
2025-11-11 14:23:45 +08:00
if (data.length > this.treeLimit) {
let subData = data.splice(0, this.treeLimit)
subData.push({
treeId: '---',
deviceId: '---',
name: '加载更多...',
isLeaf: true,
leaf: true,
type: 100,
children: [],
nextData: data.splice(this.treeLimit, data.length)
})
resolve(subData)
}else {
resolve(data)
}
2025-04-28 15:04:06 +08:00
}).finally(() => {
this.locading = false
})
} else {
resolve([])
}
},
reset: function() {
this.$forceUpdate()
},
contextmenuEventHandler: function(event, data, node, element) {
if (!this.edit && !this.contextmenu) {
2025-04-28 15:04:06 +08:00
return
}
const allMenuItem = []
if (this.edit && node.data.type === 0) {
const menuItem = [
{
label: '刷新节点',
icon: 'el-icon-refresh',
disabled: false,
onClick: () => {
this.refreshNode(node)
}
},
{
label: '新建节点',
icon: 'el-icon-plus',
disabled: false,
onClick: () => {
this.addRegion(data.id, node)
}
},
{
label: '编辑节点',
icon: 'el-icon-edit',
disabled: node.level === 1,
onClick: () => {
this.editCatalog(data, node)
}
},
{
label: '删除节点',
icon: 'el-icon-delete',
disabled: node.level === 1,
divided: true,
onClick: () => {
this.$confirm('确定删除?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.removeRegion(data.id, node)
}).catch(() => {
2025-04-28 15:04:06 +08:00
})
}
}
]
if (this.enableAddChannel) {
menuItem.push(
2025-04-28 15:04:06 +08:00
{
label: '添加设备',
2025-04-28 15:04:06 +08:00
icon: 'el-icon-plus',
disabled: node.level === 1,
onClick: () => {
this.addChannelFormDevice(data.id, node)
2025-04-28 15:04:06 +08:00
}
}
)
menuItem.push(
2025-04-28 15:04:06 +08:00
{
label: '移除设备',
2025-04-28 15:04:06 +08:00
icon: 'el-icon-delete',
disabled: node.level === 1,
divided: true,
onClick: () => {
this.removeChannelFormDevice(data.id, node)
2025-04-28 15:04:06 +08:00
}
}
)
menuItem.push(
{
label: '添加通道',
icon: 'el-icon-plus',
disabled: node.level === 1,
onClick: () => {
this.addChannel(data.id, node)
}
}
)
}
allMenuItem.push(...menuItem)
}
if (this.contextmenu && node.data.type === 1) {
for (let i = 0; i < this.contextmenu.length; i++) {
let item = this.contextmenu[i]
if (item.type === node.data.type) {
allMenuItem.push({
label: item.label,
icon: item.icon,
2025-04-28 15:04:06 +08:00
onClick: () => {
item.onClick(event, data, node)
2025-04-28 15:04:06 +08:00
}
})
}
2025-04-28 15:04:06 +08:00
}
}
if (allMenuItem.length === 0) {
return
}
this.$contextmenu({
items: allMenuItem,
event, // 鼠标事件信息
customClass: 'custom-class', // 自定义菜单 class
zIndex: 3000 // 菜单样式 z-index
})
2025-04-28 15:04:06 +08:00
return false
},
removeRegion: function(id, node) {
this.$store.dispatch('region/deleteRegion', node.data.id)
.then((data) => {
console.log('移除成功')
this.$emit('onChannelChange', node.data.deviceId)
2025-04-28 15:04:06 +08:00
node.parent.loaded = false
node.parent.expand()
}).catch(function(error) {
console.log(error)
})
},
addChannelFormDevice: function(id, node) {
this.$refs.gbDeviceSelect.openDialog((rows) => {
const deviceIds = []
for (let i = 0; i < rows.length; i++) {
deviceIds.push(rows[i].id)
}
this.$store.dispatch('commonChanel/addDeviceToRegion', {
civilCode: node.data.deviceId,
deviceIds: deviceIds
}).then((data) => {
this.$message.success({
showClose: true,
message: '保存成功'
})
this.$emit('onChannelChange', node.data.deviceId)
2025-04-28 15:04:06 +08:00
node.loaded = false
node.expand()
}).catch(function(error) {
console.log(error)
}).finally(() => {
this.loading = false
})
})
},
removeChannelFormDevice: function(id, node) {
this.$refs.gbDeviceSelect.openDialog((rows) => {
const deviceIds = []
for (let i = 0; i < rows.length; i++) {
deviceIds.push(rows[i].id)
}
this.$store.dispatch('commonChanel/deleteDeviceFromRegion', deviceIds)
.then((data) => {
this.$message.success({
showClose: true,
message: '保存成功'
})
this.$emit('onChannelChange', node.data.deviceId)
2025-04-28 15:04:06 +08:00
node.loaded = false
node.expand()
}).catch(function(error) {
console.log(error)
}).finally(() => {
this.loading = false
})
})
},
addChannel: function(id, node) {
this.$refs.gbChannelSelect.openDialog((data) => {
console.log('选择的数据')
console.log(data)
this.addChannelToCivilCode(node.data.deviceId, data)
})
},
refreshNode: function(node) {
node.loaded = false
node.expand()
},
refresh: function(id) {
// 查询node
const node = this.$refs.veTree.getNode(id)
if (node) {
if (id.includes('channel') >= 0) {
node.parent.loaded = false
node.parent.expand()
}else {
node.loaded = false
node.expand()
}
2025-04-28 15:04:06 +08:00
}
},
addRegion: function(id, node) {
console.log(node)
this.$refs.regionEdit.openDialog(form => {
node.loaded = false
node.expand()
}, {
deviceId: '',
name: '',
parentId: node.data.id,
parentDeviceId: node.data.deviceId
})
},
editCatalog: function(data, node) {
// 打开添加弹窗
this.$refs.regionEdit.openDialog(form => {
node.loaded = false
node.expand()
}, node.data)
},
nodeClickHandler: function(data, node, tree) {
2025-11-11 14:23:45 +08:00
if (data && data.nextData && data.nextData.length > 0) {
const parentNode = node.parent
let nextData = data.nextData
if (nextData.length > this.treeLimit) {
let subData = nextData.splice(0, this.treeLimit)
subData.push({
treeId: '---',
deviceId: '---',
name: '加载更多...',
isLeaf: true,
leaf: true,
type: 100,
children: [],
nextData: nextData.splice(this.treeLimit, nextData.length)
})
this.$refs.veTree.remove(data, parentNode)
for (let item of subData) {
this.$refs.veTree.append(item, parentNode)
}
} else {
this.$refs.veTree.remove(data, parentNode)
for (let item of subData) {
this.$refs.veTree.append(item, parentNode)
}
}
}else {
this.chooseId = data.deviceId
this.$emit('clickEvent', data)
}
},
listClickHandler: function(data) {
this.chooseId = data.deviceId
this.$emit('clickEvent', data)
},
channelLstClickHandler: function(data) {
this.$emit('clickEvent', {
leaf: true,
id: data.gbId
})
},
contextmenuEventHandlerForLi(event, data) {
console.log(data)
const allMenuItem = []
if (this.contextmenu) {
for (let i = 0; i < this.contextmenu.length; i++) {
let item = this.contextmenu[i]
allMenuItem.push({
label: item.label,
icon: item.icon,
onClick: () => {
item.onClick(event, {
id: data.gbId
})
}
})
}
}
if (allMenuItem.length === 0) {
return
}
this.$contextmenu({
items: allMenuItem,
event, // 鼠标事件信息
customClass: 'custom-class', // 自定义菜单 class
zIndex: 3000 // 菜单样式 z-index
})
2025-04-28 15:04:06 +08:00
}
}
}
</script>
<style scoped>
2025-04-28 15:04:06 +08:00
.custom-tree-node .el-radio__label {
padding-left: 4px !important;
}
.flow-tree {
overflow: auto;
padding-top: 10px;
2025-04-28 15:04:06 +08:00
}
.flow-tree .vue-recycle-scroller__item-wrapper{
height: 100%;
overflow-x: auto;
}
.channel-list-li {
height: 40px;
align-items: center;
cursor: pointer;
display: grid;
grid-template-columns: 26px 1fr;
margin-bottom: 10px;
}
2025-04-28 15:04:06 +08:00
</style>