From 9fb1aa745bb4447c47b0851335077cdb44b41b80 Mon Sep 17 00:00:00 2001
From: shuishen <1109946754@qq.com>
Date: Tue, 27 Jan 2026 12:12:50 +0800
Subject: [PATCH] feat:无人机轨迹显示调整
---
applications/drone-command/src/views/dataCockpit/components/RealWarning.vue | 130 +-----------
applications/drone-command/src/views/basicManage/deviceStock/FormDiaLog.vue | 57 +++--
applications/drone-command/src/components/map-container/device-map-container.vue | 250 +++++++++++++++---------
applications/drone-command/src/views/dataCockpit/components/LeftContainer.vue | 35 ++
applications/drone-command/src/views/dataCockpit/index.vue | 113 +++++++++++
5 files changed, 340 insertions(+), 245 deletions(-)
diff --git a/applications/drone-command/src/components/map-container/device-map-container.vue b/applications/drone-command/src/components/map-container/device-map-container.vue
index 49bd52b..a4311a4 100644
--- a/applications/drone-command/src/components/map-container/device-map-container.vue
+++ b/applications/drone-command/src/components/map-container/device-map-container.vue
@@ -39,7 +39,7 @@
@close="closePopup" />
<DronePopup :visible="popupVisible && isDronePopup" :position="popupPosition" :drone="selectedDevice"
- :favorite="Boolean(selectedDevice?.isFavorite)" @close="closePopup" @toggle-favorite="toggleDroneFavorite"
+ :favorite="Boolean(selectedDevice?.isFavorite)" @close="closePopup" @toggle-favorite="handleDroneFavorite"
@signal="handleDroneSignal" @counter="handleDroneCounter" />
</div>
</template>
@@ -78,6 +78,10 @@
type: Array,
default: () => [],
},
+ alarmDrones: {
+ type: Array,
+ default: () => [],
+ },
leftCollapsed: {
type: Boolean,
default: false,
@@ -91,7 +95,7 @@
default: true,
},
})
-const emit = defineEmits(['droneSignal', 'droneCounter'])
+const emit = defineEmits(['droneSignal', 'droneCounter', 'droneFavorite'])
const DEFAULT_ZONE_PAGE_SIZE = 999
@@ -363,44 +367,86 @@
})
}
-const buildSimulatedTrackPoints = () => {
- return [
- {
- longitude: 114.963191,
- latitude: 27.136716,
- height: 120
- },
- {
- longitude: 114.957308,
- latitude: 27.138452,
- height: 120
- },
- {
- longitude: 114.952,
- latitude: 27.136317,
- height: 120
- },
- {
- longitude: 114.949293,
- latitude: 27.133864,
- height: 120
- },
- {
- longitude: 114.944666,
- latitude: 27.130526,
- height: 120
- },
- {
- longitude: 114.945909,
- latitude: 27.127845,
- height: 120
- },
- {
- longitude: 114.962974,
- latitude: 27.136242,
- height: 120
- },
+const buildSimulatedTrackPoints = center => {
+ const basePoints = [
+ [
+ {
+ longitude: 114.963191,
+ latitude: 27.136716,
+ height: 120
+ },
+ {
+ longitude: 114.957308,
+ latitude: 27.138452,
+ height: 120
+ },
+ {
+ longitude: 114.952,
+ latitude: 27.136317,
+ height: 120
+ },
+ {
+ longitude: 114.949293,
+ latitude: 27.133864,
+ height: 120
+ },
+ {
+ longitude: 114.944666,
+ latitude: 27.130526,
+ height: 120
+ },
+ {
+ longitude: 114.945909,
+ latitude: 27.127845,
+ height: 120
+ },
+ {
+ longitude: 114.962974,
+ latitude: 27.136242,
+ height: 120
+ },
+ ],
+
+ [
+ {
+ longitude: 114.931063,
+ latitude: 27.095052,
+ height: 120
+ },
+ {
+ longitude: 114.928653,
+ latitude: 27.096307,
+ height: 120
+ },
+ {
+ longitude: 114.925958,
+ latitude: 27.096963,
+ height: 120
+ },
+ {
+ longitude: 114.925836,
+ latitude: 27.096102,
+ height: 120
+ },
+ {
+ longitude: 114.928384,
+ latitude: 27.095866,
+ height: 120
+ },
+ {
+ longitude: 114.929874,
+ latitude: 27.096095,
+ height: 120
+ },
+ {
+ longitude: 114.931048,
+ latitude: 27.097666,
+ height: 120
+ },
+ ]
]
+
+ return basePoints[center.trackIndex]
}
@@ -486,70 +532,67 @@
droneTrackTickHandler = null
}
-const renderSimulatedDroneTrack = () => {
+const renderSimulatedDroneTrack = (list) => {
if (!viewer) return
clearDroneTrackEntities()
+ if (!list?.length) return
ensureDroneTrackCollections()
droneTrackBillboardCollection.show = detailVisible.value
droneTrackPolylineCollection.show = detailVisible.value
droneTrackRuntime = []
- const baseCenters = [['默认区域', { longitude: 114.958541, latitude: 27.121917 }]]
const segmentDuration = 6
const baseTrackColor = Cesium.Color.fromCssColorString('red')
- baseCenters.forEach(([centerName, center], trackIndex) => {
- const points = buildSimulatedTrackPoints(center)
- if (points.length < 2) return
- const positions = points.map(point =>
- Cesium.Cartesian3.fromDegrees(point.longitude, point.latitude, point.height)
- )
- let trackMaterial = createDroneTrackMaterial({
- color: baseTrackColor,
- speed: 4.5,
- headWidth: 0.2,
- glowPower: 1.8,
- backgroundAlpha: 0.34,
+ ; (list || []).forEach((item, trackIndex) => {
+ const position = getDevicePosition(item)
+ if (!position) return
+ const points = buildSimulatedTrackPoints({ ...position, height: item.flightHeightM, trackIndex })
+ if (points.length < 2) return
+ const positions = points.map(point =>
+ Cesium.Cartesian3.fromDegrees(point.longitude, point.latitude, point.height)
+ )
+ let trackMaterial = createDroneTrackMaterial({
+ color: baseTrackColor,
+ speed: 4.5,
+ headWidth: 0.2,
+ glowPower: 1.8,
+ backgroundAlpha: 0.34,
+ })
+ if (!trackMaterial) {
+ trackMaterial = Cesium.Material.fromType('Color', { color: baseTrackColor })
+ }
+ droneTrackPolylineCollection.add({
+ positions,
+ width: 3,
+ material: trackMaterial,
+ })
+ const droneId = `drone-alarm-${item?.alarmRecordId ?? item?.id ?? trackIndex}`
+ const billboard = droneTrackBillboardCollection.add({
+ position: positions[positions.length - 1],
+ image: droneIcon,
+ width: 36,
+ height: 36,
+ verticalOrigin: Cesium.VerticalOrigin.CENTER,
+ disableDepthTestDistance: Number.POSITIVE_INFINITY,
+ })
+ billboard.id = droneId
+ const speedMs = Math.round(Cesium.Cartesian3.distance(positions[0], positions[1]) / segmentDuration)
+ dronePickMap.set(droneId, {
+ data: {
+ ...item,
+ flightHeightM: item.flightHeightM ?? points[0].height,
+ flightSpeedMs: item.flightSpeedMs ?? speedMs,
+ longitude: item.longitude ?? points[0].longitude,
+ latitude: item.latitude ?? points[0].latitude,
+ },
+ billboard,
+ })
+ droneTrackRuntime.push({
+ positions,
+ billboard,
+ segmentDuration,
+ duration: (points.length - 1) * segmentDuration,
+ })
})
- if (!trackMaterial) {
- trackMaterial = Cesium.Material.fromType('Color', { color: baseTrackColor })
- }
- droneTrackPolylineCollection.add({
- positions,
- width: 3,
- material: trackMaterial,
- })
- const droneId = `drone-track-${trackIndex}`
- const billboard = droneTrackBillboardCollection.add({
- position: positions[positions.length - 1],
- image: droneIcon,
- width: 36,
- height: 36,
- verticalOrigin: Cesium.VerticalOrigin.CENTER,
- disableDepthTestDistance: Number.POSITIVE_INFINITY,
- })
- billboard.id = droneId
- const speedMs = Math.round(Cesium.Cartesian3.distance(positions[0], positions[1]) / segmentDuration)
- dronePickMap.set(droneId, {
- data: {
- droneName: `无人机-${trackIndex + 1}`,
- droneSerialNo: `UAV-${trackIndex + 1}`,
- flightHeightM: points[0].height,
- flightSpeedMs: speedMs,
- longitude: points[0].longitude,
- latitude: points[0].latitude,
- flightStatus: 1,
- deviceName: centerName,
- dataSource: centerName,
- counterDeviceName: centerName,
- },
- billboard,
- })
- droneTrackRuntime.push({
- positions,
- billboard,
- segmentDuration,
- duration: (points.length - 1) * segmentDuration,
- })
- })
viewer.clock.multiplier = 1
startDroneTrackAnimation()
reorderCockpitPrimitives()
@@ -860,9 +903,9 @@
const popupPosition = ref({ x: 0, y: 0 })
const popupVisible = computed(() => Boolean(selectedDevice.value))
const isDronePopup = computed(() => selectedTargetType.value === 'drone')
-const toggleDroneFavorite = () => {
+const handleDroneFavorite = () => {
if (!selectedDevice.value) return
- selectedDevice.value.isFavorite = !selectedDevice.value.isFavorite
+ emit('droneFavorite', selectedDevice.value)
}
const handleDroneSignal = () => emit('droneSignal', selectedDevice.value)
const handleDroneCounter = () => emit('droneCounter', selectedDevice.value)
@@ -911,6 +954,19 @@
() => props.onlineDevices,
devices => {
renderDeviceEntities(devices || [])
+ },
+ { deep: true }
+)
+
+watch(
+ () => props.alarmDrones,
+ list => {
+ renderSimulatedDroneTrack(list || [])
+ if (selectedTargetType.value === 'drone' && selectedDevice.value) {
+ const selectedId = selectedDevice.value.alarmRecordId ?? selectedDevice.value.id
+ const match = (list || []).find(item => (item?.alarmRecordId ?? item?.id) === selectedId)
+ if (match) selectedDevice.value = { ...selectedDevice.value, ...match }
+ }
},
{ deep: true }
)
@@ -970,7 +1026,7 @@
loadPartitions()
loadAggregation()
loadCommandPosts()
- renderSimulatedDroneTrack()
+ renderSimulatedDroneTrack(props.alarmDrones)
initDeviceClickHandler()
}
diff --git a/applications/drone-command/src/views/basicManage/deviceStock/FormDiaLog.vue b/applications/drone-command/src/views/basicManage/deviceStock/FormDiaLog.vue
index b570b0f..2e63d4d 100644
--- a/applications/drone-command/src/views/basicManage/deviceStock/FormDiaLog.vue
+++ b/applications/drone-command/src/views/basicManage/deviceStock/FormDiaLog.vue
@@ -62,15 +62,20 @@
<el-table-column prop="charger" label="负责人" />
<el-table-column prop="contactPhone" label="联系电话" />
<el-table-column prop="outTarget" label="出库去向" />
- <el-table-column prop="outTime" label="出库时间" />
+
+ <el-table-column prop="outTime" show-overflow-tooltip label="出库时间">
+ <template v-slot="{ row }">
+ {{ dayjs(row.outTime).format('YYYY-MM-DD') }}
+ </template>
+ </el-table-column>
<el-table-column prop="purpose" label="用途" />
</el-table>
</div>
<div class="command-table-pagination">
- <el-pagination popper-class="command-select-popper"
- v-model:current-page="searchParams.current" v-model:page-size="searchParams.size"
- layout="total, prev, pager, next, sizes" :total="total" @change="getList" />
+ <el-pagination popper-class="command-select-popper" v-model:current-page="searchParams.current"
+ v-model:page-size="searchParams.size" layout="total, prev, pager, next, sizes" :total="total"
+ @change="getList" />
</div>
</div>
</div>
@@ -79,8 +84,8 @@
<el-row>
<el-col :span="12">
<el-form-item label="设备名称" prop="deviceName">
- <el-input class="command-input" v-model="formData.deviceName" maxlength="50"
- placeholder="请输入" clearable />
+ <el-input class="command-input" v-model="formData.deviceName" maxlength="50" placeholder="请输入"
+ clearable />
</el-form-item>
</el-col>
<el-col :span="12">
@@ -94,8 +99,8 @@
</el-col>
<el-col :span="12">
<el-form-item label="设备编码" prop="deviceSn">
- <el-input class="command-input" v-model="formData.deviceSn" maxlength="50"
- placeholder="请输入" clearable />
+ <el-input class="command-input" v-model="formData.deviceSn" maxlength="50" placeholder="请输入"
+ clearable />
</el-form-item>
</el-col>
<el-col :span="12">
@@ -109,40 +114,39 @@
</el-col>
<el-col :span="12">
<el-form-item label="型号" prop="deviceModel">
- <el-input class="command-input" v-model="formData.deviceModel" maxlength="50"
- placeholder="请输入" clearable />
+ <el-input class="command-input" v-model="formData.deviceModel" maxlength="50" placeholder="请输入"
+ clearable />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="规格" prop="deviceSpecification">
- <el-input class="command-input" v-model="formData.deviceSpecification"
- maxlength="50" placeholder="请输入" clearable />
+ <el-input class="command-input" v-model="formData.deviceSpecification" maxlength="50"
+ placeholder="请输入" clearable />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="生产厂商" prop="manufacturer">
- <el-input class="command-input" v-model="formData.manufacturer" maxlength="50"
- placeholder="请输入" clearable />
+ <el-input class="command-input" v-model="formData.manufacturer" maxlength="50" placeholder="请输入"
+ clearable />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="来源" prop="source">
- <el-input class="command-input" v-model="formData.source" maxlength="50"
- placeholder="请输入" clearable />
+ <el-input class="command-input" v-model="formData.source" maxlength="50" placeholder="请输入"
+ clearable />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="用途" prop="purpose">
- <el-input class="command-input" v-model="formData.purpose" maxlength="50"
- placeholder="请输入" clearable />
+ <el-input class="command-input" v-model="formData.purpose" maxlength="50" placeholder="请输入"
+ clearable />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="所属部门" prop="belongDept">
- <el-tree-select class="command-select"
- popper-class="command-tree-select-popper" v-model="formData.belongDept"
- node-key="id" :data="deptTree" :props="treeProps" check-strictly @change="belongDeptChange"
- clearable />
+ <el-tree-select class="command-select" popper-class="command-tree-select-popper"
+ v-model="formData.belongDept" node-key="id" :data="deptTree" :props="treeProps"
+ check-strictly @change="belongDeptChange" clearable />
</el-form-item>
</el-col>
<el-col :span="12">
@@ -155,14 +159,15 @@
</el-col>
<el-col :span="12">
<el-form-item label="联系电话" prop="contactPhone">
- <el-input class="command-input" v-model="formData.contactPhone" maxlength="50"
- placeholder="请输入" clearable />
+ <el-input class="command-input" v-model="formData.contactPhone" maxlength="50" placeholder="请输入"
+ clearable />
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
- <el-button v-if="dialogMode != 'view'" color="#2B2B4C" @click="handleCancel">{{ dialogReadonly ? '关闭' : '取消' }}</el-button>
+ <el-button v-if="dialogMode != 'view'" color="#2B2B4C" @click="handleCancel">{{ dialogReadonly ? '关闭' : '取消'
+ }}</el-button>
<el-button color="#284FE3" v-if="!dialogReadonly" type="primary" :loading="submitting"
:disabled="submitting" @click="handleSubmit">
保存
@@ -172,6 +177,8 @@
</template>
<script setup>
+import dayjs from 'dayjs'
+
import { computed, ref } from 'vue'
import { ElMessage } from 'element-plus'
import { fwDeviceDetailApi, fwDeviceSubmitApi } from '@/views/basicManage/deviceStock/fwDevice'
diff --git a/applications/drone-command/src/views/dataCockpit/components/LeftContainer.vue b/applications/drone-command/src/views/dataCockpit/components/LeftContainer.vue
index 65c2764..a524faa 100644
--- a/applications/drone-command/src/views/dataCockpit/components/LeftContainer.vue
+++ b/applications/drone-command/src/views/dataCockpit/components/LeftContainer.vue
@@ -12,7 +12,16 @@
</div>
<div class="content">
- <component :is="currentComponent" />
+ <RealWarning
+ v-if="activeIdModel === 1"
+ :data="realWarningData"
+ :loading="realWarningLoading"
+ @signal="emit('real-warning-signal', $event)"
+ @counter="emit('real-warning-counter', $event)"
+ @favorite="emit('real-warning-favorite', $event)"
+ />
+ <EquipmentWarning v-else-if="activeIdModel === 2" />
+ <HistoryWarning v-else />
</div>
</div>
@@ -24,11 +33,11 @@
<script setup>
import TitleTemplate from './templateComponents/TitleTemplate.vue'
-import RealWarning from './RealWarning.vue'
import EquipmentWarning from './EquipmentWarning.vue'
import HistoryWarning from './HistoryWarning.vue'
import { alarmStatisticsApi } from '@/api/dataCockpit'
-import { onMounted } from 'vue'
+import { computed, onMounted, ref } from 'vue'
+import RealWarning from './RealWarning.vue'
const props = defineProps({
activeId: {
@@ -38,10 +47,24 @@
collapsed: {
type: Boolean,
default: false
+ },
+ realWarningData: {
+ type: Array,
+ default: () => []
+ },
+ realWarningLoading: {
+ type: Boolean,
+ default: false
}
})
-const emit = defineEmits(['update:activeId', 'update:collapsed'])
+const emit = defineEmits([
+ 'update:activeId',
+ 'update:collapsed',
+ 'real-warning-signal',
+ 'real-warning-counter',
+ 'real-warning-favorite'
+])
const activeIdModel = computed({
get: () => props.activeId,
@@ -73,10 +96,6 @@
component: HistoryWarning
}
])
-
-const currentComponent = computed(() => {
- return categoryList.value.find(i => i.id === activeIdModel.value)?.component
-})
const toggleCollapse = () => {
collapsedModel.value = !collapsedModel.value
diff --git a/applications/drone-command/src/views/dataCockpit/components/RealWarning.vue b/applications/drone-command/src/views/dataCockpit/components/RealWarning.vue
index 132e7a2..9125f86 100644
--- a/applications/drone-command/src/views/dataCockpit/components/RealWarning.vue
+++ b/applications/drone-command/src/views/dataCockpit/components/RealWarning.vue
@@ -2,137 +2,39 @@
* @Author : yuan
* @Date : 2026-01-08 09:29:07
* @LastEditors : yuan
- * @LastEditTime : 2026-01-26 09:59:52
+ * @LastEditTime : 2026-01-27 12:01:37
* @FilePath : \applications\drone-command\src\views\dataCockpit\components\RealWarning.vue
* @Description :
* Copyright 2026 OBKoro1, All Rights Reserved.
* 2026-01-08 09:29:07
-->
<template>
- <div
- class="real-warning"
- v-loading="loading"
- element-loading-background="rgba(5, 5, 15, 0.6)"
- element-loading-text="加载中..."
- >
+ <div class="real-warning" v-loading="props.loading" element-loading-background="rgba(5, 5, 15, 0.6)"
+ element-loading-text="???...">
<div class="list-content">
- <EmptyState v-if="!realWarningData.length" />
- <RealTemplate
- v-else
- v-for="(item, ind) in realWarningData"
- :key="ind"
- :data="item"
- @signal="() => handleAction('signal', item)"
- @counter="() => handleAction('counter', item)"
- @favorite="() => handleFavorite(item)"
- />
+ <EmptyState v-if="!props.data.length && !props.loading" />
+ <RealTemplate v-else v-for="(item, ind) in props.data" :key="ind" :data="item"
+ @signal="emit('signal', item)" @counter="emit('counter', item)" @favorite="emit('favorite', item)" />
</div>
</div>
</template>
<script setup>
import RealTemplate from './templateComponents/RealTemplate.vue'
-import {
- alarmLogApi,
- alarmFavoriteRemoveApi,
- alarmFavoriteSaveApi,
- interferenceAndExpulsionApi
-} from '@/api/dataCockpit'
-import { onMounted, ref } from 'vue'
import EmptyState from './EmptyState.vue'
-import { ElMessage } from 'element-plus'
-const realWarningData = ref([])
-const loading = ref(true)
-const minLoadingMs = 400
-
-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 props = defineProps({
+ data: {
+ type: Array,
+ default: () => []
+ },
+ loading: {
+ type: Boolean,
+ default: false
+ }
})
-const handleAction = 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 handleFavorite = async (item) => {
- const alarmRecordId = getAlarmRecordId(item)
- if (!alarmRecordId) {
- ElMessage({ type: 'warning', message: '缺少告警记录ID' })
- return
- }
- const isFavorite = isFavorited(item)
- const actionText = isFavorite ? '取消关注' : '关注'
- try {
- const res = isFavorite
- ? 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()
- loading.value = true
- try {
- const params = { current: 1, size: 20, 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))
- }
- loading.value = false
- }
-}
-
-onMounted(() => {
- fetchRealWarning()
-})
+const emit = defineEmits(['signal', 'counter', 'favorite'])
</script>
<style lang="scss" scoped>
diff --git a/applications/drone-command/src/views/dataCockpit/index.vue b/applications/drone-command/src/views/dataCockpit/index.vue
index 7f44448..aafe0df 100644
--- a/applications/drone-command/src/views/dataCockpit/index.vue
+++ b/applications/drone-command/src/views/dataCockpit/index.vue
@@ -12,10 +12,23 @@
<div class="page-container">
<DeviceMapContainer
:online-devices="onlineDevices"
+ :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" />
+ <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:onlineDevices="onlineDevices" />
<CenterContainer @select-warning="onSelectWarning" @select-equipment="onSelectEquipment" />
<LegendBar class="legend-container" />
@@ -28,12 +41,23 @@
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 realWarningData = ref([]);
+ const realWarningLoading = ref(true);
+ const minLoadingMs = 400;
const onSelectWarning = (type) => {
leftActiveId.value = type;
@@ -43,6 +67,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: 20, 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">
--
Gitblit v1.9.3