<template> <div style="overflow-y: hidden"> <!--筛选条件--> <div class="map-search-div"> <el-form ref="selectForm" :inline="true" :model="listQuery" class="form-container"> <el-row> <el-form-item> <!--水表检查井编号/地址--> <el-input v-model.trim="listQuery.keywords" placeholder="井编号/设备编号/地址" clearable size="small"/> </el-form-item> <el-button class="filter-item" type="primary" icon="el-icon-search" size="small" style="margin-top: 2px" @click="initPoints">搜索</el-button> <el-form-item style="margin-left: 10px"> <el-slider v-model="alpha" style="width: 150px"/> </el-form-item> <el-form-item style="margin-left:5px"> <el-button type="primary" size="small" icon="el-icon-map-location" circle @click="flyToInit"/> </el-form-item> <el-form-item style="margin-left:5px"> <el-button :type="showAlarm?'danger':'info'" size="small" icon="el-icon-bell" circle @click="showAlarm=!showAlarm"/> </el-form-item> <el-form-item style="margin-left: 5px"> <el-switch v-model="sceneMode" active-color="#637F2C" inactive-color="#071a69" active-text="深蓝" inactive-text="实景"/> </el-form-item> <el-form-item style="margin-left: 5px"> <el-switch v-model="isShowFlow" :disabled="sceneMode" active-text="开启流向" inactive-text="关闭流向"/> </el-form-item> </el-row> </el-form> </div> <div v-if="showAlarm==true && alarmList.length>0" class="map-alarm-div"> <div class="map-alarm-div-header"> 告警列表 <span class="icon-right" @click="tableShow=!tableShow"> <i v-if="tableShow" class="el-icon-arrow-up"/> <i v-else class="el-icon-arrow-down"/> </span> </div> <transition name="el-collapse-transition"> <el-scrollbar v-show="tableShow" :style="{visibility: tableShow?'visible':'hidden'}" :class="{moredatascollor:alarmList.length>6}" :native="false"> <el-table :data="alarmList" class="alarm-list-table" border @row-dblclick="alarmRowClick"> <el-table-column v-for="column in columns" :key="column.value" :label="column.text" :width="column.width" :align="column.align" show-overflow-tooltip> <template slot-scope="scope"> {{ scope.row[column.value] }} </template> </el-table-column> </el-table> </el-scrollbar> </transition> </div> <div id="mars3dContainer" class="mars3d-container"/> <div class="cover"/> </div> </template> <script> import axios from 'axios' import { mapGetters } from 'vuex' import { getAlarmsNow, getMapping } from '@/api/overview' import 'mars3d/dist/mars3d.css' import * as mars3d from 'mars3d' import 'cesium/Source/Widgets/widgets.css'// 导入必须的样式表 var Cesium = require('../../../node_modules/cesium/Source/Cesium') var underground = null // 地球底层 var building = null // 楼房建筑图层 var flow = null // 流向图层 var street = null // 街道图层 var well_model_layer = null // 井模型层 var watch_model_layer = null // 水表模型层 var watch_icon_layer = null // 水表图标层 var zs_model_layer = null // 噪声模型层 var zs_icon_layer = null // 噪声图标层 export default { name: 'OverviewSimple', components: {}, data() { return { type: 'massMarkers', // 加载数据方式:massMarkers或cluster refreshType: 'websocket', // 刷新数据方式:clock或websocket sceneMode: true, isShowFlow: true, showAlarm: true, // 是否显示报警 alpha: 40, // 是否显示全部井 listQuery: { keywords: '', // 关键字 wellType: '' // 井类型 }, // 筛选条件 columns: [ { text: '水表检查井编号', value: 'wellCode', width: 120, align: 'center' }, { text: '设备编号', value: 'devcode', width: 130, align: 'center' }, { text: '告警原因', value: 'alarmContent', align: 'center', width: 200 }, { text: '时间', value: 'alarmTime', width: 170, align: 'center' } ], // 告警列表显示列 tableShow: true, // 是否显示告警列表 tableIcon: 'el-icon-arrow-up', showWellType: this.showWellType(), // 是 否显示井类型下拉 wellTypeList: [], // 井类型列表 showDeptTree: 0, // 是否显示权属单位下拉,0不显示,1显示树,2显示平面 alarmList: [], // 报警列表 timer: null, deptShowTop: false, // 是否显示顶级 clock: null, // 计时器 hasAlarm: false, // 是否有报警, loading: true, // 加载图标是否显示 removeHandler: null, showClearBtn: false // 是否显示清除查询按钮 } }, computed: { ...mapGetters([ 'needRefresh' ]) }, watch: { sceneMode(val) { if (val) { // 深蓝 window.map.basemap = 2011 building.show = false flow.show = false street.show = true } else { // 实景 window.map.basemap = 2021 if (window.map.scene._mode === Cesium.SceneMode.SCENE3D) { building.show = true } else { building.show = false } if (!this.isShowFlow) { flow.show = false } else { flow.show = true } street.show = false } }, isShowFlow(val) { if (!val) { flow.show = false } else { flow.show = true } }, alpha(val) { window.map.basemap.opacity = val / 100 underground.alpha = val / 100 if (building !== null) { building.setStyle({ opacity: val / 100 }) } } }, mounted() { this.initMars3D() }, methods: { // 初始化地球 async initMars3D() { var mapOptions = { scene: { sceneMode: Cesium.SceneMode.SCENE2D, // 默认视角参数 center: { lat: 35.991700, lng: 120.2405844, alt: 4000, heading: 360, pitch: -90 }, // 以下是Cesium.Globe对象相关参数 globe: { depthTestAgainstTerrain: true, // 是否启用深度监测 baseColor: '#071a69', // 地球默认背景色 showGroundAtmosphere: false, // 是否在地球上绘制的地面大气 enableLighting: false // 是否显示昼夜区域 }, // 以下是Cesium.ScreenSpaceCameraController对象相关参数 cameraController: { zoomFactor: 3.0, // 鼠标滚轮放大的步长参数 minimumZoomDistance: 1, // 地球放大的最小值(以米为单位) maximumZoomDistance: 50000000, // 地球缩小的最大值(以米为单位) enableRotate: true, // 2D和3D视图下,是否允许用户旋转相机 enableTranslate: true, // 2D和哥伦布视图下,是否允许用户平移地图 enableTilt: true, // 3D和哥伦布视图下,是否允许用户倾斜相机 enableZoom: true, // 是否允许 用户放大和缩小视图 enableCollisionDetection: true // 是否允许 地形相机的碰撞检测 } }, control: { infoBox: false, sceneModePicker: true }, basemaps: [ { pid: 10, id: 2011, name: '天地图', type: 'group', layers: [ { name: '注记', type: 'tdt', layer: 'ter_z', key: ['216ee92889e17ab1b083fae665d522b8'] }, { name: '注记', type: 'tdt', layer: 'img_z', key: ['216ee92889e17ab1b083fae665d522b8'] } ] }, { id: 2021, pid: 10, name: '天地图影像', icon: 'http://mars3d.cn/example/img/basemaps/tdt_img.png', type: 'tdt', layer: 'img_d', key: ['216ee92889e17ab1b083fae665d522b8'], show: true } ] } // 创建三维地球场景 const map = new mars3d.Map('mars3dContainer', mapOptions) map.basemap = 2011 map.scene.screenSpaceCameraController.enableCollisionDetection = false // 设置鼠标 map.scene.screenSpaceCameraController.tiltEventTypes = [Cesium.CameraEventType.RIGHT_DRAG] // 缩放设置 重新设置缩放成员 map.scene.screenSpaceCameraController.zoomEventTypes = [Cesium.CameraEventType.MIDDLE_DRAG, Cesium.CameraEventType.WHEEL, Cesium.CameraEventType.PINCH] // 鼠标左键平移 map.scene.screenSpaceCameraController.rotateEventTypes = [Cesium.CameraEventType.LEFT_DRAG] const bloomEffect = new mars3d.effect.BloomEffect({ enabled: true }) map.addEffect(bloomEffect) window.map = map // 地球底层 underground = new mars3d.thing.Underground({ alpha: this.alpha / 100 }) map.addThing(underground) map.basemap.opacity = this.alpha / 100 const graphicLayer = new mars3d.layer.GraphicLayer() map.addLayer(graphicLayer) // 建筑模型 building = new mars3d.graphic.ModelPrimitive({ position: [120.242284, 35.983704, 0], style: { url: '../static/model/m1/m1.gltf', scale: 1, heading: 18.8, opacity: this.alpha / 100 } }) graphicLayer.addGraphic(building) building.show = false this.initDrawLines() this.initPoints() // 屏幕取点 const handler = new Cesium.ScreenSpaceEventHandler(map.viewer.canvas) handler.setInputAction(function(evt) { var cartesian = map.viewer.camera.pickEllipsoid(evt.position, map.viewer.scene.globe.ellipsoid) var cartographic = Cesium.Cartographic.fromCartesian(cartesian) var lng = Cesium.Math.toDegrees(cartographic.longitude)// 经度值 var lat = Cesium.Math.toDegrees(cartographic.latitude)// 纬度值 console.log('[' + lng + ',' + lat + '],') }, Cesium.ScreenSpaceEventType.LEFT_CLICK) // 切换二三维响应函数 map.on(mars3d.EventType.morphComplete, function(event) { if (window.map.scene._mode !== Cesium.SceneMode.SCENE3D) { building.show = false } else { building.show = !this.sceneMode } }) }, // 初始化街道、流向线 async initDrawLines() { axios.get('./static/position.json').then((result) => { const positions = result.data.positions flow = new mars3d.layer.GraphicLayer() window.map.addLayer(flow) street = new mars3d.layer.GraphicLayer() window.map.addLayer(street) for (let j = 0; j < positions.length; j++) { flow.addGraphic(this.addFlow(positions[j].items, positions[j].repeat)) street.addGraphic(this.addStreet(positions[j].items)) } flow.show = false }).catch((error) => { console.log('get position error...' + error) }) }, // 初始化井,设备 async initPoints() { // 井 let params = '' getMapping(params, this.listQuery.keywords).then(response => { if (response.code === 200) { if (well_model_layer !== null) window.map.removeLayer(well_model_layer) well_model_layer = new mars3d.layer.GraphicLayer() window.map.addLayer(well_model_layer) if (response.data.length > 0) { let maxLng = parseFloat(response.data[0].longitude) let minLng = parseFloat(response.data[0].longitude) let maxLat = parseFloat(response.data[0].latitude) let minLat = parseFloat(response.data[0].latitude) for (let i = 0; i < response.data.length; i++) { if (parseFloat(response.data[i].latitude) > 100) continue const lng = parseFloat(response.data[i].longitude) const lat = parseFloat(response.data[i].latitude) if (lng > maxLng) maxLng = lng if (lng < minLng) minLng = lng if (lat > maxLat) maxLat = lat if (lat < minLat) minLat = lat well_model_layer.addGraphic(new mars3d.graphic.ModelPrimitive({ position: [lng, lat, 0], style: { url: '../static/model/ys.gltf', scale: 2 }, popup: `给水井<br />井编号:${response.data[i].wellCode}<br />所属单位:${response.data[i].deptName}<br />详细位置:${response.data[i].position}` })) } const start = Cesium.Cartographic.fromDegrees(parseFloat(maxLng), parseFloat(maxLat)) const end = Cesium.Cartographic.fromDegrees(parseFloat(minLng), parseFloat(minLat)) const geodesic = new Cesium.EllipsoidGeodesic() geodesic.setEndPoints(start, end) const distance = geodesic.surfaceDistance const center = { lat: (parseFloat(maxLat) + parseFloat(minLat)) / 2, lng: (parseFloat(maxLng) + parseFloat(minLng)) / 2, alt: distance + 1500, heading: 360, pitch: -90 } window.map.setCameraView(center) } } }) params = '13' getMapping(params, this.listQuery.keywords).then(response => { if (response.code === 200) { if (watch_model_layer !== null) window.map.removeLayer(watch_model_layer) watch_model_layer = new mars3d.layer.GraphicLayer() window.map.addLayer(watch_model_layer) if (watch_icon_layer !== null) window.map.removeLayer(watch_icon_layer) watch_icon_layer = new mars3d.layer.GraphicLayer() window.map.addLayer(watch_icon_layer) for (let i = 0; i < response.data.length; i++) { watch_model_layer.addGraphic(new mars3d.graphic.ModelPrimitive({ position: [response.data[i].longitude, response.data[i].latitude, -0.5], style: { url: '../static/model/sb.glb', scale: 2, heading: 90 }, popup: `远程水表<br />设备编号:${response.data[i].devcode}<br />设备型号:${response.data[i].modelName}<br />设备类型:${response.data[i].deviceTypeName}<br />井编号:${response.data[i].wellCode}<br />所属单位:${response.data[i].deptName}<br />详细位置:${response.data[i].position}` })) watch_icon_layer.addGraphic(new mars3d.graphic.BillboardEntity({ id: response.data[i].devcode, position: [response.data[i].longitude, response.data[i].latitude, 1], style: { image: '../static/images/icon/sb.png', scale: 1, horizontalOrigin: Cesium.HorizontalOrigin.CENTER, verticalOrigin: Cesium.VerticalOrigin.BOTTOM, scaleByDistance: new Cesium.NearFarScalar(10, 1, 2000, 0.3) }, popup: `远程水表<br />设备编号:${response.data[i].devcode}<br />设备型号:${response.data[i].modelName}<br />设备类型:${response.data[i].deviceTypeName}<br />井编号:${response.data[i].wellCode}<br />所属单位:${response.data[i].deptName}<br />详细位置:${response.data[i].position}` })) } this.refreshAlarm() } }) params = '8' getMapping(params, this.listQuery.keywords).then(response => { if (response.code === 200) { if (zs_model_layer !== null) window.map.removeLayer(zs_model_layer) zs_model_layer = new mars3d.layer.GraphicLayer() window.map.addLayer(zs_model_layer) if (zs_icon_layer !== null) window.map.removeLayer(zs_icon_layer) zs_icon_layer = new mars3d.layer.GraphicLayer() window.map.addLayer(zs_icon_layer) for (let i = 0; i < response.data.length; i++) { zs_model_layer.addGraphic(new mars3d.graphic.ModelPrimitive({ position: [response.data[i].longitude, response.data[i].latitude, 0], style: { url: '../static/model/zs.glb', scale: 1, heading: 90 }, popup: `噪声记录仪<br />设备编号:${response.data[i].devcode}<br />设备型号:${response.data[i].modelName}<br />设备类型:${response.data[i].deviceTypeName}<br />井编号:${response.data[i].wellCode}<br />所属单位:${response.data[i].deptName}<br />详细位置:${response.data[i].position}` })) zs_icon_layer.addGraphic(new mars3d.graphic.BillboardEntity({ id: response.data[i].devcode, position: [response.data[i].longitude, response.data[i].latitude, 1], style: { image: '../static/images/icon/zs.png', scale: 1, horizontalOrigin: Cesium.HorizontalOrigin.CENTER, verticalOrigin: Cesium.VerticalOrigin.BOTTOM, scaleByDistance: new Cesium.NearFarScalar(10, 1, 2000, 0.3) }, popup: `噪声记录仪<br />设备编号:${response.data[i].devcode}<br />设备型号:${response.data[i].modelName}<br />设备类型:${response.data[i].deviceTypeName}<br />井编号:${response.data[i].wellCode}<br />所属单位:${response.data[i].deptName}<br />详细位置:${response.data[i].position}` })) } this.refreshAlarm() } }) }, // 流向线 addFlow(positions, repeat) { var style = { width: 10, material: mars3d.MaterialUtil.createMaterialProperty(mars3d.MaterialType.LineFlow, { color: '#217bd9', repeat: new Cesium.Cartesian2(repeat, 1), image: '../static/images/line.png', speed: 15 }) } var graphic = new mars3d.graphic.PolylineEntity({ positions: positions, style: style }) return graphic }, // 道路线 addStreet(positions) { var graphic = new mars3d.graphic.PolylineEntity({ positions: positions, style: { width: 8, color: Cesium.Color.AQUA, clampToGround: true } }) return graphic }, // 回到原点 flyToInit() { let center if (window.map._viewer.scene._mode === Cesium.SceneMode.SCENE3D) { center = { lat: 35.97, lng: 120.2384, alt: 2000, heading: 360, pitch: -45 } } else { center = { lat: 35.991700, lng: 120.2405844, alt: 4000, heading: 360, pitch: -90 } } window.map.setCameraView(center) }, // 刷新报警列表 async refreshAlarm() { this.count = 60 this.loading = true getAlarmsNow().then(response => { if (response.code === 200) { this.loading = false // 获取当前报警列表 this.alarmList = response.data if (this.alarmList.length > 0) { this.hasAlarm = true } for (const alarm of response.data) { for (const watch of watch_icon_layer.graphics) { if (alarm.devcode === watch.options.id) { if (!watch.popup.startsWith('报警')) { watch.setStyle({ image: '../static/images/icon/asb.png', scale: 1, horizontalOrigin: Cesium.HorizontalOrigin.CENTER, verticalOrigin: Cesium.VerticalOrigin.BOTTOM, scaleByDistance: new Cesium.NearFarScalar(10, 1, 2000, 0.3) }) watch.popup = `报警远程水表<br />设备编号:${alarm.devcode}<br />井编号:${alarm.wellCode}<br />井类型:${alarm.wellTypeName}<br />报警时间:${alarm.alarmTime}<br />报警数值:${alarm.alarmValue}<br />报警内容:${alarm.alarmContent}<br />详细位置:${alarm.position}` } break } } for (const zs of zs_icon_layer.graphics) { if (alarm.devcode === zs.options.id) { if (!zs.popup.startsWith('报警')) { zs.setStyle({ image: '../static/images/icon/azs.png', scale: 1, horizontalOrigin: Cesium.HorizontalOrigin.CENTER, verticalOrigin: Cesium.VerticalOrigin.BOTTOM, scaleByDistance: new Cesium.NearFarScalar(10, 1, 2000, 0.3) }) zs.popup = `报警噪声记录仪仪<br />设备编号:${alarm.devcode}<br />井编号:${alarm.wellCode}<br />井类型:${alarm.wellTypeName}<br />报警时间:${alarm.alarmTime}<br />报警数值:${alarm.alarmValue}<br />报警内容:${alarm.alarmContent}<br />详细位置:${alarm.position}` } break } } } } }) }, // 点击报警列表 alarmRowClick(row, column, event) { if (this.alpha < 10) { this.alpha = 15 } let center for (const watch of watch_icon_layer.graphics) { if (row.devcode === watch.options.id) { center = { lat: watch._point._lat, lng: watch._point._lng, alt: 50, heading: 360, pitch: -90 } window.map.setCameraView(center) break } } for (const zs of zs_icon_layer.graphics) { if (row.devcode === zs.options.id) { center = { lat: zs._point._lat, lng: zs._point._lng, alt: 50, heading: 360, pitch: -90 } window.map.setCameraView(center) break } } } } } </script> <style rel="stylesheet/scss" lang="scss" scoped> /deep/ .mars3d-popup-content { margin: 20px; line-height: 1.9; font-size: 18px; } /deep/ .cesium-toolbar-button { margin-top: 5px !important; width: 48px !important; height: 48px !important; } /depp/ span.cesium-sceneModePicker-wrapper { margin: 0 50px !important; } /deep/ .mars3d-popup-close-button { top: 10px; right: 10px; } /deep/ .mars3d-popup{ margin-top: -40px; } /deep/ .mars3d-popup-content { margin: 15px; line-height: 1.5; font-size: 16px; } /deep/ .mars3d-popup-content-wrapper { box-shadow: 0 2px 6px #00192faa; max-height: 1000px; } /deep/ .mars3d-popup-background { background: #00192faa; border-radius: 10px; } /deep/ .mars3d-popup-tip { border-radius: 0px !important; } /deep/.mars3d-popup-close-button{ top: 10px; } // 查询框 .map-search-div{ position: absolute; z-index: 100; padding: 0px 10px; background-color: rgba(244, 244, 244, 0.9); /*left: 90px;*/ .el-form-item{ margin-bottom: 0px; } } // 刷新框 .function-div{ position: absolute; left: 0px; right: 10px; z-index: 1100; padding: 10px; color: #ce8b74; font-size: 14px; /*background-color: rgba(244, 233, 230, 1.0);*/ .font-red{ color: red; font-weight: bold; } .el-icon-refresh:hover{ color: red; font-weight: bold; cursor: pointer; } } // 报警列表 .map-alarm-div{ position: absolute; z-index: 100; background-color: rgba(255, 234, 241,0.8); top: 40px; left: 0px; .map-alarm-div-header{ line-height: 35px; width: 621px; padding-left: 10px; .icon-right{ position: absolute; right: 15px; } .icon-right:hover{ color: #409EFF; cursor: pointer; } } .el-scrollbar { /*height: 200px;*/ width: 100%; } .moredatascollor{ height: 200px; } .el-scrollbar__wrap { overflow-y: auto; overflow-x: hidden; padding:0px !important; margin-bottom: 0px !important; } .el-table th{ padding: 7px 0px; } .el-table td{ padding: 5px 0px; } .el-table td:hover{ } .transition-box { margin-bottom: 10px; width: 200px; height: 100px; border-radius: 4px; background-color: #409EFF; text-align: center; color: #fff; padding: 40px 20px; box-sizing: border-box; margin-right: 20px; } } // 刷新框 .refresh-div{ position: absolute; right: 10px; top: 7px; z-index: 100; padding: 10px; color: #ce8b74; font-size: 14px; background-color: rgba(244, 233, 230, 1.0); .font-red{ color: red; font-weight: bold; } .el-icon-refresh:hover{ color: red; font-weight: bold; cursor: pointer; } } // 地图 .el-divider--horizontal{ margin: 5px 0; } </style> <style rel="stylesheet/scss" lang="scss"> .map-alarm-div { .el-scrollbar__wrap { overflow-y: auto; overflow-x: hidden; padding: 0px !important; margin-bottom: 0px !important; } } .cover{ position: absolute; bottom: 3px; left: 0px; background-color: #122252; width: 130px; height: 32px; } </style>