From 8739df8c235b3c36df0b47ddc20a691dadc7bb4f Mon Sep 17 00:00:00 2001
From: 罗广辉 <guanghui.luo@foxmail.com>
Date: Mon, 09 Feb 2026 15:58:05 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/master'

---
 applications/drone-command/src/views/dataCockpit/index.vue |  336 ++++++++++++++++++++++++++++---------------------------
 1 files changed, 169 insertions(+), 167 deletions(-)

diff --git a/applications/drone-command/src/views/dataCockpit/index.vue b/applications/drone-command/src/views/dataCockpit/index.vue
index 1224bd5..d9399c1 100644
--- a/applications/drone-command/src/views/dataCockpit/index.vue
+++ b/applications/drone-command/src/views/dataCockpit/index.vue
@@ -2,7 +2,7 @@
  * @Author       : yuan
  * @Date         : 2026-01-06 16:35:50
  * @LastEditors  : yuan
- * @LastEditTime : 2026-01-31 15:40:15
+ * @LastEditTime : 2026-02-09 15:40:07
  * @FilePath     : \applications\drone-command\src\views\dataCockpit\index.vue
  * @Description  : 
  * Copyright 2026 OBKoro1, All Rights Reserved. 
@@ -10,201 +10,203 @@
 -->
 <template>
   <div class="page-container">
-    <DeviceMapContainer
-      :all-devices="allDevices"
-      :alarm-drones="realWarningData"
-      :left-collapsed="leftCollapsed"
-      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"
+    <DeviceMapContainer ref="deviceMapRef" :all-devices="allDevices" :alarm-drones="realWarningData"
+      :left-collapsed="leftCollapsed" 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" />  
-    <CenterContainer @select-warning="onSelectWarning" @select-equipment="onSelectEquipment" />  
+      @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 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';
+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 allDevices = ref([]);
-  const realWarningData = ref([]);
-  const realWarningLoading = ref(true);
-  const minLoadingMs = 400;
+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 actionTextMap = {
-    signal: '信号干扰',
-    counter: '诱导驱离'
-  };
+const handleSceneClick = (item) => {
+  if (item?.longitude && item?.latitude) {
+    deviceMapRef.value?.flyTo({
+      position: {
+        longitude: Number(item.longitude),
+        latitude: Number(item.latitude),
+        height: 18000
+      },
+    })
+  }
+}
 
-  const getAlarmRecordId = (item) => item?.alarmRecordId ?? item?.id;
-  const getFavoriteId = (item) =>
-    item?.favoriteId ??
-    item?.alarmFavoriteId ??
-    item?.fwAlarmFavoriteId ??
-    item?.favoriteRecordId ??
-    getAlarmRecordId(item);
+const actionTextMap = {
+  signal: '信号干扰',
+  counter: '诱导驱离'
+}
 
-  const isFavorited = (item) => {
-    const value = item?.favorited ?? item?.isFavorite;
-    return value === 1 || value === '1' || value === true;
-  };
+const getAlarmRecordId = (item) => item?.alarmRecordId ?? item?.id
+const getFavoriteId = (item) =>
+  item?.favoriteId ??
+  item?.alarmFavoriteId ??
+  item?.fwAlarmFavoriteId ??
+  item?.favoriteRecordId ??
+  getAlarmRecordId(item)
 
-  const buildPayload = (type, item) => ({
-    counterWay: type === 'signal' ? 1 : type === 'counter' ? 2 : '',
-    alarmRecordId: getAlarmRecordId(item)
-  });
+const isFavorited = (item) => {
+  const value = item?.favorited ?? item?.isFavorite
+  return value === 1 || value === '1' || value === true
+}
 
-  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 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 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 + '失败' })
     }
-    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 + '失败' });
-    }
-  };
+  } catch (error) {
+    ElMessage({ type: 'error', message: actionText + '失败' })
+  }
+}
 
-  const fetchRealWarning = async () => {
-    const startAt = Date.now();
-    realWarningLoading.value = true;
-    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 {
-      const elapsed = Date.now() - startAt;
-      if (elapsed < minLoadingMs) {
-        await new Promise((resolve) => setTimeout(resolve, minLoadingMs - elapsed));
-      }
-      realWarningLoading.value = false;
-    }
-  };
+const fetchRealWarning = async () => {
+  // 只有超过200ms才显示loading,避免闪烁
+  loadingTimer.value = setTimeout(() => {
+    realWarningLoading.value = true
+  }, 200)
 
-  onMounted(() => {
-    fetchRealWarning();
-  });
+  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;
-    bottom: 20px;
+    top: 0;
+    bottom: 0;
+    padding: 20px;
     width: 300px;
-    z-index: 9;
-    backdrop-filter: blur(2px);
+    background: rgba(0, 0, 0, 0.3);
+    backdrop-filter: blur(16px);
     border-radius: 10px 10px 10px 10px;
-
-    ::v-deep(.wrapper) {
-      display: flex;
-      flex-direction: column;
-      position: absolute;
-      top: 0;
-      bottom: 0;
-      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;
-    }
+    box-sizing: border-box;
   }
+}
 
-  .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%);
-  }
+.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%);
+}
 
-  .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: 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%);
+}
 
-  .legend-container {
-    position: absolute;
-    left: 50%;
-    bottom: 22px;
-    transform: translateX(-50%);
-    z-index: 9;
-  }
+.legend-container {
+  position: absolute;
+  left: 50%;
+  bottom: 22px;
+  transform: translateX(-50%);
+  z-index: 9;
+}
 </style>

--
Gitblit v1.9.3