From dc89af73e55f7bda6018bace4813a4107b5248d4 Mon Sep 17 00:00:00 2001
From: shuishen <1109946754@qq.com>
Date: Mon, 26 Jan 2026 19:11:33 +0800
Subject: [PATCH] feat:数据驾驶舱等页面调整
---
applications/drone-command/src/components/map-container/device-map-container.vue | 119 ++++++++++++++++++++++-------
applications/drone-command/src/views/dataCockpit/components/LegendBar.vue | 8 +-
applications/drone-command/src/views/detectionCountermeasure/detectionRange/DetectionRangeDialog.vue | 28 ++++++-
applications/drone-command/src/components/map-container/device-map-materials.js | 40 +++++++--
applications/drone-command/src/views/dataCockpit/components/templateComponents/RealEquipmentTemplate.vue | 2
applications/drone-command/src/views/detectionCountermeasure/detectionRange/index.vue | 6 +
applications/drone-command/src/api/dataCockpit/index.js | 5
7 files changed, 155 insertions(+), 53 deletions(-)
diff --git a/applications/drone-command/src/api/dataCockpit/index.js b/applications/drone-command/src/api/dataCockpit/index.js
index f08ac7f..68024bd 100644
--- a/applications/drone-command/src/api/dataCockpit/index.js
+++ b/applications/drone-command/src/api/dataCockpit/index.js
@@ -2,7 +2,7 @@
* @Author : yuan
* @Date : 2026-01-09 11:14:04
* @LastEditors : yuan
- * @LastEditTime : 2026-01-26 09:38:16
+ * @LastEditTime : 2026-01-26 19:02:07
* @FilePath : \applications\drone-command\src\api\dataCockpit\index.js
* @Description :
* Copyright 2026 OBKoro1, All Rights Reserved.
@@ -78,7 +78,8 @@
export const cockpitAggregationApi = (params) => {
return request({
url: '/drone-fw/device/fwDevice/statisticalDeviceOut',
- method: 'get'
+ method: 'get',
+ params
})
}
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 a8f8566..43b373e 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
@@ -2,8 +2,9 @@
<div class="map-shell">
<CommonCesiumMap ref="mapRef" class="command-cesium map-container" :dom-id="props.containerId" :active="true"
:flat-mode="false" :terrain="true" :layer-mode="4" :contour="false" :boundary="false"
- :show-admin-boundary="true" :zoom-to-boundary="true" :enable-stage-emit="true" :cluster-height="100000"
- @ready="handleMapReady" @stage-change="handleStageChange" />
+ :show-admin-boundary="true" :zoom-to-boundary="true" :enable-stage-emit="true"
+ :cluster-height="CLUSTER_HEIGHT" :detail-height="DETAIL_HEIGHT" @ready="handleMapReady"
+ @stage-change="handleStageChange" />
<div v-if="props.showLayerControl" class="layer-control-root" :class="{ collapsed: props.leftCollapsed }">
<div class="layer-control-wrap" ref="layerWrapRef">
<div class="layer-control" @click="toggleLayerPanel">
@@ -63,6 +64,9 @@
createRadialGradientMaterial,
getTexturedVertexFormat,
} from './device-map-materials'
+
+const CLUSTER_HEIGHT = 100000
+const DETAIL_HEIGHT = 10000
const props = defineProps({
onlineDevices: {
@@ -157,6 +161,14 @@
const latitude = Number(latitudeRaw)
if (!Number.isFinite(longitude) || !Number.isFinite(latitude)) return null
return { longitude, latitude }
+}
+
+const getDeviceRange = item => {
+ if (!item) return null
+ const rawRange = item.effectiveRangeKm ?? item.range ?? item.coverRadiusM
+ const range = Number(rawRange)
+ if (!Number.isFinite(range) || range <= 0) return null
+ return range
}
const ensureCockpitPrimitiveLayer = () => {
@@ -305,6 +317,20 @@
if (aggregationSource) aggregationSource.show = visible
}
+const setDroneVisibility = visible => {
+ if (droneTrackBillboardCollection) droneTrackBillboardCollection.show = visible
+ if (droneTrackPolylineCollection) droneTrackPolylineCollection.show = visible
+ if (!visible && selectedTargetType.value === 'drone') {
+ closePopup()
+ }
+}
+const getStageByHeight = height => {
+ if (height == null) return 'detail'
+ if (height >= CLUSTER_HEIGHT) return 'cluster'
+ if (height <= DETAIL_HEIGHT) return 'detail'
+ return 'mid'
+}
+
const ensureCountyCenterMap = () => {
if (countyCenterMap.size) return
const geojson = JSON.parse(jaGeojsonRaw)
@@ -316,24 +342,44 @@
})
}
-const buildSimulatedTrackPoints = base => {
- ensureCountyCenterMap()
- const anchor = base || { longitude: 116.397, latitude: 39.908 }
- const offsets = [
- [0, 0, 120],
- [0.02, 0.012, 150],
- [0.04, 0.006, 180],
- [0.06, -0.008, 200],
- [0.03, -0.02, 160],
- [0.0, -0.015, 140],
- [-0.02, -0.005, 120],
- [-0.01, 0.01, 130],
+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
+ },
]
- return offsets.map(item => ({
- longitude: anchor.longitude + item[0],
- latitude: anchor.latitude + item[1],
- height: item[2],
- }))
}
@@ -422,13 +468,11 @@
const renderSimulatedDroneTrack = () => {
if (!viewer) return
clearDroneTrackEntities()
- ensureCountyCenterMap()
ensureDroneTrackCollections()
+ droneTrackBillboardCollection.show = detailVisible.value
+ droneTrackPolylineCollection.show = detailVisible.value
droneTrackRuntime = []
- const centers = Array.from(countyCenterMap.entries())
- const baseCenters = centers.length
- ? centers.slice(0, 4)
- : [['默认区域', { longitude: 116.397, latitude: 39.908 }]]
+ const baseCenters = [['默认区域', { longitude:114.958541, latitude: 27.121917 }]]
const segmentDuration = 6
const baseTrackColor = Cesium.Color.fromCssColorString('red')
baseCenters.forEach(([centerName, center], trackIndex) => {
@@ -454,7 +498,7 @@
})
const droneId = `drone-track-${trackIndex}`
const billboard = droneTrackBillboardCollection.add({
- position: positions[0],
+ position: positions[positions.length - 1],
image: droneIcon,
width: 36,
height: 36,
@@ -511,7 +555,8 @@
const position = getDevicePosition(item)
if (!position) return
const entityId = `online-device-${item.id ?? index}-${index}`
- addDeviceRings(position, ringFillInstancesByStyle, ringOutlineInstancesByStyle)
+ const rangeMeters = getDeviceRange(item)
+ addDeviceRings(position, ringFillInstancesByStyle, ringOutlineInstancesByStyle, rangeMeters)
const billboard = deviceBillboardCollection.add({
position: Cesium.Cartesian3.fromDegrees(position.longitude, position.latitude, 0),
image: equipmentIcon,
@@ -528,9 +573,20 @@
ringFillInstancesByStyle.forEach((instances, index) => {
if (!instances.length) return
const ring = RING_STYLES[index]
+ const alpha = ring.alpha ?? 0.64
+ const innerRatio =
+ typeof ring.innerRatio === 'number'
+ ? ring.innerRatio
+ : ring.inner && ring.outer
+ ? Math.min(Math.max(ring.inner / ring.outer, 0), 0.9)
+ : 0
const material = createRadialGradientMaterial(
- Cesium.Color.fromCssColorString(ring.gradient[0]).withAlpha(0.64),
- Cesium.Color.fromCssColorString(ring.gradient[1]).withAlpha(0.64)
+ Cesium.Color.fromCssColorString(ring.gradient[0]).withAlpha(alpha),
+ Cesium.Color.fromCssColorString(ring.gradient[1]).withAlpha(alpha),
+ {
+ gamma: 1.7,
+ innerCutoff: innerRatio,
+ }
)
const primitive = new Cesium.GroundPrimitive({
geometryInstances: instances,
@@ -629,7 +685,7 @@
const renderDefenseZones = zones => {
if (!viewer) return
clearDefenseZoneEntities()
- const result = buildZonePrimitives(zones, '#19D266', '#2AEDBF', '#012B11')
+ const result = buildZonePrimitives(zones, '#72F3FF', '#72F3FF', '#0A7C88')
defenseZonePrimitive = result.primitive
defenseZoneOutlinePrimitive = result.outlinePrimitive
if (defenseZonePrimitive) defenseZonePrimitive.show = detailVisible.value
@@ -640,7 +696,7 @@
const renderPartitions = zones => {
if (!viewer) return
clearPartitionEntities()
- const result = buildZonePrimitives(zones, '#FFCD2A', '#FFC609', '#583300')
+ const result = buildZonePrimitives(zones, '#FFD772', '#FFD772', '#A86B00')
partitionPrimitive = result.primitive
partitionOutlinePrimitive = result.outlinePrimitive
if (partitionPrimitive) partitionPrimitive.show = detailVisible.value
@@ -855,13 +911,14 @@
const showCluster = stage === 'cluster'
setClusterVisibility(showCluster)
setDetailVisibility(!showCluster)
+ setDroneVisibility(!showCluster)
}
const handleMapReady = ({ viewer: mapViewer }) => {
viewer = mapViewer
ensureCockpitPrimitiveLayer()
const height = viewer?.camera?.positionCartographic?.height
- const stage = height != null && height >= 100000 ? 'cluster' : 'detail'
+ const stage = getStageByHeight(height)
updateStageDisplay(stage)
renderDeviceEntities(props.onlineDevices)
loadDefenseZones()
diff --git a/applications/drone-command/src/components/map-container/device-map-materials.js b/applications/drone-command/src/components/map-container/device-map-materials.js
index bf2edc8..6177bb7 100644
--- a/applications/drone-command/src/components/map-container/device-map-materials.js
+++ b/applications/drone-command/src/components/map-container/device-map-materials.js
@@ -1,6 +1,15 @@
import * as Cesium from 'cesium'
-export const RING_STYLES = [{ inner: 0, outer: 2000, gradient: ['#FF361C', '#360B00'] }]
+export const RING_STYLES = [
+ {
+ inner: 0,
+ outer: 2000,
+ gradient: ['#FF6A57', '#A11806'],
+ alpha: 0.42,
+ outlineAlpha: 0.85,
+ innerRatio: 0.12,
+ },
+]
export const MATERIAL_TYPE = 'RadialGradientMaterial'
export const DRONE_TRACK_MATERIAL_TYPE = 'DroneTrackFlowMaterial'
@@ -26,15 +35,25 @@
uniforms: {
color1: new Cesium.Color(1.0, 1.0, 1.0, 1.0),
color2: new Cesium.Color(0.0, 0.0, 0.0, 1.0),
+ gamma: 1.7,
+ innerCutoff: 0.0,
},
source: `
+ uniform vec4 color1;
+ uniform vec4 color2;
+ uniform float gamma;
+ uniform float innerCutoff;
+
czm_material czm_getMaterial(czm_materialInput materialInput) {
czm_material material = czm_getDefaultMaterial(materialInput);
vec2 st = materialInput.st - vec2(0.5);
float t = clamp(length(st) * 2.0, 0.0, 1.0);
vec4 color = mix(color1, color2, t);
+ float ramp = smoothstep(innerCutoff, 1.0, t);
+ float shaped = pow(t, gamma);
+ float alpha = color.a * ramp * shaped;
material.diffuse = color.rgb;
- material.alpha = color.a;
+ material.alpha = alpha;
return material;
}
`,
@@ -82,9 +101,9 @@
})
}
-export const createRadialGradientMaterial = (color1, color2) => {
+export const createRadialGradientMaterial = (color1, color2, options = {}) => {
registerRadialGradientMaterial()
- return Cesium.Material.fromType(MATERIAL_TYPE, { color1, color2 })
+ return Cesium.Material.fromType(MATERIAL_TYPE, { color1, color2, ...(options || {}) })
}
export const createDroneTrackMaterial = options => {
@@ -115,18 +134,19 @@
return positions
}
-export const addDeviceRings = (center, ringFillInstancesByStyle, ringOutlineInstancesByStyle) => {
+export const addDeviceRings = (center, ringFillInstancesByStyle, ringOutlineInstancesByStyle, rangeMeters) => {
if (!ringFillInstancesByStyle) return
const centerPosition = Cesium.Cartesian3.fromDegrees(center.longitude, center.latitude, 0)
const vertexFormat = getTexturedVertexFormat()
RING_STYLES.forEach((ring, index) => {
if (!ringFillInstancesByStyle[index]) return
+ const outer = Number.isFinite(rangeMeters) && rangeMeters > 0 ? rangeMeters : ring.outer
ringFillInstancesByStyle[index].push(
new Cesium.GeometryInstance({
geometry: new Cesium.EllipseGeometry({
center: centerPosition,
- semiMajorAxis: ring.outer,
- semiMinorAxis: ring.outer,
+ semiMajorAxis: outer,
+ semiMinorAxis: outer,
vertexFormat,
}),
})
@@ -135,7 +155,9 @@
if (!ringOutlineInstancesByStyle) return
RING_STYLES.forEach((ring, index) => {
if (!ringOutlineInstancesByStyle[index]) return
- const positions = buildCirclePositions(center, ring.outer)
+ const outer = Number.isFinite(rangeMeters) && rangeMeters > 0 ? rangeMeters : ring.outer
+ const positions = buildCirclePositions(center, outer)
+ const outlineAlpha = typeof ring.outlineAlpha === 'number' ? ring.outlineAlpha : 0.8
ringOutlineInstancesByStyle[index].push(
new Cesium.GeometryInstance({
geometry: new Cesium.GroundPolylineGeometry({
@@ -144,7 +166,7 @@
}),
attributes: {
color: Cesium.ColorGeometryInstanceAttribute.fromColor(
- Cesium.Color.fromCssColorString(ring.gradient[0]).withAlpha(0.8)
+ Cesium.Color.fromCssColorString(ring.gradient[0]).withAlpha(outlineAlpha)
),
},
})
diff --git a/applications/drone-command/src/views/dataCockpit/components/LegendBar.vue b/applications/drone-command/src/views/dataCockpit/components/LegendBar.vue
index d115225..52535aa 100644
--- a/applications/drone-command/src/views/dataCockpit/components/LegendBar.vue
+++ b/applications/drone-command/src/views/dataCockpit/components/LegendBar.vue
@@ -85,13 +85,13 @@
}
.legend-color.defense {
- background: radial-gradient(50% 50% at 50% 50%, #2aedbf 0%, #012b11 100%);
- border: 1px solid #19d266;
+ background: radial-gradient(50% 50% at 50% 50%, rgba(114, 243, 255, 0.45) 0%, rgba(10, 124, 136, 0.55) 100%);
+ border: 1px solid rgba(114, 243, 255, 0.85);
}
.legend-color.partition {
- background: radial-gradient(50% 50% at 50% 50%, #ffc609 0%, #583300 100%);
- border: 1px solid #ffcd2a;
+ background: radial-gradient(50% 50% at 50% 50%, rgba(255, 215, 114, 0.5) 0%, rgba(168, 107, 0, 0.6) 100%);
+ border: 1px solid rgba(255, 215, 114, 0.9);
}
.legend-icon {
diff --git a/applications/drone-command/src/views/dataCockpit/components/templateComponents/RealEquipmentTemplate.vue b/applications/drone-command/src/views/dataCockpit/components/templateComponents/RealEquipmentTemplate.vue
index 631a674..0315403 100644
--- a/applications/drone-command/src/views/dataCockpit/components/templateComponents/RealEquipmentTemplate.vue
+++ b/applications/drone-command/src/views/dataCockpit/components/templateComponents/RealEquipmentTemplate.vue
@@ -67,7 +67,7 @@
</div>
<div class="col">
<span class="label">有效范围</span>
- {{ data.effectiveRangeKm }}m
+ {{ Number(data.effectiveRangeKm).toFixed(0) }}m
</div>
</div>
</div>
diff --git a/applications/drone-command/src/views/detectionCountermeasure/detectionRange/DetectionRangeDialog.vue b/applications/drone-command/src/views/detectionCountermeasure/detectionRange/DetectionRangeDialog.vue
index ca54c44..a939219 100644
--- a/applications/drone-command/src/views/detectionCountermeasure/detectionRange/DetectionRangeDialog.vue
+++ b/applications/drone-command/src/views/detectionCountermeasure/detectionRange/DetectionRangeDialog.vue
@@ -123,6 +123,7 @@
v-model="formData.effectiveRangeKm"
:min="0"
:precision="0"
+ :step="1"
:controls="false"
placeholder="请输入"
/>
@@ -227,7 +228,14 @@
function formatRange(value) {
if (value == null || value === '') return '-'
- return `${value}`
+ const normalized = normalizeRange(value)
+ return normalized == null ? '-' : `${normalized}`
+}
+
+function normalizeRange(value) {
+ const numeric = Number(value)
+ if (!Number.isFinite(numeric)) return null
+ return Math.trunc(numeric)
}
// 关闭弹框
@@ -242,14 +250,16 @@
submitting.value = true
try {
const {longitude, latitude} = parseDeployLocation(formData.value.deployLocation)
+ const normalizedRange = normalizeRange(formData.value.effectiveRangeKm)
const payload = {
id: formData.value.id || formData.value.deviceId || undefined,
- effectiveRangeKmIsNotNull: formData.value.effectiveRangeKm ? 1 : 2,
- effectiveRangeKm: formData.value.effectiveRangeKm,
+ effectiveRangeKmIsNotNull: normalizedRange != null ? 1 : 2,
+ effectiveRangeKm: normalizedRange,
longitude,
latitude
}
+ formData.value.effectiveRangeKm = normalizedRange
delete payload.deviceId
await detectionRangeSubmitApi(payload)
@@ -280,6 +290,7 @@
current: 1,
size: 200,
effectiveRangeKmIsNotNull: 2,
+ isTrack: 1
})
const records = res?.data?.data?.records ?? []
deviceOptions.value = records.map(item => ({
@@ -432,9 +443,18 @@
watch(
() => formData.value.effectiveRangeKm,
value => {
+ const normalized = normalizeRange(value)
+ if (value != null && normalized == null) {
+ formData.value.effectiveRangeKm = null
+ return
+ }
+ if (value != null && normalized !== value) {
+ formData.value.effectiveRangeKm = normalized
+ return
+ }
const parsed = parseDeployLocation(formData.value.deployLocation)
if (!parsed) return
- updateRangeCircle(parsed.longitude, parsed.latitude, value)
+ updateRangeCircle(parsed.longitude, parsed.latitude, normalized)
}
)
</script>
diff --git a/applications/drone-command/src/views/detectionCountermeasure/detectionRange/index.vue b/applications/drone-command/src/views/detectionCountermeasure/detectionRange/index.vue
index c2bda53..34735d3 100644
--- a/applications/drone-command/src/views/detectionCountermeasure/detectionRange/index.vue
+++ b/applications/drone-command/src/views/detectionCountermeasure/detectionRange/index.vue
@@ -204,8 +204,10 @@
function formatRange(row) {
if (!row) return '-'
- const value = row.effectiveRangeKm ?? row.range
- return value === null || value === undefined || value === '' ? '-' : value
+
+ let value = row.effectiveRangeKm ?? row.range
+
+ return value === null || value === undefined || value === '' ? '-' : Number(value).toFixed(0)
}
function formatDeviceCode(row) {
--
Gitblit v1.9.3