浏览代码

feat(bd): 添加室内定位功能并优化地图相关组件

- 新增 RoomMap 组件用于室内定位
- 更新 Pannel 组件以支持图标插槽
-调整地图组件的加载逻辑和参数
- 优化实时定位和围栏事件的显示
chen.cheng 9 月之前
父节点
当前提交
361669a4ec

+ 1 - 0
ruoyi-ui/src/assets/icons/svg/bd_room_location.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1729736779904" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4735" xmlns:xlink="http://www.w3.org/1999/xlink" width="48" height="48"><path d="M679.6 520L556 597.6l77.2 88L368 842.8l10.4 21.2 290.8-173.2-77.2-88 98-58.8-10.4-24z m-324 320S179.2 601.6 179.2 500c0-200 176.4-202.4 176.4-202.4s178.4 2 178.4 201.2C534 604 355.6 840 355.6 840z m0.8-440.4c-39.2 0-70.8 30.4-70.8 68s31.6 68 70.8 68c39.2 0 70.8-30.4 70.8-68 0.4-37.6-31.6-68-70.8-68zM684.8 516S552.4 355.2 552.4 286.4c0-135.2 132.4-136.4 132.4-136.4s134 1.2 134 136c0 70.8-134 230-134 230z m0.4-297.2c-29.6 0-53.2 20.4-53.2 46 0 25.2 24 46 53.2 46 29.6 0 53.2-20.4 53.2-46 0.4-25.6-23.6-46-53.2-46z m0 0" p-id="4736" fill="#ffffff"></path><path d="M925.2 854.4c0 40.8-35.2 74-78.4 74H175.2c-43.6 0-78.8-33.2-78.8-74V550.8h-80v303.6c0 82.4 71.2 149.6 158.8 149.6h671.6c87.6 0 158.8-67.2 158.8-149.6V550.8h-80v303.6zM846.8 14.8H175.2C87.6 14.8 16.4 82 16.4 164.4V468h80V164.4c0-40.8 35.2-74 78.8-74h671.6c43.6 0 78.4 33.2 78.4 74V468h80.4V164.4c0-82.4-71.6-149.6-158.8-149.6z m0 0" p-id="4737" fill="#ffffff"></path></svg>

+ 3 - 0
ruoyi-ui/src/views/bd/fence/index.vue

@@ -1,5 +1,8 @@
 <template>
   <pannel class="fence-location-container">
+    <template v-slot:icon>
+      <svg-icon icon-class="bd_fence" />
+    </template>
     <template v-slot:title>
       围栏闯禁
     </template>

+ 3 - 0
ruoyi-ui/src/views/bd/fenceEvt/index.vue

@@ -1,5 +1,8 @@
 <template>
   <pannel class="fence-location-container">
+    <template v-slot:icon>
+      <svg-icon icon-class="bd_evt" />
+    </template>
     <template v-slot:title>
       围栏闯禁事件
     </template>

+ 3 - 1
ruoyi-ui/src/views/bd/index.scss

@@ -51,12 +51,14 @@
     transform: translateY(-50%);
     left: 0;
     width: 150px;
-    height: 400px;
     display: flex;
     align-items: center;
     justify-content: space-between;
     flex-direction: column;
 
+    :not(:first-child) {
+      margin-top: 20px;
+    }
     .menu-item {
       height: 80px;
       width: 70px;

+ 9 - 4
ruoyi-ui/src/views/bd/index.vue

@@ -20,7 +20,7 @@
       <fence v-if="activeMenu[menus.fence.name]" />
       <fence-vio-evt v-if="activeMenu[menus.evt.name]" />
       <realtime-location v-if="activeMenu[menus.realtime_location.name]"></realtime-location>
-      <room-location></room-location>
+      <room-location v-if="activeMenu[menus.room_location.name]"></room-location>
     </div>
   </div>
 </template>
@@ -56,6 +56,11 @@ const menus = {
     title: '实时定位',
     icon: 'bd_real_time',
   },
+  room_location: {
+    name: 'room_location',
+    title: '室内定位',
+    icon: 'bd_room_location',
+  },
 };
 export default {
   name: 'bd',
@@ -85,8 +90,7 @@ export default {
   },
   methods: {
     loaded(map) {
-      window.map = this.mapView;
-      this.mapLoaded = true;
+      window.map = map;
       const d3tiles = new BDLayers.Lib.Layer.CB3DtilesLayer('3dtiles', {
         offet: {
           from: 'GCJ02',
@@ -104,6 +108,7 @@ export default {
         ],
       });
       map.addCustomLayers(d3tiles, -1, true);
+      this.mapLoaded = true;
     },
     menuClick(e) {
       const type = e.currentTarget.dataset.type;
@@ -111,7 +116,7 @@ export default {
       const result = {
         ...this.activeMenu,
       };
-      const selectedTogether = [this.menus.evt.name, this.menus.realtime_location.name];
+      const selectedTogether = [this.menus.evt.name, this.menus.realtime_location.name, this.menus.room_location.name];
       // 选中以下的菜单,其他菜单均取消选中
       if (selectedTogether.includes(type) && this.activeMenu[type]) {
         Object.keys(result).forEach((key) => {

+ 83 - 103
ruoyi-ui/src/views/bd/location/index.vue

@@ -1,5 +1,8 @@
 <template>
   <pannel class="devc-location-container">
+    <template v-slot:icon>
+      <svg-icon icon-class="bd_location" />
+    </template>
     <template v-slot:title>
       轨迹查询
     </template>
@@ -14,7 +17,7 @@
       <div class="location-list">
         <div class="list-item">
           <span class="over-flow-hidden" style="width: 40%">
-            定位设备1定位设备
+            园区安保巡逻轨迹
           </span>
           <span class="over-flow-hidden" style="width: 40%">
             2024-08-21 15:30
@@ -25,26 +28,27 @@
                 :title="playItem[1]&&playItem[1].play ? '暂停': '开始播放' "
                 @click="()=>onLocationPlay({key:1})"
             />
+            <i class="el-icon-refresh-left" title="重播" @click="()=>replayLocation({key:1})" />
             <i class="el-icon-circle-close" title="清空轨迹" @click="()=>clearLocation({key:1})" />
           </span>
         </div>
-        <div class="list-item">
-          <span class="over-flow-hidden" style="width: 40%">
-            定位设备1定位设备
-          </span>
-          <span class="over-flow-hidden" style="width: 40%">
-            2024-08-21 15:30
-          </span>
-          <span class="over-flow-hidden" style="width: 20%">
-            <i
-                :class="playItem[2]&&playItem[2].play ? 'el-icon-video-pause':'el-icon-video-play'"
-                :title="playItem[2]&&playItem[2].play ? '暂停': '开始播放' "
-                @click="()=>onLocationPlay({key:2})"
-            />
-             <i class="el-icon-refresh-left" title="重播" @click="()=>replayLocation({key:2})" />
-            <i class="el-icon-circle-close" title="清空轨迹" @click="()=>clearLocation({key:2})" />
-          </span>
-        </div>
+        <!--        <div class="list-item">-->
+        <!--          <span class="over-flow-hidden" style="width: 40%">-->
+        <!--            定位设备1定位设备-->
+        <!--          </span>-->
+        <!--          <span class="over-flow-hidden" style="width: 40%">-->
+        <!--            2024-08-21 15:30-->
+        <!--          </span>-->
+        <!--          <span class="over-flow-hidden" style="width: 20%">-->
+        <!--            <i-->
+        <!--                :class="playItem[2]&&playItem[2].play ? 'el-icon-video-pause':'el-icon-video-play'"-->
+        <!--                :title="playItem[2]&&playItem[2].play ? '暂停': '开始播放' "-->
+        <!--                @click="()=>onLocationPlay({key:2})"-->
+        <!--            />-->
+        <!--             <i class="el-icon-refresh-left" title="重播" @click="()=>replayLocation({key:2})" />-->
+        <!--            <i class="el-icon-circle-close" title="清空轨迹" @click="()=>clearLocation({key:2})" />-->
+        <!--          </span>-->
+        <!--        </div>-->
       </div>
     </template>
   </pannel>
@@ -98,91 +102,67 @@ export default {
     },
     startPlay() {
       const coordinates = [
-        [118.510344073029572, 32.093731676821307],
-        [118.510374370940283, 32.093527573458772],
-        [118.510387650407282, 32.093425544068282],
-        [118.510400982227964, 32.09332669752061],
-        [118.510410732278714, 32.09323744409496],
-        [118.510428221966407, 32.093164015714144],
-        [118.510441867993563, 32.093084266230839],
-        [118.510448612429926, 32.093039617220981],
-        [118.510485058313833, 32.092981880106635],
-        [118.510517293848437, 32.09289554196976],
-        [118.510538155585763, 32.092799789067762],
-        [118.510585136919985, 32.092700541165151],
-        [118.510653765503889, 32.092553283001713],
-        [118.510696483876899, 32.092422251207211],
-        [118.510717502501578, 32.09233604681264],
-        [118.51072719979102, 32.092243610516697],
-        [118.510718674363204, 32.092180042810142],
-        [118.51072858119106, 32.092100337892759],
-        [118.510740969534041, 32.091944200094105],
-        [118.510764731477138, 32.091797477034682],
-        [118.510795499488424, 32.091622019166245],
-        [118.510779024971171, 32.091529895046364],
-        [118.510838861565105, 32.091189345833804],
-        [118.51087340381045, 32.090902421451432],
-        [118.51087812135782, 32.090848246178545],
-        [118.510876016211085, 32.090833945673786],
-        [118.510692239599265, 32.090801119629013],
-        [118.510366127552757, 32.090754073380161],
-        [118.51000060154216, 32.090697945771666],
-        [118.509934963475075, 32.090685994408759],
-        [118.509749422753075, 32.090659554955813],
-        [118.509625833684098, 32.090648294195802],
-        [118.509481838386677, 32.090646826930168],
-        [118.509253799073093, 32.090651136213971],
-        [118.509027812249769, 32.090666562784293],
-        [118.508799929784459, 32.090680419798431],
-        [118.508667360005134, 32.090691549387145],
-        [118.508486159867502, 32.09070166630147],
-        [118.508389082289696, 32.090710781144516],
-        [118.508232158009235, 32.09071901684954],
-        [118.508146087550671, 32.090715266544017],
-        [118.507979371809753, 32.090696559011214],
-        [118.507793883792232, 32.090673299526408],
-        [118.507657000016053, 32.090649461216543],
-        [118.507493997112689, 32.090629117108001],
-        [118.507282154936803, 32.090595028382964],
-        [118.507194110693021, 32.09058493397027],
-        [118.507085424792962, 32.09057030990261],
-        [118.506926239284013, 32.090554694844201],
-        [118.506794937915217, 32.090529197439537],
-        [118.506617084744747, 32.090515395808161],
-        [118.50649331329619, 32.090492991990665],
-        [118.506400000570864, 32.090503652264289],
-        [118.506291863284133, 32.090522447458177],
-        [118.506271075849355, 32.09062297409131],
-        [118.506279384788115, 32.090901429202418],
-        [118.506276335902569, 32.091057455655339],
-        [118.506275574271015, 32.091238922688987],
-        [118.506265256688522, 32.091407769471331],
-        [118.506269834544227, 32.091629762276384],
-        [118.50626926881327, 32.091823164988803],
-        [118.506270044714256, 32.091927414499395],
-        [118.50627274985375, 32.09197831789384],
-        [118.50626805356525, 32.092147893674429],
-        [118.506291184226299, 32.092247102107017],
-        [118.506348259438596, 32.092306909277831],
-        [118.506388235638639, 32.09235020656353],
-        [118.506454214078786, 32.09238284827272],
-        [118.506470221749083, 32.092389820684197],
-        [118.506749994247556, 32.092461304228593],
-        [118.506920765421185, 32.092499065902963],
-        [118.507102910091703, 32.092546242421875],
-        [118.50729442822707, 32.092594898857307],
-        [118.507504248793609, 32.092619461113586],
-        [118.507619120567171, 32.092669029325684],
-        [118.50787825251615, 32.092735980829012],
-        [118.508088648792068, 32.092795553437476],
-        [118.508205495121302, 32.092851464536842],
-        [118.508542138019706, 32.092970018886092],
-        [118.508674228089234, 32.093043257063009],
-        [118.508899947338264, 32.093124930063404],
-        [118.50902011479775, 32.09315533305918],
-        [118.509103364510494, 32.093214827069964],
-        [118.509204785389386, 32.093242269788632],
-        [118.50925201865843, 32.093271949905017],
+        [118.868474555524, 32.013913750075],
+        [118.868459917135, 32.0138560330253],
+        [118.868460650064, 32.0137600494265],
+        [118.868469791963, 32.0135491295906],
+        [118.868450597046, 32.0135969285238],
+        [118.868451821878, 32.0134372342673],
+        [118.868369085172, 32.0134271059761],
+        [118.868229813542, 32.0134261784667],
+        [118.868037844538, 32.0134249000077],
+        [118.867988911263, 32.013424574126],
+        [118.867990212059, 32.0132809893746],
+        [118.867986825628, 32.0132395072755],
+        [118.867987028075, 32.0132171885197],
+        [118.867987432888, 32.0131725599655],
+        [118.867984539806, 32.0130769425047],
+        [118.867977454441, 32.0130291167663],
+        [118.86797791828, 32.0129781711549],
+        [118.867978150146, 32.0129527041872],
+        [118.867974855578, 32.0129017568948],
+        [118.868046176274, 32.0129117791912],
+        [118.868121507934, 32.0128931867922],
+        [118.868117943319, 32.0128708893801],
+        [118.868126616248, 32.012737367597],
+        [118.868127634971, 32.0126197858525],
+        [118.868127662494, 32.0126166091195],
+        [118.868165320753, 32.0126041528561],
+        [118.868173101262, 32.0125724412675],
+        [118.868240681514, 32.0125728913369],
+        [118.868308235972, 32.0125765173023],
+        [118.868334874981, 32.0125322352762],
+        [118.868324305199, 32.012446455205],
+        [118.868361835438, 32.0124467051483],
+        [118.868364679658, 32.0125610134717],
+        [118.868492254263, 32.0125713907483],
+        [118.868541014618, 32.0125780675563],
+        [118.868732580782, 32.012566639437],
+        [118.868841456955, 32.0125673645282],
+        [118.868976574771, 32.0125746162152],
+        [118.869070453844, 32.0125720654824],
+        [118.869096734551, 32.0125722405062],
+        [118.869156822422, 32.0125694647922],
+        [118.869179313588, 32.0125759664106],
+        [118.869201684821, 32.0126047016424],
+        [118.869186178487, 32.0126935647542],
+        [118.869193065594, 32.0128080658432],
+        [118.869192510216, 32.0129098661745],
+        [118.86919198924, 32.0130053604978],
+        [118.869179854563, 32.0131613771548],
+        [118.869190250492, 32.0133240705021],
+        [118.869185964264, 32.0134197772962],
+        [118.86917071489, 32.0134547924615],
+        [118.869159014503, 32.0135281642937],
+        [118.869166174307, 32.0135953030259],
+        [118.869165521059, 32.0137135723353],
+        [118.869187426642, 32.0138416759025],
+        [118.869153188005, 32.0138990608231],
+        [118.868990969654, 32.0139203908971],
+        [118.868768561862, 32.0139189097324],
+        [118.868572541435, 32.0139176042992],
+        [118.868557462941, 32.0139175038812],
+        [118.868474555524, 32.013913750075],
       ];
       let playLine = bdmap.comp.Trajectory.loadTrajectory({
         mapView: window.map,

+ 1 - 2
ruoyi-ui/src/views/bd/map/index.vue

@@ -19,7 +19,6 @@ export default {
     },
   },
   mounted() {
-
     this.$nextTick(() => {
       const options = {
         mapType: BDLayers.Lib.Constant.BaseLayerType.Blank,
@@ -27,7 +26,7 @@ export default {
         center: [118.8738802982145, 32.010241883966096],
         defaultZoom: 15,
         showCenter: false,
-        baseControl: true,
+        baseControl: false,
         pitch: 45,
         lights: {
           directional: {

+ 5 - 1
ruoyi-ui/src/views/bd/pannel/index.scss

@@ -17,7 +17,11 @@
     letter-spacing: 0;
     text-shadow: 2px 2px 2px rgba(0, 0, 0, 0.50);
     font-weight: 500;
-
+    .svg-icon{
+      width: 20px;
+      height: 20px;
+      margin-right: 14px;
+    }
     > i {
       margin-left: auto;
 

+ 1 - 0
ruoyi-ui/src/views/bd/pannel/index.vue

@@ -1,6 +1,7 @@
 <template>
   <div class="devc-location-container pannel">
     <div class="pannel-header">
+      <slot name="icon" />
       <slot name="title" />
       <slot name="action" />
     </div>

二进制
ruoyi-ui/src/views/bd/realtimeLocation/icon/position.png


+ 0 - 1
ruoyi-ui/src/views/bd/realtimeLocation/icon/position.svg

@@ -1 +0,0 @@
-<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1729589950554" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6654" xmlns:xlink="http://www.w3.org/1999/xlink" width="48" height="48"><path d="M623.5 957.6h-226c-27.7 0-50.3-22.6-50.3-50.3 0-27.7 22.6-50.3 50.3-50.3h226c27.7 0 50.3 22.6 50.3 50.3 0 27.7-22.7 50.3-50.3 50.3z" fill="#00EFEF" p-id="6655"></path><path d="M510.4 812.3c-82.5 0-161.9-61.6-223.7-173.6-47.9-86.9-78.9-194.1-78.9-273.1C207.8 198.8 343.5 63 510.4 63S813 198.8 813 365.6c0 79-31 186.2-78.9 273.1-61.8 112-141.2 173.6-223.7 173.6z m0-634c-103.3 0-187.3 84-187.3 187.3 0 125.9 104.6 331.4 187.3 331.4s187.3-205.5 187.3-331.4c0-103.2-84-187.3-187.3-187.3z" fill="#52A9FF" p-id="6656"></path><path d="M510.4 359.6m-79.2 0a79.2 79.2 0 1 0 158.4 0 79.2 79.2 0 1 0-158.4 0Z" fill="#00EFEF" p-id="6657"></path></svg>

+ 6 - 4
ruoyi-ui/src/views/bd/realtimeLocation/index.vue

@@ -1,5 +1,8 @@
 <template>
   <pannel class="fence-location-container">
+    <template v-slot:icon>
+      <svg-icon icon-class="bd_real_time" />
+    </template>
     <template v-slot:title>
       实时坐标
     </template>
@@ -40,7 +43,7 @@ import SocketMessage from '@/components/WebsocketMessage/index.vue';
 import item from '@/layout/components/Sidebar/Item.vue';
 import Pannel from '@/views/bd/pannel/index.vue';
 import dayjs from 'dayjs';
-import position from './icon/position.svg';
+import position from './icon/position.png';
 
 export default {
   name: 'realtime-location',
@@ -75,7 +78,7 @@ export default {
   },
   created() {
     this.markLayer = new BDLayers.Lib.Layer.CBVectorLayer('markerLayer', true);
-    window.map.addCustomLayers(this.markLayer);
+    window.map.addCustomLayers(this.markLayer, 5);
   },
   mounted() {
     this.getFenceVioEvtList();
@@ -100,7 +103,7 @@ export default {
           [longitude, latitude],
           {
             imgurl: position,
-            iconSize: [45, 60],
+            iconSize: [60, 45],
             symbol: {
               'textName': 'm4',
               'textSize': 14,
@@ -123,7 +126,6 @@ export default {
       this.selectedDevice = [...this.selectedDevice];
     },
     onMessage(a) {
-      debugger
       const data = JSON.parse(a.data);
       const {
         latitude,

+ 7 - 1
ruoyi-ui/src/views/bd/roomlocation/index.vue

@@ -1,5 +1,8 @@
 <template>
   <pannel class="rooms-container">
+    <template v-slot:icon>
+      <svg-icon icon-class="bd_room_location" />
+    </template>
     <template v-slot:title>
       室内定位
     </template>
@@ -17,6 +20,7 @@
           </span>
           </div>
         </template>
+        <room-map ref="roomMap"></room-map>
         <socket-message :onMessage="onMessage" :ws="ws"></socket-message>
       </div>
     </template>
@@ -29,6 +33,7 @@ import SocketMessage from '@/components/WebsocketMessage/index.vue';
 import { uuid } from '@/utils';
 import maphandle from '@/views/bd/map/maphandle';
 import Pannel from '@/views/bd/pannel/index.vue';
+import RoomMap from '@/views/bd/roomlocation/roommap/index.vue';
 import dayjs from 'dayjs';
 import room_location from './icon/room_location.jpg';
 
@@ -36,6 +41,7 @@ export default {
   name: 'room-location',
   mixins: [maphandle],
   components: {
+    RoomMap,
     SocketMessage,
     Pannel,
   },
@@ -109,7 +115,7 @@ export default {
           },
       );
       marker.on('click', () => {
-
+        this.$refs.roomMap.show();
       });
       this.markLayer.addMarker(marker);
       // marker.getMarker().addTo(window.map.map);

+ 108 - 0
ruoyi-ui/src/views/bd/roomlocation/roommap/index.vue

@@ -0,0 +1,108 @@
+<template>
+  <el-dialog
+      title="室内定位"
+      :visible.sync="centerDialogVisible"
+      width="60%"
+      center>
+    <div style="width: 100%;height: 50vh;">
+      <bd-map :loaded="loaded" map-id="room-map" />
+      <socket-message
+          v-if="centerDialogVisible"
+          :key="`device_uwb001`" :onMessage="onMessage"
+          :ws="`/ws/point/uwb001`"></socket-message>
+    </div>
+
+  </el-dialog>
+</template>
+
+<script>
+
+import SocketMessage from '@/components/WebsocketMessage/index.vue';
+import BdMap from '@/views/bd/map/index.vue';
+import maphandle from '@/views/bd/map/maphandle';
+import position from '@/views/bd/realtimeLocation/icon/position.png';
+import dayjs from 'dayjs';
+
+export default {
+  name: 'room-map',
+  mixins: [maphandle],
+  components: {
+    BdMap,
+    SocketMessage,
+  },
+  data() {
+    return {
+      centerDialogVisible: false,
+      locationMarkers: {},
+      mapIns: null,
+    };
+  },
+  // 组件卸载前清空图层信息
+  beforeDestroy() {
+    this.markLayer && window.map.removeLayersById('markerLayer');
+  },
+  created() {
+
+  },
+  mounted() {
+  },
+  methods: {
+    dayjs,
+    loaded(map) {
+      const vtLayer = new BDLayers.Lib.Layer.CBTileLayer('blayer_ng_s', {
+        url: 'http://bd.xt.wenhq.top:8083/geoserver/gwc/service/wmts?REQUEST=GetTile&SERVICE=WMTS&VERSION=1.0.0&LAYER=bdlayers:bdl_cyy_pingmian&STYLE=&TILEMATRIX=EPSG:900913:{z}&TILEMATRIXSET=EPSG:900913&Format=image/jpeg&TILECOL={x}&TILEROW={y}',
+        maxZoom: 22,
+        minZoom: 15,
+      });
+      map.addCustomLayers(vtLayer);
+      this.markLayer = new BDLayers.Lib.Layer.CBVectorLayer('markerLayer', true);
+      map.addCustomLayers(this.markLayer);
+      this.mapIns = map;
+      map.setPitch(0);
+      map.setZoom(22);
+      map.setCenter([118.869046506393, 32.0133281708171]);
+    },
+    show() {
+      this.centerDialogVisible = true;
+    },
+    addMarker(data) {
+      const {
+        latitude,
+        longitude,
+        deviceId,
+      } = data;
+      const marker = new BDLayers.Lib.Overlays.MarkerImg(
+          `marker${deviceId}`,
+          [longitude, latitude],
+          {
+            imgurl: position,
+            iconSize: [60, 45],
+            symbol: {
+              'textName': 'm4',
+              'textSize': 14,
+              'markerFile': position,
+              'markerHorizontalAlignment': 'middle', // left, middle(默认), right
+              'markerVerticalAlignment': 'middle', // top, middle, bottom(默认)
+            },
+          },
+      );
+      this.markLayer.addMarker(marker);
+      return marker;
+    },
+    onMessage(a) {
+      const data = JSON.parse(a.data);
+      const {
+        latitude,
+        longitude,
+        deviceId,
+      } = data;
+      console.log('>>>>>>>>>>>>>>>>>>>>>>>>', data);
+      if (!this.locationMarkers[deviceId]) {
+        this.locationMarkers[deviceId] = this.addMarker(data);
+        return;
+      }
+      this.locationMarkers[deviceId].moveMarker([longitude, latitude], 2000, false);
+    },
+  },
+};
+</script>