吉安感知网项目-前端
shuishen
2026-02-03 89380e6260a75d1d3b94de687ebcc2f50d50659d
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-09 16:34:39
 * @LastEditTime : 2026-01-31 15:40:15
 * @FilePath     : \applications\drone-command\src\views\dataCockpit\index.vue
 * @Description  : 
 * Copyright 2026 OBKoro1, All Rights Reserved. 
@@ -10,24 +10,55 @@
-->
<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" />
    <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"
      @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" />  
    <LegendBar class="legend-container" />
  </div>
</template>
<script setup>
  import MapContainer from './components/MapContainer.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 rightCollapsed = ref(false);
  const onlineDevices = ref([]);
  const allDevices = ref([]);
  const realWarningData = ref([]);
  const realWarningLoading = ref(true);
  const minLoadingMs = 400;
  const onSelectWarning = (type) => {
    leftActiveId.value = type;
@@ -37,6 +68,93 @@
  const onSelectEquipment = () => {
    rightCollapsed.value = false;
  };
  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 () => {
    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;
    }
  };
  onMounted(() => {
    fetchRealWarning();
  });
</script>
<style scoped lang="scss">
@@ -49,44 +167,44 @@
  .left-container,
  .right-container {
    position: absolute;
    top: 96px;
    bottom: 0;
    width: 401px;
    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: 17px;
      bottom: 20px;
      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;
    }
  }
  .left-container {
    top: 96px;
    left: 0;
    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: 54px;
    right: 0;
    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%);
  }
    ::v-deep(.wrapper) {
      top: 21px;
      right: 17px;
    }
  .legend-container {
    position: absolute;
    left: 50%;
    bottom: 22px;
    transform: translateX(-50%);
    z-index: 9;
  }
</style>