Files
admin-sjzx/src/views/pqs/panorama/components/map.vue

520 lines
18 KiB
Vue
Raw Normal View History

2024-12-23 09:29:59 +08:00
<template>
<div class="default-main">
<DatePicker ref="datePickerRef" theCurrentTime style="display: none" />
2024-12-30 16:28:12 +08:00
<!-- 搜索框 -->
<div class="query-box-wrap">
<el-input v-model.trim="inputQuery" style="height: 46px; width: 334px" @keyup.enter="DeviceQ"
placeholder="请输入终端名称">
<template #prefix>
<div class="Icon"></div>
</template>
<template #suffix>
<el-icon @click="DeviceQ" class="el-input__icon">
<Search />
</el-icon>
</template>
</el-input>
</div>
<!-- 搜索内容展示 -->
<div class="query-box-wrap collapse" v-show="showWrap">
<div v-if="QueryList.length == 0" class="collapse_none">查询无结果</div>
<el-collapse v-if="QueryList.length > 0 && showCollapse" v-model="activeName" accordion>
<el-collapse-item v-for="(item, i) in QueryList" :name="i">
<template #title>
{{ item.psrName }}
<span class="ml10" style="color: #0d867f">{{ item.count }}</span>
</template>
<div class="collapseBox">
<div class="group-list__item"
:style="colorKey == k.coordinate ? 'background-color: #009ea81a;' : ''"
v-for="k in item.psrList" @click="flyTo(k)">
<p>{{ k.psrName }}</p>
<p>{{ k.vlevelName }}|{{ k.maintOrgName }}</p>
</div>
</div>
</el-collapse-item>
</el-collapse>
2025-01-07 16:32:42 +08:00
2024-12-30 16:28:12 +08:00
<div v-if="QueryList.length > 0 && !showCollapse" class="collapse_none" style="color: #009ea8"
@click="showCollapse = true">
展开搜索结果
</div>
2025-01-07 16:32:42 +08:00
<div class="collapse_none" style="color: red;cursor: pointer" @click="showWrap = false">关闭</div>
2024-12-30 16:28:12 +08:00
</div>
<baidu-map class="map" :style="height" @ready="initMap" @zoomend='syncCenterAndZoom' :center="center"
2025-01-15 10:44:57 +08:00
:zoom="zoomMap" :scroll-wheel-zoom='true' >
2024-12-23 09:29:59 +08:00
<!-- 线-->
<div v-if='zoom > 13'>
<bm-polyline :path='path' v-for='(path, index) in polyline' :key='index'></bm-polyline>
</div>
<!-- 变电站-->
<template v-if='zoom > 13'>
<bm-marker :position='path' v-for='path in siteList' :key='path.subId' :icon='path.icon'
@click='markerClick(path)'></bm-marker>
</template>
<!-- -->
2025-01-15 10:44:57 +08:00
<div :maxZoom='12' v-if='zoom > 9'>
2024-12-23 09:29:59 +08:00
<bm-marker :position='path' v-for='path in areaLineInfo' :key='path.lineId' :icon='path.icon'
2024-12-30 16:28:12 +08:00
@click='markerClick(path)' :zIndex="1">
<bm-label v-if='zoom > 14' :content="path.lineName"
:labelStyle="{ color: '#fff', border: '0px solid #fff', backgroundColor: 'rgba(0, 0, 0, 0.5)', borderRadius: '10px', padding: '2px 5px', fontSize: '12px', lineHeight: '15px', transform: 'translateX(-30%)' }"
:offset="{ height: 33 }" />
</bm-marker>
2025-01-15 10:44:57 +08:00
</div>
2024-12-30 16:28:12 +08:00
<!-- 详情 -->
<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' @click='lookPoint(infoWindowPoint)'>查看详情</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>
2024-12-23 09:29:59 +08:00
<!-- 行政区划 -->
2025-01-15 10:44:57 +08:00
<div v-if='zoom <= 11'>
<div v-for="item in AreaData">
<bm-polygon v-for="timeK in item.boundary" :path="timeK" :strokeWeight="2" strokeColor="#fff"
:strokeOpacity="1" :fillColor="item.background || ''" :fillOpacity="0.5"></bm-polygon>
</div>
</div>
<!-- 信息弹框 -->
<div v-if='zoom <= 9'>
<bm-overlay v-for="item in AreaData" pane="labelPane" :class="{ sample: true, }"
@draw="draw($event, item.LngLat)">
<div class="my-radiusPop" :style="{ background: item.background }">
<img :src="PopKey == 2 ? imgUrl2 : PopKey == 1 ? imgUrl1 : PopKey == 0 ? imgUrl0 : ''" />
<div class="infoBox">
<div>
总数<br />{{ PopKey == 2 ? item.lineNum : PopKey == 1 ? item.deviceNum : PopKey == 0 ?
item.subNum :
'/' }}
</div>
<div>
{{ PopKey == 2 ? '在线' : PopKey == 1 ? '在运' : '告警' }}<br />{{ PopKey == 2 ?
item.onlineNum :
PopKey
== 1
?
item.alarmSubNum : PopKey == 0 ?
item.onDevice : '/' }}
</div>
<div v-if="PopKey == 2">
告警<br />{{ PopKey == 2 ? item.alarm : PopKey == 1 ? item.xx : PopKey == 0 ? item.xx :
'/' }}
</div>
</div>
</div>
</bm-overlay>
</div>
2024-12-23 09:29:59 +08:00
</baidu-map>
</div>
</template>
<script setup lang='ts'>
import { mainHeight } from '@/utils/layout'
import { getAreaLineInfo } from '@/api/event-boot/areaInfo'
import { ref, reactive, onMounted } from 'vue'
import DatePicker from '@/components/form/datePicker/index.vue'
import { useDictData } from '@/stores/dictData'
2024-12-30 16:28:12 +08:00
import { Search } from '@element-plus/icons-vue'
2025-01-15 10:44:57 +08:00
import { BaiduMap, BmOverlay } from 'vue-baidu-map-3x'
import { getAssessOverview } from '@/api/device-boot/panorama'
import { getGridDiagramAreaData } from '@/api/device-boot/panorama'
2024-12-30 16:28:12 +08:00
const emit = defineEmits(['changeValue', 'drop', 'show'])
2025-01-15 10:44:57 +08:00
import mapJson from './boundary';
2024-12-23 09:29:59 +08:00
const datePickerRef = ref()
const height = mainHeight(20)
// 页面中直接引入就可以
const dictData = useDictData()
2024-12-30 16:28:12 +08:00
const inputQuery: any = ref('')
const QueryList: any = ref([])
const activeName: any = ref(0)
2025-01-15 10:44:57 +08:00
const zoomMap = ref(8.8)
2024-12-30 16:28:12 +08:00
const colorKey = ref('')
const showCollapse: any = ref(true)
const showWrap: any = ref(false)
2024-12-23 09:29:59 +08:00
const deptIndex = ref(dictData.state.area[0].id)
2025-01-15 10:44:57 +08:00
const assessList: any = ref([])
const AreaData: any = ref([])
const PopKey: any = ref(2)
const imgUrl0 = new URL('@/assets/img/BDZ-ZS.png', import.meta.url).href
const imgUrl1 = new URL('@/assets/img/ZD-ZS.png', import.meta.url).href
const imgUrl2 = new URL('@/assets/img/JCD-ZS.png', import.meta.url).href
const boundaryList: any = ref([
{
orgName: '唐山',
LngLat: [118.335849137, 39.7513593355],
boundary: mapJson.tsJSON
},
{
orgName: '张家口',
LngLat: [115.032504679, 40.8951549951],
boundary: mapJson.zjkJSON
},
{
orgName: '秦皇岛',
LngLat: [119.185113833, 40.1179119754],
boundary: mapJson.qhdJSON
},
{
orgName: '承德',
LngLat: [117.548498365, 41.3775890632],
boundary: mapJson.cdJSON
},
{
orgName: '廊坊',
LngLat: [116.628004129, 39.0589378611],
boundary: mapJson.lfJSON
}
2024-12-23 09:29:59 +08:00
])
const zoom = ref(13)
const areaLineInfo = ref<any>([])
const siteList = ref<any>([])
const polyline = ref<any>([])
const lineId = ref('')
const center = ref({
2025-01-15 10:44:57 +08:00
lng: 116.84428600000001, lat: 40.57707185292256
2024-12-30 16:28:12 +08:00
})
const infoWindowPoint = ref<anyObj>({
2024-12-23 09:29:59 +08:00
lng: 0,
2024-12-30 16:28:12 +08:00
lat: 0,
show: false
})
// 地图实例
2024-12-23 09:29:59 +08:00
const initMap = async ({ BMap, map }: any) => {
}
2024-12-30 16:28:12 +08:00
// 加载点
2024-12-23 09:29:59 +08:00
const addMarkers = async (row?: any, key?: any, num?: any) => {
let params = {
deptIndex: deptIndex.value,
monitorFlag: 2,
powerFlag: 2,
searchBeginTime: datePickerRef.value.timeValue[0],
searchEndTime: datePickerRef.value.timeValue[1],
serverName: 'event-boot',
statisticalType: {},
...row
}
let { data } = await getAreaLineInfo(params)
2024-12-30 16:28:12 +08:00
polyline.value = []
areaLineInfo.value = []
2024-12-23 09:29:59 +08:00
let r = 0.0035
let list = data.filter((item: any) => item.lng != 0)
list.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 = list
2024-12-30 16:28:12 +08:00
// center.value.lng = areaLineInfo.value[0].lng
// center.value.lat = areaLineInfo.value[0].lat
2024-12-23 09:29:59 +08:00
}
2024-12-30 16:28:12 +08:00
// 获取zoom
2024-12-23 09:29:59 +08:00
const syncCenterAndZoom = (e: any) => {
zoom.value = e.target.getZoom()
}
const locatePositions = (e: any) => {
deptIndex.value = e.data.id
// 加载点
addMarkers()
// powerManageGridMap.value.drillDown({
// // 判断超高压
// orgId: e.data.code == '1100F3DE246A6FADE050007F01006CBE' ? '1100F3DE20806FADE050007F01006CBE' : e.data.code,
// onlyDisplay: true
// })
}
2024-12-30 16:28:12 +08:00
// 点击点
2024-12-23 09:29:59 +08:00
const markerClick = (e: any) => {
2025-01-07 16:32:42 +08:00
showCollapse.value = false
2024-12-30 16:28:12 +08:00
infoWindowPoint.value = e
infoWindowPoint.value.show = true
2024-12-23 09:29:59 +08:00
}
2024-12-30 16:28:12 +08:00
// 查看详情
const lookPoint = (e: any) => {
emit('drop', e.lineId)
emit('show', true)
}
// 搜索
const DeviceQ = () => {
showCollapse.value = true
if (inputQuery.value.length == 0) return
let list = []
let regex = new RegExp(inputQuery.value, 'i')
let data = areaLineInfo.value.filter((item: any) => regex.test(item.lineName))
.map((item: any) => {
return {
psrName: item.lineName,
vlevelName: item.voltageScale,
maintOrgName: item.gdName,
coordinate: [item.lng, item.lat]
}
})
// data.replace(//s/g,',')
if (data.length > 0) {
list.push({
count: data.length,
psrList: data,
psrName: '监测点'
})
}
QueryList.value = list
showWrap.value = true
}
// 定位
2025-01-15 10:44:57 +08:00
const flyTo = (e: any, zoom?: number) => {
2024-12-30 16:28:12 +08:00
let regex = new RegExp(e.psrName, 'i')
center.value.lng = e.coordinate[0]
center.value.lat = e.coordinate[1]
2025-01-15 10:44:57 +08:00
if (zoom) { zoomMap.value = zoom }
else {
zoomMap.value = 15
let data = areaLineInfo.value.filter((item: any) => regex.test(item.lineName))[0]
if (data) {
markerClick(data)
}
2024-12-30 16:28:12 +08:00
}
2024-12-23 09:29:59 +08:00
2025-01-07 16:32:42 +08:00
2025-01-15 10:44:57 +08:00
}
// 市级统计数据
const grids = (row: any) => {
let form = {
...row,
id: row.orgNo,
deptIndex: row.orgNo,
orgId: row.orgNo,
ids: [],
statisticalType: dictData.getBasicData('Statistical_Type', ['Report_Type'])[0],
isUpToGrid: row.isUpToGrid,
monitorFlag: row.isUpToGrid == 0 ? null : row.isUpToGrid
}
AreaData.value=[]
assessList.value=[]
// 综合评估
getAssessOverview(form).then(res => {
assessList.value = res.data?.children
getGridDiagramAreaData({ ...form, deptIndex: deptIndex.value }).then((res: any) => {
AreaData.value = res.data
GridDiagramArea()
})
// if (powerManageGridMap.value) powerLoad()
})
}
const radiusPop = (k: any) => {
console.log("🚀 ~ radiusPop ~ k:", k)
if (k != undefined) PopKey.value = k
}
const GridDiagramArea = () => {
boundaryList.value.forEach((item: any) => {
assessList.value.forEach((y: any) => {
if (item.orgName == y.name) {
if (y.score == 3.14159) {
} else if (y.score > 4.5) {
item.background = '#33996699'
} else if (y.score > 4) {
item.background = '#3399ff99'
} else if (y.score > 3) {
item.background = '#ffcc3399'
} else if (y.score > 2) {
item.background = '#db088799'
} else if (y.score > 0) {
item.background = '#ff000099'
}
}
})
AreaData.value.forEach((k: any, i: any) => {
if (item.orgName == k.orgName) {
for (let kk in item) {
k[kk] = item[kk]
}
}
})
})
AreaData.value = AreaData.value.filter((item: any) => item.orgName != '超高压' && item.orgName != '风光储')
setTimeout(() => {
// radiusPop()
}, 0)
}
// 市级统计
const draw = ({ el, BMap, map }, val) => {
const pixel = map.pointToOverlayPixel(new BMap.Point(val[0], val[1]))
el.style.left = pixel.x - 60 + 'px'
el.style.top = pixel.y - 20 + 'px'
2025-01-07 16:32:42 +08:00
}
// 重置
const reset = () => {
inputQuery.value = ''
showWrap.value = false
2024-12-23 09:29:59 +08:00
}
onMounted(() => {
})
2025-01-15 10:44:57 +08:00
defineExpose({ addMarkers, locatePositions, reset, grids, radiusPop, flyTo })
2024-12-23 09:29:59 +08:00
</script>
<style lang="scss" scoped>
2024-12-30 16:28:12 +08:00
@use '@/views/pqs/qualityInspeection/panorama/components/style/map.scss';
2024-12-23 09:29:59 +08:00
.map {
width: 100%;
}
2024-12-30 16:28:12 +08:00
.query-box-wrap {
z-index: 1;
}
2025-01-07 16:32:42 +08:00
:deep(.el-collapse-item__content) {
padding-bottom: 0px !important;
}
2025-01-15 10:44:57 +08:00
.sample {
position: absolute;
.my-radiusPop {
width: 200px;
height: 50px;
border-radius: 5px;
background: rgba(0, 0, 0, 0.5);
overflow: hidden;
// box-shadow: 0 0 5px #000;
color: #fff;
text-align: center;
padding: 5px 5px !important;
display: flex;
img {
height: 40px;
margin-right: 10px;
}
.infoBox {
flex: 1;
display: flex;
justify-content: space-around;
text-align: center;
div {
cursor: pointer;
}
}
}
}
</style>
./cds.js./boundary