|
@@ -4,151 +4,144 @@
|
|
<div class="map-controls">
|
|
<div class="map-controls">
|
|
<button @click="zoomIn">放大</button>
|
|
<button @click="zoomIn">放大</button>
|
|
<button @click="zoomOut">缩小</button>
|
|
<button @click="zoomOut">缩小</button>
|
|
- <button @click="toggleMapType">切换地图类型({{ mapType === 'BMAP_NORMAL_MAP' ? '地图' : '卫星' }})</button>
|
|
|
|
|
|
+ <button @click="toggleMapType"
|
|
|
|
+ >切换地图类型({{ mapType === 'BMAP_NORMAL_MAP' ? '地图' : '卫星' }})</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
+ <DeviceMonitorDrawer :model-value="drawerVisible" @update:model-value="(val) => (drawerVisible = val)" :id="deviceId" :deviceName="deviceName" :lastLineTime="lastLineTime"
|
|
|
|
+ :ifLine="ifLine" :dept="dept" :deviceCode="deviceCode"
|
|
|
|
+ ref="showDrawer" />
|
|
</template>
|
|
</template>
|
|
|
|
|
|
-<script lang="ts">
|
|
|
|
-import { defineComponent, onMounted, onBeforeUnmount, ref } from 'vue';
|
|
|
|
-import {DICT_TYPE, getDictLabel} from "@/utils/dict";
|
|
|
|
|
|
+<script setup lang="ts">
|
|
|
|
+import { onBeforeUnmount, onMounted, ref } from 'vue'
|
|
|
|
+import { DICT_TYPE, getDictLabel } from '@/utils/dict'
|
|
import { IotDeviceApi, IotDeviceVO } from '@/api/pms/device'
|
|
import { IotDeviceApi, IotDeviceVO } from '@/api/pms/device'
|
|
-import {aY} from "@fullcalendar/core/internal-common";
|
|
|
|
|
|
+import DeviceMonitorDrawer from '@/views/pms/map/DeviceMonitorDrawer.vue'
|
|
|
|
+import * as DeptApi from '@/api/system/dept'
|
|
|
|
|
|
interface Cluster {
|
|
interface Cluster {
|
|
- lng: number;
|
|
|
|
- lat: number;
|
|
|
|
- count: number;
|
|
|
|
- devices?: Device[];
|
|
|
|
|
|
+ lng: number
|
|
|
|
+ lat: number
|
|
|
|
+ count: number
|
|
|
|
+ devices?: Device[]
|
|
|
|
+}
|
|
|
|
+defineOptions({ name: 'DeviceMap' })
|
|
|
|
+const showDrawer = ref()
|
|
|
|
+const drawerVisible = ref<boolean>(false)
|
|
|
|
+const mapContainer = ref<HTMLElement | null>(null)
|
|
|
|
+const map = ref<any>(null)
|
|
|
|
+const mapType = ref<'BMAP_NORMAL_MAP' | 'BMAP_SATELLITE_MAP'>('BMAP_NORMAL_MAP')
|
|
|
|
+const selectedDevice = ref<IotDeviceVO | null>(null)
|
|
|
|
+const hoverDevice = ref<IotDeviceVO | null>(null)
|
|
|
|
+const clusters = ref<Cluster[]>([])
|
|
|
|
+const deviceId = ref()
|
|
|
|
+const deviceName = ref('')
|
|
|
|
+const lastLineTime = ref('')
|
|
|
|
+const ifLine = ref()
|
|
|
|
+const dept = ref('')
|
|
|
|
+const deviceCode = ref('')
|
|
|
|
+
|
|
|
|
+// 设备数据示例
|
|
|
|
+const devices = ref<IotDeviceVO[]>()
|
|
|
|
+
|
|
|
|
+// 初始化地图
|
|
|
|
+const initMap = () => {
|
|
|
|
+ if (!mapContainer.value) return
|
|
|
|
+
|
|
|
|
+ const script = document.createElement('script')
|
|
|
|
+ script.src = `https://api.map.baidu.com/api?v=3.0&ak=c0crhdxQ5H7WcqbcazGr7mnHrLa4GmO0&type=webgl`
|
|
|
|
+ script.async = true
|
|
|
|
+ script.onload = () => {
|
|
|
|
+ if ((window as any).BMap) {
|
|
|
|
+ map.value = new (window as any).BMap.Map(mapContainer.value)
|
|
|
|
+ const point = new (window as any).BMap.Point(104.114129, 37.550339)
|
|
|
|
+ map.value.centerAndZoom(point, 6)
|
|
|
|
+
|
|
|
|
+ map.value.enableScrollWheelZoom(true)
|
|
|
|
+ map.value.setMapType((window as any)[mapType.value])
|
|
|
|
+
|
|
|
|
+ map.value.addControl(new (window as any).BMap.NavigationControl())
|
|
|
|
+ map.value.addControl(new (window as any).BMap.ScaleControl())
|
|
|
|
+
|
|
|
|
+ initDeviceMarkers()
|
|
|
|
+ map.value.addEventListener('zoomend', () => {
|
|
|
|
+ initDeviceMarkers()
|
|
|
|
+ })
|
|
|
|
+ } else {
|
|
|
|
+ console.error('百度地图API加载失败')
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ script.onerror = () => {
|
|
|
|
+ console.error('百度地图API加载失败')
|
|
|
|
+ }
|
|
|
|
+ document.head.appendChild(script)
|
|
}
|
|
}
|
|
|
|
|
|
-export default defineComponent({
|
|
|
|
- name: 'ChinaDeviceMap',
|
|
|
|
- setup() {
|
|
|
|
- const mapContainer = ref<HTMLElement | null>(null);
|
|
|
|
- const map = ref<any>(null);
|
|
|
|
- const mapType = ref<'BMAP_NORMAL_MAP' | 'BMAP_SATELLITE_MAP'>('BMAP_NORMAL_MAP');
|
|
|
|
- const selectedDevice = ref<IotDeviceVO | null>(null);
|
|
|
|
- const hoverDevice = ref<IotDeviceVO | null>(null);
|
|
|
|
- const clusters = ref<Cluster[]>([]);
|
|
|
|
-
|
|
|
|
- // 设备数据示例
|
|
|
|
- const devices = ref<IotDeviceVO[]>();
|
|
|
|
-
|
|
|
|
- // const devices = ref<Device[]>([
|
|
|
|
- // { id: 'D001', deviceName: '设备1', location: '北京', deviceStatus: 1, lng: 84.053192, lat: 41.319412 },
|
|
|
|
- // { id: 'D002', deviceName: '设备2', location: '上海', deviceStatus: 2, lng: 121.474, lat: 31.230 },
|
|
|
|
- // { id: 'D003', deviceName: '设备3', location: '广州', deviceStatus: 1, lng: 113.264, lat: 23.129 },
|
|
|
|
- // { id: 'D004', deviceName: '设备4', location: '深圳', deviceStatus: 3, lng: 114.058, lat: 22.543 },
|
|
|
|
- // { id: 'D005', deviceName: '设备5', location: '成都', deviceStatus: 1, lng: 104.065, lat: 30.659 },
|
|
|
|
- // { id: 'D006', deviceName: '设备6', location: '武汉', deviceStatus: 2, lng: 114.305, lat: 30.593 },
|
|
|
|
- // { id: 'D007', deviceName: '设备7', location: '西安', deviceStatus: 1, lng: 108.948, lat: 34.263 },
|
|
|
|
- // { id: 'D008', deviceName: '设备8', location: '杭州', deviceStatus: 3, lng: 120.155, lat: 30.274 },
|
|
|
|
- // { id: 'D009', deviceName: '设备9', location: '南京', deviceStatus: 1, lng: 118.797, lat: 32.060 },
|
|
|
|
- // { id: 'D010', deviceName: '设备10', location: '重庆', deviceStatus: 2, lng: 106.505, lat: 29.533 },
|
|
|
|
- // ]);
|
|
|
|
- // const deviceStatusMap = {
|
|
|
|
- // 1: '在线',
|
|
|
|
- // 2: '离线',
|
|
|
|
- // 3: '异常'
|
|
|
|
- // };
|
|
|
|
-
|
|
|
|
- // 初始化地图
|
|
|
|
- const initMap = () => {
|
|
|
|
- if (!mapContainer.value) return;
|
|
|
|
-
|
|
|
|
- const script = document.createElement('script');
|
|
|
|
- script.src = `https://api.map.baidu.com/api?v=3.0&ak=c0crhdxQ5H7WcqbcazGr7mnHrLa4GmO0&type=webgl`;
|
|
|
|
- script.async = true;
|
|
|
|
- script.onload = () => {
|
|
|
|
- if ((window as any).BMap) {
|
|
|
|
- map.value = new (window as any).BMap.Map(mapContainer.value);
|
|
|
|
- const point = new (window as any).BMap.Point(104.114129, 37.550339);
|
|
|
|
- map.value.centerAndZoom(point, 6);
|
|
|
|
-
|
|
|
|
- map.value.enableScrollWheelZoom(true);
|
|
|
|
- map.value.setMapType((window as any)[mapType.value]);
|
|
|
|
-
|
|
|
|
- map.value.addControl(new (window as any).BMap.NavigationControl());
|
|
|
|
- map.value.addControl(new (window as any).BMap.ScaleControl());
|
|
|
|
-
|
|
|
|
- initDeviceMarkers();
|
|
|
|
- map.value.addEventListener('zoomend', () => {
|
|
|
|
- initDeviceMarkers();
|
|
|
|
- });
|
|
|
|
- } else {
|
|
|
|
- console.error('百度地图API加载失败');
|
|
|
|
|
|
+const initDeviceMarkers = () => {
|
|
|
|
+ if (!map.value) return
|
|
|
|
+
|
|
|
|
+ map.value.clearOverlays()
|
|
|
|
+
|
|
|
|
+ const zoomLevel = map.value.getZoom()
|
|
|
|
+ if (zoomLevel > 8) {
|
|
|
|
+ // 高缩放级别下显示单个设备标记
|
|
|
|
+ devices.value.forEach((device) => {
|
|
|
|
+ const point = new (window as any).BMap.Point(device.lng, device.lat)
|
|
|
|
+ const marker = createDeviceMarker(device, point)
|
|
|
|
+ map.value.addOverlay(marker)
|
|
|
|
+ })
|
|
|
|
+ } else {
|
|
|
|
+ // 低缩放级别下进行聚合
|
|
|
|
+ clusters.value = clusterDevices(devices.value, map.value)
|
|
|
|
+ clusters.value.forEach((cluster) => {
|
|
|
|
+ if (cluster.count === 1) {
|
|
|
|
+ // 只有一个设备时显示设备图标
|
|
|
|
+ const device = cluster.devices?.[0]
|
|
|
|
+ if (device) {
|
|
|
|
+ const point = new (window as any).BMap.Point(device.lng, device.lat)
|
|
|
|
+ const marker = createDeviceMarker(device, point)
|
|
|
|
+ map.value.addOverlay(marker)
|
|
}
|
|
}
|
|
- };
|
|
|
|
- script.onerror = () => {
|
|
|
|
- console.error('百度地图API加载失败');
|
|
|
|
- };
|
|
|
|
- document.head.appendChild(script);
|
|
|
|
- };
|
|
|
|
-
|
|
|
|
- const initDeviceMarkers = () => {
|
|
|
|
- if (!map.value) return;
|
|
|
|
-
|
|
|
|
- map.value.clearOverlays();
|
|
|
|
-
|
|
|
|
- const zoomLevel = map.value.getZoom();
|
|
|
|
- if (zoomLevel > 8) {
|
|
|
|
- // 高缩放级别下显示单个设备标记
|
|
|
|
- devices.value.forEach(device => {
|
|
|
|
- const point = new (window as any).BMap.Point(device.lng, device.lat);
|
|
|
|
- const marker = createDeviceMarker(device, point);
|
|
|
|
- map.value.addOverlay(marker);
|
|
|
|
- });
|
|
|
|
- } else {
|
|
|
|
- // 低缩放级别下进行聚合
|
|
|
|
- debugger;
|
|
|
|
- clusters.value = clusterDevices(devices.value, map.value);
|
|
|
|
- clusters.value.forEach(cluster => {
|
|
|
|
- if (cluster.count === 1) {
|
|
|
|
- // 只有一个设备时显示设备图标
|
|
|
|
- const device = cluster.devices?.[0];
|
|
|
|
- if (device) {
|
|
|
|
- const point = new (window as any).BMap.Point(device.lng, device.lat);
|
|
|
|
- const marker = createDeviceMarker(device, point);
|
|
|
|
- map.value.addOverlay(marker);
|
|
|
|
- }
|
|
|
|
- } else if (cluster.count > 1) {
|
|
|
|
- // 多个设备时显示聚合标签
|
|
|
|
- const point = new (window as any).BMap.Point(cluster.lng, cluster.lat);
|
|
|
|
- const label = createClusterLabel(cluster, point);
|
|
|
|
- map.value.addOverlay(label);
|
|
|
|
- }
|
|
|
|
- });
|
|
|
|
|
|
+ } else if (cluster.count > 1) {
|
|
|
|
+ // 多个设备时显示聚合标签
|
|
|
|
+ const point = new (window as any).BMap.Point(cluster.lng, cluster.lat)
|
|
|
|
+ const label = createClusterLabel(cluster, point)
|
|
|
|
+ map.value.addOverlay(label)
|
|
|
|
+ }
|
|
|
|
+ })
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+const createDeviceMarker = (device: IotDeviceVO, point: any) => {
|
|
|
|
+ const marker = new (window as any).BMap.Marker(point, {
|
|
|
|
+ icon: new (window as any).BMap.Icon(
|
|
|
|
+ 'https://iot.deepoil.cc/images/ding300.svg',
|
|
|
|
+ new (window as any).BMap.Size(28, 30),
|
|
|
|
+ {
|
|
|
|
+ anchor: new (window as any).BMap.Size(14, 25)
|
|
|
|
+ // imageOffset: new (window as any).BMap.Size(0, -5)
|
|
}
|
|
}
|
|
- };
|
|
|
|
-
|
|
|
|
- const createDeviceMarker = (device: IotDeviceVO, point: any) => {
|
|
|
|
- const marker = new (window as any).BMap.Marker(point, {
|
|
|
|
- icon: new (window as any).BMap.Icon('https://iot.deepoil.cc/images/ding300.svg', new (window as any).BMap.Size(28, 30),
|
|
|
|
- {
|
|
|
|
- anchor: new (window as any).BMap.Size(14, 25),
|
|
|
|
- // imageOffset: new (window as any).BMap.Size(0, -5)
|
|
|
|
- }
|
|
|
|
- )
|
|
|
|
- });
|
|
|
|
-
|
|
|
|
- // 添加点击事件
|
|
|
|
- marker.addEventListener('click', () => {
|
|
|
|
- showDeviceInfoWindow(device, point);
|
|
|
|
- });
|
|
|
|
-
|
|
|
|
- return marker;
|
|
|
|
- };
|
|
|
|
-
|
|
|
|
- const createClusterLabel = (cluster: Cluster, point: any) => {
|
|
|
|
- const label = new (window as any).BMap.Label(cluster.count.toString(), {
|
|
|
|
- position: point,
|
|
|
|
- offset: new (window as any).BMap.Size(-10, -10)
|
|
|
|
- });
|
|
|
|
-
|
|
|
|
- // 创建一个 style 标签并添加到 head 中,定义呼吸动画
|
|
|
|
- const style = document.createElement('style');
|
|
|
|
- style.textContent = `
|
|
|
|
|
|
+ )
|
|
|
|
+ })
|
|
|
|
+
|
|
|
|
+ // 添加点击事件
|
|
|
|
+ marker.addEventListener('click', () => {
|
|
|
|
+ showDeviceInfoWindow(device, point)
|
|
|
|
+ })
|
|
|
|
+
|
|
|
|
+ return marker
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+const createClusterLabel = (cluster: Cluster, point: any) => {
|
|
|
|
+ const label = new (window as any).BMap.Label(cluster.count.toString(), {
|
|
|
|
+ position: point,
|
|
|
|
+ offset: new (window as any).BMap.Size(-10, -10)
|
|
|
|
+ })
|
|
|
|
+
|
|
|
|
+ // 创建一个 style 标签并添加到 head 中,定义呼吸动画
|
|
|
|
+ const style = document.createElement('style')
|
|
|
|
+ style.textContent = `
|
|
@keyframes breathing {
|
|
@keyframes breathing {
|
|
0% {
|
|
0% {
|
|
border-color: rgba(255, 255, 255, 0.3);
|
|
border-color: rgba(255, 255, 255, 0.3);
|
|
@@ -160,171 +153,173 @@ export default defineComponent({
|
|
border-color: rgba(255, 255, 255, 0.3);
|
|
border-color: rgba(255, 255, 255, 0.3);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- `;
|
|
|
|
- document.head.appendChild(style);
|
|
|
|
-
|
|
|
|
- // 初始样式
|
|
|
|
- label.setStyle({
|
|
|
|
- color: '#fff',
|
|
|
|
- backgroundColor: '#c38f65',
|
|
|
|
- borderRadius: '50%',
|
|
|
|
- width: '50px',
|
|
|
|
- height: '50px',
|
|
|
|
- textAlign: 'center',
|
|
|
|
- lineHeight: '40px',
|
|
|
|
- cursor: 'pointer',
|
|
|
|
- fontSize: '18px',
|
|
|
|
- fontWeight: 'bold',
|
|
|
|
- boxShadow: '0 2px 4px rgba(0, 0, 0, 0.2)',
|
|
|
|
- transition: 'all 0.3s ease',
|
|
|
|
- border: '4px solid rgba(255, 255, 255, 0.5)', // 添加带有不透明度的边框
|
|
|
|
- animation: 'breathing 2s infinite' // 添加呼吸动画
|
|
|
|
- });
|
|
|
|
-
|
|
|
|
- // 鼠标悬停样式
|
|
|
|
- const hoverStyle = {
|
|
|
|
- backgroundColor: '#2196df',
|
|
|
|
- transform: 'scale(1.1)'
|
|
|
|
- };
|
|
|
|
-
|
|
|
|
- // 鼠标移出样式
|
|
|
|
- const normalStyle = {
|
|
|
|
- backgroundColor: '#c38f65',
|
|
|
|
- transform: 'scale(1)'
|
|
|
|
- };
|
|
|
|
-
|
|
|
|
- // // 添加鼠标悬停事件
|
|
|
|
- // label.addEventListener('mouseover', () => {
|
|
|
|
- // Object.assign(label.getStyle(), hoverStyle);
|
|
|
|
- // label.setStyle(label.getStyle());
|
|
|
|
- // });
|
|
|
|
- //
|
|
|
|
- // // 添加鼠标移出事件
|
|
|
|
- // label.addEventListener('mouseout', () => {
|
|
|
|
- // Object.assign(label.getStyle(), normalStyle);
|
|
|
|
- // label.setStyle(label.getStyle());
|
|
|
|
- // });
|
|
|
|
-
|
|
|
|
- // 添加点击事件
|
|
|
|
- label.addEventListener('click', () => {
|
|
|
|
- map.value?.setZoom(9);
|
|
|
|
- map.value?.panTo(point);
|
|
|
|
- });
|
|
|
|
-
|
|
|
|
- return label;
|
|
|
|
- };
|
|
|
|
-
|
|
|
|
- const clusterDevices = (devices: IotDeviceVO[], map: any): Cluster[] => {
|
|
|
|
- const clusters: Cluster[] = [];
|
|
|
|
- debugger
|
|
|
|
- const gridSize = getGridSize(map.getZoom());
|
|
|
|
-
|
|
|
|
- const gridMap = new Map<string, Cluster>();
|
|
|
|
-
|
|
|
|
- devices.forEach(device => {
|
|
|
|
- const gridKey = `${Math.floor(device.lng / gridSize)}_${Math.floor(device.lat / gridSize)}`;
|
|
|
|
-
|
|
|
|
- if (!gridMap.has(gridKey)) {
|
|
|
|
- gridMap.set(gridKey, {
|
|
|
|
- lng: Math.floor(device.lng / gridSize) * gridSize + gridSize / 2,
|
|
|
|
- lat: Math.floor(device.lat / gridSize) * gridSize + gridSize / 2,
|
|
|
|
- count: 0,
|
|
|
|
- devices: []
|
|
|
|
- });
|
|
|
|
- }
|
|
|
|
|
|
+ `
|
|
|
|
+ document.head.appendChild(style)
|
|
|
|
+
|
|
|
|
+ // 初始样式
|
|
|
|
+ label.setStyle({
|
|
|
|
+ color: '#fff',
|
|
|
|
+ backgroundColor: '#c38f65',
|
|
|
|
+ borderRadius: '50%',
|
|
|
|
+ width: '50px',
|
|
|
|
+ height: '50px',
|
|
|
|
+ textAlign: 'center',
|
|
|
|
+ lineHeight: '40px',
|
|
|
|
+ cursor: 'pointer',
|
|
|
|
+ fontSize: '18px',
|
|
|
|
+ fontWeight: 'bold',
|
|
|
|
+ boxShadow: '0 2px 4px rgba(0, 0, 0, 0.2)',
|
|
|
|
+ transition: 'all 0.3s ease',
|
|
|
|
+ border: '4px solid rgba(255, 255, 255, 0.5)', // 添加带有不透明度的边框
|
|
|
|
+ animation: 'breathing 2s infinite' // 添加呼吸动画
|
|
|
|
+ })
|
|
|
|
+
|
|
|
|
+ // 鼠标悬停样式
|
|
|
|
+ const hoverStyle = {
|
|
|
|
+ backgroundColor: '#2196df',
|
|
|
|
+ transform: 'scale(1.1)'
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 鼠标移出样式
|
|
|
|
+ const normalStyle = {
|
|
|
|
+ backgroundColor: '#c38f65',
|
|
|
|
+ transform: 'scale(1)'
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 添加点击事件
|
|
|
|
+ label.addEventListener('click', () => {
|
|
|
|
+ map.value?.setZoom(9)
|
|
|
|
+ map.value?.panTo(point)
|
|
|
|
+ })
|
|
|
|
+
|
|
|
|
+ return label
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+const clusterDevices = (devices: IotDeviceVO[], map: any): Cluster[] => {
|
|
|
|
+ const clusters: Cluster[] = []
|
|
|
|
+ const gridSize = getGridSize(map.getZoom())
|
|
|
|
+
|
|
|
|
+ const gridMap = new Map<string, Cluster>()
|
|
|
|
+
|
|
|
|
+ devices.forEach((device) => {
|
|
|
|
+ const gridKey = `${Math.floor(device.lng / gridSize)}_${Math.floor(device.lat / gridSize)}`
|
|
|
|
|
|
- const cluster = gridMap.get(gridKey)!;
|
|
|
|
- cluster.count++;
|
|
|
|
- if (!cluster.devices) cluster.devices = [];
|
|
|
|
- cluster.devices.push(device);
|
|
|
|
- });
|
|
|
|
-
|
|
|
|
- return Array.from(gridMap.values());
|
|
|
|
- };
|
|
|
|
-
|
|
|
|
- const getGridSize = (zoom: number): number => {
|
|
|
|
- debugger
|
|
|
|
- if (zoom <= 5) return 2;
|
|
|
|
- if (zoom <= 8) return 1;
|
|
|
|
- if (zoom < 10) return 5;
|
|
|
|
- return 0.1;
|
|
|
|
- };
|
|
|
|
- const deviceDetail = (device: IotDeviceVO, point: any) => {
|
|
|
|
- alert("abc")
|
|
|
|
|
|
+ if (!gridMap.has(gridKey)) {
|
|
|
|
+ gridMap.set(gridKey, {
|
|
|
|
+ lng: Math.floor(device.lng / gridSize) * gridSize + gridSize / 2,
|
|
|
|
+ lat: Math.floor(device.lat / gridSize) * gridSize + gridSize / 2,
|
|
|
|
+ count: 0,
|
|
|
|
+ devices: []
|
|
|
|
+ })
|
|
}
|
|
}
|
|
- const showDeviceInfoWindow = (device: IotDeviceVO, point: any) => {
|
|
|
|
- const content = `
|
|
|
|
|
|
+
|
|
|
|
+ const cluster = gridMap.get(gridKey)!
|
|
|
|
+ cluster.count++
|
|
|
|
+ if (!cluster.devices) cluster.devices = []
|
|
|
|
+ cluster.devices.push(device)
|
|
|
|
+ })
|
|
|
|
+
|
|
|
|
+ return Array.from(gridMap.values())
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+const getGridSize = (zoom: number): number => {
|
|
|
|
+ if (zoom <= 5) return 2
|
|
|
|
+ if (zoom <= 8) return 1
|
|
|
|
+ if (zoom < 10) return 5
|
|
|
|
+ return 0.1
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+const showDeviceInfoWindow = (device: IotDeviceVO, point: any) => {
|
|
|
|
+ DeptApi.getDept(device.deptId).then(res=>{
|
|
|
|
+ dept.value = res.name
|
|
|
|
+ const content = `
|
|
<div style="margin-top: 5px">
|
|
<div style="margin-top: 5px">
|
|
<p><strong>设备编码:</strong> ${device.deviceCode}</p>
|
|
<p><strong>设备编码:</strong> ${device.deviceCode}</p>
|
|
<p><strong>设备名称:</strong> ${device.deviceName}</p>
|
|
<p><strong>设备名称:</strong> ${device.deviceName}</p>
|
|
|
|
+ <p><strong>所在部门:</strong> ${res.name}</p>
|
|
<p><strong>位置:</strong> ${device.location}</p>
|
|
<p><strong>位置:</strong> ${device.location}</p>
|
|
<p><strong>状态:</strong> ${getDictLabel(DICT_TYPE.PMS_DEVICE_STATUS, device.deviceStatus)}</p>
|
|
<p><strong>状态:</strong> ${getDictLabel(DICT_TYPE.PMS_DEVICE_STATUS, device.deviceStatus)}</p>
|
|
|
|
+ <p><strong>是否在线:</strong> ${getDictLabel(DICT_TYPE.IOT_DEVICE_STATUS, device.ifInline)}</p>
|
|
|
|
+ <p><strong>最后在线时间:</strong> ${device.lastInlineTime}</p>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<div>
|
|
- <button :@click="deviceDetail" style=" background-color: #2196f3;
|
|
|
|
- color: white;
|
|
|
|
- border: none;
|
|
|
|
- padding: 8px 16px;
|
|
|
|
- border-radius: 4px;
|
|
|
|
- margin-top: 15px;
|
|
|
|
- cursor: pointer;">查看</button>
|
|
|
|
|
|
+ <button id="device-detail-btn" style=" background-color: #2196f3;
|
|
|
|
+ color: white;
|
|
|
|
+ border: none;
|
|
|
|
+ padding: 8px 16px;
|
|
|
|
+ border-radius: 4px;
|
|
|
|
+ margin-top: 15px;
|
|
|
|
+ cursor: pointer;">查看</button>
|
|
</div>
|
|
</div>
|
|
- `;
|
|
|
|
- const infoWindow = new (window as any).BMap.InfoWindow(content, {
|
|
|
|
- width: 300,
|
|
|
|
- height: 180
|
|
|
|
- });
|
|
|
|
- map.value.openInfoWindow(infoWindow, point);
|
|
|
|
- };
|
|
|
|
-
|
|
|
|
- const zoomIn = () => {
|
|
|
|
- if (map.value) {
|
|
|
|
- map.value.zoomIn();
|
|
|
|
- }
|
|
|
|
- };
|
|
|
|
|
|
+ `
|
|
|
|
+ const infoWindow = new (window as any).BMap.InfoWindow(content, {
|
|
|
|
+ width: 350,
|
|
|
|
+ height: 220
|
|
|
|
+ })
|
|
|
|
+ map.value.openInfoWindow(infoWindow, point)
|
|
|
|
+
|
|
|
|
+ // 事件绑定(需延迟确保DOM加载)
|
|
|
|
+ setTimeout(function () {
|
|
|
|
+ document.getElementById('device-detail-btn').addEventListener('click', function () {
|
|
|
|
+ drawerVisible.value = true
|
|
|
|
+ deviceId.value = device.id;
|
|
|
|
+ deviceCode.value = device.deviceCode
|
|
|
|
+ deviceName.value = device.deviceName
|
|
|
|
+ ifLine.value = device.ifInline
|
|
|
|
+ lastLineTime.value = device.lastInlineTime
|
|
|
|
+ showDrawer.value.openDrawer()
|
|
|
|
|
|
- const zoomOut = () => {
|
|
|
|
- if (map.value) {
|
|
|
|
- map.value.zoomOut();
|
|
|
|
- }
|
|
|
|
- };
|
|
|
|
|
|
+ })
|
|
|
|
+ }, 200)
|
|
|
|
+ })
|
|
|
|
|
|
- const toggleMapType = () => {
|
|
|
|
- if (!map.value) return;
|
|
|
|
|
|
+}
|
|
|
|
|
|
- mapType.value = mapType.value === 'BMAP_NORMAL_MAP'
|
|
|
|
- ? 'BMAP_SATELLITE_MAP'
|
|
|
|
- : 'BMAP_NORMAL_MAP';
|
|
|
|
- map.value.setMapType((window as any)[mapType.value]);
|
|
|
|
- };
|
|
|
|
|
|
+const zoomIn = () => {
|
|
|
|
+ if (map.value) {
|
|
|
|
+ map.value.zoomIn()
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
|
|
- const getData = async () =>{
|
|
|
|
- await IotDeviceApi.getMapDevice().then(res=>{
|
|
|
|
- devices.value = res
|
|
|
|
- initMap()
|
|
|
|
- })
|
|
|
|
- }
|
|
|
|
- onMounted(async () => {
|
|
|
|
- await getData();
|
|
|
|
- });
|
|
|
|
|
|
+const zoomOut = () => {
|
|
|
|
+ if (map.value) {
|
|
|
|
+ map.value.zoomOut()
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
|
|
- onBeforeUnmount(() => {
|
|
|
|
- if (map.value) {
|
|
|
|
- map.value.destroy();
|
|
|
|
- }
|
|
|
|
- });
|
|
|
|
-
|
|
|
|
- return {
|
|
|
|
- mapContainer,
|
|
|
|
- selectedDevice,
|
|
|
|
- hoverDevice,
|
|
|
|
- // deviceStatusMap,
|
|
|
|
- zoomIn,
|
|
|
|
- zoomOut,
|
|
|
|
- toggleMapType
|
|
|
|
- };
|
|
|
|
|
|
+const toggleMapType = () => {
|
|
|
|
+ if (!map.value) return
|
|
|
|
+
|
|
|
|
+ mapType.value = mapType.value === 'BMAP_NORMAL_MAP' ? 'BMAP_SATELLITE_MAP' : 'BMAP_NORMAL_MAP'
|
|
|
|
+ map.value.setMapType((window as any)[mapType.value])
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+const getData = async () => {
|
|
|
|
+ await IotDeviceApi.getMapDevice().then((res) => {
|
|
|
|
+ devices.value = res
|
|
|
|
+ initMap()
|
|
|
|
+ })
|
|
|
|
+}
|
|
|
|
+onMounted(async () => {
|
|
|
|
+ await getData()
|
|
|
|
+})
|
|
|
|
+
|
|
|
|
+onBeforeUnmount(() => {
|
|
|
|
+ if (map.value) {
|
|
|
|
+ map.value.destroy()
|
|
}
|
|
}
|
|
-});
|
|
|
|
|
|
+})
|
|
|
|
+
|
|
|
|
+// return {
|
|
|
|
+// mapContainer,
|
|
|
|
+// selectedDevice,
|
|
|
|
+// hoverDevice,
|
|
|
|
+// // deviceStatusMap,
|
|
|
|
+// zoomIn,
|
|
|
|
+// zoomOut,
|
|
|
|
+// toggleMapType
|
|
|
|
+// }
|
|
|
|
+// })
|
|
</script>
|
|
</script>
|
|
|
|
|
|
<style scoped>
|
|
<style scoped>
|