262 lines
5.9 KiB
Vue
262 lines
5.9 KiB
Vue
<template>
|
||
<section class="deviceSlider">
|
||
<div class="mainPane" v-if="show">
|
||
<div flex overview>
|
||
<b>监控设备</b>
|
||
<div>
|
||
<div>设备总数:{{ overview.total }}</div>
|
||
<div flex>在线设备:<p v-text="overview.online"/></div>
|
||
</div>
|
||
<el-progress type="circle" :width="40" :percentage="overview.percent" color="#19D286" :stroke-width="4"/>
|
||
</div>
|
||
<div flex search>
|
||
<el-select v-model="search.bind" size="mini" placeholder="全部" clearable @change="onChange">
|
||
<el-option v-for="(op,i) in dict.getDict('deviceStatus')" :key="i" :value="op.dictValue"
|
||
:label="op.dictName"/>
|
||
</el-select>
|
||
<el-input v-model="search.name" size="mini" placeholder="设备名称" prefix-icon="el-icon-search"
|
||
@change="handleTreeFilter" clearable/>
|
||
</div>
|
||
<div title>
|
||
<div>设备列表</div>
|
||
<el-button type="text" icon="iconfont iconResetting" @click="updateDev" size="mini" :loading="btnLoading">刷新</el-button>
|
||
</div>
|
||
<div fill class="deviceList">
|
||
<el-scrollbar>
|
||
<el-tree ref="deviceTree" :data="treeData" :props="propsConfig" @node-click="handleNodeClick"
|
||
:render-content="renderItem" :filter-node-method="handleFilter"/>
|
||
</el-scrollbar>
|
||
</div>
|
||
</div>
|
||
<div class="rightBtn" :class="{show}" @click="handleShow">
|
||
<i class="iconfont iconArrow_Right"/>
|
||
</div>
|
||
</section>
|
||
</template>
|
||
|
||
<script>
|
||
export default {
|
||
name: "deviceSlider",
|
||
props: {
|
||
show: Boolean,
|
||
ins: Function,
|
||
dict: Object,
|
||
renderItem: Function
|
||
},
|
||
computed: {
|
||
overview() {
|
||
let total = this.list?.length || 0,
|
||
online = this.list?.filter(e => e.deviceStatus == 1)?.length || 0
|
||
return {
|
||
total, online,
|
||
percent: Math.ceil(online / total * 100) || 0
|
||
}
|
||
},
|
||
propsConfig() {
|
||
return {
|
||
label: 'name',
|
||
children: 'children'
|
||
}
|
||
},
|
||
treeData() {
|
||
let {list, noArea, staData} = this
|
||
let meta = [staData?.reduce((t, e) => {
|
||
return t.type <= e.type ? t : e
|
||
}, {name: '读取中...'})]
|
||
meta.map(p => this.addChild(p, [...staData, ...list].map(s => ({
|
||
...s,
|
||
parentId: s.areaId || s.parent_id
|
||
}))))
|
||
return [...meta, {
|
||
id: 'no_area',
|
||
name: '未知区划',
|
||
children: noArea
|
||
}]
|
||
}
|
||
},
|
||
data() {
|
||
return {
|
||
list: [],
|
||
noArea: [],
|
||
staData: [],
|
||
name: '',
|
||
search: {
|
||
bind: ''
|
||
},
|
||
btnLoading: false,
|
||
}
|
||
},
|
||
methods: {
|
||
handleShow() {
|
||
this.$emit('update:show', !this.show)
|
||
},
|
||
getDevices() {
|
||
this.ins.post("/app/appzyvideoequipment/tree", null, {
|
||
params: {size: 999}
|
||
}).then(res => {
|
||
if (res?.data) {
|
||
this.staData = res.data.count
|
||
this.list = res.data.list
|
||
this.noArea = res.data.noArea
|
||
this.$emit('list', this.list)
|
||
}
|
||
})
|
||
},
|
||
updateDev() {
|
||
this.btnLoading = true
|
||
this.ins.post(`/app/appzyvideoequipment/sync`, null, {
|
||
timeout: 1000000
|
||
}).then(res => {
|
||
if (res.code == 0) {
|
||
this.$message.success('更新成功')
|
||
this.getDevices()
|
||
}
|
||
}).finally(() => this.btnLoading = false)
|
||
},
|
||
handleNodeClick(data) {
|
||
this.$emit('select', data)
|
||
},
|
||
handleFilter(v, data) {
|
||
if (!v) {
|
||
return !this.search.bind ? true : data.deviceStatus === this.search.bind
|
||
}
|
||
|
||
return data?.name?.indexOf(v) > -1 && (!this.search.bind ? true : data.deviceStatus === this.search.bind)
|
||
},
|
||
handleTreeFilter(v) {
|
||
this.$refs.deviceTree?.filter(v)
|
||
},
|
||
|
||
onChange() {
|
||
this.$refs.deviceTree?.filter(this.search.name)
|
||
}
|
||
},
|
||
created() {
|
||
this.dict.load("deviceStatus")
|
||
this.getDevices()
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.deviceSlider {
|
||
display: flex;
|
||
align-items: center;
|
||
flex-shrink: 0;
|
||
color: #fff;
|
||
|
||
div[flex] {
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
div[fill] {
|
||
flex: 1;
|
||
min-width: 0;
|
||
min-height: 0;
|
||
}
|
||
|
||
.mainPane {
|
||
width: 280px;
|
||
height: 100%;
|
||
background: #333C53;
|
||
display: flex;
|
||
flex-direction: column;
|
||
padding-top: 16px;
|
||
overflow: hidden;
|
||
box-sizing: border-box;
|
||
|
||
b {
|
||
font-size: 18px;
|
||
}
|
||
|
||
div[overview], div[search] {
|
||
box-sizing: border-box;
|
||
font-size: 12px;
|
||
justify-content: space-between;
|
||
padding: 0 16px;
|
||
gap: 4px;
|
||
margin-bottom: 16px;
|
||
|
||
::v-deep.el-input__inner {
|
||
color: #fff;
|
||
}
|
||
}
|
||
|
||
div[title] {
|
||
height: 28px;
|
||
background: #3E4A69;
|
||
padding: 0 16px;
|
||
line-height: 28px;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
|
||
::v-deep .el-button {
|
||
padding: 0 4px;
|
||
height: 28px;
|
||
background: #3E4A69;
|
||
}
|
||
|
||
::v-deep .el-button:hover {
|
||
border: none;
|
||
}
|
||
}
|
||
|
||
::v-deep.deviceList {
|
||
padding: 0 8px;
|
||
|
||
.el-scrollbar {
|
||
height: 100%;
|
||
|
||
.el-scrollbar__wrap {
|
||
box-sizing: content-box;
|
||
padding-bottom: 17px;
|
||
}
|
||
}
|
||
}
|
||
|
||
::v-deep .el-progress__text, p {
|
||
color: #19D286;
|
||
}
|
||
|
||
::v-deep .el-input__inner {
|
||
background: #282F45;
|
||
border: none;
|
||
}
|
||
|
||
::v-deep .el-tree {
|
||
background: transparent;
|
||
color: #fff;
|
||
|
||
.el-tree-node:focus > .el-tree-node__content, .el-tree-node__content:hover {
|
||
background: rgba(#fff, .1);
|
||
}
|
||
}
|
||
|
||
::v-deep .el-input__icon {
|
||
color: #89b;
|
||
}
|
||
}
|
||
|
||
.rightBtn {
|
||
width: 16px;
|
||
height: 80px;
|
||
background: url("https://cdn.cunwuyun.cn/monitor/drawerBtn.png");
|
||
color: #fff;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
|
||
.iconfont {
|
||
transition: transform 0.2s;
|
||
}
|
||
|
||
|
||
&.show > .iconfont {
|
||
transform: rotate(180deg);
|
||
}
|
||
}
|
||
}
|
||
</style>
|