<template> <div class="map_assembly_container"> <!-- 地图 --> <div id="map"/> <div id="mapAssembly_container" class="body_container"> <div class="body_flex_box"> <!-- 左侧面板 --> <div class="left"> <base-table :info="info" use-type="dutyInfo"/> <base-table :info="info" use-type="reservePlanInfo" is-reserve-plan/> <base-table :info="info" use-type="addressBook"/> </div> <!-- 右侧面板 --> <div class="right"> <sysChat :chat-data="chatData" @orderMessage="handlerOrderMessage" @reFlush="initInfo()" @endRescue="endRescue()"/> </div> </div> <div class="top_search"> <span v-for="(item, index) in rangeList" :class="{ active: activeIndex === index }" :key="index" class="range_item" @click="setActive(item, index)" >{{ item }} 米</span> </div> <div class="bottom-center"> <div class="secon_modal"> <span v-for="(sos, ind) in currSubControlPoint" :key="ind" @click="subToggleCheck(sos, ind)"> <img :src="!sos.check ? sos.imgUrl : sos.check_img" alt=""> <p>{{ sos.label }}</p> </span> </div> <div class="control_pointer"> <span v-for="(item, index) in controlPoint" :key="index" style="cursor: pointer;" @click="toggleCheck(item, index)"> <img :src="!item.check ? item.imgUrl : item.check_img" alt=""> <p>{{ item.label }}</p> </span> </div> </div> </div> <dialog-index :visible.sync="infoDialog.visible" :value="{ ...infoDialog.info }" :title="infoDialog.title"/> </div> </template> <script> import { requestFN } from '@/utils/request' import baseTable from './baseTable.vue' import sysChat from './sysChat.vue' import DialogIndex from './dialog.vue' let mapInstance export default { components: { baseTable, sysChat, DialogIndex }, data() { return { info: { dutyInfoData: [], reservePlan: {}, addressBook: [] }, chatData: [], infoDialog: { visible: false, id: '', info: {}, title: '' }, activeIndex: 0, range: 20, rangeList: [20, 50, 100, 500, 1000, 5000], mapIco: [ { id: 'e1899a925eb7478653007a9e7d17d588', ico: require('../../../../assets/map/emergency_rescue/point/img1.png') }, { id: 'ea3555185c6498b2d3d07023de723806', ico: require('../../../../assets/map/emergency_rescue/point/img2.png') }, { id: '52ddb251b528987c58c4d84fe0d83952', ico: require('../../../../assets/map/emergency_rescue/point/img3.png') }, { id: '7f3d41464cdf450422ffe385c3aa870e', ico: require('../../../../assets/map/emergency_rescue/point/img4.png') }, { id: '2ef8327624adad89b2dbf6b2e03ac6ef', ico: require('../../../../assets/map/emergency_rescue/point/img5.png') }, { id: 'e1899a925eb7478653007a9e7d17d588', ico: require('../../../../assets/map/emergency_rescue/point/img6.png') }, { id: '122abe9858feaecae1c80d2d851fcd57', ico: require('../../../../assets/map/emergency_rescue/point/img7.png') }, { id: '637b70684bddcfbee0421db1443a972a', ico: require('../../../../assets/map/emergency_rescue/point/img8.png') }, { id: '950700c9cd80c5e1b22a6c6cdf63a61d', ico: require('../../../../assets/map/emergency_rescue/point/img9.png') }, { id: '1edb69abc25785c02e2e475162d65b17', ico: require('../../../../assets/map/emergency_rescue/point/img10.png') }, { id: 'd25f2cae07902e373b72e74757e7a6ea', ico: require('../../../../assets/map/emergency_rescue/point/img11.png') }, { id: 'be31acea122c423a9dbb431cc66a1351', ico: require('../../../../assets/map/emergency_rescue/point/img12.png') }, { id: '759d323be34eae4bd83289b36af9ea47', ico: require('../../../../assets/map/emergency_rescue/point/img13.png') } ], controlPoint: [ { id: '0', label: '应急资源', imgUrl: require('../../../../assets/map/emergency_rescue/ico1.png'), check_img: require('../../../../assets/map/emergency_rescue/ico1_on.png'), check: true }, { id: '1', label: '消防信息', imgUrl: require('../../../../assets/map/emergency_rescue/ico2.png'), check_img: require('../../../../assets/map/emergency_rescue/ico2_on.png'), check: false }, { id: '2', label: '人员定位', imgUrl: require('../../../../assets/map/emergency_rescue/ico3.png'), check_img: require('../../../../assets/map/emergency_rescue/ico3_on.png'), check: false }, { id: '3', label: '视频监控', imgUrl: require('../../../../assets/map/emergency_rescue/ico4.png'), check_img: require('../../../../assets/map/emergency_rescue/ico4_on.png'), check: false }, { id: '4', label: '气象监测', imgUrl: require('../../../../assets/map/emergency_rescue/ico5.png'), check_img: require('../../../../assets/map/emergency_rescue/ico5_on.png'), check: false } ], ctlActiveIndex: 0, subControlPoint: { '0': [ { id: '9b3b9451cf9a86b1e8a44c9a9b0de826', code: '0', label: '资料装备库', imgUrl: require('../../../../assets/map/emergency_rescue/i1.png'), check_img: require('../../../../assets/map/emergency_rescue/i1_on.png'), check: true }, { id: 'f61af43a0af59c86187913f9fe084588', code: '1', label: '应急避难场所', imgUrl: require('../../../../assets/map/emergency_rescue/i2.png'), check_img: require('../../../../assets/map/emergency_rescue/i2_on.png'), check: false }, { id: '7a38cf58e55995c0a5ce2c8e1f5bcc79', code: '2', label: '排水井', imgUrl: require('../../../../assets/map/emergency_rescue/i3.png'), check_img: require('../../../../assets/map/emergency_rescue/i3_on.png'), check: false }, { id: 'a0fd60946978e28dac5b8a2965e00a2b', code: '3', label: '封闭卡口', imgUrl: require('../../../../assets/map/emergency_rescue/i4.png'), check_img: require('../../../../assets/map/emergency_rescue/i4_on.png'), check: false } ], '1': [ { id: '1768cf2b0fb0844dedbb6db1dca3cc79', code: '4', label: '消防控制室', imgUrl: require('../../../../assets/map/emergency_rescue/i5.png'), check_img: require('../../../../assets/map/emergency_rescue/i5_on.png'), check: false }, { id: '18849e29cce63a9408117ca26186203b', code: '5', label: '消防泵房', imgUrl: require('../../../../assets/map/emergency_rescue/i6.png'), check_img: require('../../../../assets/map/emergency_rescue/i6_on.png'), check: false }, { id: 'da52ba25c3f15ad932b18fbd4d028062', code: '6', label: '消防水源', imgUrl: require('../../../../assets/map/emergency_rescue/i7.png'), check_img: require('../../../../assets/map/emergency_rescue/i7_on.png'), check: false }, { id: 'e241e3ef479ac7fb217c7b496816dc7e', code: '7', label: '消防点位', imgUrl: require('../../../../assets/map/emergency_rescue/i8.png'), check_img: require('../../../../assets/map/emergency_rescue/i8_on.png'), check: false } ], '2': [ { id: '93f7e01c8e4d906053916d314e1d3a2a', code: '8', label: '人员定位', imgUrl: require('../../../../assets/map/emergency_rescue/i9.png'), check_img: require('../../../../assets/map/emergency_rescue/i9_on.png'), check: false }, { id: '30fcda69c3eae93adbab78dea360b6b0', code: '9', label: '人员轨迹', imgUrl: require('../../../../assets/map/emergency_rescue/i10.png'), check_img: require('../../../../assets/map/emergency_rescue/i10_on.png'), check: false } ], '3': [ { id: '6ac1fc24fde38671ee70d7aebeed5276', code: '10', label: '摄像头', imgUrl: require('../../../../assets/map/emergency_rescue/i11.png'), check_img: require('../../../../assets/map/emergency_rescue/i11_on.png'), check: false } ], '4': [ { id: '3f858ab418dbf791353ba6ff87c59e85', code: '12', label: '气象站', imgUrl: require('../../../../assets/map/emergency_rescue/i12.png'), check_img: require('../../../../assets/map/emergency_rescue/i12_on.png'), check: false }, { id: '997392774d64efd8507c7c518c23fc44', code: '11', label: '风速站', imgUrl: require('../../../../assets/map/emergency_rescue/i13.png'), check_img: require('../../../../assets/map/emergency_rescue/i13_on.png'), check: false } ] }, // 当前点击后选择的二级坐标点位分类集合 currSubControlPoint: [], subControlPointIndex: 0, webSocket: null, heartbeat: null, REPORT_ID: null, FIRERESERVEPLAN_ID: null, CODE: null, CORPIFNO_ID: JSON.parse(sessionStorage.getItem('user')).CORPIFNO_ID, firstPoint: { x: null, y: null }, mapLevel: 20 } }, mounted() { /** 调用地图初始化方法 */ this.firstInitPoint() /** 调用初始化点位绘制方法 */ // this.initPoints() /** 初始化选中首个二级坐标点位分类 */ this.currSubControlPoint = this.subControlPoint['0'] }, created() { this.REPORT_ID = this.$route.query.REPORT_ID this.FIRERESERVEPLAN_ID = this.$route.query.FIRERESERVEPLAN_ID this.initInfo() this.initWebsocket() this.initPoint({ code: 0, REPORT_ID: this.REPORT_ID, range: this.range }) }, beforeDestroy() { if (this.webSocket) { this.webSocket.close() } if (this.heartbeat) { clearInterval(this.heartbeat) } }, methods: { /** 地图初始化 */ mapInit(e) { this.firstPoint.x = e.x this.firstPoint.y = e.y mapInstance = new window.BMapGL.Map('map') // 创建地图实例 mapInstance.centerAndZoom(new window.BMapGL.Point(e.y, e.x), this.mapLevel) // 创建点坐标 mapInstance.enableScrollWheelZoom(true) // 开启鼠标滚轮缩放能力 var point = new window.BMapGL.Point(this.firstPoint.y, this.firstPoint.x) // 设置中心点坐标(例如北京天安门) mapInstance.centerAndZoom(point, this.mapLevel) // 设置中心点和缩放级别 mapInstance.enableScrollWheelZoom(true) var circle = new window.BMapGL.Circle(point, this.range, { strokeColor: 'blue', strokeWeight: 2, strokeOpacity: 0.5, fillColor: 'blue', fillOpacity: 0.2 }) mapInstance.addOverlay(circle) }, setActive(item, index) { // 设置被选中项的索引 this.activeIndex = index this.range = item mapInstance.clearOverlays() var point = new window.BMapGL.Point(this.firstPoint.y, this.firstPoint.x) // 设置中心点坐标(例如北京天安门) mapInstance.centerAndZoom(point, this.mapLevel) // 设置中心点和缩放级别 mapInstance.enableScrollWheelZoom(true) var circle = new window.BMapGL.Circle(point, item, { // 2000米半径 strokeColor: 'blue', strokeWeight: 2, strokeOpacity: 0.5, fillColor: 'blue', fillOpacity: 0.2 }) mapInstance.addOverlay(circle) this.initPoint({ code: this.CODE, reportId: this.REPORT_ID, range: this.range }) }, /** 扎点方法 */ addPoint(anchor) { if (!anchor.icon) throw new Error('请传入图标') if (!anchor.y) throw new Error('请传入经度') if (!anchor.x) throw new Error('请传入纬度') const imageSize = new window.BMapGL.Size(23, 30) const icon = new window.BMapGL.Icon(config.fileUrl + anchor.icon, imageSize, { imageSize }) const point = new window.BMapGL.Point(anchor.y, anchor.x) const marker = new window.BMapGL.Marker(point, { icon }) // 创建标注 marker.addEventListener('click', async() => { this.infoDialog.visible = true this.infoDialog.info = anchor this.infoDialog.title = anchor.typeName }) mapInstance.addOverlay(marker) // 将标注添加到地图中 }, /** 给地图扎点标记事件事故 */ addPointCallback(anchor) { if (!anchor.icon) throw new Error('请传入图标') if (!anchor.y) throw new Error('请传入经度') if (!anchor.x) throw new Error('请传入纬度') const imageSize = new window.BMapGL.Size(33, 40) const icon = new window.BMapGL.Icon(config.fileUrl + anchor.icon, imageSize, { imageSize }) // 创建 icon 图标 var point = new window.BMapGL.Point(anchor.y, anchor.x) const marker = new window.BMapGL.Marker(point, { icon }) // 创建标注 mapInstance.addOverlay(marker) // 将标注添加到地图中 // 处理标注事件点击行为 marker.addEventListener('click', async() => { let accidentParams = {} let nearbyResourcesList = [] // 获取指定点位所对应的范围等详细信息 this.currentSelectPointAccident = anchor const result = await this.getQueryScopeAsync(anchor) if (result.code === 200) { mapInstance.clearOverlays() // 清除地图上所有覆盖物 const { accident, nearbyResources } = result.data accidentParams = accident nearbyResourcesList = nearbyResources const point = new window.BMapGL.Point(accidentParams.LONGITUDE, accidentParams.LATITUDE) const marker = new window.BMapGL.Marker(point, { icon }) mapInstance.addOverlay(marker) this.infoWindowPointerController({ point, marker, info: result.data }) if (nearbyResourcesList.length === 0) return nearbyResourcesList.forEach(item => { this.addPoint(item) }) } }) }, infoWindowPointerController(config) { const { point, marker, info } = config var opts = { width: 300, height: 200, title: '事故点位信息' } const sContent = ` <div> <ul> <li>机主姓名: ${info.accident.OWNER_NAME || '无'}</li> <li>访问模式: ${info.accident.ACCESS_MODE || '无'}</li> <li>呼入电话: ${info.accident.INCOMING_PHONE || '无'}</li> <li>事件类型: ${info.accident.EVENT_TYPE || '无'}</li> <li>接报时间: ${info.accident.REPORT_TIME || '无'}</li> <li>发生时间: ${info.accident.OCCURRENCE_TIME || '无'}</li> <li>救援情况: ${info.accident.RESCUE_SITUATION || '无'}</li> </ul> </div> ` const infoWindow = new window.BMapGL.InfoWindow(sContent, opts) marker.addEventListener('mouseover', () => { mapInstance.openInfoWindow(infoWindow, point) }) }, /** 获取指定点位所在周围范围等详细信息 */ getQueryScopeAsync(enterParams) { return new Promise((resolve, reject) => { requestFN('major/comprehensive/scope', { accidentId: enterParams.id, type: enterParams.type ? enterParams.type : '' }).then((data) => { resolve(data) return data }).catch((error) => { reject(error) }) }) }, /** 初始化点位绘制方法 */ async initPoints() { const result = await this.getAccidentList() result.data.forEach((item) => { this.addPointCallback(item) }) }, /** 获取事故列表的所有点位信息 */ getAccidentList() { return new Promise((resolve, reject) => { requestFN('/major/comprehensive/accidentList') .then((data) => { resolve(data) }).catch((e) => { }) }) }, // 一级坐标点位点击事件 toggleCheck(item, index) { // 遍历所有项,将点击项的 check 设置为 true,其他项的 check 设置为 false this.controlPoint.forEach((item, idx) => { if (idx === index) { item.check = true } else { item.check = false } }) this.currSubControlPoint = this.subControlPoint[index] }, // 二级坐标点位点击事件 subToggleCheck(sos, ind) { mapInstance.clearOverlays() var point = new window.BMapGL.Point(this.firstPoint.y, this.firstPoint.x) // 设置中心点坐标(例如北京天安门) mapInstance.centerAndZoom(point, 10) // 设置中心点和缩放级别 mapInstance.enableScrollWheelZoom(true) var circle = new window.BMapGL.Circle(point, this.range, { // 2000米半径 strokeColor: 'blue', strokeWeight: 2, strokeOpacity: 0.5, fillColor: 'blue', fillOpacity: 0.2 }) mapInstance.addOverlay(circle) this.initPoint(sos) this.currSubControlPoint.forEach((item, idx) => { if (idx === ind) { item.check = true } else { item.check = false } }) }, // 接收子组件传递出来的指令发送的事件 handlerOrderMessage() { this.infoDialog.visible = true this.infoDialog.info = { type: 'sendMessage', FIRERESERVEPLAN_ID: this.FIRERESERVEPLAN_ID, REPORT_ID: this.REPORT_ID } this.infoDialog.title = '指令信息' }, initInfo() { const loading = this.$loading({ lock: true, text: 'Loading', spinner: 'el-icon-loading', background: 'rgba(0, 0, 0, 0.7)' }) requestFN( '/bi/emergency/getYjBiInformation', { FIRERESERVEPLAN_ID: this.FIRERESERVEPLAN_ID, REPORT_ID: this.REPORT_ID } ).then((data) => { if (data.result === 'success') { // 值班列表 this.info.dutyInfoData = data.dutyList // 预案信息 this.info.reservePlan = data.planInfo this.info.addressBook = data.addressBookList this.chatData = data.instructList } loading.close() }).catch((e) => { console.log(e) loading.close() }) }, initWebsocket() { const wsUrl = config.YjSysUrl + '/yjMessage/' + this.REPORT_ID this.webSocket = new WebSocket(encodeURI(wsUrl)) this.webSocket.onopen = () => { console.info('指挥调度的webSocket链接成功') this.webSocket.send('链接成功') } this.webSocket.onerror = () => { this.$router.back() } this.webSocket.onclose = () => { this.$router.push('/emergen_cyrescue/incident_management') } var _this = this this.webSocket.onmessage = function(message) { _this.initInfo() } // 新建心跳,持续监听链接是否存活 this.heartbeat = setInterval(() => { try { if (this.webSocket) { this.webSocket.send('企业端' + this.REPORT_ID) } } catch (e) { console.log('链接已断开') } }, 3000) }, initPoint(row) { const loading = this.$loading({ lock: true, text: 'Loading', spinner: 'el-icon-loading', background: 'rgba(0, 0, 0, 0.7)' }) this.CODE = row.code requestFN( '/bi/emergency/getPoint', { code: row.code, reportId: this.REPORT_ID, range: this.range } ).then((data) => { if (data.result === 'success') { for (let i = 0; i < data.list.length; i++) { this.addPoint(data.list[i]) } } loading.close() }).catch((e) => { console.log(e) loading.close() }) }, firstInitPoint() { const loading = this.$loading({ lock: true, text: 'Loading', spinner: 'el-icon-loading', background: 'rgba(0, 0, 0, 0.7)' }) requestFN( '/bi/emergency/firstPoint', { code: 0, reportId: this.REPORT_ID, range: this.range } ).then((data) => { if (data.result === 'success') { this.mapInit(data.firstPoint) } loading.close() }).catch((e) => { console.log(e) loading.close() }) }, endRescue() { requestFN('/bi/emergency/endRescue', { ID: this.REPORT_ID }) .then((data) => { this.$message({ message: '确认已收到指令', type: 'success' }) this.$router.push('/emergen_cyrescue/incident_management') }).catch((error) => { console.log(error) }) } } } </script> <style scoped lang="scss"> .map_assembly_container { height: 100%; position: relative; // 地图的宽高样式限制 #map { position: fixed; left: 0; top: 0; width: 100%; height: 100%; } .body_container { position: absolute; left: 0; top: 0; padding: 18px; width: 100%; height: 100%; .body_flex_box { height: 100%; display: flex; align-items: center; justify-content: space-between; .left, .right { box-sizing: border-box; z-index: 99; width: 380px; height: 100%; background-color: #000d27bd; border-radius: 6px; border: 2px solid #034383; } .left { .scroll-box { height: 40px; overflow-x: hidden; overflow-y: auto; } } .right { position: relative; width: 410px; } } .top_search { z-index: 99; position: absolute; left: 405px; top: 18px; display: flex; align-items: center; justify-content: center; .range_item { overflow: hidden; cursor: pointer; border-right: 1px solid #183c70; display: inline-block; width: 67px; text-align: center; height: 34px; line-height: 34px; color: #fff; background-color: #223050; &:first-child { border-top-left-radius: 6px; border-bottom-left-radius: 6px; } &:last-child { border-top-right-radius: 6px; border-bottom-right-radius: 6px; border-right: none; } &.active { background-color: #06417d; color: #4aecff; } } } .bottom-center { z-index: 99; position: absolute; bottom: 18px; left: 50%; transform: translateX(-50%); width: calc(100% - 1123px); min-width: 335px; height: 80px; background-image: url('../../../../assets/map/emergency_rescue/menubg.png'); background-repeat: no-repeat; background-size: contain; background-size: 100% 77px; .secon_modal { gap: 23px; padding: 0 18px; height: 60px; border-radius: 6px; border: 1px solid #364260; background-color: #214e8caf; position: absolute; left: 0px; top: -75px; display: flex; align-items: center; justify-content: space-evenly; & span { cursor: pointer; display: flex; align-items: center; justify-content: center; flex-direction: column; } & img { width: 30px; height: 30px; margin-bottom: 4px; } & p { color: #ffffff; margin: 0; padding: 0; font-size: 12px; } } .control_pointer { width: 100%; display: flex; align-items: center; justify-content: space-evenly; position: absolute; top: -23px; & img { width: 70px; height: 70px; } & p { color: #ffffff; margin: 0; padding: 0; } } } } } </style>