<template>
|
<div id="deviceJobDetailsMap" class="ztzf-cesium">
|
</div>
|
|
</template>
|
<script setup>
|
import * as Cesium from 'cesium'
|
import { PublicCesium } from '@/utils/cesium/publicCesium'
|
import { flyVisual } from '@/utils/cesium/mapUtil'
|
import _ from 'lodash'
|
import photoDirection from '@/assets/images/historyMapPopup/photoDirection-new.png'
|
import panoramaPoint from '@/assets/images/panorama/panorama-point.png' //全景图标
|
import { getShowImg } from '@/utils/util'
|
import { getEventImage } from '@/utils/stateToImageMap/event'
|
import { getPanoramaList } from '@/api/panorama'
|
import CreateRouteLine from '@/utils/cesium/createRouteLine'
|
import { useStore } from 'vuex'
|
import { getOdmToken } from '@/api/model'
|
const createRouteLineExample = new CreateRouteLine()
|
const store = useStore()
|
const userAreaCode = computed(() => store.state.user.userInfo.detail.areaCode)
|
let viewer = null
|
let publicCesiumInstance = null
|
const viewInstance = shallowRef(null)
|
import { cloneDeep } from 'lodash'
|
let handler = null
|
let curMoveEntity = null
|
const tokenStr = ref('')
|
const emit = defineEmits(['showImageeclick'])
|
const props = defineProps(['detailsData', 'yuanImages', 'jobId'])
|
|
const initMap = () => {
|
publicCesiumInstance = new PublicCesium({
|
dom: 'deviceJobDetailsMap',
|
terrain: true,
|
flatMode: false,
|
layerMode: 4,
|
})
|
|
viewer = publicCesiumInstance.getViewer()
|
viewInstance.value = publicCesiumInstance
|
viewer.scene.globe.depthTestAgainstTerrain = true
|
createRouteLineExample.initCreateRoute(viewer)
|
handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)
|
handler.setInputAction(click => {
|
const pickedObjects = viewer.scene.drillPick(click.position)
|
LeftClickEvent(click, pickedObjects, viewer)
|
}, Cesium.ScreenSpaceEventType.LEFT_CLICK)
|
|
handler.setInputAction(e => {
|
let pick = viewer.scene.drillPick(e.endPosition)
|
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
|
}
|
// 绘制线和飞行
|
const drawLine = async () => {
|
Promise.all(
|
props.detailsData.way_lines.map(
|
async item =>
|
await createRouteLineExample.parsingFiles(
|
{
|
...item,
|
url: `${item.url}?_t=${new Date().getTime()}`,
|
},
|
{
|
longitude: item.longitude,
|
latitude: item.latitude,
|
height: item.height,
|
},
|
true,
|
false
|
)
|
)
|
).then(res => {
|
createRouteLineExample.showDetailMapPopup(props.detailsData.way_lines)
|
let arr = res.map(i => i.filePositions)
|
let newArr = _.flatten(arr)
|
flyVisual({
|
positionsData: newArr.map(i => [i.lng, i.lat, i.alt]),
|
viewer,
|
pitch: -60,
|
})
|
})
|
}
|
const lastSelectedId = ref(null)
|
// 鼠标左键点击事件
|
const LeftClickEvent = (click, pick, viewer) => {
|
// pick是一个数组
|
if (pick && pick.length > 0) {
|
let startEntity = pick.find(
|
i => i.id.name === 'work-drone-route-planar-polyline' || i.id.name === 'work-drone-route-point-polyline'
|
)?.id
|
if (startEntity) {
|
createRouteLineExample.showSingleDetailMapPopup(startEntity?.customData?.data)
|
return
|
}
|
let imagePath = []
|
let categories = ''
|
let panoramic = ''
|
pick.forEach(item => {
|
const index = item.id.index
|
if (item.id.customType == 'spotImages') {
|
imagePath.push(item.id.customInfo.link)
|
} else if (item.id.customType == 'aggregationSplashed') {
|
imagePath.push(item.id.customInfo.link)
|
} else if (item.id.customType == 'panorama') {
|
//全景
|
imagePath.push(item.id.customInfo.link)
|
categories = item.id.customInfo.resultType
|
}
|
})
|
if (imagePath.length === 0) return
|
const finalImagePaths = categories === 5 ? imagePath : imagePath.map(i => getShowImg(i))
|
emit('showImageeclick', finalImagePaths, 0, categories)
|
}
|
}
|
const removeMap = () => {
|
viewer.entities.removeAll()
|
publicCesiumInstance?.viewerDestroy()
|
publicCesiumInstance = null
|
viewer = null
|
}
|
|
watch(
|
() => props.detailsData,
|
(newValue, oldValue) => {
|
if (newValue) {
|
drawLine()
|
}
|
}
|
)
|
const zsList = ref([])
|
// 获取odmtoken
|
function getOdmTokenStr() {
|
getOdmToken().then(res => {
|
if (res.data.code !== 200) return
|
tokenStr.value = res.data.data
|
})
|
}
|
// 获取正射列表
|
function getZSList(newVal) {
|
let list = []
|
newVal.map((item, index) => {
|
item.childrens.map(zschilditem => {
|
if (zschilditem?.data) {
|
zschilditem?.data.map(dataitem => {
|
list.push(dataitem)
|
})
|
}
|
})
|
})
|
return list
|
}
|
// 获取正射请求地图聚合数据
|
const zsMapList = ref([])
|
function getZSMapList(valSn) {
|
const params = {
|
areaCode: userAreaCode.value,
|
deviceSn: valSn,
|
resultType: 4,
|
wayLineJobId: props.jobId,
|
}
|
getPanoramaList(params).then(res => {
|
const resData = res?.data?.data
|
zsMapList.value = resData?.childrens || []
|
zsList.value = getZSList(zsMapList.value)
|
|
renderOrthophoto()
|
})
|
}
|
// 解析经纬度
|
function getLonLat(str) {
|
if (!str) return []
|
return str
|
.replace('POLYGON((', '')
|
.replace('))', '')
|
.split(',')
|
.map(pair => {
|
const [lon, lat] = pair.trim().split(' ').map(Number)
|
return [lon, lat]
|
})
|
}
|
// 渲染正射
|
function renderOrthophoto() {
|
zsList.value.forEach((item, index) => {
|
const cur = viewInstance.value.addCustomImageryProviderDataSource(
|
new Cesium.UrlTemplateImageryProvider({
|
url: `${import.meta.env.VITE_APP_AREA_NAME}/webodm${item.url}?jwt=${tokenStr.value.split(' ')[1]}`,
|
})
|
)
|
})
|
}
|
watch(
|
() => props.yuanImages,
|
(newValue, oldValue) => {
|
|
// 增加箭头
|
if (!viewer || !newValue?.length) return;
|
// 清除旧实体
|
const oldEntities = viewer.entities.values.filter(e =>
|
e.id?.startsWith('spotImages') ||
|
e.id?.startsWith('aggregationSplashed') ||
|
e.id?.startsWith('panorama')
|
);
|
oldEntities.forEach(e => viewer.entities.remove(e));
|
// 添加新实体
|
let eventArr = newValue.filter(i => i.resultType === 2)
|
let originalArr = newValue.filter(i => i.resultType === 0)
|
let panoramicArr = newValue.filter(i => i.resultType === 5)
|
let orthographicArr = newValue.filter(i => i.resultType === 4)
|
if (orthographicArr.length >0) {
|
getZSMapList(orthographicArr[0]?.deviceSn)
|
}
|
originalArr.forEach((item_in, index) => {
|
// 根据偏航角度展示图片拍摄的方向
|
let yawAngleDegrees =
|
item_in.metadata.gimbalYawDegree < 0
|
? 360 + Number(item_in.metadata.gimbalYawDegree)
|
: Number(item_in.metadata.gimbalYawDegree)
|
|
viewer.entities.add({
|
position: Cesium.Cartesian3.fromDegrees(
|
+item_in.metadata.shootPosition.lng,
|
+item_in.metadata.shootPosition.lat,
|
+item_in.metadata.absoluteAltitude
|
),
|
id: 'spotImages' + item_in.id,
|
customType: 'spotImages',
|
customInfo: {
|
...item_in,
|
},
|
index: index,
|
billboard: {
|
image: photoDirection,
|
outlineWidth: 0,
|
width: 14,
|
height: 21,
|
disableDepthTestDistance: Number.POSITIVE_INFINITY,
|
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
|
},
|
})
|
})
|
|
eventArr.forEach((item, index) => {
|
viewer.entities.add({
|
id: `aggregationSplashed${item.id}`,
|
customType: 'aggregationSplashed',
|
customInfo: {
|
...item,
|
},
|
position: Cesium.Cartesian3.fromDegrees(
|
+item.metadata.shootPosition.lng,
|
+item.metadata.shootPosition.lat,
|
+item.metadata.absoluteAltitude
|
),
|
billboard: {
|
image: getEventImage(item.status),
|
width: 30,
|
height: 30,
|
disableDepthTestDistance: Number.POSITIVE_INFINITY,
|
},
|
index: index,
|
properties: {
|
customData: {
|
data: item,
|
},
|
},
|
})
|
})
|
// 全景
|
panoramicArr.forEach((item, index) => {
|
viewer.entities.add({
|
id: `panorama${item.id}`,
|
customType: 'panorama',
|
customInfo: {
|
...item,
|
},
|
position: Cesium.Cartesian3.fromDegrees(
|
+item.metadata.shootPosition.lng,
|
+item.metadata.shootPosition.lat,
|
+item.metadata.absoluteAltitude
|
),
|
billboard: {
|
image: panoramaPoint,
|
width: 30,
|
height: 30,
|
disableDepthTestDistance: Number.POSITIVE_INFINITY,
|
},
|
index: index,
|
properties: {
|
customData: {
|
data: item,
|
},
|
},
|
})
|
})
|
},
|
{ immediate: true, deep: true }
|
)
|
onBeforeUnmount(() => {
|
// 移除事件监听
|
handler?.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK)
|
handler?.destroy()
|
handler = null
|
|
createRouteLineExample.destroyedCustomDom()
|
|
removeMap()
|
})
|
|
onMounted(() => {
|
getOdmTokenStr()
|
nextTick(() => {
|
initMap()
|
})
|
})
|
</script>
|
<style scoped lang="scss">
|
#deviceJobDetailsMap {
|
position: relative;
|
height: 100%;
|
}
|
</style>
|