-
+
-
-
-
智慧水务地图
-
MapLibre 地图将在此处加载
+
+
+
+
+
+
+
{{ initError }}
+
返回
+
+
+
+
+
+ {{ error }}
@@ -85,9 +166,15 @@ function handleToolClick(label: string) {
flex: 1;
position: relative;
margin: 0;
+
+ :deep(.maplibregl-map) {
+ width: 100%;
+ height: 100%;
+ }
}
-.map-placeholder {
+/* ── 加载 & 错误覆盖层 ── */
+.map-overlay {
position: absolute;
inset: 0;
display: flex;
@@ -95,20 +182,39 @@ function handleToolClick(label: string) {
align-items: center;
justify-content: center;
background: #f0f3f7;
+ z-index: 5;
+ gap: 12px;
+}
- .placeholder-title {
- margin: 12px 0 4px 0;
- font-size: 18px;
- font-weight: 600;
- color: var(--color-text-regular);
- }
+.overlay-text {
+ font-size: 14px;
+ color: var(--color-text-placeholder);
+ margin: 0;
+}
- .placeholder-hint {
- font-size: 13px;
- color: var(--color-text-placeholder);
+.map-error {
+ .overlay-text {
+ color: #F44336;
+ font-size: 14px;
}
}
+/* ── 运行时错误横幅 ── */
+.map-error-banner {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ z-index: 6;
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ padding: 6px 12px;
+ background: #fff3f3;
+ color: #F44336;
+ font-size: 12px;
+}
+
.bottom-tools {
display: flex;
justify-content: space-around;
diff --git a/src/views/monitoringEquipment/mapMonitoring.vue b/src/views/monitoringEquipment/mapMonitoring.vue
index 9536216..f08494a 100644
--- a/src/views/monitoringEquipment/mapMonitoring.vue
+++ b/src/views/monitoringEquipment/mapMonitoring.vue
@@ -5,13 +5,25 @@
* 在地图上展示监测设备位置和状态,
* 可点击设备查看实时数据。
*/
-import { ref } from 'vue'
+import { ref, watch, onMounted, onUnmounted } from 'vue'
import { useRouter } from 'vue-router'
+import maplibregl from 'maplibre-gl'
+import { MapManager } from '@/map/MapManager'
+import { MapFactory } from '@/map/MapFactory'
+import { useMap } from '@/map/composables/useMap'
+import { usePopup } from '@/map/composables/usePopup'
const router = useRouter()
-/** 地图加载状态 */
-const mapLoaded = ref(false)
+// ── 地图状态 ──────────────────────────────────────────────
+const { map, loading, error, isReady } = useMap()
+const { showPopup, hidePopup } = usePopup()
+
+/** 初始化错误 */
+const initError = ref
(null)
+
+/** 标记是否已添加设备标记 */
+const markersAdded = ref(false)
/** 模拟设备点位 */
const devicePoints = ref([
@@ -27,7 +39,98 @@ const statusColorMap: Record = {
offline: '#999',
}
-/** 跳转设备详情 */
+/** 存储动态创建的 Marker,用于清理 */
+const markers: maplibregl.Marker[] = []
+
+// ── 添加设备点位标记 ────────────────────────────────────
+function addDeviceMarkers(m: maplibregl.Map): void {
+ if (markersAdded.value) return
+ markersAdded.value = true
+
+ devicePoints.value.forEach((point) => {
+ const color = statusColorMap[point.status] || '#999'
+ const el = document.createElement('div')
+ el.style.cssText = `
+ width: 14px; height: 14px; border-radius: 50%;
+ background: ${color}; border: 2px solid #fff;
+ box-shadow: 0 1px 4px rgba(0,0,0,0.3); cursor: pointer;
+ `
+ const marker = new maplibregl.Marker({ element: el })
+ .setLngLat([point.lng, point.lat])
+ .addTo(m)
+
+ // 点击弹出设备信息
+ el.addEventListener('click', () => {
+ showPopup(
+ [point.lng, point.lat],
+ ``,
+ { maxWidth: '220px', closeOnClick: true },
+ )
+ })
+
+ markers.push(marker)
+ })
+}
+
+function clearMarkers(): void {
+ markers.forEach((m) => m.remove())
+ markers.length = 0
+ markersAdded.value = false
+}
+
+// ── 初始化地图 ───────────────────────────────────────────
+onMounted(() => {
+ const manager = MapManager.getInstance()
+
+ // 如果地图已存在,复用并添加标记
+ if (manager.hasMap()) {
+ const m = manager.getMap()
+ if (m) addDeviceMarkers(m)
+ return
+ }
+
+ const container = document.getElementById('mapmonitor-container')
+ if (!container) {
+ initError.value = '地图容器 #mapmonitor-container 未找到'
+ return
+ }
+
+ try {
+ MapFactory.createWithBasemap('osm', {
+ container: 'mapmonitor-container',
+ zoom: 10,
+ center: [104.0, 30.5],
+ onLoad: (m) => {
+ console.log('[MapMonitoring] 地图已加载')
+ addDeviceMarkers(m)
+ },
+ })
+ } catch (err: unknown) {
+ const msg = err instanceof Error ? err.message : '地图初始化失败'
+ initError.value = msg
+ console.error('[MapMonitoring] 地图创建失败:', err)
+ }
+})
+
+// ── 监听 isReady,加载标记 ──────────────────────────────
+watch(isReady, (ready) => {
+ if (ready && map.value && !markersAdded.value) {
+ addDeviceMarkers(map.value)
+ }
+})
+
+// ── 组件卸载 ─────────────────────────────────────────────
+onUnmounted(() => {
+ clearMarkers()
+ hidePopup()
+ MapManager.getInstance().destroyMap()
+})
+
+// ── 跳转设备详情 ─────────────────────────────────────────
function goEquipmentInfo(id: number) {
router.push(`/equipmentInfo?id=${id}`)
}
@@ -37,11 +140,25 @@ function goEquipmentInfo(id: number) {
-
-
-
-
地图监控
-
设备点位将在此地图上展示
+
+
+
+
+
+
+
+
+
+
+
+ {{ error }}
+
@@ -82,31 +199,60 @@ function goEquipmentInfo(id: number) {
}
}
-.map-placeholder {
+.map-area {
flex: 1;
+ position: relative;
+ margin: 8px;
+ border-radius: 10px;
+ overflow: hidden;
+ min-height: 300px;
+
+ :deep(.maplibregl-map) {
+ width: 100%;
+ height: 100%;
+ }
+}
+
+.map-status {
+ position: absolute;
+ inset: 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background: #f5f7fa;
- margin: 8px;
border-radius: 10px;
- border: 1px dashed #ddd;
- min-height: 300px;
+ z-index: 5;
+ gap: 8px;
- .map-title {
- margin: 12px 0 4px 0;
- font-size: 18px;
- font-weight: 600;
- color: var(--color-text-regular);
- }
-
- .map-hint {
- font-size: 13px;
+ p {
+ margin: 0;
+ font-size: 14px;
color: var(--color-text-placeholder);
}
}
+.map-error-state {
+ p {
+ color: #F44336;
+ }
+}
+
+.map-error-banner {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ z-index: 6;
+ display: flex;
+ align-items: center;
+ gap: 4px;
+ padding: 4px 10px;
+ background: #fff3f3;
+ color: #F44336;
+ font-size: 11px;
+}
+
.device-panel {
background: var(--color-bg-card);
margin: 0 8px 8px;