From 4c390d209b45d516fbe2f7552d26048687c83972 Mon Sep 17 00:00:00 2001
From: chenyao <1219716595@qq.com>
Date: Wed, 05 Aug 2026 14:29:25 +0800
Subject: [PATCH] feat:tab切换太快的时候内容不对应

---
 applications/drone-command/src/views/dataCockpit/index.vue |  248 ++++++++++++++++++++++++++++++++++++------------
 1 files changed, 184 insertions(+), 64 deletions(-)

diff --git a/applications/drone-command/src/views/dataCockpit/index.vue b/applications/drone-command/src/views/dataCockpit/index.vue
index 5226ea0..5a0de73 100644
--- a/applications/drone-command/src/views/dataCockpit/index.vue
+++ b/applications/drone-command/src/views/dataCockpit/index.vue
@@ -2,91 +2,211 @@
  * @Author       : yuan
  * @Date         : 2026-01-06 16:35:50
  * @LastEditors  : yuan
- * @LastEditTime : 2026-01-09 16:34:39
+ * @LastEditTime : 2026-02-09 15:40:07
  * @FilePath     : \applications\drone-command\src\views\dataCockpit\index.vue
- * @Description  : 
- * Copyright 2026 OBKoro1, All Rights Reserved. 
+ * @Description  :
+ * Copyright 2026 OBKoro1, All Rights Reserved.
  * 2026-01-06 16:35:50
 -->
 <template>
   <div class="page-container">
-    <MapContainer :online-devices="onlineDevices" :left-collapsed="leftCollapsed" />  
-    <LeftContainer class="left-container" v-model:activeId="leftActiveId" v-model:collapsed="leftCollapsed" />  
-    <RightContainer class="right-container" v-model:collapsed="rightCollapsed" v-model:onlineDevices="onlineDevices" />  
-    <CenterContainer @select-warning="onSelectWarning" @select-equipment="onSelectEquipment" />  
+    <DeviceMapContainer ref="deviceMapRef" :all-devices="allDevices" :alarm-drones="realWarningData"
+      :right-collapsed="rightCollapsed" container-id="data-cockpit-map"
+      @drone-signal="handleAlarmAction('signal', $event)" @drone-counter="handleAlarmAction('counter', $event)"
+      @drone-favorite="handleAlarmFavorite" />
+    <LeftContainer class="left-container" v-model:activeId="leftActiveId" v-model:collapsed="leftCollapsed"
+      :real-warning-data="realWarningData" :real-warning-loading="realWarningLoading"
+      @real-warning-signal="handleAlarmAction('signal', $event)"
+      @real-warning-counter="handleAlarmAction('counter', $event)" @real-warning-favorite="handleAlarmFavorite" />
+    <RightContainer class="right-container" v-model:collapsed="rightCollapsed" v-model:allDevices="allDevices"
+      @scene-click="handleSceneClick" />
+    <CenterContainer @select-warning="onSelectWarning" @select-equipment="onSelectEquipment" />
+    <LegendBar class="legend-container" />
   </div>
 </template>
 
 <script setup>
-  import MapContainer from './components/MapContainer.vue';
-  import LeftContainer from './components/LeftContainer.vue';
-  import RightContainer from './components/RightContainer.vue';
-  import CenterContainer from './components/CenterContainer.vue';
+import DeviceMapContainer from '@/components/map-container/device-map-container.vue'
+import LeftContainer from './components/LeftContainer.vue'
+import RightContainer from './components/RightContainer.vue'
+import CenterContainer from './components/CenterContainer.vue'
+import LegendBar from './components/LegendBar.vue'
+import {
+  alarmLogApi,
+  alarmFavoriteRemoveApi,
+  alarmFavoriteSaveApi,
+  interferenceAndExpulsionApi
+} from '@/api/dataCockpit'
+import { ElMessage } from 'element-plus'
+import { onMounted, ref } from 'vue'
 
-  const leftActiveId = ref(1);
-  const leftCollapsed = ref(false);
+const leftActiveId = ref(1)
+const leftCollapsed = ref(false)
 
-  const rightCollapsed = ref(false);
-  const onlineDevices = ref([]);
+const rightCollapsed = ref(false)
+const allDevices = ref([])
+const realWarningData = ref([])
+const realWarningLoading = ref(false)
+const loadingTimer = ref(null)
+const deviceMapRef = ref(null)
 
-  const onSelectWarning = (type) => {
-    leftActiveId.value = type;
-    leftCollapsed.value = false;
-  };
+const onSelectWarning = (type) => {
+  leftActiveId.value = type
+  leftCollapsed.value = false
+}
 
-  const onSelectEquipment = () => {
-    rightCollapsed.value = false;
-  };
+const onSelectEquipment = () => {
+  rightCollapsed.value = false
+}
+
+const handleSceneClick = (item) => {
+  if (item?.longitude && item?.latitude) {
+    deviceMapRef.value?.flyTo({
+      position: {
+        longitude: Number(item.longitude),
+        latitude: Number(item.latitude),
+        height: 18000
+      },
+    })
+  }
+}
+
+const actionTextMap = {
+  signal: '信号干扰',
+  counter: '诱导驱离'
+}
+
+const getAlarmRecordId = (item) => item?.alarmRecordId ?? item?.id
+const getFavoriteId = (item) =>
+  item?.favoriteId ??
+  item?.alarmFavoriteId ??
+  item?.fwAlarmFavoriteId ??
+  item?.favoriteRecordId ??
+  getAlarmRecordId(item)
+
+const isFavorited = (item) => {
+  const value = item?.favorited ?? item?.isFavorite
+  return value === 1 || value === '1' || value === true
+}
+
+const buildPayload = (type, item) => ({
+  counterWay: type === 'signal' ? 1 : type === 'counter' ? 2 : '',
+  alarmRecordId: getAlarmRecordId(item)
+})
+
+const handleAlarmAction = async (type, item) => {
+  const actionText = actionTextMap[type] || '操作'
+  try {
+    const res = await interferenceAndExpulsionApi(buildPayload(type, item))
+    if (res?.data?.success) {
+      ElMessage({ type: 'success', message: actionText + '成功' })
+      await fetchRealWarning()
+    } else {
+      ElMessage({ type: 'error', message: res?.data?.msg || actionText + '失败' })
+    }
+  } catch (error) {
+    ElMessage({ type: 'error', message: actionText + '失败' })
+  }
+}
+
+const handleAlarmFavorite = async (item) => {
+  const alarmRecordId = getAlarmRecordId(item)
+  if (!alarmRecordId) {
+    ElMessage({ type: 'warning', message: '缺少告警记录ID' })
+    return
+  }
+  const favorite = isFavorited(item)
+  const actionText = favorite ? '取消关注' : '关注'
+  try {
+    const res = favorite
+      ? await alarmFavoriteRemoveApi(getFavoriteId(item))
+      : await alarmFavoriteSaveApi({ alarmRecordId })
+    if (res?.data?.success) {
+      ElMessage({ type: 'success', message: actionText + '成功' })
+      await fetchRealWarning()
+    } else {
+      ElMessage({ type: 'error', message: res?.data?.msg || actionText + '失败' })
+    }
+  } catch (error) {
+    ElMessage({ type: 'error', message: actionText + '失败' })
+  }
+}
+
+const fetchRealWarning = async () => {
+  // 只有超过200ms才显示loading,避免闪烁
+  loadingTimer.value = setTimeout(() => {
+    realWarningLoading.value = true
+  }, 200)
+
+  try {
+    const params = { current: 1, size: 9999, alarmType: '1' }
+    const res = await alarmLogApi(params)
+    const records = res?.data?.data?.records ?? []
+    realWarningData.value = records.map((record) => ({
+      ...record,
+      isFavorite:
+        record?.isFavorite ??
+        (record?.favorited === 1 || record?.favorited === '1')
+    }))
+  } finally {
+    if (loadingTimer.value) clearTimeout(loadingTimer.value)
+    realWarningLoading.value = false
+  }
+}
+
+onMounted(() => {
+  fetchRealWarning()
+})
 </script>
 
 <style scoped lang="scss">
-  .page-container {
-    position: relative;
-    width: 100%;
-    height: 100%;
-  }
+.page-container {
+  position: relative;
+  width: 100%;
+  height: 100%;
+}
 
-  .left-container,
-  .right-container {
+.left-container,
+.right-container {
+  position: absolute;
+  bottom: 20px;
+  width: 300px;
+  z-index: 9;
+  backdrop-filter: blur(2px);
+  border-radius: 10px 10px 10px 10px;
+
+  ::v-deep(.wrapper) {
+    display: flex;
+    flex-direction: column;
     position: absolute;
-    top: 96px;
+    top: 0;
     bottom: 0;
-    width: 401px;
-    z-index: 9;
-    backdrop-filter: blur(2px);
-
-    ::v-deep(.wrapper) {
-      display: flex;
-      flex-direction: column;
-      position: absolute;
-      top: 17px;
-      bottom: 20px;
-      padding: 20px;
-      width: 300px;
-      background: rgba(0,0,0,0.3);
-      backdrop-filter: blur(16px);
-      border-radius: 10px 10px 10px 10px;
-    }
+    padding: 20px;
+    width: 300px;
+    background: rgba(0, 0, 0, 0.3);
+    backdrop-filter: blur(16px);
+    border-radius: 10px 10px 10px 10px;
+    box-sizing: border-box;
   }
+}
 
-  .left-container {
-    top: 96px;
-    left: 0;
-    background: linear-gradient( 270deg, rgba(17,23,34,0) 0%, rgba(17,23,34,0.56) 50%, rgba(17,23,34,0.96) 100%);
+.left-container {
+  top: 113px;
+  left: 17px;
+  background: linear-gradient(270deg, rgba(17, 23, 34, 0) 0%, rgba(17, 23, 34, 0.56) 50%, rgba(17, 23, 34, 0.96) 100%);
+}
 
-    ::v-deep(.wrapper) {
-      left: 17px;
-    }
-  }
+.right-container {
+  top: 75px;
+  right: 17px;
+  background: linear-gradient(270deg, rgba(17, 23, 34, 0.96) 0.16%, rgba(17, 23, 34, 0.56) 57.57%, rgba(4, 30, 37, 0) 100%);
+}
 
-  .right-container {
-    top: 54px;
-    right: 0;
-    background: linear-gradient( 270deg, rgba(17,23,34,0.96) 0.16%, rgba(17,23,34,0.56) 57.57%, rgba(4,30,37,0) 100%);
-
-    ::v-deep(.wrapper) {
-      top: 21px;
-      right: 17px;
-    }
-  }
+.legend-container {
+  position: absolute;
+  left: 50%;
+  bottom: 22px;
+  transform: translateX(-50%);
+  z-index: 9;
+}
 </style>

--
Gitblit v1.9.3