|
@@ -0,0 +1,706 @@
|
|
|
|
|
+<script setup lang='ts'>
|
|
|
|
|
+import {
|
|
|
|
|
+ Viewer, ScreenSpaceEventType, Cartesian3,
|
|
|
|
|
+ Math as CMath, Color, EventHelper, UrlTemplateImageryProvider,
|
|
|
|
|
+ DistanceDisplayCondition, ScreenSpaceEventHandler, WebMercatorTilingScheme,
|
|
|
|
|
+ VerticalOrigin, HeightReference, Cartesian2, Cartographic, GeoJsonDataSource, SceneMode, WebMapTileServiceImageryProvider, GeographicTilingScheme
|
|
|
|
|
+} from 'cesium'
|
|
|
|
|
+import {
|
|
|
|
|
+ computed, onMounted, onUnmounted, ref, watch
|
|
|
|
|
+} from 'vue'
|
|
|
|
|
+// import useStore from '@/pages/store/index'
|
|
|
|
|
+import lnglatIcon from '@/assets/icons/lnglat.svg'
|
|
|
|
|
+import camera from '@/assets/icons/camera.svg'
|
|
|
|
|
+import broadcast from '@/assets/icons/broadcast.svg'
|
|
|
|
|
+import preBranke from '@/assets/icons/preBranke.svg'
|
|
|
|
|
+import carBranke from '@/assets/icons/carBranke.svg'
|
|
|
|
|
+import { NInput, useNotification, useDialog } from 'naive-ui'
|
|
|
|
|
+import EquipmentService, { TreeList, Device } from '@/services/equipmentTree.service'
|
|
|
|
|
+
|
|
|
|
|
+const notification = useNotification()
|
|
|
|
|
+const dialog = useDialog()
|
|
|
|
|
+const equipmentService = new EquipmentService()
|
|
|
|
|
+// const store = useStore()
|
|
|
|
|
+const props = defineProps({
|
|
|
|
|
+ type: { default: true, type: Boolean },
|
|
|
|
|
+ checkList: { default: [], type: Array<TreeList> },
|
|
|
|
|
+ treeList: { default: [], type: Array<TreeList> }
|
|
|
|
|
+})
|
|
|
|
|
+const isAdmin = computed(() => props.type)
|
|
|
|
|
+let viewer = null as Any
|
|
|
|
|
+let Helper = new EventHelper() as Any
|
|
|
|
|
+let handler = null as Any
|
|
|
|
|
+const currenIcon = ref({ icon: '', x: 0, y: 0 })
|
|
|
|
|
+const icontypes = [
|
|
|
|
|
+ {
|
|
|
|
|
+ name: '摄像机', type: 'camera', icon: camera, deviceType: 0
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ name: '广播', type: 'broadcast', icon: broadcast, deviceType: 1
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ name: '人行闸机', type: 'preBranke', icon: preBranke, deviceType: 2
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ name: '车行闸机', type: 'carBranke', icon: carBranke, deviceType: 3
|
|
|
|
|
+ }
|
|
|
|
|
+]
|
|
|
|
|
+const modelShow = ref(false)
|
|
|
|
|
+const model = ref({
|
|
|
|
|
+ deviceId: '',
|
|
|
|
|
+ itemId: -1,
|
|
|
|
|
+ longitude: '',
|
|
|
|
|
+ latitude: '',
|
|
|
|
|
+ describeData: '',
|
|
|
|
|
+ selfId: '',
|
|
|
|
|
+ deviceType: 0
|
|
|
|
|
+})
|
|
|
|
|
+const rules = {
|
|
|
|
|
+ deviceId: [ { required: true, message: '请输入设备ID' } ],
|
|
|
|
|
+ itemId: [ { required: true, message: '请选择项目' } ],
|
|
|
|
|
+ longitude: [ { required: true, message: '请输入经度' } ],
|
|
|
|
|
+ latitude: [ { required: true, message: '请输入维度' } ],
|
|
|
|
|
+ describeData: [ { required: true, message: '请输入安装位置描述' } ]
|
|
|
|
|
+}
|
|
|
|
|
+const options = ref([] as Array<TreeList>)
|
|
|
|
|
+
|
|
|
|
|
+const formRef = ref()
|
|
|
|
|
+const isAdd = ref(false)
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * 添加路径
|
|
|
|
|
+ * @param lngLat 经纬度数组
|
|
|
|
|
+ * @param displayMin 最小显示范围
|
|
|
|
|
+ * @param displayMax 最大显示范围
|
|
|
|
|
+ */
|
|
|
|
|
+function addLine(lngLat: Array<number>, displayMin?: number, displayMax?: number) {
|
|
|
|
|
+ if (!viewer) return
|
|
|
|
|
+ viewer.entities.add({
|
|
|
|
|
+ position: Cartesian3.fromDegrees(lngLat[0], lngLat[1]),
|
|
|
|
|
+ polyline: {
|
|
|
|
|
+ positions: Cartesian3.fromDegreesArray(lngLat),
|
|
|
|
|
+ width: 5,
|
|
|
|
|
+ material: Color.fromCssColorString('#55F8F8'),
|
|
|
|
|
+ clampToGround: true,
|
|
|
|
|
+ distanceDisplayCondition: new DistanceDisplayCondition(displayMin, displayMax)
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * 添加label
|
|
|
|
|
+ * @param lng 经度
|
|
|
|
|
+ * @param lat 纬度
|
|
|
|
|
+ * @param icon 图标
|
|
|
|
|
+ * @param text 文本内容
|
|
|
|
|
+ * @param displayMin 最小显示范围
|
|
|
|
|
+ * @param displayMax 最大显示范围
|
|
|
|
|
+ */
|
|
|
|
|
+function addLable(lng: number, lat: number, icon: string, text: string, displayMin?: number, displayMax?: number, oldData?: Device) {
|
|
|
|
|
+ if (!viewer) return
|
|
|
|
|
+ viewer.entities.add({
|
|
|
|
|
+ position: Cartesian3.fromDegrees(lng, lat),
|
|
|
|
|
+ billboard: {
|
|
|
|
|
+ image: icon || lnglatIcon,
|
|
|
|
|
+ width: 25,
|
|
|
|
|
+ height: 25,
|
|
|
|
|
+ verticalOrigin: VerticalOrigin.BOTTOM,
|
|
|
|
|
+ disableDepthTestDistance: 21618529,
|
|
|
|
|
+ heightReference: HeightReference.CLAMP_TO_GROUND,
|
|
|
|
|
+ distanceDisplayCondition: new DistanceDisplayCondition(displayMin, displayMax)
|
|
|
|
|
+ },
|
|
|
|
|
+ label: {
|
|
|
|
|
+ text,
|
|
|
|
|
+ font: '12px MicrosoftYaHei',
|
|
|
|
|
+ backgroundColor: Color.fromCssColorString('#0F2830'),
|
|
|
|
|
+ showBackground: true,
|
|
|
|
|
+ fillColor: Color.WHITE,
|
|
|
|
|
+ pixelOffset: new Cartesian2(0, -40),
|
|
|
|
|
+ disableDepthTestDistance: 21618529,
|
|
|
|
|
+ heightReference: HeightReference.CLAMP_TO_GROUND,
|
|
|
|
|
+ distanceDisplayCondition: new DistanceDisplayCondition(displayMin, displayMax)
|
|
|
|
|
+ },
|
|
|
|
|
+ oldData
|
|
|
|
|
+ })
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * 加载geojson
|
|
|
|
|
+ * @param path 文件路径
|
|
|
|
|
+ * @param callback
|
|
|
|
|
+ * @param displayMin
|
|
|
|
|
+ * @param displayMax
|
|
|
|
|
+ */
|
|
|
|
|
+function loadGeoJson(path:string, displayMin?: number, displayMax?: number) {
|
|
|
|
|
+ GeoJsonDataSource.load(path, {
|
|
|
|
|
+ stroke: Color.fromCssColorString('#55F8F8'),
|
|
|
|
|
+ strokeWidth: 3,
|
|
|
|
|
+ clampToGround: false,
|
|
|
|
|
+ fill: Color.fromCssColorString('rgba(0,0,0,0)')
|
|
|
|
|
+ }).then((res) => {
|
|
|
|
|
+ const entities = res.entities.values
|
|
|
|
|
+ // console.log(55555, entities)
|
|
|
|
|
+ // for (let k = 0; k < entities.length; k++) {
|
|
|
|
|
+ // const el = entities[k]
|
|
|
|
|
+ // const polygon = el.polygon as Any
|
|
|
|
|
+ // const polyline = el.polyline as Any
|
|
|
|
|
+ // const billboard = el.billboard as Any
|
|
|
|
|
+ // if (polygon || polyline || el.billboard) {
|
|
|
|
|
+ // if (polygon) polygon.distanceDisplayCondition = new DistanceDisplayCondition(displayMin, displayMax)
|
|
|
|
|
+ // if (polyline) polyline.distanceDisplayCondition = new DistanceDisplayCondition(displayMin, displayMax)
|
|
|
|
|
+ // if (billboard) billboard.distanceDisplayCondition = new DistanceDisplayCondition(displayMin, displayMax)
|
|
|
|
|
+ // }
|
|
|
|
|
+ // }
|
|
|
|
|
+ if (viewer) {
|
|
|
|
|
+ viewer.dataSources.add(res)
|
|
|
|
|
+ viewer.scene.requestRender()
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * 移动
|
|
|
|
|
+ * @param lng
|
|
|
|
|
+ * @param lat
|
|
|
|
|
+ * @param profundity 高度
|
|
|
|
|
+ */
|
|
|
|
|
+function flyTo(lng: number, lat: number, profundity = 19633) {
|
|
|
|
|
+ if (!viewer) return
|
|
|
|
|
+ viewer.camera.flyTo({
|
|
|
|
|
+ destination: Cartesian3.fromDegrees(lng, lat * 0.997, profundity),
|
|
|
|
|
+ orientation: {
|
|
|
|
|
+ heading: CMath.toRadians(0.0),
|
|
|
|
|
+ pitch: CMath.toRadians(-60.0),
|
|
|
|
|
+ roll: CMath.toRadians(0.0)
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * 屏幕坐标转经纬度
|
|
|
|
|
+ * @param position xy
|
|
|
|
|
+ */
|
|
|
|
|
+function XYToLngLat(position: { x: number, y: number }) {
|
|
|
|
|
+ // 二维屏幕坐标转为三维笛卡尔空间直角坐标(世界坐标)
|
|
|
|
|
+ const cartesian3 = viewer.scene.globe.pick(viewer.camera.getPickRay(position), viewer.scene)
|
|
|
|
|
+ // 第一步:笛卡尔空间直角坐标系转为地理坐标(弧度制)
|
|
|
|
|
+ const cartographic = Cartographic.fromCartesian(cartesian3)
|
|
|
|
|
+ // 第二步: 地理坐标(弧度制) 转为经纬度坐标
|
|
|
|
|
+ const lat = CMath.toDegrees(cartographic.latitude)
|
|
|
|
|
+ const lng = CMath.toDegrees(cartographic.longitude)
|
|
|
|
|
+ return { lng, lat }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 初始化移动添加标点
|
|
|
|
|
+function initMove() {
|
|
|
|
|
+ // 添加标点
|
|
|
|
|
+ const dom = document.querySelector('.maps') as HTMLElement
|
|
|
|
|
+ dom.onmousedown = (e: Any) => {
|
|
|
|
|
+ const item = e.target.parentElement.dataset.type
|
|
|
|
|
+ if (item) {
|
|
|
|
|
+ const isNoPro = props.checkList.find((el) => el.lastData === 0 || !el.lastData)
|
|
|
|
|
+ if (isNoPro || !props.checkList.length || modelShow.value || props.checkList.length > 1) {
|
|
|
|
|
+ let txt = ''
|
|
|
|
|
+ if (isNoPro) txt = '请选择项目'
|
|
|
|
|
+ if (!props.checkList.length) txt = '请先选择项目'
|
|
|
|
|
+ if (modelShow.value) txt = '请完成你的操作再来!'
|
|
|
|
|
+ if (props.checkList.length > 1) txt = '请不要勾选多个项目'
|
|
|
|
|
+ notification.warning({
|
|
|
|
|
+ content: txt,
|
|
|
|
|
+ duration: 3000
|
|
|
|
|
+ })
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ let ismove = false
|
|
|
|
|
+ modelShow.value = false
|
|
|
|
|
+ dom.onmousemove = (em) => {
|
|
|
|
|
+ // 移动样式
|
|
|
|
|
+ if (!ismove) ismove = true
|
|
|
|
|
+ if (currenIcon.value.icon !== item) currenIcon.value.icon = item
|
|
|
|
|
+ currenIcon.value.x = em.x - 15 + window.scrollX
|
|
|
|
|
+ currenIcon.value.y = em.y - 100 + window.scrollY
|
|
|
|
|
+ }
|
|
|
|
|
+ dom.onmouseup = (eu) => {
|
|
|
|
|
+ currenIcon.value = { icon: '', x: 0, y: 0 }
|
|
|
|
|
+ const { lng, lat } = XYToLngLat({ x: eu.x + window.scrollX, y: eu.y - 74 + window.scrollY })
|
|
|
|
|
+ const items = icontypes.find((el) => el.type === item)
|
|
|
|
|
+ if (ismove) {
|
|
|
|
|
+ addLable(lng, lat, items?.icon!, items?.name!, 1, 16219740)
|
|
|
|
|
+ model.value = {
|
|
|
|
|
+ deviceId: '',
|
|
|
|
|
+ itemId: +props.checkList[0].id,
|
|
|
|
|
+ longitude: lng.toString(),
|
|
|
|
|
+ latitude: lat.toString(),
|
|
|
|
|
+ describeData: '',
|
|
|
|
|
+ selfId: '',
|
|
|
|
|
+ deviceType: icontypes.filter((el) => el.type === item)[0].deviceType
|
|
|
|
|
+ }
|
|
|
|
|
+ modelShow.value = true
|
|
|
|
|
+ isAdd.value = true
|
|
|
|
|
+ }
|
|
|
|
|
+ // flyTo(lng, lat)
|
|
|
|
|
+ viewer.scene.requestRender()
|
|
|
|
|
+ console.log('经纬度', lng, lat, props.checkList, model.value)
|
|
|
|
|
+
|
|
|
|
|
+ dom.onmousemove = null
|
|
|
|
|
+ dom.onmouseup = null
|
|
|
|
|
+ ismove = false
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 初始化
|
|
|
|
|
+async function initMap(callback:()=>void) {
|
|
|
|
|
+ // store.setLoading(true)
|
|
|
|
|
+ // init
|
|
|
|
|
+ viewer = new Viewer('cesiumContainer', {
|
|
|
|
|
+ baseLayerPicker: false,
|
|
|
|
|
+ geocoder: false,
|
|
|
|
|
+ infoBox: false,
|
|
|
|
|
+ homeButton: false,
|
|
|
|
|
+ sceneModePicker: false,
|
|
|
|
|
+ navigationHelpButton: false,
|
|
|
|
|
+ animation: false,
|
|
|
|
|
+ creditContainer: 'cesiumContainer',
|
|
|
|
|
+ timeline: false,
|
|
|
|
|
+ fullscreenButton: false,
|
|
|
|
|
+ vrButton: false,
|
|
|
|
|
+ requestRenderMode: true,
|
|
|
|
|
+ scene3DOnly: true,
|
|
|
|
|
+ selectionIndicator: false,
|
|
|
|
|
+ navigationInstructionsInitiallyVisible: false
|
|
|
|
|
+ // sceneMode: SceneMode.COLUMBUS_VIEW
|
|
|
|
|
+ })
|
|
|
|
|
+ // 增加地形属性
|
|
|
|
|
+ viewer.scene.globe.depthTestAgainstTerrain = true
|
|
|
|
|
+ // 缩放范围
|
|
|
|
|
+ viewer.scene.screenSpaceCameraController.minimumZoomDistance = 100
|
|
|
|
|
+ viewer.scene.screenSpaceCameraController.maximumZoomDistance = 7546388
|
|
|
|
|
+ // viewer.imageryLayers.removeAll(true)
|
|
|
|
|
+ // viewer.imageryLayers.get(0).show = false// 不显示底图
|
|
|
|
|
+ // viewer.scene.globe.baseColor = Color.fromCssColorString('#07101a') // 设置地球颜色07101a
|
|
|
|
|
+ viewer.imageryLayers.addImageryProvider(new UrlTemplateImageryProvider({
|
|
|
|
|
+ url: 'https://webst02.is.autonavi.com/appmaptile?x={x}&y={y}&z={z}&lang=zh_cn&size=1&scale=1&style=8'
|
|
|
|
|
+ }))
|
|
|
|
|
+ // loadGeoJson('are.json', 1, 7546388)
|
|
|
|
|
+ // loadGeoJson('road.json', 1, 7546388)
|
|
|
|
|
+ // 加载图层
|
|
|
|
|
+ // viewer.imageryLayers.addImageryProvider(new UrlTemplateImageryProvider({
|
|
|
|
|
+ // url: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}',
|
|
|
|
|
+ // subdomains: [ '0', '1', '2', '3' ],
|
|
|
|
|
+ // tilingScheme: new WebMercatorTilingScheme(),
|
|
|
|
|
+ // maximumLevel: 14
|
|
|
|
|
+ // }))
|
|
|
|
|
+
|
|
|
|
|
+ // 加载地形
|
|
|
|
|
+ // viewer.terrainProvider = await (CesiumTerrainProvider as any).fromUrl('https://www.supermapol.com/realspace/services/3D-stk_terrain/rest/realspace/datas/info/data/path', {
|
|
|
|
|
+ // requestMetadata: true,
|
|
|
|
|
+ // requestVertexNormals: true,
|
|
|
|
|
+ // requestWaterMask: true
|
|
|
|
|
+ // })
|
|
|
|
|
+
|
|
|
|
|
+ viewer.cesiumWidget.screenSpaceEventHandler.removeInputAction(ScreenSpaceEventType.LEFT_DOUBLE_CLICK) // 取消原双击事件
|
|
|
|
|
+ viewer.cesiumWidget.screenSpaceEventHandler.removeInputAction(ScreenSpaceEventType.LEFT_CLICK) // 取消原单击事件
|
|
|
|
|
+
|
|
|
|
|
+ // viewer.camera.changed.addEventListener(() => {
|
|
|
|
|
+ // // 打印中心点坐标、高度
|
|
|
|
|
+ // const { height } = viewer.scene.globe.ellipsoid.cartesianToCartographic(viewer.camera.position)
|
|
|
|
|
+ // console.log(999999, height)
|
|
|
|
|
+ // })
|
|
|
|
|
+
|
|
|
|
|
+ // 重新注册点击事件
|
|
|
|
|
+ handler = new ScreenSpaceEventHandler(viewer.scene.canvas)
|
|
|
|
|
+
|
|
|
|
|
+ // 右键还原
|
|
|
|
|
+ handler.setInputAction(() => {
|
|
|
|
|
+ viewer.camera.flyTo({
|
|
|
|
|
+ destination: Cartesian3.fromDegrees(101.84599, 30.04260, 7546388),
|
|
|
|
|
+ orientation: {
|
|
|
|
|
+ heading: CMath.toRadians(0.0),
|
|
|
|
|
+ pitch: CMath.toRadians(-85.0),
|
|
|
|
|
+ roll: CMath.toRadians(0.0)
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+ }, ScreenSpaceEventType.RIGHT_CLICK)
|
|
|
|
|
+
|
|
|
|
|
+ // 点击左键
|
|
|
|
|
+ handler.setInputAction((movement: Any) => {
|
|
|
|
|
+ const pick = viewer.scene.pick(movement.position)
|
|
|
|
|
+ if (!isAdmin.value || !pick) return
|
|
|
|
|
+ if (isAdd.value) {
|
|
|
|
|
+ notification.warning({
|
|
|
|
|
+ content: '请完成你的操作再来!',
|
|
|
|
|
+ duration: 3000
|
|
|
|
|
+ })
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ console.log('点击详情', pick.id)
|
|
|
|
|
+ isAdd.value = false
|
|
|
|
|
+ const { oldData } = pick.id
|
|
|
|
|
+ model.value = { ...oldData, selfId: pick.id.id }
|
|
|
|
|
+ modelShow.value = true
|
|
|
|
|
+ }, ScreenSpaceEventType.LEFT_CLICK)
|
|
|
|
|
+
|
|
|
|
|
+ // 监听加载结束
|
|
|
|
|
+ Helper.add(viewer.scene.globe.tileLoadProgressEvent, (e: any) => {
|
|
|
|
|
+ if (e === 0) {
|
|
|
|
|
+ viewer.camera.flyTo({
|
|
|
|
|
+ destination: Cartesian3.fromDegrees(101.84599, 30.04260, 7546388),
|
|
|
|
|
+ orientation: {
|
|
|
|
|
+ heading: CMath.toRadians(0.0),
|
|
|
|
|
+ pitch: CMath.toRadians(-85.0),
|
|
|
|
|
+ roll: CMath.toRadians(0.0)
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+ // store.setLoading(false)
|
|
|
|
|
+ Helper.removeAll()
|
|
|
|
|
+ // 初始化添加标点
|
|
|
|
|
+ callback()
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function close() {
|
|
|
|
|
+ if (isAdd.value) {
|
|
|
|
|
+ const { values } = viewer.entities
|
|
|
|
|
+ if (values.length) viewer.entities.removeById(values[values.length - 1].id)
|
|
|
|
|
+ viewer.scene.requestRender()
|
|
|
|
|
+ isAdd.value = false
|
|
|
|
|
+ }
|
|
|
|
|
+ modelShow.value = false
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+async function submit() {
|
|
|
|
|
+ await formRef.value.validate()
|
|
|
|
|
+ // 提交数据
|
|
|
|
|
+ const msg = isAdd.value ? await equipmentService.addDevice({ ...model.value }) : await equipmentService.upDevice({ ...model.value })
|
|
|
|
|
+ notification.success({
|
|
|
|
|
+ content: msg,
|
|
|
|
|
+ duration: 3000
|
|
|
|
|
+ })
|
|
|
|
|
+ // 属性赋值
|
|
|
|
|
+ const { values } = viewer.entities
|
|
|
|
|
+ values[values.length - 1].oldData = { ...model.value, selfId: values[values.length - 1].id }
|
|
|
|
|
+ modelShow.value = false
|
|
|
|
|
+ isAdd.value = false
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+async function del() {
|
|
|
|
|
+ dialog.info({
|
|
|
|
|
+ title: '你确定要删除当前设备?',
|
|
|
|
|
+ positiveText: '确定',
|
|
|
|
|
+ onPositiveClick: async () => {
|
|
|
|
|
+ const msg = await equipmentService.delDevice({ ...model.value })
|
|
|
|
|
+ notification.success({
|
|
|
|
|
+ content: msg,
|
|
|
|
|
+ duration: 3000
|
|
|
|
|
+ })
|
|
|
|
|
+ viewer.entities.removeById(model.value.selfId)
|
|
|
|
|
+ viewer.scene.requestRender()
|
|
|
|
|
+ modelShow.value = false
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/** 递归 */
|
|
|
|
|
+function recursion(arr: Array<TreeList>, newData: Array<TreeList>) {
|
|
|
|
|
+ for (let k = 0; k < arr.length; k++) {
|
|
|
|
|
+ const el = arr[k]
|
|
|
|
|
+ if (el.lastData === 1 || el.lastData === 0) {
|
|
|
|
|
+ newData.push({
|
|
|
|
|
+ name: el.name,
|
|
|
|
|
+ id: el.id,
|
|
|
|
|
+ lastData: el.lastData,
|
|
|
|
|
+ itemLongitude: el.itemLongitude,
|
|
|
|
|
+ itemLatitude: el.itemLatitude,
|
|
|
|
|
+ deviceDataList: el.deviceDataList
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+ if (el.children && el.children.length) recursion(el.children, newData)
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+/** input 正则 */
|
|
|
|
|
+function onlyAllowNumber(value:string, type:boolean) {
|
|
|
|
|
+ if (type) {
|
|
|
|
|
+ return +(value) >= 0 && +(value) <= 180
|
|
|
|
|
+ }
|
|
|
|
|
+ return +(value) >= 0 && +(value) <= 90
|
|
|
|
|
+}
|
|
|
|
|
+// 选中时
|
|
|
|
|
+watch(() => props.checkList, (v) => {
|
|
|
|
|
+ if (!isAdmin.value) return
|
|
|
|
|
+ if (!v.length) {
|
|
|
|
|
+ viewer.entities.removeAll()
|
|
|
|
|
+ } else {
|
|
|
|
|
+ equipmentService.getDevice(v[0]?.id as number).then((res) => {
|
|
|
|
|
+ viewer.entities.removeAll()
|
|
|
|
|
+ for (let k = 0; k < res.length; k++) {
|
|
|
|
|
+ const el = res[k]
|
|
|
|
|
+ if (el.del === 1) {
|
|
|
|
|
+ const items = icontypes.find((es) => es.deviceType === el.deviceType)
|
|
|
|
|
+ addLable(+(el.longitude!), +(el.latitude!), items!.icon, items!.name, 1, 16219740, el)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ viewer.scene.requestRender()
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+ viewer.scene.requestRender()
|
|
|
|
|
+ close()
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+// 树列表
|
|
|
|
|
+watch(() => props.treeList, (v) => {
|
|
|
|
|
+ options.value = v
|
|
|
|
|
+ viewer.entities.removeAll()
|
|
|
|
|
+ if (isAdmin.value || !v.length) return
|
|
|
|
|
+ const newData = [] as TreeList[]
|
|
|
|
|
+ recursion(v, newData)
|
|
|
|
|
+ for (let k = 0; k < newData.length; k++) {
|
|
|
|
|
+ const el = newData[k]
|
|
|
|
|
+ if (el.lastData === 1) {
|
|
|
|
|
+ // 项目
|
|
|
|
|
+ if (el.itemLongitude) {
|
|
|
|
|
+ const lngLat = el.itemLongitude?.split(',')
|
|
|
|
|
+ addLable(+(lngLat![0]), +(lngLat![1]), lnglatIcon, el.nameReferred || el.name, 1038633, 4938633)
|
|
|
|
|
+ }
|
|
|
|
|
+ if (el.deviceDataList && el.deviceDataList.length) {
|
|
|
|
|
+ // 设备
|
|
|
|
|
+ for (let j = 0; j < el.deviceDataList.length; j++) {
|
|
|
|
|
+ const es = el.deviceDataList[j]
|
|
|
|
|
+ if (es.del === 1) {
|
|
|
|
|
+ const items = icontypes.find((ed) => ed.deviceType === es.deviceType)
|
|
|
|
|
+ addLable(+(es.longitude!), +(es.latitude!), items!.icon, items!.name, 1, 938633)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 公司
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ viewer.scene.requestRender()
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+// 修改经纬度=>同步图标
|
|
|
|
|
+watch(() => [ model.value.longitude, model.value.latitude ], (v) => {
|
|
|
|
|
+ if (isAdd.value) return
|
|
|
|
|
+ const ens = viewer.entities.getById(model.value.selfId)
|
|
|
|
|
+ ens.position = Cartesian3.fromDegrees(+v[0], +v[1])
|
|
|
|
|
+ setTimeout(() => {
|
|
|
|
|
+ viewer.scene.requestRender()
|
|
|
|
|
+ }, 1500)
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+onMounted(() => {
|
|
|
|
|
+ initMap(() => {
|
|
|
|
|
+ if (isAdmin.value) initMove()
|
|
|
|
|
+ // loadGeoJson('geo.json')
|
|
|
|
|
+ // loadGeoJson('1.geojson')
|
|
|
|
|
+ // loadGeoJson('2.geojson')
|
|
|
|
|
+ // loadGeoJson('3.geojson')
|
|
|
|
|
+ // loadGeoJson('4.geojson')
|
|
|
|
|
+ // loadGeoJson('5.geojson')
|
|
|
|
|
+ // loadGeoJson('6.geojson')
|
|
|
|
|
+
|
|
|
|
|
+ // loadGeoJson('gm.geojson')
|
|
|
|
|
+ // loadGeoJson('tmy.geojson')
|
|
|
|
|
+ // loadGeoJson('dd.geojson')
|
|
|
|
|
+ })
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+onUnmounted(() => {
|
|
|
|
|
+ // store.setLoading(false)
|
|
|
|
|
+ if (viewer) {
|
|
|
|
|
+ if (viewer.entities) viewer.entities.removeAll()
|
|
|
|
|
+ viewer.destroy()
|
|
|
|
|
+ }
|
|
|
|
|
+ viewer = null
|
|
|
|
|
+ Helper = null
|
|
|
|
|
+ handler = null
|
|
|
|
|
+ const dom = (document.querySelector('.maps') as HTMLElement)
|
|
|
|
|
+ if (dom && dom.onmousedown) dom.onmousedown = null
|
|
|
|
|
+})
|
|
|
|
|
+</script>
|
|
|
|
|
+<template>
|
|
|
|
|
+ <div class="maps">
|
|
|
|
|
+ <div id="cesiumContainer" />
|
|
|
|
|
+ <template v-if="isAdmin">
|
|
|
|
|
+ <div class="topbar">
|
|
|
|
|
+ <template
|
|
|
|
|
+ v-for="(item, index) in icontypes"
|
|
|
|
|
+ :key="index"
|
|
|
|
|
+ >
|
|
|
|
|
+ <div>
|
|
|
|
|
+ <Icon
|
|
|
|
|
+ :name="item.type"
|
|
|
|
|
+ :size="50"
|
|
|
|
|
+ :data-type="item.type"
|
|
|
|
|
+ />
|
|
|
|
|
+ <p>{{ item.name }}</p>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <Icon
|
|
|
|
|
+ :name="currenIcon.icon"
|
|
|
|
|
+ :size="25"
|
|
|
|
|
+ class="moveIcon"
|
|
|
|
|
+ :style="`left:${currenIcon.x};top:${currenIcon.y}`"
|
|
|
|
|
+ />
|
|
|
|
|
+ <div
|
|
|
|
|
+ v-if="modelShow"
|
|
|
|
|
+ class="details"
|
|
|
|
|
+ >
|
|
|
|
|
+ <n-card
|
|
|
|
|
+ style="width: 400px"
|
|
|
|
|
+ :bordered="false"
|
|
|
|
|
+ size="huge"
|
|
|
|
|
+ role="dialog"
|
|
|
|
|
+ aria-modal="true"
|
|
|
|
|
+ class="n-modal"
|
|
|
|
|
+ >
|
|
|
|
|
+ <n-form
|
|
|
|
|
+ ref="formRef"
|
|
|
|
|
+ :model="model"
|
|
|
|
|
+ :rules="rules"
|
|
|
|
|
+ >
|
|
|
|
|
+ <n-form-item
|
|
|
|
|
+ path="deviceId"
|
|
|
|
|
+ label="设备ID"
|
|
|
|
|
+ >
|
|
|
|
|
+ <n-input
|
|
|
|
|
+ v-model:value="model.deviceId"
|
|
|
|
|
+ :readonly="!isAdd"
|
|
|
|
|
+ />
|
|
|
|
|
+ </n-form-item>
|
|
|
|
|
+ <n-form-item
|
|
|
|
|
+ path="itemId"
|
|
|
|
|
+ label="所属项目"
|
|
|
|
|
+ >
|
|
|
|
|
+ <n-tree-select
|
|
|
|
|
+ v-model:value="model.itemId"
|
|
|
|
|
+ :options="options"
|
|
|
|
|
+ :render-label="(info:any)=>info.option.nameReferred || info.option.name"
|
|
|
|
|
+ label-field="name"
|
|
|
|
|
+ key-field="id"
|
|
|
|
|
+ check-strategy="child"
|
|
|
|
|
+ clearable
|
|
|
|
|
+ filterable
|
|
|
|
|
+ />
|
|
|
|
|
+ </n-form-item>
|
|
|
|
|
+ <n-form-item
|
|
|
|
|
+ path="longitude"
|
|
|
|
|
+ label="经度"
|
|
|
|
|
+ >
|
|
|
|
|
+ <n-input
|
|
|
|
|
+ v-model:value="model.longitude"
|
|
|
|
|
+ :allow-input="(e: string) => onlyAllowNumber(e, true)"
|
|
|
|
|
+ />
|
|
|
|
|
+ </n-form-item>
|
|
|
|
|
+ <n-form-item
|
|
|
|
|
+ path="latitude"
|
|
|
|
|
+ label="纬度"
|
|
|
|
|
+ >
|
|
|
|
|
+ <n-input
|
|
|
|
|
+ v-model:value="model.latitude"
|
|
|
|
|
+ :allow-input="(e: string) => onlyAllowNumber(e, false)"
|
|
|
|
|
+ />
|
|
|
|
|
+ </n-form-item>
|
|
|
|
|
+ <n-form-item
|
|
|
|
|
+ path="describeData"
|
|
|
|
|
+ label="安装位置描述"
|
|
|
|
|
+ >
|
|
|
|
|
+ <n-input
|
|
|
|
|
+ v-model:value="model.describeData"
|
|
|
|
|
+ type="textarea"
|
|
|
|
|
+ size="small"
|
|
|
|
|
+ :autosize="{
|
|
|
|
|
+ minRows: 3,
|
|
|
|
|
+ maxRows: 5
|
|
|
|
|
+ }"
|
|
|
|
|
+ :maxlength="150"
|
|
|
|
|
+ />
|
|
|
|
|
+ </n-form-item>
|
|
|
|
|
+ </n-form>
|
|
|
|
|
+ <template #footer>
|
|
|
|
|
+ <n-button @click="close">
|
|
|
|
|
+ 取消
|
|
|
|
|
+ </n-button>
|
|
|
|
|
+ <n-button
|
|
|
|
|
+ v-if="!isAdd"
|
|
|
|
|
+ type="error"
|
|
|
|
|
+ @click="del"
|
|
|
|
|
+ >
|
|
|
|
|
+ 删除
|
|
|
|
|
+ </n-button>
|
|
|
|
|
+ <n-button
|
|
|
|
|
+ type="primary"
|
|
|
|
|
+ @click="submit"
|
|
|
|
|
+ >
|
|
|
|
|
+ 确定
|
|
|
|
|
+ </n-button>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </n-card>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </div>
|
|
|
|
|
+</template>
|
|
|
|
|
+<style scoped lang="scss">
|
|
|
|
|
+.maps {
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ height: 100%;
|
|
|
|
|
+ position: absolute;
|
|
|
|
|
+ left: 0;
|
|
|
|
|
+ top: 0;
|
|
|
|
|
+
|
|
|
|
|
+ #cesiumContainer {
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ height: 100%;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .topbar {
|
|
|
|
|
+ position: absolute;
|
|
|
|
|
+ top: 10px;
|
|
|
|
|
+ left: 50%;
|
|
|
|
|
+ width: 1080px;
|
|
|
|
|
+ height: 104px;
|
|
|
|
|
+ transform: translate(-50%, 0);
|
|
|
|
|
+ background: linear-gradient(229deg, rgba(26, 65, 78, 0.85) 0%, rgba(3, 20, 26, 0.95) 100%);
|
|
|
|
|
+ border: 1px solid rgba(105, 206, 206, 0.8);
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+
|
|
|
|
|
+ div {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-flow: column;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ width: 65px;
|
|
|
|
|
+ user-select: none;
|
|
|
|
|
+ cursor: pointer;
|
|
|
|
|
+ font-size: 14px;
|
|
|
|
|
+
|
|
|
|
|
+ &:first-child {
|
|
|
|
|
+ margin-left: 10px;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ p {
|
|
|
|
|
+ margin-top: 5px;
|
|
|
|
|
+ text-align: center;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .moveIcon {
|
|
|
|
|
+ position: absolute;
|
|
|
|
|
+ top: 0;
|
|
|
|
|
+ left: 0;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .details {
|
|
|
|
|
+ position: absolute;
|
|
|
|
|
+ right: 10px;
|
|
|
|
|
+ top: 10px;
|
|
|
|
|
+ min-height: 400px;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+</style>
|