| | |
| | | * @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. |
| | |
| | | --> |
| | | <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(false); |
| | | const loadingTimer = ref(null); |
| | | 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 () => { |
| | | // 只有超过200ms才显示loading,避免闪烁 |
| | | loadingTimer.value = setTimeout(() => { |
| | | realWarningLoading.value = true; |
| | | }, 200); |
| | | 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; |
| | | } |
| | | }; |
| | | 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(); |
| | | }); |
| | | 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> |