@@ -72,6 +72,18 @@ export function getQuestionList(params) { | |||
params | |||
}) | |||
} | |||
/** | |||
* @description: 获取飞行轨迹列表 | |||
* @param {*} id 任务id | |||
* @return {*} | |||
*/ | |||
export function getTrackList(id) { | |||
return request({ | |||
url: `/inspection/track/${id}`, | |||
method: 'GET' | |||
}) | |||
} | |||
/** | |||
* @description: 获取问题列表 | |||
* @param {*} params |
@@ -0,0 +1,101 @@ | |||
//定义一些常量 | |||
var x_PI = 3.14159265358979324 * 3000.0 / 180.0; | |||
var PI = 3.1415926535897932384626; | |||
var a = 6378245.0; | |||
var ee = 0.00669342162296594323; | |||
/** | |||
* 百度坐标系 (BD-09) 与 火星坐标系 (GCJ-02)的转换 | |||
* 即 百度 转 谷歌、高德 | |||
*/ | |||
export function bd09togcj02(bd_lon, bd_lat) { | |||
var x_pi = 3.14159265358979324 * 3000.0 / 180.0; | |||
var x = bd_lon - 0.0065; | |||
var y = bd_lat - 0.006; | |||
var z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * x_pi); | |||
var theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * x_pi); | |||
var gg_lng = z * Math.cos(theta); | |||
var gg_lat = z * Math.sin(theta); | |||
return [gg_lng, gg_lat] | |||
} | |||
/** | |||
* 火星坐标系 (GCJ-02) 与百度坐标系 (BD-09) 的转换 | |||
* 即谷歌、高德 转 百度 | |||
*/ | |||
export function gcj02tobd09(lng, lat) { | |||
var z = Math.sqrt(lng * lng + lat * lat) + 0.00002 * Math.sin(lat * x_PI); | |||
var theta = Math.atan2(lat, lng) + 0.000003 * Math.cos(lng * x_PI); | |||
var bd_lng = z * Math.cos(theta) + 0.0065; | |||
var bd_lat = z * Math.sin(theta) + 0.006; | |||
return [bd_lng, bd_lat] | |||
} | |||
/** | |||
* WGS84转GCj02 | |||
*/ | |||
export function wgs84togcj02(coordinate) { | |||
let lng=parseFloat(coordinate[0]); | |||
let lat=parseFloat(coordinate[1]); | |||
if (out_of_china(lng, lat)) { | |||
return [lng, lat] | |||
} | |||
else { | |||
var dlat = transformlat(lng - 105.0, lat - 35.0); | |||
var dlng = transformlng(lng - 105.0, lat - 35.0); | |||
var radlat = lat / 180.0 * PI; | |||
var magic = Math.sin(radlat); | |||
magic = 1 - ee * magic * magic; | |||
var sqrtmagic = Math.sqrt(magic); | |||
var dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * PI); | |||
var dlng = (dlng * 180.0) / (a / sqrtmagic * Math.cos(radlat) * PI); | |||
var mglat = lat + dlat; | |||
var mglng = lng + dlng; | |||
return [mglng, mglat] | |||
} | |||
} | |||
/** | |||
* GCJ02 转换为 WGS84 | |||
*/ | |||
export function gcj02towgs84(lng, lat) { | |||
if (out_of_china(lng, lat)) { | |||
return [lng, lat] | |||
} | |||
else { | |||
var dlat = transformlat(lng - 105.0, lat - 35.0); | |||
var dlng = transformlng(lng - 105.0, lat - 35.0); | |||
var radlat = lat / 180.0 * PI; | |||
var magic = Math.sin(radlat); | |||
magic = 1 - ee * magic * magic; | |||
var sqrtmagic = Math.sqrt(magic); | |||
dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * PI); | |||
dlng = (dlng * 180.0) / (a / sqrtmagic * Math.cos(radlat) * PI); | |||
var mglat = lat + dlat; | |||
var mglng = lng + dlng; | |||
return [lng * 2 - mglng, lat * 2 - mglat] | |||
} | |||
} | |||
export function transformlat(lng, lat) { | |||
var ret = -100.0 + 2.0 * lng + 3.0 * lat + 0.2 * lat * lat + 0.1 * lng * lat + 0.2 * Math.sqrt(Math.abs(lng)); | |||
ret += (20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0 / 3.0; | |||
ret += (20.0 * Math.sin(lat * PI) + 40.0 * Math.sin(lat / 3.0 * PI)) * 2.0 / 3.0; | |||
ret += (160.0 * Math.sin(lat / 12.0 * PI) + 320 * Math.sin(lat * PI / 30.0)) * 2.0 / 3.0; | |||
return ret | |||
} | |||
export function transformlng(lng, lat) { | |||
var ret = 300.0 + lng + 2.0 * lat + 0.1 * lng * lng + 0.1 * lng * lat + 0.1 * Math.sqrt(Math.abs(lng)); | |||
ret += (20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0 / 3.0; | |||
ret += (20.0 * Math.sin(lng * PI) + 40.0 * Math.sin(lng / 3.0 * PI)) * 2.0 / 3.0; | |||
ret += (150.0 * Math.sin(lng / 12.0 * PI) + 300.0 * Math.sin(lng / 30.0 * PI)) * 2.0 / 3.0; | |||
return ret | |||
} | |||
/** | |||
* 判断是否在国内,不在国内则不做偏移 | |||
*/ | |||
export function out_of_china(lng, lat) { | |||
return (lng < 72.004 || lng > 137.8347) || ((lat < 0.8293 || lat > 55.8271) || false); | |||
} |
@@ -0,0 +1,55 @@ | |||
import axios from 'axios' | |||
import { wgs84togcj02 } from '@/utils/coordinate-util' | |||
export default function getDroneLine(url, map, isfitView = true) { | |||
if (!url) return Promise.resolve(null) | |||
const temp = url.split('//') | |||
url = temp[temp.length - 1] | |||
url = process.env.VUE_APP_API_BASE_URL + url | |||
const generateMarker = () => { | |||
const dotContainer = document.createElement('div') | |||
dotContainer.style = 'height:16px;width:16px;background-color:#5798FF;border-radius:50%;position:relative' | |||
const dotInner = document.createElement('div') | |||
dotInner.style = 'height:8px;width:8px;background-color:#fff;border-radius:50%;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)' | |||
dotContainer.appendChild(dotInner) | |||
return dotContainer | |||
} | |||
return axios.get(url).then((res) => { | |||
const text = res.data | |||
let arr = text.split('\r\n') | |||
arr.shift() | |||
arr.pop() | |||
arr = arr.map((text) => { | |||
return text.split(/\s+/) | |||
}) | |||
const polylinePath = [] | |||
// let markerArr = []; | |||
const overlayGroup = new AMap.OverlayGroup() | |||
for (const point of arr) { | |||
if (point[9] !== 0) { | |||
const coordinate = wgs84togcj02([point[9], point[8]]) | |||
polylinePath.push(coordinate) | |||
const marker = new AMap.Marker({ | |||
position: new AMap.LngLat(coordinate[0], coordinate[1]), | |||
content: generateMarker(), | |||
anchor: 'center', | |||
zIndex: 20 | |||
}) | |||
overlayGroup.addOverlay(marker) | |||
} | |||
} | |||
const polyline = new AMap.Polyline({ | |||
path: polylinePath, | |||
strokeColor: '#5798FF', | |||
strokeWeight: 4, | |||
strokeStyle: 'dashed' | |||
}) | |||
overlayGroup.addOverlay(polyline) | |||
map.add(overlayGroup) | |||
if (isfitView) { | |||
map.setFitView(overlayGroup.getOverlays(), true, [70, 100, 300, 50]) | |||
} | |||
return overlayGroup | |||
}) | |||
} |
@@ -0,0 +1,10 @@ | |||
export const handleTextToList = function(text) { | |||
let arr = text.split('\r\n') | |||
arr.shift() | |||
arr.pop() | |||
arr = arr.map((text) => { | |||
return text.split(/\s+/) | |||
}) | |||
arr = arr.map(item => [item[9], item[8]]) | |||
return arr | |||
} |
@@ -52,6 +52,7 @@ import { transform, fromLonLat } from 'ol/proj' | |||
import { getVectorContext } from 'ol/render' | |||
import * as control from 'ol/control' | |||
import { styleList } from '../tools/style.js' | |||
import { getTrackList } from '@/api/task/index.js' | |||
// 视频组件 | |||
import VideoPlayer from '@/components/VideoPlayer/index.vue' | |||
@@ -81,15 +82,7 @@ export default defineComponent({ | |||
trackLayer: null, | |||
trackInfo: null, | |||
// 轨迹数据 | |||
trackList: [ | |||
{ lng: '118.765591', lat: '32.050993' }, | |||
{ lng: '118.665591', lat: '32.150993' }, | |||
{ lng: '118.565591', lat: '32.070993' }, | |||
{ lng: '118.465591', lat: '32.020993' }, | |||
{ lng: '118.365591', lat: '32.110993' }, | |||
{ lng: '118.265591', lat: '32.080993' }, | |||
{ lng: '118.165591', lat: '32.150993' } | |||
], | |||
trackList: [], | |||
disdance: null, | |||
animating: null, | |||
detailData: { | |||
@@ -207,14 +200,24 @@ export default defineComponent({ | |||
aiVideoRef.value.playVideo() | |||
} | |||
watch([() => props.visible, () => data.videoStatus], ([visible, status]) => { | |||
if (visible) { | |||
// initTrack(formatTradeList(data.trackList), 'route') | |||
} | |||
/* 获取轨迹数据 */ | |||
const getTrackData = async function() { | |||
const res = await getTrackList(props.data.id) | |||
const trackList = res.data | |||
return Promise.resolve({ | |||
trackList | |||
}) | |||
} | |||
watch([() => data.videoStatus], ([status]) => { | |||
if (status.status === 'ready' && status.aiStatus === 'ready') { | |||
startAllVideo() | |||
initMap() | |||
initTrack(formatTradeList(data.trackList), 'route') | |||
getTrackData().then(res => { | |||
if (res.trackList.length > 0) { | |||
initTrack(formatTradeList(res.trackList), 'route') | |||
} | |||
}) | |||
} | |||
}, { deep: true }) | |||
@@ -4,7 +4,7 @@ | |||
<div class="main_container"> | |||
<div id="live-map" /> | |||
<!-- 视频播放 --> | |||
<div v-if="detailData?.name" class="videobox"> | |||
<div class="videobox"> | |||
<!-- 视频开关 --> | |||
<div | |||
class="flagbox" | |||
@@ -33,7 +33,6 @@ | |||
:class="videoShow == 'back' ? 'video_show' : 'video_hidden'" | |||
> | |||
<VideoPlayer :options="getVideoOptions" /> | |||
<div class="flagbox">AI识别视频</div> | |||
<VideoPlayer :options="getVideoLiveOptions" /> | |||
</div> | |||
</div> | |||
@@ -43,7 +42,7 @@ | |||
</template> | |||
<script> | |||
import { defineComponent, computed, reactive, toRefs, onMounted } from 'vue' | |||
import { defineComponent, computed, reactive, toRefs, watch } from 'vue' | |||
import { Map, View, Feature } from 'ol' | |||
import 'ol/ol.css' | |||
import { Tile, Vector as VectorLayer } from 'ol/layer' | |||
@@ -53,10 +52,9 @@ import { XYZ, Vector as VectorSource } from 'ol/source' | |||
import { transform, fromLonLat } from 'ol/proj' | |||
import { getVectorContext } from 'ol/render' | |||
import VectorContext from 'ol/render/VectorContext' | |||
import { Draw } from 'ol/interaction' | |||
import { toRaw } from '@vue/reactivity' | |||
import * as control from 'ol/control' | |||
import { styleList } from '../tools/style.js' | |||
import { getTrackList } from '@/api/task/index.js' | |||
// 视频组件 | |||
import VideoPlayer from '@/components/VideoPlayer/index.vue' | |||
@@ -96,15 +94,14 @@ export default defineComponent({ | |||
{ lng: '118.265591', lat: '32.080993' }, | |||
{ lng: '118.165591', lat: '32.150993' }, | |||
{ lng: '118.765591', lat: '32.150993' }, | |||
{ lng: '118.665591', lat: '32.050993' }, | |||
{ lng: '118.66551', lat: '32.050993' }, | |||
{ lng: '118.365591', lat: '32.060993' }, | |||
{ lng: '118.265591', lat: '32.180993' }, | |||
{ lng: '118.165591', lat: '32.050993' } | |||
], | |||
addIndex: 0, | |||
// 轨迹数据 | |||
trackList: [], | |||
// 历史轨迹坐标数据 | |||
trajectoryList: [ | |||
trackList: [ | |||
{ lng: '118.765591', lat: '32.050993' }, | |||
{ lng: '118.665591', lat: '32.150993' }, | |||
{ lng: '118.565591', lat: '32.070993' }, | |||
@@ -131,7 +128,7 @@ export default defineComponent({ | |||
const getVideoOptions = computed(() => { | |||
return { | |||
id: 'video-live', | |||
width: '378px', | |||
width: '800px', | |||
height: '212px', | |||
source: data.detailData.pullUrl, | |||
isLive: true | |||
@@ -141,7 +138,7 @@ export default defineComponent({ | |||
const getVideoLiveOptions = computed(() => { | |||
return { | |||
id: 'video-live', | |||
width: '378px', | |||
width: '800px', | |||
height: '212px', | |||
source: data.detailData.pullUrl, | |||
isLive: true | |||
@@ -152,13 +149,48 @@ export default defineComponent({ | |||
emit('update:visible', false) | |||
} | |||
onMounted(() => { | |||
initMap() | |||
// 加载航线 | |||
initTrack(formatTradeList(data.lineTrajectoryList), 'lineTrackLayer', 'lineRoute') | |||
// 加载历史轨迹和实时轨迹 | |||
setLiveTrack(formatTradeList(data.trajectoryList)) | |||
}) | |||
/* 获取轨迹数据 */ | |||
const getTrackData = async function() { | |||
const res = await getTrackList(props.data.id) | |||
const trackList = res.data | |||
return Promise.resolve({ | |||
trackList | |||
}) | |||
} | |||
watch(() => props.visible, (value) => { | |||
if (value) { | |||
if (!data.mapData) { | |||
if (document.getElementById('live-map')) { | |||
initMap() | |||
// 加载机场航线 | |||
// initTrack(formatTradeList(data.lineTrajectoryList), 'lineTrackLayer', 'lineRoute') | |||
// 加载历史轨迹和实时轨迹 | |||
getTrackData().then(({ trackList }) => { | |||
if (trackList.length > 0) { | |||
setLiveTrack(formatTradeList(trackList)) | |||
} | |||
}) | |||
} else { | |||
setTimeout(() => { | |||
initMap() | |||
// 加载机场航线 | |||
// initTrack(formatTradeList(data.lineTrajectoryList), 'lineTrackLayer', 'lineRoute') | |||
// 加载历史轨迹和实时轨迹 | |||
getTrackData().then(({ trackList }) => { | |||
data.trackList = trackList | |||
if (trackList.length > 0) { | |||
setLiveTrack(formatTradeList(data.trackList)) | |||
} | |||
}) | |||
}, 500) | |||
} | |||
} | |||
} else { | |||
clearInterval(data.socket) | |||
data.socket = null | |||
} | |||
}, { deep: true }) | |||
/* 初始化地图 */ | |||
const initMap = function() { | |||
@@ -204,11 +236,11 @@ export default defineComponent({ | |||
type: routeType, | |||
geometry: route | |||
}) | |||
const startMarker = new Feature({ | |||
const endMarker = new Feature({ | |||
type: 'icon', | |||
geometry: new Point(route.getFirstCoordinate()) | |||
geometry: new Point(route.getLastCoordinate()) | |||
}) | |||
const position = startMarker.getGeometry().clone() | |||
const position = endMarker.getGeometry().clone() | |||
const geoMarker = new Feature({ | |||
type: 'geoMarker', | |||
geometry: position | |||
@@ -242,23 +274,11 @@ export default defineComponent({ | |||
} | |||
} | |||
/* 轨迹改变 */ | |||
const changeTrack = (event) => { | |||
try { | |||
const vectorContext = getVectorContext(event) | |||
vectorContext.setStyle(styleList['geoMarker']) | |||
VectorContext.drawGeometry(data.trackInfo.position) | |||
vectorContext.drawGeometry(data.trackInfo.route) | |||
data.mapData.render() | |||
} catch { | |||
console.log(event) | |||
} | |||
} | |||
/* 加载实时轨迹 */ | |||
const setLiveTrack = function(hisTrackList) { | |||
data.animating = false | |||
data.disdance = 0 | |||
var changeTrack | |||
if (hisTrackList.length > 1) { | |||
data.trackInfo = initTrack(hisTrackList, 'liveTrackLayer', 'route') | |||
if (data.trackInfo.vectorLayer) { | |||
@@ -266,18 +286,25 @@ export default defineComponent({ | |||
} | |||
} | |||
/* 轨迹改变 */ | |||
changeTrack = (event) => { | |||
try { | |||
const vectorContext = getVectorContext(event) | |||
vectorContext.setStyle(styleList['geoMarker']) | |||
VectorContext.drawGeometry(data.trackInfo.position) | |||
vectorContext.drawGeometry(data.trackInfo.route) | |||
data.mapData.render() | |||
} catch { | |||
console.log(event) | |||
} | |||
} | |||
// 两秒钟获取一次数据 | |||
data.socket = setInterval(() => { | |||
// getTrackdata({ inspectionId: id }).then((res) => { | |||
// const coordinate = fromLonLat([res.data.lng, res.data.lat]) | |||
// const unUseableCoordinate = !coordinate.every((item) => !isNaN(item)) | |||
// if (unUseableCoordinate) return | |||
// // 赋值动态无人机坐标 | |||
// if (coordinate.length) { | |||
// data.trajectoryList.lng = coordinate[0] | |||
// data.trajectoryList.lat = coordinate[1] | |||
// } | |||
// data.trackList.push(coordinate) | |||
// if (data.trackList.length > 1 && !data.trackInfo) { | |||
// initTrack(data.trackList) | |||
@@ -288,7 +315,16 @@ export default defineComponent({ | |||
// data.trackInfo.position.setCoordinates(coordinate) | |||
// } | |||
// }) | |||
}, 2000) | |||
const obj = data.lineTrajectoryList[data.addIndex] | |||
const coordinate = fromLonLat([obj.lng, obj.lat]) | |||
console.log(coordinate) | |||
data.addIndex = data.addIndex + 1 | |||
if (data.trackInfo) { | |||
data.trackInfo.route.appendCoordinate(coordinate) | |||
data.trackInfo.vectorLayer.getSource().changed() | |||
data.trackInfo.position.setCoordinates(coordinate) | |||
} | |||
}, 1000) | |||
// 移动要素 | |||
const moveFeature = function(event) { | |||
var lastTime | |||
@@ -347,7 +383,7 @@ export default defineComponent({ | |||
} | |||
/* 视频 */ | |||
.videobox { | |||
width: 378px; | |||
width: 800px; | |||
display: flex; | |||
flex-direction: column; | |||
justify-content: flex-start; | |||
@@ -357,7 +393,7 @@ export default defineComponent({ | |||
right: 10px; | |||
} | |||
.flagbox { | |||
width: 378px; | |||
width: 800px; | |||
height: 27px; | |||
background: #fff; | |||
padding: 0 10px; | |||
@@ -366,7 +402,7 @@ export default defineComponent({ | |||
align-items: center; | |||
} | |||
.flagbox_open { | |||
width: 378px; | |||
width: 800px; | |||
animation: openbox 1s; | |||
} | |||
.flaxbox_back { | |||
@@ -375,7 +411,7 @@ export default defineComponent({ | |||
} | |||
@keyframes backbox { | |||
from { | |||
width: 378px; | |||
width: 800px; | |||
} | |||
to { | |||
width: 116px; | |||
@@ -386,11 +422,11 @@ export default defineComponent({ | |||
width: 116px; | |||
} | |||
to { | |||
width: 378px; | |||
width: 800px; | |||
} | |||
} | |||
.video_content { | |||
width: 378px; | |||
width: 800px; | |||
height: 220px; | |||
position: relative; | |||
} | |||
@@ -419,5 +455,10 @@ export default defineComponent({ | |||
opacity: 0; | |||
} | |||
} | |||
.imageicon { | |||
width: 16px; | |||
height: 16px; | |||
margin-right: 10px; | |||
} | |||
</style> |
@@ -29,7 +29,7 @@ | |||
<!-- 新增、编辑弹窗 --> | |||
<TaskModal v-if="modalShow" v-model:visible="modalShow" :type="modalType" :data="rowData" @reload="handleSearch" /> | |||
<!-- 直播抽屉 --> | |||
<LiveDrawer v-if="liveDrawer" v-model:visible="liveDrawer" :data="rowData" /> | |||
<LiveDrawer v-model:visible="liveDrawer" :data="rowData" /> | |||
<!-- 轨迹回放 --> | |||
<DemandDrawer v-model:visible="demandDrawer" :data="rowData" /> | |||
<!-- 问题核实 --> | |||
@@ -82,7 +82,6 @@ export default { | |||
} | |||
function handleChange(value) { | |||
console.log(value) | |||
const { airportId } = value | |||
if (data.airportId !== airportId) { | |||
if (!airportId) { |