在线监测点

This commit is contained in:
仲么了
2024-02-21 16:41:40 +08:00
parent 30513eb374
commit c9ae51e141
17 changed files with 637 additions and 1 deletions

View File

@@ -0,0 +1,10 @@
import request from '@/utils/request'
// 获取区域中断设备
export function getTerminalTreeForFive(data:any) {
return request({
url: '/device-boot/terminalTree/getTerminalTreeForFive',
method: 'post',
data: data,
})
}

View File

@@ -23,6 +23,7 @@
size="18"
class="fold ml10 menu-collapse"
style="cursor: pointer"
v-if='props.canExpand'
/>
</div>
<el-tree
@@ -61,10 +62,12 @@ defineOptions({
})
interface Props {
width?: string
canExpand?: boolean
}
const props = withDefaults(defineProps<Props>(), {
width: '280px'
width: '280px',
canExpand: true
})
const { proxy } = useCurrentInstance()
const menuCollapse = ref(false)

View File

@@ -0,0 +1,116 @@
<template>
<div style='height: 100%;width: 100%;display: flex;flex-direction: column'>
<el-select v-model='formData.statisticalType' placeholder='请选择' style='min-width: unset;padding: 10px 10px 0'
@change='loadData'>
<el-option v-for='item in classificationData' :key='item.id' :label='item.name'
:value='item.id'></el-option>
</el-select>
<div style='flex: 1;overflow: hidden'>
<Tree ref='treRef' :data='tree' style='width: 100%;height: 100%' :canExpand='false' />
</div>
</div>
</template>
<script lang='ts' setup>
import { ref, nextTick } from 'vue'
import Tree from '../index.vue'
import { useAdminInfo } from '@/stores/adminInfo'
import { useDictData } from '@/stores/dictData'
import { getTerminalTreeForFive } from '@/api/device-boot/terminalTree'
import { useConfig } from '@/stores/config'
defineOptions({
name: 'pms/pointTree'
})
const emit = defineEmits(['init'])
const adminInfo = useAdminInfo()
const dictData = useDictData()
const config = useConfig()
const classificationData = dictData.getBasicData('Statistical_Type', ['Report_Type'])
console.log(classificationData)
const tree = ref()
const treRef = ref()
const formData = ref({
deptIndex: adminInfo.$state.deptIndex,
monitorFlag: 2,
powerFlag: 2,
loadType: null,
manufacturer: null,
serverName: 'event-boot',
statisticalType: classificationData[0].id,
scale: null
})
console.log(formData)
const loadData = () => {
let form = JSON.parse(JSON.stringify(formData.value))
form.statisticalType = classificationData.find((item: any) => item.id == form.statisticalType)
getTerminalTreeForFive(form).then(res => {
console.log(res)
let arr: any[] = []
res.data.forEach((item: any) => {
item.icon = 'fa-solid fa-synagogue'
item.color = config.getColorVal('elementUiPrimary')
item.children.forEach((item2: any) => {
item2.icon = 'fa-solid fa-city'
item.color = config.getColorVal('elementUiPrimary')
item2.children.forEach((item3: any) => {
item3.icon = 'fa-solid fa-building'
item3.color = config.getColorVal('elementUiPrimary')
item3.children.forEach((item4: any) => {
item4.icon = 'fa-solid fa-tower-observation'
item4.color = config.getColorVal('elementUiPrimary')
item4.children.forEach((item5: any) => {
item5.icon = 'fa-solid fa-location-dot'
item5.color = config.getColorVal('elementUiPrimary')
if (item5.comFlag === 0) {
item5.color = 'red !important'
} else if (item5.comFlag === 1) {
item5.color = '#00f93b !important'
} else if (item5.comFlag === 2) {
item5.color = '#8c8c8c !important'
}
})
})
})
})
})
tree.value = res.data
})
}
loadData()
// getTerminalTreeForFive().then(res => {
// let arr: any[] = []
// res.data.forEach((item: any) => {
// item.icon = 'el-icon-HomeFilled'
// item.color = config.getColorVal('elementUiPrimary')
// item.children.forEach((item2: any) => {
// item2.icon = 'el-icon-List'
// item.color = config.getColorVal('elementUiPrimary')
// item2.children.forEach((item3: any) => {
// item3.icon = 'el-icon-Platform'
// item3.color = config.getColorVal('elementUiPrimary')
// if (item3.comFlag === 1) {
// item3.color = '#e26257 !important'
// }
// item3.children.forEach((item4: any) => {
// item4.icon = 'el-icon-LocationFilled'
// arr.push(item4)
// })
// })
// })
// })
// tree.value = res.data
// nextTick(() => {
// if (arr.length) {
// treRef.value.treeRef.setCurrentKey(arr[0].id)
// // 注册父组件事件
// emit('init', {
// level: 2,
// ...arr[0]
// })
// } else {
// emit('init')
// }
// })
// })
</script>

View File

@@ -0,0 +1,10 @@
<template>
<div class='default-main'>
</div>
</template>
<script setup lang='ts'>
import { ref } from 'vue'
</script>
<style></style>

View File

@@ -0,0 +1,10 @@
<template>
<div class='default-main'>
</div>
</template>
<script setup lang='ts'>
import { ref } from 'vue'
</script>
<style></style>

View File

@@ -0,0 +1,10 @@
<template>
<div class='default-main'>
</div>
</template>
<script setup lang='ts'>
import { ref } from 'vue'
</script>
<style></style>

View File

@@ -0,0 +1,10 @@
<template>
<div class='default-main'>
</div>
</template>
<script setup lang='ts'>
import { ref } from 'vue'
</script>
<style></style>

View File

@@ -0,0 +1,20 @@
<template>
<div class='default-main'>
<el-tabs v-model='activeName' type='border-card' class='demo-tabs'>
<el-tab-pane label='导航' name='1'>
</el-tab-pane>
<el-tab-pane label='事件统计' name='2'>
</el-tab-pane>
<el-tab-pane label='事件分析' name='3'>
</el-tab-pane>
<el-tab-pane label='运行情况' name='4'>
</el-tab-pane>
</el-tabs>
</div>
</template>
<script setup lang='ts'>
import { ref } from 'vue'
const activeName = ref('1')
</script>
<style></style>

View File

@@ -0,0 +1,10 @@
<template>
<div class='default-main'>
</div>
</template>
<script setup lang='ts'>
import { ref } from 'vue'
</script>
<style></style>

View File

@@ -0,0 +1,10 @@
<template>
<div class='default-main'>
</div>
</template>
<script setup lang='ts'>
import { ref } from 'vue'
</script>
<style></style>

View File

@@ -0,0 +1,10 @@
<template>
<div class='default-main'>
</div>
</template>
<script setup lang='ts'>
import { ref } from 'vue'
</script>
<style></style>

View File

@@ -0,0 +1,33 @@
<template>
<div class='default-main'>
<el-tabs v-model='activeName' type='border-card' class='demo-tabs'>
<el-tab-pane label='导航' name='1' :style='height'>
<Navigation />
</el-tab-pane>
<el-tab-pane label='事件统计' name='2'>
<EventStatistics />
</el-tab-pane>
<el-tab-pane label='事件分析' name='3'>
<EventStudy />
</el-tab-pane>
<el-tab-pane label='运行情况' name='4'>
<RunningCondition />
</el-tab-pane>
</el-tabs>
</div>
</template>
<script setup lang='ts'>
import { defineOptions, ref } from 'vue'
import Navigation from './navigation/index.vue'
import EventStatistics from './eventStatistics/index.vue'
import EventStudy from './eventStudy/index.vue'
import RunningCondition from './runningCondition/index.vue'
import { mainHeight } from '@/utils/layout'
defineOptions({
name: 'Descentsystem/monitoringpoint'
})
const height = mainHeight(82)
const activeName = ref('1')
</script>
<style></style>

View File

@@ -0,0 +1,32 @@
<template>
<splitpanes style='height: 100%;' class='default-theme' id='navigation-splitpanes'>
<pane :size='size'>
<PointTree></PointTree>
</pane>
<pane>
<Map></Map>
</pane>
</splitpanes>
</template>
<script setup lang='ts'>
import { defineOptions, onMounted, ref } from 'vue'
import 'splitpanes/dist/splitpanes.css'
import { Splitpanes, Pane } from 'splitpanes'
import PointTree from '@/components/tree/pms/pointTree.vue'
import Map from './map.vue'
const size = ref(0)
onMounted(() => {
const dom = document.getElementById('navigation-splitpanes')
if (dom) {
size.value = parseInt(240 / dom.offsetHeight * 100)
}
})
</script>
<style lang='scss'>
.splitpanes.default-theme .splitpanes__pane {
background: #eaeef1;
}
</style>

View File

@@ -0,0 +1,299 @@
<template>
<div style='position: relative; height: 100%' v-loading='loading'>
<div style='display: none'>
<DatePicker ref='datePickerRef'></DatePicker>
</div>
<div class='iconBox'>
<div class='div'>
<img src='@/assets/jcd.png' alt='' />
<span>变电站</span>
</div>
<div class='div'>
<img src='@/assets/rby.png' alt='' />
<span>热备用</span>
</div>
<div class='div'>
<img src='@/assets/ty.png' alt='' />
<span>停运</span>
</div>
<div class='div'>投运</div>
<div class='div' style='padding-left: 10px'>
<span>通讯正常</span>
</div>
<div class='div' style='padding-left: 20px'>
<img src='@/assets/txzcyzj.gif' alt='' />
<span>有暂降</span>
</div>
<div class='div' style='padding-left: 20px'>
<img src='@/assets/txzcwzj.png' alt='' />
<span>无暂降</span>
</div>
<div class='div' style='padding-left: 10px'>
<span>通讯异常</span>
</div>
<div class='div' style='padding-left: 20px'>
<img src='@/assets/txycyzj.gif' alt='' />
<span>有暂降</span>
</div>
<div class='div' style='padding-left: 20px'>
<img src='@/assets/txzdwzj.png' alt='' />
<span>无暂降</span>
</div>
</div>
<baidu-map
class='bm-view'
:zoom='zoom'
:map-click='false'
:scroll-wheel-zoom='true'
:center='center'
@ready='handler'
@zoomend='syncCenterAndZoom'
>
<bm-map-type
:map-types="['BMAP_NORMAL_MAP', 'BMAP_HYBRID_MAP']"
anchor='BMAP_ANCHOR_TOP_RIGHT'
></bm-map-type>
<!-- 线-->
<bm-polyline :path='path' v-for='(path, index) in polyline' :key='index'></bm-polyline>
<!-- 变电站-->
<template v-if='zoom > 12'>
<bm-marker
:position='path'
v-for='path in siteList'
:key='path.subId'
:icon='path.icon'
@click='markerClick(path)'
></bm-marker>
</template>
<!-- 点 -->
<BmlMarkerClusterer>
<bm-marker
:position='path'
v-for='path in areaLineInfo'
:key='path.lineId'
:icon='path.icon'
@click='markerClick(path)'
></bm-marker>
</BmlMarkerClusterer>
<bm-marker :position='infoWindowPoint' :icon="{ url: '1', size: { width: 0, height: 0 } }">
<bm-info-window :show='infoWindowPoint.show' @close='infoWindowPoint.show = false'>
<el-descriptions :title='infoWindowPoint.lineName' :column='1' v-if='infoWindowPoint.lineId'>
<el-descriptions-item label='供电公司'>{{ infoWindowPoint.gdName }}</el-descriptions-item>
<el-descriptions-item label='变电站'>{{ infoWindowPoint.subName }}</el-descriptions-item>
<el-descriptions-item label='母线'>{{ infoWindowPoint.voltageName }}</el-descriptions-item>
<el-descriptions-item label='网络参数'>
{{ infoWindowPoint.ip }}
</el-descriptions-item>
<el-descriptions-item label='PT变化'>{{ infoWindowPoint.pt2 }}</el-descriptions-item>
<el-descriptions-item label='CT变化'>{{ infoWindowPoint.ct2 }}</el-descriptions-item>
<el-descriptions-item label='生产厂家'>
{{ infoWindowPoint.manufacturer }}
</el-descriptions-item>
<el-descriptions-item label='终端状态'>
{{
infoWindowPoint.runFlag == 0
? '投运'
: infoWindowPoint.runFlag == 1
? '热备用'
: '停运'
}}
</el-descriptions-item>
<el-descriptions-item label='通讯状态'>
{{ infoWindowPoint.comFlag == 0 ? '中断' : '正常' }}
</el-descriptions-item>
<el-descriptions-item>
<el-button type='primary' size='small'>查看监测点</el-button>
<el-button type='primary' size='small' @click='lookEvent'>
未处理事件({{ infoWindowPoint.noDealCount }})
</el-button>
</el-descriptions-item>
</el-descriptions>
<el-descriptions
:title='infoWindowPoint.subName'
:column='1'
v-else-if='infoWindowPoint.subId'
style='padding-top: 10px'
></el-descriptions>
</bm-info-window>
</bm-marker>
</baidu-map>
</div>
</template>
<script setup lang='ts'>
import { BmlMarkerClusterer } from 'vue-baidu-map-3x'
import { ref } from 'vue'
import { getAreaLineInfo } from '@/api/event-boot/areaInfo'
import DatePicker from '@/components/form/datePicker/index.vue'
import { useAdminInfo } from '@/stores/adminInfo'
const adminInfo = useAdminInfo()
const datePickerRef = ref()
const zoom = ref(11)
const loading = ref(true)
const popupEvent = ref()
const params = ref({
deptIndex: '',
monitorFlag: 2,
powerFlag: 2,
searchBeginTime: '',
searchEndTime: '',
serverName: 'event-boot',
statisticalType: {}
})
const center = ref({
lng: 0,
lat: 0
})
const infoWindowPoint = ref<anyObj>({
lng: 0,
lat: 0,
show: false
})
const areaLineInfo = ref<any>([])
const siteList = ref<any>([])
const polyline = ref<any>([])
const lineId = ref('')
const handler = async ({ BMap, map }: any) => {
params.value.deptIndex = adminInfo.$state.deptId
params.value.searchBeginTime = datePickerRef.value.timeValue[0]
params.value.searchEndTime = datePickerRef.value.timeValue[1]
let { data } = await getAreaLineInfo(params.value)
let r = 0.0035
data.forEach((item: any) => {
// 变电站图标
item.icon = {
url: new URL('@/assets/jcd.png', import.meta.url).href,
size: {
width: 40,
height: 40
}
}
if (item.children.length > 10 && item.children.length < 100) {
r = 0.0055
} else if (item.children.length >= 100) {
r = 0.01055
}
item.children.forEach((val: any, i: number) => {
val.lng = item.lng + r * Math.cos((2 * Math.PI * i) / item.children.length)
val.lat = item.lat + r * Math.sin((2 * Math.PI * i) / item.children.length)
// 监测点图标
val.icon = {
url: '',
size: {
width: 40,
height: 40
}
}
switch (val.runFlag) {
case 0:
// 投运
if (val.comFlag == 0) {
// 异常
if (val.noDealCount > 0) {
// 异常有暂降
val.icon.url = new URL('@/assets/txycyzj.gif', import.meta.url).href
} else if (val.noDealCount == 0) {
// 异常无暂降
val.icon.url = new URL('@/assets/txzdwzj.png', import.meta.url).href
}
} else if (val.comFlag == 1) {
// 正常
if (val.noDealCount > 0) {
// 正常有暂降
val.icon.url = new URL('@/assets/txzcyzj.gif', import.meta.url).href
} else if (val.noDealCount == 0) {
// 正常无暂降
val.icon.url = new URL('@/assets/txzcwzj.png', import.meta.url).href
}
}
break
case 1:
val.icon.url = new URL('@/assets/rby.png', import.meta.url).href
break
case 2:
val.icon.url = new URL('@/assets/ty.png', import.meta.url).href
break
default:
break
}
polyline.value.push([
{
lng: item.lng,
lat: item.lat
},
{
lng: val.lng,
lat: val.lat
}
])
})
areaLineInfo.value.push(...item.children)
})
siteList.value = data
center.value.lng = areaLineInfo.value[0].lng
center.value.lat = areaLineInfo.value[0].lat
infoWindowPoint.value = areaLineInfo.value[0]
infoWindowPoint.value.show = true
zoom.value = 15
setTimeout(() => {
loading.value = false
}, 1500)
}
const syncCenterAndZoom = (e: any) => {
zoom.value = e.target.getZoom()
}
const markerClick = (e: any) => {
infoWindowPoint.value = e
infoWindowPoint.value.show = true
}
const lookEvent = (e: any) => {
popupEvent.value.open({
id: infoWindowPoint.value.lineId,
searchBeginTime: datePickerRef.value.timeValue[0],
searchEndTime: datePickerRef.value.timeValue[1]
})
}
</script>
<style lang='scss' scoped>
.bm-view {
width: 100%;
height: 100%;
}
.selectBox {
position: absolute;
top: 16px;
left: 165px;
z-index: 2000;
width: 240px;
}
.iconBox {
position: absolute;
bottom: 10px;
right: 10px;
z-index: 2000;
width: 150px;
height: 260px;
padding: 10px;
background: rgba(255, 255, 255, 0.75) !important;
border: 1px solid #ccc;
border-radius: 4px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.12), 0 0 6px rgba(0, 0, 0, 0.04);
font-size: 12px;
.div {
display: flex;
margin-bottom: 5px;
img {
height: 20px;
margin-right: 5px;
}
}
}
</style>

View File

@@ -0,0 +1,10 @@
<template>
<div class='default-main'>
</div>
</template>
<script setup lang='ts'>
import { ref } from 'vue'
</script>
<style></style>