xml
复制代码
<template>
<div id="map">
<div style="position: absolute;left: 40px;top: 10px;z-index: 99;display: flex;flex-direction: column;align-items: center;justify-content: center;">
<el-select
v-model="pkFireArea"
placeholder="请选择区域"
size="default"
style="width: 240px;margin-bottom: 8px"
@change="changeAreaId"
v-if="propertyShow"
>
<el-option
v-for="item in areaCoordinates"
:key="item.pkFireArea"
:label="item.areaName"
:value="item.pkFireArea"
/>
</el-select>
<el-select
v-model="alarmType"
placeholder="请选择类型"
size="default"
style="width: 240px;"
@change="changeAlarmType"
>
<el-option
v-for="item in alarmTypes"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</div>
<div class="rest" @click="restMap">
<Refresh style="width: 1em; height: 1em;" />
</div>
<!--弹窗元素-->
<div id="popupEquip" ref="popupEquipRef" v-show="currentShow">
<div class="popupContent">
<div class="popupInformat">
<div style="width: 100%;height: 30px;display: flex;border: 1px solid #d4d4d4;">
<div style="width: 30%;height: 100%;background-color: #efefef;border-right: 1px solid #d4d4d4;line-height: 30px;text-align: center;font-weight: 800;color: #888888;">小区名称</div>
<div style="width: 70%;height: 100%;line-height: 30px;text-indent: 14px;white-space: nowrap;text-overflow: ellipsis;overflow: hidden;">{{ currentEquip.communityName }}</div>
</div>
<div style="width: 100%;height: 30px;display: flex;border: 1px solid #d4d4d4;border-top: none;">
<div style="width: 30%;height: 100%;background-color: #efefef;border-right: 1px solid #d4d4d4;line-height: 30px;text-align: center;font-weight: 800;color: #888888;">压力值</div>
<div style="width: 70%;height: 100%;line-height: 30px;text-indent: 14px;">{{ currentEquip.pressure == null ? '--' : currentEquip.pressure + 'MPa' }}</div>
</div>
<div style="width: 100%;height: 30px;display: flex;border: 1px solid #d4d4d4;border-top: none;">
<div style="width: 30%;height: 100%;background-color: #efefef;border-right: 1px solid #d4d4d4;line-height: 30px;text-align: center;font-weight: 800;color: #888888;">温度</div>
<div style="width: 70%;height: 100%;line-height: 30px;text-indent: 14px;">{{ currentEquip.temperature == null ? '--' : currentEquip.temperature + '℃' }}</div>
</div>
<div style="width: 100%;height: 30px;display: flex;border: 1px solid #d4d4d4;border-top: none;">
<div style="width: 30%;height: 100%;background-color: #efefef;border-right: 1px solid #d4d4d4;line-height: 30px;text-align: center;font-weight: 800;color: #888888;">安装地址</div>
<div style="width: 70%;height: 100%;line-height: 30px;text-indent: 14px;white-space: nowrap;text-overflow: ellipsis;overflow: hidden;">{{ currentEquip.installPosition }}</div>
</div>
<div style="width: 100%;height: 30px;display: flex;border: 1px solid #d4d4d4;border-top: none;">
<div style="width: 30%;height: 100%;background-color: #efefef;border-right: 1px solid #d4d4d4;line-height: 30px;text-align: center;font-weight: 800;color: #888888;">更新时间</div>
<div style="width: 70%;height: 100%;line-height: 30px;text-indent: 14px;">{{ currentEquip.dataUpdate }}</div>
</div>
<div style="width: 100%;height: 30px;display: flex;border: 1px solid #d4d4d4;border-top: none;">
<div style="width: 30%;height: 100%;background-color: #efefef;border-right: 1px solid #d4d4d4;line-height: 30px;text-align: center;font-weight: 800;color: #888888;">详细信息</div>
<div style="width: 70%;height: 100%;line-height: 30px;text-indent: 14px;cursor: pointer;color: blue;" @click="imgInfor">查看详细信息</div>
</div>
</div>
<span class="popupClose" @click="closePopup">✖</span>
</div>
</div>
<!-- 添加对话框 -->
<el-dialog title="表具详细信息" v-model="open" width="1000px" append-to-body>
<el-form ref="postRef" style="height: 500px;">
<div style="width: 100%;height: 100%;display: flex;justify-content: center;align-items: center;">
<span style="position: absolute;left: 15%;top: 23%;">压力值:{{ currentEquip.pressure == null ? '--' : currentEquip.pressure + 'MPa' }}</span>
<span style="position: absolute;left: 15%;top: 82%;">温度:{{ currentEquip.temperature == null ? '--' : currentEquip.temperature + '℃' }}</span>
<span style="position: absolute;left: 80%;top: 82%;">电量:{{ currentEquip.temperature == null ? '--' : currentEquip.temperature + 'V' }}</span>
<span style="position: absolute;left: 80%;top: 23%;">网络:{{ currentEquip.networkState == null ? '--' : currentEquip.networkState }}</span>
<img v-if="currentEquip.pkFactory == 1" src="../assets/images//biaoju1.png" alt="">
<img v-if="currentEquip.pkFactory == 2" src="../assets/images//biaoju2.png" alt="">
</div>
</el-form>
</el-dialog>
<el-dialog title="电导率图表" v-model="showData" width="1000px" append-to-body>
<HandlerHistoryEcharts v-model:isshowData="showData" :tableList="tableList" :tag="'conductivity'" />
</el-dialog>
</div>
</template>
<script name="Index">
import { getAreaList, getDeviceList, getEquipment } from "../api/equip/home";
import { onMounted, reactive } from 'vue';
// import { require } from '../../src/utils/tool';
import gcjMecator from '../../src/utils/gcjMecator'
import { Feature, Map, View, Overlay } from 'ol'
import { XYZ, Vector as VectorSource } from 'ol/source'
import { Tile as TileLayer, Vector as VectorLayer } from 'ol/layer'
import { Zoom, defaults as defaultControls } from 'ol/control'
import { ScaleLine } from 'ol/control'
import { Fill, Stroke, Style, Icon } from 'ol/style'
import { Polygon } from 'ol/geom'
import Point from 'ol/geom/Point'
import useUserStore from '@/store/modules/user'
import dibiao from '../assets/icon/dibiao.png'
import biaoju from '../assets/icon/biaoju.png'
import xiaofangshuan from '../assets/icon/xiaofangshuan.png'
import {deviceInfoDetail, getDeviceHistoryData, getDeviceInfoList} from "../api/dataMiddleOffice/device";
import {dayjs} from "element-plus";
import HandlerHistoryEcharts from "./dataMiddleOffice/components/HandlerHistoryEcharts";
export default {
components: {HandlerHistoryEcharts},
setup() {
//电导率
const openEcharts = ref(false)
const alarmType = ref('1')
const alarmTypes = ref([{value:'1',label:'消火栓'},{value:'2',label:'电导率'}])
function changeAlarmType(){
if(alarmType.value == '1'){
getXiaofang()
}else if(alarmType.value == '2'){
getAlarm()
}
}
const tableList = ref([])
const showData = ref(false)
const latlng = ref([])
const propertyShow = ref(true)
const userStore = useUserStore()
const user = ref({})
const open = ref(false);
let map = ref(null)
let gaodeMap = ref(null)
let areaCoordinates = ref([]) //区域
let pkFireArea = ref(null) //选中区域id
let equips = ref([]) //表具所有坐标点信息
let alarms = ref([]) //表具所有坐标点信息
let mapScale = ref(0) //获取地图比例尺
let currentFeature = ref(null) //选中的要素
let currentEquip = ref({}) //选中的要素详细信息
let currentShow = ref(false)
let popupEquipLayer = ref(null)
let layerMap = reactive({
equipment: null, //设备
alarm: null, //电导率
inspectionArea: null, //片区
landmark: null, //地标
})
let layerSouceMap = reactive({
equipment: new VectorSource(),
alarm: new VectorSource(),
inspectionArea: new VectorSource(),
landmark: new VectorSource(),
})
function initMap() {
gaodeMap = new TileLayer({
crossOrigin: 'anonymous',
wrapX: false,
source: new XYZ({
projection: gcjMecator,
url: "https://webrd04.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=7&x={x}&y={y}&z={z}"
})
})
//片区
layerMap.inspectionArea = new VectorLayer({
name: 'inspectionArea',
source: layerSouceMap['inspectionArea'],
style: new Style({
fill: new Fill({
color: 'rgba(0, 0, 255, 0.3)'
}),
stroke: new Stroke({
color: 'blue',
width: 1
})
}),
visible: true
})
//地标
layerMap.landmark = new VectorLayer({
name: 'landmark',
source: layerSouceMap['landmark'],
style: new Style({
image: new Icon({
src: dibiao,
scale: 0.6,
anchor: [0.5, 0.5]
})
}),
visible: true
})
//消防栓
layerMap.equipment = new VectorLayer({
name: 'equipment',
source: layerSouceMap['equipment'],
style: new Style({
image: new Icon({
src: xiaofangshuan,
scale: 0.6,
anchor: [0.5, 0.5]
})
}),
visible: true
})
//电导率
layerMap.alarm = new VectorLayer({
name: 'alarm',
source: layerSouceMap['alarm'],
style: new Style({
image: new Icon({
src: biaoju,
scale: 0.6,
anchor: [0.5, 0.5]
})
}),
visible: true
})
map = new Map({
target: 'map',
layers: [
gaodeMap,
layerMap['inspectionArea'], //片区
// layerMap['landmark'], //地标
layerMap['equipment'], //设备点
layerMap['alarm'] //电导率
],
view: new View({
center: [120.28,31.92], //视图中心位置
projection: 'EPSG:4326', //指定投影
zoom: 8, //默认缩放级别
minZoom: 8, //最小缩放级别
maxZoom: 18, //最大缩放级别
extent: [119.95,31.63, 120.83,32.03]
}),
controls: defaultControls({
zoom: false //禁用右上角缩放组件true开启false禁用
})
})
//表具弹窗
popupEquipLayer = new Overlay({
element: document.getElementById("popupEquip"), // 弹窗标签,在html里
// autoPan: true, // 如果弹窗在底图边缘时,底图会移动
// autoPanAnimation: {
// // 底图移动动画
// duration: 250
// },
zIndex: 9999,
offset: [-160, -228] // 设置偏移量
})
map.addOverlay(popupEquipLayer)
// 鼠标移动到目标改变光标形状
// map.un('pointermove', pointerMoveToFeature)
// map.on('pointermove', pointerMoveToFeature)
scaleLineCtl();
zoomCtl();
initAllArea();
map.getView().un('change:resolution', mapChanges)
map.getView().on('change:resolution', mapChanges)
map.un('singleclick', featureClick)
map.on('singleclick', featureClick)
getXiaofang()
};
//查询点标记并初始化
function getXiaofang(){
const obj = reactive({})
obj.pkFireArea = pkFireArea.value
obj.pageSize = 1000
obj.pageNum = 1
getDeviceList(obj).then(res => {
equips.value = res.rows
initEquips();
});
}
function getAlarm(){
const obj = reactive({})
obj.pkFireArea = pkFireArea.value
obj.pageSize = 1000
obj.pageNum = 1
getDeviceInfoList(obj).then(res => {
alarms.value = res.rows
initAlarm();
});
}
/** 获取片区 */
function getArea() {
getAreaList().then(res => {
areaCoordinates.value = res.rows;
initAllLandmark();
});
}
//选择区域后加载
function changeAreaId (data) {
if (data) {
const selected = areaCoordinates.value.find(item => item.pkFireArea == data);
const [lon, lat] = selected.lngLat.split(',');
latlng.value = [Number(lon),Number(lat)]
map.getView().setCenter(latlng.value)
map.getView().setZoom(15);
// map.getView().animate({ // 只设置需要的属性即可
// center: [Number(lon),Number(lat)], // 中心点
// zoom: 18, // 缩放级别
// rotation: undefined, // 缩放完成view视图旋转弧度
// duration: 2000 // 缩放持续时间,默认不需要设置
// })
changeAlarmType()
}
}
//加载消防栓
function initEquips() {
if(layerSouceMap['alarm']) layerSouceMap['alarm'].clear()
if(layerSouceMap['equipment']) layerSouceMap['equipment'].clear()
// layerMap['equipment'].getSource().clear()
if (equips.value.length > 0) {
equips.value.forEach(item => {
item.feature = new Feature({
geometry: new Point([Number(item.longitude), Number(item.latitude)])
})
item.feature.setId(item.pkFireDevice)
layerMap['equipment'].getSource().addFeature(item.feature)
})
}
}
//加载电导率
function initAlarm() {
if(layerSouceMap['alarm']) layerSouceMap['alarm'].clear()
if(layerSouceMap['equipment']) layerSouceMap['equipment'].clear()
// layerMap['equipment'].getSource().clear()
if (alarms.value.length > 0) {
alarms.value.forEach(item => {
if(!item.latLng || !item.latLng.includes(',')) {
// 跳出循环
return
}
let latLng = item.latLng.split(',')
item.feature = new Feature({
geometry: new Point([Number(latLng[0]), Number(latLng[1])])
})
item.feature.setId(item.pkConductivity)
layerMap['alarm'].getSource().addFeature(item.feature)
})
}
}
function mapChanges() {
// mapScale.value = (map.getView().getResolution() * 377952755.90551).toFixed(0)
// const layers = map.getLayers().getArray()
// layers.forEach(item => {
// if (item.get('name') === 'equipment' && pkFireArea.value) {
// if (mapScale.value >= 30000) {
// item.setVisible(false)
// } else {
// item.setVisible(true)
// }
// }
// })
}
//点击地图获取选中的要素
function featureClick(e) {
currentFeature.value = null
const destfeatureInfo = map.forEachFeatureAtPixel(e.pixel, (feature, layer) => {
return { feature: feature, layer: layer }
})
if (destfeatureInfo) {
currentFeature.value = destfeatureInfo.feature
}
if(destfeatureInfo.layer.get('name') === 'equipment'){
//消防栓
queryEquipment();
}else if(destfeatureInfo.layer.get('name') === 'alarm'){
//电导率
queryAlarmDetail()
}else if (destfeatureInfo.layer.get('name') === 'landmark') {
//暂未使用
pkFireArea.value = currentFeature.value.getId()
const selected = areaCoordinates.value.find(item => item.pkFireArea == currentFeature.value.getId());
const [lon, lat] = selected.lngLat.split(',');
map.getView().setCenter([Number(lon),Number(lat)])
map.getView().setZoom(15);
const obj = reactive({})
obj.pkFireArea = selected.pkFireArea
getDeviceList(obj).then(res => {
equips.value = res.rows
initEquips();
});
}
}
//根据选中的要素查询详细信息
function queryEquipment() {
getEquipment(currentFeature.value.getId()).then(res => {
currentEquip.value = res.data
if (currentEquip.value) {
const view = map.getView()
view.animate({ center: [Number(currentEquip.value.longitude), Number(currentEquip.value.latitude)] })
currentShow.value = true
popupEquipLayer.setPosition([Number(currentEquip.value.longitude), Number(currentEquip.value.latitude)])
} else {
currentShow.value = false
currentEquip.value = {};
}
});
}
async function queryAlarmDetail() {
let id = currentFeature.value.getId()
let detailRes = await deviceInfoDetail(id)
let query = {
imei: detailRes.data.imei,
tag: 'conductivity',
deviceType: 1,
pkConductivity: id,
startTime: dayjs().startOf('date').format('YYYY-MM-DD HH:mm:ss'),
endTime: dayjs().endOf('date').format('YYYY-MM-DD HH:mm:ss'),
}
try{
const res = await getDeviceHistoryData(query)
tableList.value = res.data.map(item => ({
...item
}))
showData.value = true
}catch (e) {
showData.value = false
}
}
//关闭弹窗
function closePopup() {
if (popupEquipLayer) {
// 把弹窗位置设置为undefined,并清空坐标数据
popupEquipLayer.setPosition(undefined)
currentShow.value = false
currentFeature.value = null
equips.value = []
}
}
//点击详细弹窗
function imgInfor() {
open.value = true
// 假设要传递的信息是一个对象
// const infoToPass = { message: '这是传递的信息' };
// router.push({ path: '/destination-page', query: infoToPass });
}
//重置
function restMap() {
if (user.value.dept != null && user.value.dept.parentId == 200) {
map.getView().setCenter([119.95,31.63, 120.83,32.03])
map.getView().setZoom(8);
currentShow.value = false
} else {
map.getView().setCenter([119.95,31.63, 120.83,32.03])
map.getView().setZoom(8);
pkFireArea.value = null
// layerSouceMap['equipment'].clear()
// layerMap['equipment'].getSource().clear()
// currentShow.value = false
// currentEquip.value = {};
alarmType.value = '1'
getXiaofang()
}
}
//加载片区
function initAllArea() {
let geoList = [
[
120.59072,
31.740568
],
[
120.583005,
31.738926
],
[
120.574022,
31.729073
],
[
120.561393,
31.724091
],
[
120.548349,
31.729369
],
[
120.533142,
31.724792
],
[
120.512126,
31.737844
],
[
120.498151,
31.714217
],
[
120.487081,
31.711494
],
[
120.480856,
31.715605
],
[
120.468794,
31.713523
],
[
120.457134,
31.717111
],
[
120.442157,
31.707243
],
[
120.408805,
31.707004
],
[
120.372039,
31.694962
],
[
120.352578,
31.689317
],
[
120.327915,
31.700443
],
[
120.277332,
31.70358
],
[
120.271497,
31.726044
],
[
120.231901,
31.730344
],
[
120.217418,
31.726069
],
[
120.202877,
31.727572
],
[
120.198508,
31.733949
],
[
120.198549,
31.75435
],
[
120.198048,
31.764681
],
[
120.17661,
31.795971
],
[
120.16588,
31.804638
],
[
120.162303,
31.806509
],
[
120.168753,
31.805678
],
[
120.174295,
31.813942
],
[
120.158492,
31.834044
],
[
120.176787,
31.853194
],
[
120.180648,
31.863128
],
[
120.169143,
31.871762
],
[
120.150861,
31.870802
],
[
120.140234,
31.859773
],
[
120.119908,
31.862149
],
[
120.080356,
31.855118
],
[
120.037348,
31.825387
],
[
120.029551,
31.824515
],
[
120.018446,
31.830841
],
[
120.001276,
31.827033
],
[
119.996351,
31.842722
],
[
119.985485,
31.856629
],
[
119.999472,
31.862247
],
[
120.008367,
31.873
],
[
120.010121,
31.88446
],
[
119.993929,
31.896687
],
[
119.998666,
31.909871
],
[
120.014334,
31.918103
],
[
120.001815,
31.938215
],
[
120.004175,
31.953587
],
[
120.013485,
31.969902
],
[
120.014351,
31.96929
],
[
120.029476,
31.963174
],
[
120.093559,
31.952695
],
[
120.150516,
31.934242
],
[
120.231317,
31.934924
],
[
120.25,
31.937345
],
[
120.325522,
31.970092
],
[
120.367272,
31.995932
],
[
120.368293,
31.946211
],
[
120.386779,
31.931632
],
[
120.374517,
31.915511
],
[
120.386228,
31.908881
],
[
120.397809,
31.909054
],
[
120.438486,
31.895517
],
[
120.438358,
31.890922
],
[
120.460006,
31.892147
],
[
120.462252,
31.878872
],
[
120.469398,
31.876887
],
[
120.472787,
31.879991
],
[
120.485448,
31.875159
],
[
120.49788,
31.852356
],
[
120.498642,
31.843388
],
[
120.505616,
31.846864
],
[
120.525707,
31.832046
],
[
120.524795,
31.814878
],
[
120.517098,
31.812417
],
[
120.518864,
31.800482
],
[
120.529528,
31.790294
],
[
120.551086,
31.796111
],
[
120.570512,
31.793232
],
[
120.579942,
31.784908
],
[
120.591464,
31.761722
],
[
120.595597,
31.746723
],
[
120.59072,
31.740568
]
]
//创建要素,设置样式
const feature = new Feature({
geometry: new Polygon([geoList])
})
feature.setStyle(
new Style({
stroke: new Stroke({
color: 'blue',
width: 2
}),
fill: new Fill({
color: 'rgba(0, 90, 212, 0.1)'
})
})
)
//创建数据源,添加要素
layerMap['inspectionArea'].getSource().addFeature(feature)
}
//加载地标
function initAllLandmark() {
let geoList = ref([])
if (areaCoordinates.value.length > 0) {
areaCoordinates.value.forEach(item => {
const [lngStr, latStr] = item.lngLat.split(',');
const lng = Number(lngStr);
const lat = Number(latStr);
geoList.value.push({
lng: lng,
lat: lat,
pkFireArea: item.pkFireArea
});
});
geoList.value.forEach(item => {
item.feature = new Feature({
geometry: new Point([item.lng, item.lat])
})
item.feature.setId(item.pkFireArea)
layerMap['landmark'].getSource().addFeature(item.feature)
})
}
}
//比例尺
function scaleLineCtl() {
//实例化比例尺控件(ScaleLine)
let scaleLineControl = new ScaleLine({
//设置比例尺单位,degrees、imperial、us、nautical、metric(度量单位)
units: 'metric',
bar: true, //渲染比例尺而不是一条线
text: true //渲染比例尺上方的文本比例。仅适用于baris true
})
map.addControl(scaleLineControl)
}
function zoomCtl() {
let zoom = new Zoom({
className: 'ol-zoom-custom', //CSS 类名
duration: 1000,
zoomInLabel: '+', //放大的文本标签
zoomInTipLabel: '放大', //用于按钮提示的文本标签
zoomOutTipLabel: '缩小', //用于按钮提示的文本标签
delta: 1 //每次单击时应用的缩放增量
})
map.addControl(zoom)
}
function pointerMoveToFeature(e) {
const pixel = map.getEventPixel(e.originalEvent)
const hit = map.hasFeatureAtPixel(pixel)
map.getTargetElement().style.cursor = hit ? 'pointer' : ''
}
onMounted(() => {
initMap();
userStore.getInfo().then( res=> {
user.value = res.user
// console.log(11, user.value)
// console.log(22, user.value.dept)
if (user.value.dept != null && user.value.dept.parentId == 200) {
propertyShow.value = false
pkFireArea.value = ''
alarmType.value = '1'
latlng.value = []
getXiaofang()
} else {
getArea();
}
})
})
return {
latlng,
showData,
openEcharts,
tableList,
alarmType,
alarmTypes,
propertyShow,
userStore,
open,
popupEquipLayer,
currentShow,
currentEquip,
currentFeature,
mapScale,
equips,
map,
gaodeMap,
layerMap,
layerSouceMap,
pkFireArea,
areaCoordinates,
changeAlarmType,
initMap,
scaleLineCtl,
zoomCtl,
initAllArea,
getArea,
changeAreaId,
initAllLandmark,
initEquips,
pointerMoveToFeature,
mapChanges,
featureClick,
queryEquipment,
closePopup,
imgInfor,
restMap
}
}
}
</script>
<style scoped lang="scss">
#map {
width: 100vw;
height: 100vh;
}
/*鼠标位置样式 */
#mouse-position {
position: absolute;
right: 190px;
bottom: 145px;
z-index: 10;
color: #ffffff;
background-color: rgba(34, 34, 34, 0.6);
width: 230px;
height: 20px;
font-size: 14px;
line-height: 20px;
text-align: center;
border-radius: 4px;
}
/*比例尺样式 */
:deep(.ol-scale-bar) {
left: 20px;
bottom: 100px;
position: absolute;
z-index: 9999;
}
/*放大缩小样式 */
:deep(.ol-viewport .ol-zoom-custom) {
top: 10px;
left: 5px;
}
#popupEquip {
width: 320px;
height: 200px;
box-shadow: 0 0 6px #808080;
border: 1px solid #d8d8d8;
/* 弹窗下方的小三角形 */
&::after {
display: block;
content: '';
width: 0;
height: 0;
position: absolute;
border: 12px solid transparent;
border-top-color: #ffffff;
bottom: -23px;
left: 50%;
transform: translateX(-50%);
}
.popupContent {
width: 100%;
height: 100%;
padding: 9px;
background-color: #ffffff;
display: flex;
.popupInformat {
width: 280px;
height: 100%;
margin-right: 8px;
}
.popupClose {
cursor: pointer;
}
}
}
.rest {
width: 24px;
height: 24px;
background-color: #fff;
position: absolute;
left: 5px;
top: 56px;
z-index: 99;
border-radius: 2px;
border: 1px solid #bcbcbc;
display: flex;
justify-content: center;
align-items: center;
}
.rest:hover {
border: 1px solid #2c2c2c;
}
</style>