| | |
| | | <div class="command-table-container"> |
| | | <div class="command-table-content"> |
| | | <el-table class="command-table" ref="deviceTableRef" :data="deviceOptions" |
| | | row-key="id"> |
| | | row-key="id" @row-click="handleDeviceRowClick"> |
| | | <el-table-column prop="deviceName" label="设备名称" /> |
| | | <el-table-column prop="deviceType" label="类型"> |
| | | <template v-slot="{ row }"> |
| | |
| | | <el-form-item prop="deviceIds" label-width="0"> |
| | | <el-table class="command-table" ref="deviceTableRef" |
| | | :data="deviceOptions.filter(item => item.deviceName.includes(searchName))" row-key="id" |
| | | @selection-change="handleDeviceSelectionChange"> |
| | | @selection-change="handleDeviceSelectionChange" |
| | | @row-click="handleDeviceRowClick"> |
| | | <el-table-column type="selection" width="55" :reserve-selection="true" /> |
| | | <el-table-column prop="deviceName" label="设备名称" /> |
| | | <el-table-column prop="deviceType" label="类型"> |
| | |
| | | let pointList = [] |
| | | let viewEntity |
| | | let shapeDisplaySource |
| | | const deviceRangePrimitiveMap = new Map() |
| | | let deviceRangeMaterialRegistered = false |
| | | const activeToolMode = ref('') |
| | | |
| | | const rules = { |
| | |
| | | clearActiveTool() |
| | | hideTypePanel() |
| | | clearShapeDisplay() |
| | | clearDeviceRangePrimitives() |
| | | } |
| | | } |
| | | ) |
| | |
| | | viewer.dataSources.add(shapeDisplaySource) |
| | | } |
| | | return shapeDisplaySource |
| | | } |
| | | |
| | | function registerDeviceRangeMaterial () { |
| | | if (deviceRangeMaterialRegistered || !Cesium?.Material) return |
| | | deviceRangeMaterialRegistered = true |
| | | Cesium.Material._materialCache.addMaterial('DeviceRangeEllipsoid', { |
| | | fabric: { |
| | | type: 'DeviceRangeEllipsoid', |
| | | uniforms: { |
| | | color: new Cesium.Color(1.0, 0.0, 0.0, 0.7), |
| | | speed: 3.0, |
| | | }, |
| | | source: ` |
| | | uniform vec4 color; |
| | | uniform float speed; |
| | | czm_material czm_getMaterial(czm_materialInput materialInput){ |
| | | czm_material material = czm_getDefaultMaterial(materialInput); |
| | | vec2 st = materialInput.st; |
| | | float time = fract(czm_frameNumber * speed / 1000.0); |
| | | float alpha = abs(smoothstep(0.5,1.,fract( -st.t - time))); |
| | | alpha += .1; |
| | | material.alpha = alpha; |
| | | material.diffuse = color.rgb; |
| | | return material; |
| | | } |
| | | `, |
| | | }, |
| | | translucent: () => true, |
| | | }) |
| | | } |
| | | |
| | | function createDeviceRangeMaterial () { |
| | | registerDeviceRangeMaterial() |
| | | return Cesium.Material.fromType('DeviceRangeEllipsoid', { |
| | | color: Cesium.Color.fromBytes(0, 255, 255, 155), |
| | | }) |
| | | } |
| | | |
| | | function clearDeviceRangePrimitives () { |
| | | if (!viewer || !deviceRangePrimitiveMap.size) return |
| | | for (const primitive of deviceRangePrimitiveMap.values()) { |
| | | viewer.scene.primitives.remove(primitive) |
| | | } |
| | | deviceRangePrimitiveMap.clear() |
| | | } |
| | | |
| | | function normalizeDeviceRange (value) { |
| | | const range = Number(value) |
| | | if (!Number.isFinite(range) || range <= 0) return 2000 |
| | | return range |
| | | } |
| | | |
| | | function getDeviceLngLat (device) { |
| | | const lngRaw = device?.longitude ?? device?.lng ?? device?.lon |
| | | const latRaw = device?.latitude ?? device?.lat |
| | | const lng = Number(lngRaw) |
| | | const lat = Number(latRaw) |
| | | if (!Number.isFinite(lng) || !Number.isFinite(lat)) return null |
| | | return { lng, lat } |
| | | } |
| | | |
| | | function createDeviceRangePrimitive (device) { |
| | | if (!viewer) return null |
| | | if (!device) return null |
| | | const position = getDeviceLngLat(device) |
| | | if (!position) return null |
| | | const rangeMeters = normalizeDeviceRange(device.effectiveRangeKm) |
| | | const center = Cesium.Cartesian3.fromDegrees(position.lng, position.lat, 0) |
| | | const radii = new Cesium.Cartesian3(rangeMeters, rangeMeters, rangeMeters) |
| | | const geometry = new Cesium.EllipsoidGeometry({ |
| | | radii, |
| | | vertexFormat: Cesium.MaterialAppearance.MaterialSupport.TEXTURED?.vertexFormat |
| | | || Cesium.VertexFormat.POSITION_AND_NORMAL, |
| | | }) |
| | | const instance = new Cesium.GeometryInstance({ |
| | | geometry, |
| | | modelMatrix: Cesium.Transforms.eastNorthUpToFixedFrame(center), |
| | | }) |
| | | return new Cesium.Primitive({ |
| | | geometryInstances: instance, |
| | | appearance: new Cesium.MaterialAppearance({ |
| | | material: createDeviceRangeMaterial(), |
| | | closed: true, |
| | | translucent: true, |
| | | flat: true, |
| | | faceForward: true, |
| | | }), |
| | | asynchronous: false, |
| | | }) |
| | | } |
| | | |
| | | function renderDeviceRangeSingle (device) { |
| | | if (!viewer) return |
| | | clearDeviceRangePrimitives() |
| | | const primitive = createDeviceRangePrimitive(device) |
| | | if (!primitive) return |
| | | deviceRangePrimitiveMap.set(String(device?.id ?? Date.now()), primitive) |
| | | viewer.scene.primitives.add(primitive) |
| | | } |
| | | |
| | | function renderDeviceRanges (rows) { |
| | | if (!viewer) return |
| | | const selectedRows = Array.isArray(rows) ? rows : [] |
| | | const nextIds = new Set(selectedRows.map(row => String(row?.id))) |
| | | for (const [id, primitive] of deviceRangePrimitiveMap.entries()) { |
| | | if (!nextIds.has(id)) { |
| | | viewer.scene.primitives.remove(primitive) |
| | | deviceRangePrimitiveMap.delete(id) |
| | | } |
| | | } |
| | | selectedRows.forEach(row => { |
| | | const id = String(row?.id) |
| | | if (!id || deviceRangePrimitiveMap.has(id)) return |
| | | const primitive = createDeviceRangePrimitive(row) |
| | | if (!primitive) return |
| | | deviceRangePrimitiveMap.set(id, primitive) |
| | | viewer.scene.primitives.add(primitive) |
| | | }) |
| | | } |
| | | |
| | | function clearShapeDisplay () { |
| | |
| | | selectedDeviceRows.value = rows |
| | | const ids = rows.map(item => item.id) |
| | | formData.value.deviceIds = ids.join(',') |
| | | renderDeviceRanges(rows) |
| | | } |
| | | |
| | | function handleDeviceRowClick (row) { |
| | | if (readonly.value) { |
| | | renderDeviceRangeSingle(row) |
| | | return |
| | | } |
| | | renderDeviceRanges(selectedDeviceRows.value) |
| | | } |
| | | |
| | | // 同步选择状态 |
| | |
| | | await nextTick() |
| | | initMap() |
| | | clearShapeDisplay() |
| | | clearDeviceRangePrimitives() |
| | | viewEntity && viewer?.entities?.remove(viewEntity) |
| | | viewEntity = null |
| | | clearActiveTool() |
| | |
| | | } |
| | | await nextTick() |
| | | syncDeviceSelection() |
| | | if (!readonly.value) { |
| | | renderDeviceRanges(selectedDeviceRows.value) |
| | | } |
| | | } |
| | | |
| | | onMounted(() => { |