Merge remote-tracking branch 'origin/master'
11 files modified
7 files added
| New file |
| | |
| | | <template> |
| | | <div :id="mapId" class="common-cesium-map"></div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { onBeforeUnmount, onMounted, ref, watch } from 'vue' |
| | | import { PublicCesium } from '@/utils/cesium/publicCesium' |
| | | import { loadJaAdminBoundary, removeJaAdminBoundary } from '@/utils/cesium/adminBoundary' |
| | | |
| | | const props = defineProps({ |
| | | active: { |
| | | type: Boolean, |
| | | default: true, |
| | | }, |
| | | domId: { |
| | | type: String, |
| | | default: '', |
| | | }, |
| | | flatMode: { |
| | | type: Boolean, |
| | | default: false, |
| | | }, |
| | | terrain: { |
| | | type: Boolean, |
| | | default: true, |
| | | }, |
| | | layerMode: { |
| | | type: Number, |
| | | default: 4, |
| | | }, |
| | | boundary: { |
| | | type: Boolean, |
| | | default: false, |
| | | }, |
| | | contour: { |
| | | type: Boolean, |
| | | default: false, |
| | | }, |
| | | showAdminBoundary: { |
| | | type: Boolean, |
| | | default: true, |
| | | }, |
| | | zoomToBoundary: { |
| | | type: Boolean, |
| | | default: true, |
| | | }, |
| | | enableStageEmit: { |
| | | type: Boolean, |
| | | default: false, |
| | | }, |
| | | clusterHeight: { |
| | | type: Number, |
| | | default: 100000, |
| | | }, |
| | | detailHeight: { |
| | | type: Number, |
| | | default: 10000, |
| | | }, |
| | | }) |
| | | |
| | | const emit = defineEmits(['ready', 'height-change', 'stage-change']) |
| | | const mapId = props.domId || `common-cesium-map-${Math.random().toString(36).slice(2, 10)}` |
| | | const viewInstance = ref(null) |
| | | const viewer = ref(null) |
| | | let adminBoundarySources = null |
| | | let initialized = false |
| | | let removeCameraListener = null |
| | | |
| | | const initMap = async () => { |
| | | if (initialized) return |
| | | initialized = true |
| | | viewInstance.value = new PublicCesium({ |
| | | dom: mapId, |
| | | flatMode: props.flatMode, |
| | | terrain: props.terrain, |
| | | layerMode: props.layerMode, |
| | | boundary: props.boundary, |
| | | contour: props.contour, |
| | | }) |
| | | viewer.value = viewInstance.value.getViewer() |
| | | if (props.showAdminBoundary) { |
| | | adminBoundarySources = await loadJaAdminBoundary(viewer.value, { |
| | | zoomTo: props.zoomToBoundary, |
| | | }) |
| | | } |
| | | if (props.enableStageEmit) { |
| | | let lastStage = '' |
| | | const onCameraChanged = () => { |
| | | const height = viewer.value?.camera?.positionCartographic?.height |
| | | if (height == null) return |
| | | emit('height-change', height) |
| | | let stage = 'mid' |
| | | if (height >= props.clusterHeight) stage = 'cluster' |
| | | if (height <= props.detailHeight) stage = 'detail' |
| | | if (stage !== lastStage) { |
| | | lastStage = stage |
| | | emit('stage-change', stage) |
| | | } |
| | | } |
| | | viewer.value?.camera?.changed?.addEventListener(onCameraChanged) |
| | | removeCameraListener = () => viewer.value?.camera?.changed?.removeEventListener(onCameraChanged) |
| | | } |
| | | emit('ready', { viewer: viewer.value, publicCesium: viewInstance.value }) |
| | | } |
| | | |
| | | watch( |
| | | () => props.active, |
| | | active => { |
| | | if (active) initMap() |
| | | } |
| | | ) |
| | | |
| | | onMounted(() => { |
| | | if (props.active) initMap() |
| | | }) |
| | | |
| | | onBeforeUnmount(() => { |
| | | if (removeCameraListener) removeCameraListener() |
| | | removeJaAdminBoundary(viewer.value, adminBoundarySources) |
| | | viewInstance.value?.viewerDestroy?.() |
| | | }) |
| | | |
| | | const getMap = () => ({ viewer: viewer.value, publicCesium: viewInstance.value }) |
| | | const getViewer = () => viewer.value |
| | | const getPublicCesium = () => viewInstance.value |
| | | |
| | | defineExpose({ getMap, getViewer, getPublicCesium }) |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .common-cesium-map { |
| | | width: 100%; |
| | | height: 100%; |
| | | } |
| | | </style> |
| | |
| | | <template> |
| | | <div class="command-cesium map-container" :id="props.containerId"></div> |
| | | <CommonCesiumMap |
| | | ref="mapRef" |
| | | class="command-cesium map-container" |
| | | :dom-id="props.containerId" |
| | | :active="true" |
| | | :flat-mode="false" |
| | | :terrain="false" |
| | | :layer-mode="4" |
| | | :contour="false" |
| | | :boundary="false" |
| | | :show-admin-boundary="true" |
| | | :zoom-to-boundary="true" |
| | | @ready="handleMapReady" |
| | | /> |
| | | <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"> |
| | |
| | | |
| | | <script setup> |
| | | import * as Cesium from 'cesium' |
| | | import { PublicCesium } from '@/utils/cesium/publicCesium' |
| | | import CommonCesiumMap from '@/components/map-container/common-cesium-map.vue' |
| | | import { geomAnalysis } from '@ztzf/utils' |
| | | import { fwDefenseZonePageApi } from '@/views/areaManage/defenseZone/defenseZoneApi' |
| | | import { fwAreaDividePageApi } from '@/views/areaManage/partition/partitionApi' |
| | | import jaGeojsonRaw from '@/assets/geojson/ja.geojson?raw' |
| | | import layerControlIcon from '@/assets/images/dataCockpit/layerControl.png' |
| | | import equipmentIcon from '@/assets/images/dataCockpit/map/equipment.png' |
| | | |
| | |
| | | |
| | | const DEFAULT_ZONE_PAGE_SIZE = 999 |
| | | |
| | | let viewInstance = null |
| | | const mapRef = ref(null) |
| | | let viewer = null |
| | | const deviceEntityIds = new Set() |
| | | let defenseZoneSource = null |
| | | let partitionSource = null |
| | | let adminBoundarySource = null |
| | | let adminBoundaryLabelSource = null |
| | | let adminBoundaryLineSource = null |
| | | let adminBoundaryFlyDone = false |
| | | const showLayerPanel = ref(false) |
| | | const layerWrapRef = ref(null) |
| | | const layerTreeProps = { |
| | |
| | | partitionSource.entities.removeAll() |
| | | } |
| | | |
| | | const clearAdminBoundaryEntities = () => { |
| | | if (!adminBoundarySource) return |
| | | adminBoundarySource.entities.removeAll() |
| | | } |
| | | |
| | | const clearAdminBoundaryLabels = () => { |
| | | if (!adminBoundaryLabelSource) return |
| | | adminBoundaryLabelSource.entities.removeAll() |
| | | } |
| | | |
| | | const clearAdminBoundaryLines = () => { |
| | | if (!adminBoundaryLineSource) return |
| | | adminBoundaryLineSource.entities.removeAll() |
| | | } |
| | | |
| | | const RING_STYLES = [ |
| | | { inner: 0, outer: 2000, gradient: ['#FF361C', '#360B00'] } |
| | |
| | | position: Cesium.Cartesian3.fromDegrees(position.longitude, position.latitude, 0), |
| | | billboard: { |
| | | image: equipmentIcon, |
| | | width: 40.34, |
| | | height: 40.34, |
| | | width: 40, |
| | | height: 56, |
| | | verticalOrigin: Cesium.VerticalOrigin.BOTTOM, |
| | | }, |
| | | }) |
| | | }) |
| | |
| | | } |
| | | } |
| | | |
| | | const loadAdminBoundary = async () => { |
| | | if (!viewer) return |
| | | try { |
| | | if (adminBoundarySource) { |
| | | viewer.dataSources.remove(adminBoundarySource) |
| | | adminBoundarySource = null |
| | | } |
| | | if (adminBoundaryLabelSource) { |
| | | viewer.dataSources.remove(adminBoundaryLabelSource) |
| | | adminBoundaryLabelSource = null |
| | | } |
| | | if (adminBoundaryLineSource) { |
| | | viewer.dataSources.remove(adminBoundaryLineSource) |
| | | adminBoundaryLineSource = null |
| | | } |
| | | const geojson = JSON.parse(jaGeojsonRaw) |
| | | adminBoundarySource = await Cesium.GeoJsonDataSource.load(geojson, { |
| | | stroke: Cesium.Color.fromCssColorString('#FFFFFF'), |
| | | strokeWidth: 2, |
| | | fill: Cesium.Color.fromCssColorString('#FFFFFF').withAlpha(0.05), |
| | | clampToGround: true, |
| | | }) |
| | | viewer.dataSources.add(adminBoundarySource) |
| | | if (!adminBoundaryFlyDone) { |
| | | adminBoundaryFlyDone = true |
| | | viewer.flyTo(adminBoundarySource, { |
| | | duration: 0, |
| | | offset: new Cesium.HeadingPitchRange(0, Cesium.Math.toRadians(-75), 0), |
| | | }) |
| | | } |
| | | |
| | | adminBoundaryLineSource = new Cesium.CustomDataSource('adminBoundaryLineSource') |
| | | adminBoundarySource.entities.values.forEach(entity => { |
| | | const polygon = entity.polygon |
| | | if (!polygon) return |
| | | const hierarchy = polygon.hierarchy?.getValue?.(viewer.clock.currentTime) |
| | | const positions = hierarchy?.positions |
| | | if (!positions?.length) return |
| | | adminBoundaryLineSource.entities.add({ |
| | | polyline: { |
| | | positions, |
| | | clampToGround: true, |
| | | width: 2, |
| | | material: Cesium.Color.WHITE, |
| | | }, |
| | | }) |
| | | }) |
| | | viewer.dataSources.add(adminBoundaryLineSource) |
| | | |
| | | adminBoundaryLabelSource = new Cesium.CustomDataSource('adminBoundaryLabelSource') |
| | | geojson.features?.forEach(feature => { |
| | | const name = feature?.properties?.name |
| | | const point = feature?.properties?.centroid || feature?.properties?.center |
| | | if (!name || !Array.isArray(point) || point.length < 2) return |
| | | adminBoundaryLabelSource.entities.add({ |
| | | position: Cesium.Cartesian3.fromDegrees(point[0], point[1]), |
| | | label: { |
| | | text: name, |
| | | font: '14px Source Han Sans CN', |
| | | fillColor: Cesium.Color.WHITE, |
| | | outlineColor: Cesium.Color.BLACK.withAlpha(0.6), |
| | | outlineWidth: 2, |
| | | style: Cesium.LabelStyle.FILL_AND_OUTLINE, |
| | | heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, |
| | | verticalOrigin: Cesium.VerticalOrigin.CENTER, |
| | | horizontalOrigin: Cesium.HorizontalOrigin.CENTER, |
| | | disableDepthTestDistance: Number.POSITIVE_INFINITY, |
| | | }, |
| | | }) |
| | | }) |
| | | viewer.dataSources.add(adminBoundaryLabelSource) |
| | | } catch (error) { |
| | | clearAdminBoundaryEntities() |
| | | clearAdminBoundaryLabels() |
| | | clearAdminBoundaryLines() |
| | | } |
| | | } |
| | | |
| | | watch( |
| | | () => props.onlineDevices, |
| | |
| | | showLayerPanel.value = !showLayerPanel.value |
| | | } |
| | | |
| | | const handleMapReady = ({ viewer: mapViewer }) => { |
| | | viewer = mapViewer |
| | | renderDeviceEntities(props.onlineDevices) |
| | | loadDefenseZones() |
| | | loadPartitions() |
| | | } |
| | | |
| | | const handleClickOutside = event => { |
| | | if (!showLayerPanel.value) return |
| | | const target = event.target |
| | |
| | | |
| | | onMounted(() => { |
| | | document.addEventListener('click', handleClickOutside) |
| | | viewInstance = new PublicCesium({ |
| | | dom: props.containerId, |
| | | flatMode: false, |
| | | terrain: false, |
| | | layerMode: 4, |
| | | contour: false, |
| | | }) |
| | | |
| | | viewer = viewInstance.getViewer() |
| | | renderDeviceEntities(props.onlineDevices) |
| | | loadDefenseZones() |
| | | loadPartitions() |
| | | loadAdminBoundary() |
| | | const map = mapRef.value?.getMap() |
| | | if (map?.viewer) handleMapReady(map) |
| | | }) |
| | | |
| | | onBeforeUnmount(() => { |
| | |
| | | clearDeviceEntities() |
| | | clearDefenseZoneEntities() |
| | | clearPartitionEntities() |
| | | clearAdminBoundaryEntities() |
| | | clearAdminBoundaryLabels() |
| | | clearAdminBoundaryLines() |
| | | if (viewInstance) { |
| | | viewInstance?.viewerDestroy() |
| | | viewInstance = null |
| | | } |
| | | |
| | | viewer = null |
| | | }) |
| | | </script> |
| New file |
| | |
| | | import * as Cesium from 'cesium' |
| | | import jaGeojsonRaw from '@/assets/geojson/ja.geojson?raw' |
| | | |
| | | const DEFAULT_OPTIONS = { |
| | | strokeColor: '#00F9EC', |
| | | strokeWidth: 2, |
| | | fillColor: '#FFFFFF', |
| | | fillAlpha: 0.05, |
| | | labelFont: '14px Source Han Sans CN', |
| | | labelFill: '#FFFFFF', |
| | | labelOutline: '#18305C', |
| | | labelOutlineAlpha: 1, |
| | | zoomTo: true, |
| | | } |
| | | |
| | | export const loadJaAdminBoundary = async (viewer, options = {}) => { |
| | | if (!viewer) return null |
| | | const config = { ...DEFAULT_OPTIONS, ...options } |
| | | const geojson = JSON.parse(jaGeojsonRaw) |
| | | |
| | | const boundarySource = await Cesium.GeoJsonDataSource.load(geojson, { |
| | | stroke: Cesium.Color.fromCssColorString(config.strokeColor), |
| | | strokeWidth: config.strokeWidth, |
| | | fill: Cesium.Color.fromCssColorString(config.fillColor).withAlpha(config.fillAlpha), |
| | | clampToGround: true, |
| | | }) |
| | | viewer.dataSources.add(boundarySource) |
| | | |
| | | const lineSource = new Cesium.CustomDataSource('jaBoundaryLineSource') |
| | | boundarySource.entities.values.forEach(entity => { |
| | | const polygon = entity.polygon |
| | | if (!polygon) return |
| | | const hierarchy = polygon.hierarchy?.getValue?.(viewer.clock.currentTime) |
| | | const positions = hierarchy?.positions |
| | | if (!positions?.length) return |
| | | lineSource.entities.add({ |
| | | polyline: { |
| | | positions, |
| | | clampToGround: true, |
| | | width: config.strokeWidth, |
| | | material: Cesium.Color.fromCssColorString(config.strokeColor), |
| | | }, |
| | | }) |
| | | }) |
| | | viewer.dataSources.add(lineSource) |
| | | |
| | | const labelSource = new Cesium.CustomDataSource('jaBoundaryLabelSource') |
| | | geojson.features?.forEach(feature => { |
| | | const name = feature?.properties?.name |
| | | const point = feature?.properties?.centroid || feature?.properties?.center |
| | | if (!name || !Array.isArray(point) || point.length < 2) return |
| | | labelSource.entities.add({ |
| | | position: Cesium.Cartesian3.fromDegrees(point[0], point[1]), |
| | | label: { |
| | | text: name, |
| | | font: config.labelFont, |
| | | fillColor: Cesium.Color.fromCssColorString(config.labelFill), |
| | | outlineColor: Cesium.Color.fromCssColorString(config.labelOutline).withAlpha( |
| | | config.labelOutlineAlpha |
| | | ), |
| | | outlineWidth: 2, |
| | | style: Cesium.LabelStyle.FILL_AND_OUTLINE, |
| | | heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, |
| | | verticalOrigin: Cesium.VerticalOrigin.CENTER, |
| | | horizontalOrigin: Cesium.HorizontalOrigin.CENTER, |
| | | disableDepthTestDistance: Number.POSITIVE_INFINITY, |
| | | }, |
| | | }) |
| | | }) |
| | | viewer.dataSources.add(labelSource) |
| | | |
| | | if (config.zoomTo) { |
| | | await viewer.flyTo(boundarySource, { |
| | | duration: 0, |
| | | offset: new Cesium.HeadingPitchRange(0, Cesium.Math.toRadians(-75), 0), |
| | | }) |
| | | } |
| | | |
| | | return { boundarySource, lineSource, labelSource } |
| | | } |
| | | |
| | | export const removeJaAdminBoundary = (viewer, sources) => { |
| | | if (!viewer || !sources) return |
| | | const { boundarySource, lineSource, labelSource } = sources |
| | | if (boundarySource) viewer.dataSources.remove(boundarySource) |
| | | if (lineSource) viewer.dataSources.remove(lineSource) |
| | | if (labelSource) viewer.dataSources.remove(labelSource) |
| | | } |
| | |
| | | dockOptions = {}, |
| | | boundaryChange, |
| | | terrainLoadCallback, |
| | | boundaryColor = '#7FFFD4', |
| | | boundaryColor = '#00F9EC', |
| | | dockRangeType = 1, |
| | | useDockHeight = false |
| | | } = options |
| | |
| | | <el-dialog class="command-page-map-view-dialog" v-model="visible" :show-close="false" :close-on-click-modal="false"> |
| | | <div class="dialog-container"> |
| | | <div class="left-container"> |
| | | <div class="leftMap command-cesium" id="mapContainer"></div> |
| | | <CommonCesiumMap |
| | | ref="mapRef" |
| | | class="leftMap command-cesium" |
| | | :active="visible" |
| | | :flat-mode="false" |
| | | :terrain="true" |
| | | :layer-mode="4" |
| | | :boundary="false" |
| | | /> |
| | | </div> |
| | | |
| | | <div class="right-container"> |
| | |
| | | import { fwDefenseZoneDetailApi, fwDefenseZoneSubmitApi } from './defenseZoneApi' |
| | | import { fwDefenseSceneListApi } from '@/views/areaManage/sceneConfig/sceneConfigApi' |
| | | import { fieldRules, geomAnalysis, getDictLabel } from '@ztzf/utils' |
| | | import { PublicCesium } from '@/utils/cesium/publicCesium' |
| | | import CommonCesiumMap from '@/components/map-container/common-cesium-map.vue' |
| | | import { DrawPolygon } from '@/utils/cesium/DrawPolygon' |
| | | import { cartesian3Convert } from '@/utils/cesium/mapUtil' |
| | | import * as turf from '@turf/turf' |
| | |
| | | const sceneList = ref([]) // 关联场景列表 |
| | | const selectedSceneRows = ref([]) // 选中场景 |
| | | const dictObj = inject('dictObj') |
| | | const mapRef = ref(null) |
| | | let viewer |
| | | let drawPolygonExample |
| | | let pointList = [] |
| | |
| | | |
| | | // 初始化地图实例 |
| | | function initMap () { |
| | | const publicCesiumInstance = new PublicCesium({ |
| | | dom: 'mapContainer', |
| | | flatMode: false, |
| | | terrain: true, |
| | | layerMode: 4, |
| | | boundary: false, |
| | | }) |
| | | viewer = publicCesiumInstance.getViewer() |
| | | if (viewer) return |
| | | const map = mapRef.value?.getMap() |
| | | viewer = map?.viewer || null |
| | | } |
| | | |
| | | // 绘制完成回调 |
| | |
| | | noClosedList.map(item => ({ lng: item.longitude, lat: item.latitude })) |
| | | ) |
| | | drawPolygonExample.subscribe('getPolygonPositions', drawFinished) |
| | | if (noClosedList.length) { |
| | | const result = noClosedList.map(item => [item.longitude, item.latitude]).flat() |
| | | const tempEntity = viewer.entities?.add({ |
| | | position: Cesium.Cartesian3.fromDegrees(result[0], result[1]), |
| | | polyline: { |
| | | positions: Cesium.Cartesian3.fromDegreesArray(result), |
| | | clampToGround: true, |
| | | width: 1, |
| | | material: Cesium.Color.TRANSPARENT, |
| | | }, |
| | | }) |
| | | if (tempEntity) { |
| | | viewer.flyTo(tempEntity, { duration: 0 }) |
| | | viewer.entities.remove(tempEntity) |
| | | } |
| | | } |
| | | } |
| | | |
| | | // 查看面 |
| | |
| | | material: Cesium.Color.RED, |
| | | }, |
| | | }) |
| | | viewer.flyTo(mian) |
| | | viewer.flyTo(mian, { duration: 0 }) |
| | | } |
| | | |
| | | // 打开弹框 |
| | |
| | | :close-on-click-modal="false"> |
| | | <div class="dialog-container"> |
| | | <div class="left-container"> |
| | | <div class="leftMap command-cesium" id="mapContainer"></div> |
| | | <CommonCesiumMap |
| | | ref="mapRef" |
| | | class="leftMap command-cesium" |
| | | :active="visible" |
| | | :flat-mode="false" |
| | | :terrain="true" |
| | | :layer-mode="4" |
| | | :boundary="false" |
| | | /> |
| | | </div> |
| | | |
| | | <div class="right-container"> |
| | |
| | | import { ElMessage } from 'element-plus' |
| | | import { fwAreaDivideDetailApi, fwAreaDivideSubmitApi } from './partitionApi' |
| | | import { fieldRules, geomAnalysis, getDictLabel } from '@ztzf/utils' |
| | | import { PublicCesium } from '@/utils/cesium/publicCesium' |
| | | import CommonCesiumMap from '@/components/map-container/common-cesium-map.vue' |
| | | import { DrawPolygon } from '@/utils/cesium/DrawPolygon' |
| | | import { cartesian3Convert } from '@/utils/cesium/mapUtil' |
| | | import * as turf from '@turf/turf' |
| | |
| | | const policeStationOptions = ref([]) // 关联派出所 |
| | | const deviceOptions = ref([]) // 关联设备 |
| | | const dictObj = inject('dictObj') |
| | | const mapRef = ref(null) |
| | | let viewer |
| | | let drawPolygonExample |
| | | let pointList = [] |
| | |
| | | |
| | | // 初始化地图实例 |
| | | function initMap () { |
| | | const publicCesiumInstance = new PublicCesium({ |
| | | dom: 'mapContainer', |
| | | flatMode: false, |
| | | terrain: true, |
| | | layerMode: 4, |
| | | boundary: false, |
| | | }) |
| | | viewer = publicCesiumInstance.getViewer() |
| | | if (viewer) return |
| | | const map = mapRef.value?.getMap() |
| | | viewer = map?.viewer || null |
| | | } |
| | | |
| | | // 绘制完成回调 |
| | |
| | | pointList.map(item => ({ lng: item.longitude, lat: item.latitude })) |
| | | ) |
| | | drawPolygonExample.subscribe('getPolygonPositions', drawFinished) |
| | | if (pointList1.length) { |
| | | const result = pointList1.map(item => [item.longitude, item.latitude]).flat() |
| | | const tempEntity = viewer.entities?.add({ |
| | | position: Cesium.Cartesian3.fromDegrees(result[0], result[1]), |
| | | polyline: { |
| | | positions: Cesium.Cartesian3.fromDegreesArray(result), |
| | | clampToGround: true, |
| | | width: 1, |
| | | material: Cesium.Color.TRANSPARENT, |
| | | }, |
| | | }) |
| | | if (tempEntity) { |
| | | viewer.flyTo(tempEntity, { duration: 0 }) |
| | | viewer.entities.remove(tempEntity) |
| | | } |
| | | } |
| | | } |
| | | |
| | | // 查看面 |
| | |
| | | material: Cesium.Color.RED, |
| | | }, |
| | | }) |
| | | viewer.flyTo(mian) |
| | | viewer.flyTo(mian, { duration: 0 }) |
| | | } |
| | | |
| | | // 获取派出所列表 |
| | |
| | | :close-on-click-modal="false" destroy-on-close @closed="positionClosed"> |
| | | <div class="dialog-container"> |
| | | <div class="left-container"> |
| | | <div class="leftMap command-cesium" id="mapContainer"></div> |
| | | <CommonCesiumMap |
| | | ref="mapRef" |
| | | class="leftMap command-cesium" |
| | | :active="visible1" |
| | | :flat-mode="false" |
| | | :terrain="true" |
| | | :layer-mode="4" |
| | | :boundary="false" |
| | | /> |
| | | </div> |
| | | </div> |
| | | |
| | |
| | | import { ElMessage } from 'element-plus' |
| | | import { fwPoliceStationDetailApi, fwPoliceStationSubmitApi } from './precinctInfoApi' |
| | | import { fieldRules } from '@ztzf/utils' |
| | | import { PublicCesium } from '@/utils/cesium/publicCesium' |
| | | import CommonCesiumMap from '@/components/map-container/common-cesium-map.vue' |
| | | import * as Cesium from 'cesium' |
| | | import axios from 'axios' |
| | | |
| | |
| | | const readonly = computed(() => dialogMode.value === 'view') |
| | | const titleEnum = ref({ edit: '编辑', view: '查看', add: '新增' }) |
| | | const tempLocation = ref({ longitude: null, latitude: null }) |
| | | const mapRef = ref(null) |
| | | |
| | | const rules = { |
| | | address: fieldRules(true, 50), |
| | |
| | | |
| | | let viewer |
| | | let redPointEntity |
| | | let leftClickBound = false |
| | | function setMapPoint (longitude, latitude) { |
| | | if (!viewer || longitude == null || latitude == null) return |
| | | if (!redPointEntity) { |
| | |
| | | async function selectLocation () { |
| | | visible1.value = true |
| | | await nextTick() |
| | | const publicCesiumInstance = new PublicCesium({ |
| | | dom: 'mapContainer', |
| | | flatMode: false, |
| | | terrain: true, |
| | | layerMode: 4, |
| | | boundary: false, |
| | | }) |
| | | publicCesiumInstance.addLeftClickEvent(null, LeftClickEvent) |
| | | viewer = publicCesiumInstance.getViewer() |
| | | const map = mapRef.value?.getMap() |
| | | viewer = map?.viewer || null |
| | | if (viewer && !leftClickBound) { |
| | | map.publicCesium?.addLeftClickEvent?.(null, LeftClickEvent) |
| | | leftClickBound = true |
| | | } |
| | | if (formData.value.longitude != null && formData.value.latitude != null) { |
| | | tempLocation.value = { longitude: formData.value.longitude, latitude: formData.value.latitude } |
| | | setMapPoint(formData.value.longitude, formData.value.latitude) |
| | |
| | | } |
| | | visible1.value = false |
| | | } |
| | | |
| | | // 打开弹框 |
| | | async function open ({ mode, row } = {}) { |
| | | dialogMode.value = mode || 'add' |
| | |
| | | <el-dialog class="command-page-map-view-dialog" v-model="visible" :show-close="false" :close-on-click-modal="false"> |
| | | <div class="dialog-container"> |
| | | <div class="left-container"> |
| | | <div class="leftMap command-cesium" id="mapContainer"></div> |
| | | <CommonCesiumMap |
| | | ref="mapRef" |
| | | class="leftMap command-cesium" |
| | | :active="visible" |
| | | :flat-mode="false" |
| | | :terrain="true" |
| | | :layer-mode="4" |
| | | :boundary="false" |
| | | /> |
| | | </div> |
| | | <div class="right-container"> |
| | | <div class="header"> |
| | |
| | | import { ElMessage } from 'element-plus' |
| | | import { fwDefenseSceneDetailApi, fwDefenseSceneSubmitApi } from './sceneConfigApi' |
| | | import { fieldRules, geomAnalysis, getDictLabel } from '@ztzf/utils' |
| | | import { PublicCesium } from '@/utils/cesium/publicCesium' |
| | | import CommonCesiumMap from '@/components/map-container/common-cesium-map.vue' |
| | | import * as Cesium from 'cesium' |
| | | import { fwAreaDivideListApi } from '../partition/partitionApi' |
| | | import { DrawPolygon } from '@/utils/cesium/DrawPolygon' |
| | |
| | | const areaList = ref([]) // 关联区域列表 |
| | | const selectedAreaRows = ref([]) //选中列表 |
| | | const dictObj = inject('dictObj') |
| | | const mapRef = ref(null) |
| | | let viewer |
| | | let redPointEntity |
| | | let leftClickBound = false |
| | | |
| | | const rules = { |
| | | sceneName: fieldRules(true, 50), |
| | |
| | | let geometricSource |
| | | // 初始化地图实例 |
| | | function initMap () { |
| | | const publicCesiumInstance = new PublicCesium({ |
| | | dom: 'mapContainer', |
| | | flatMode: false, |
| | | terrain: true, |
| | | layerMode: 4, |
| | | boundary: false, |
| | | }) |
| | | if (!readonly.value) { |
| | | publicCesiumInstance.addLeftClickEvent(null, LeftClickEvent) |
| | | if (viewer) return |
| | | const map = mapRef.value?.getMap() |
| | | if (!map?.viewer) return |
| | | viewer = map.viewer |
| | | if (!readonly.value && !leftClickBound) { |
| | | map.publicCesium?.addLeftClickEvent?.(null, LeftClickEvent) |
| | | leftClickBound = true |
| | | } |
| | | viewer = publicCesiumInstance.getViewer() |
| | | geometricSource = new Cesium.CustomDataSource('geometricSource') |
| | | viewer.dataSources.add(geometricSource) |
| | | if (!geometricSource) { |
| | | geometricSource = new Cesium.CustomDataSource('geometricSource') |
| | | viewer.dataSources.add(geometricSource) |
| | | } |
| | | } |
| | | |
| | | function LeftClickEvent (click) { |
| New file |
| | |
| | | <!-- |
| | | * @Author : yuan |
| | | * @Date : 2026-01-17 14:51:39 |
| | | * @LastEditors : yuan |
| | | * @LastEditTime : 2026-01-17 15:13:50 |
| | | * @FilePath : \applications\drone-command\src\views\dataCockpit\components\LegendBar.vue |
| | | * @Description : |
| | | * Copyright 2026 OBKoro1, All Rights Reserved. |
| | | * 2026-01-17 14:51:39 |
| | | --> |
| | | <template> |
| | | <div class="legend-bar"> |
| | | <div class="legend-title" data-text="图例">图例</div> |
| | | <div class="legend-item"> |
| | | <span class="legend-color defense"></span> |
| | | <span class="legend-text" data-text="防区">防区</span> |
| | | </div> |
| | | <div class="legend-item"> |
| | | <span class="legend-color partition"></span> |
| | | <span class="legend-text" data-text="区域">区域</span> |
| | | </div> |
| | | <div class="legend-item"> |
| | | <img class="legend-icon drone" :src="droneIcon" alt="无人机" /> |
| | | <span class="legend-text" data-text="无人机">无人机</span> |
| | | </div> |
| | | <div class="legend-item"> |
| | | <img class="legend-icon" :src="commandPostIcon" alt="指挥点" /> |
| | | <span class="legend-text" data-text="指挥点">指挥点</span> |
| | | </div> |
| | | <div class="legend-item"> |
| | | <img class="legend-icon" :src="equipmentIcon" alt="设备" /> |
| | | <span class="legend-text" data-text="设备">设备</span> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import droneIcon from '@/assets/images/dataCockpit/legend/drone.png' |
| | | import commandPostIcon from '@/assets/images/dataCockpit/legend/command-post.png' |
| | | import equipmentIcon from '@/assets/images/dataCockpit/legend/equipment.png' |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .legend-bar { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 20px; |
| | | padding: 10px 16px; |
| | | |
| | | font-family: Source Han Sans CN, Source Han Sans CN; |
| | | font-size: 14px; |
| | | color: #FFFFFF; |
| | | text-align: center; |
| | | font-style: normal; |
| | | text-transform: none; |
| | | } |
| | | |
| | | .legend-title { |
| | | font-weight: 800; |
| | | } |
| | | |
| | | .legend-item { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 8px; |
| | | font-size: 12px; |
| | | } |
| | | |
| | | .legend-title, |
| | | .legend-text { |
| | | position: relative; |
| | | white-space: nowrap; |
| | | |
| | | text-shadow: |
| | | -1px -1px 0 black, |
| | | 1px -1px 0 black, |
| | | -1px 1px 0 black, |
| | | 1px 1px 0 black; |
| | | } |
| | | |
| | | .legend-color { |
| | | width: 30px; |
| | | height: 30px; |
| | | border-radius: 0; |
| | | } |
| | | |
| | | .legend-color.defense { |
| | | background: radial-gradient(50% 50% at 50% 50%, #2aedbf 0%, #012b11 100%); |
| | | border: 1px solid #19d266; |
| | | } |
| | | |
| | | .legend-color.partition { |
| | | background: radial-gradient(50% 50% at 50% 50%, #ffc609 0%, #583300 100%); |
| | | border: 1px solid #ffcd2a; |
| | | } |
| | | |
| | | .legend-icon { |
| | | width: 30px; |
| | | height: 42px; |
| | | display: block; |
| | | } |
| | | |
| | | .legend-icon.drone { |
| | | width: 30px; |
| | | height: 30px; |
| | | display: block; |
| | | } |
| | | </style> |
| | |
| | | <LeftContainer class="left-container" v-model:activeId="leftActiveId" v-model:collapsed="leftCollapsed" /> |
| | | <RightContainer class="right-container" v-model:collapsed="rightCollapsed" v-model:onlineDevices="onlineDevices" /> |
| | | <CenterContainer @select-warning="onSelectWarning" @select-equipment="onSelectEquipment" /> |
| | | <LegendBar class="legend-container" /> |
| | | </div> |
| | | </template> |
| | | |
| | |
| | | import LeftContainer from './components/LeftContainer.vue'; |
| | | import RightContainer from './components/RightContainer.vue'; |
| | | import CenterContainer from './components/CenterContainer.vue'; |
| | | import LegendBar from './components/LegendBar.vue'; |
| | | |
| | | const leftActiveId = ref(1); |
| | | const leftCollapsed = ref(false); |
| | |
| | | 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; |
| | | } |
| | | </style> |
| | |
| | | > |
| | | <div class="dialog-container"> |
| | | <div class="left-container"> |
| | | <div class="leftMap command-cesium" id="detectionRangeMap"></div> |
| | | <CommonCesiumMap |
| | | ref="mapRef" |
| | | class="leftMap command-cesium" |
| | | :active="visible" |
| | | :flat-mode="false" |
| | | :terrain="true" |
| | | :layer-mode="4" |
| | | :boundary="false" |
| | | /> |
| | | </div> |
| | | |
| | | <div class="right-container"> |
| | |
| | | detectionRangePageApi, |
| | | detectionRangeSubmitApi, |
| | | } from '@/api/detectionCountermeasure/detectionRange' |
| | | import { PublicCesium } from '@/utils/cesium/publicCesium' |
| | | import CommonCesiumMap from '@/components/map-container/common-cesium-map.vue' |
| | | import * as Cesium from 'cesium' |
| | | import deviceZcImg from '@/assets/images/dataCockpit/device-zc.svg' |
| | | |
| | |
| | | const submitting = ref(false) // 提交中 |
| | | const deviceOptions = ref([]) |
| | | const dialogReadonly = computed(() => dialogMode.value === 'view') |
| | | const mapRef = ref(null) |
| | | let viewer |
| | | let redPointEntity |
| | | let rangeCircleEntity |
| | |
| | | |
| | | function initMap() { |
| | | if (viewer) return |
| | | const publicCesiumInstance = new PublicCesium({ |
| | | dom: 'detectionRangeMap', |
| | | flatMode: false, |
| | | terrain: true, |
| | | layerMode: 4, |
| | | boundary: false, |
| | | }) |
| | | const map = mapRef.value?.getMap() |
| | | if (!map?.viewer) return |
| | | viewer = map.viewer |
| | | if (!dialogReadonly.value) { |
| | | publicCesiumInstance.addLeftClickEvent(null, handleMapClick) |
| | | map.publicCesium?.addLeftClickEvent?.(null, handleMapClick) |
| | | } |
| | | viewer = publicCesiumInstance.getViewer() |
| | | } |
| | | |
| | | function handleMapClick(click) { |
| | |
| | | geoJsonLayer && map.removeLayer(geoJsonLayer) |
| | | geoJsonLayer = L.geoJSON(row.gJson, { |
| | | style: feature => ({ |
| | | color: '#37D2D5', // 边界线颜色 |
| | | color: '#00F9EC', // 边界线颜色 |
| | | weight: 2, // 边界线宽度 |
| | | fillOpacity: 0, // 填充透明度 |
| | | }), |
| | |
| | | dockOptions = {}, |
| | | boundaryChange, |
| | | terrainLoadCallback, |
| | | boundaryColor = '#7FFFD4', |
| | | boundaryColor = '#00F9EC', |
| | | dockRangeType = 1, |
| | | useDockHeight = false |
| | | } = options |