享飞-小程序
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

444 lines
17 KiB

<script setup>
import {onMounted, ref, onUnmounted, reactive, watch, computed} from "vue";
import * as Taro from "@tarojs/taro";
import * as turf from '@turf/turf';
import LeftSide from './LeftSide.vue';
import RightSide from './RightSide.vue';
import BottomSide from './BottomSide.vue';
import { creatEightShaped } from '../flightMap/utils';
// import ResultModal from './ResultModal.vue';
import { useAirFieldsStore, useStandardStore, useSupervisionStore } from "../../stores";
import { useDroneMarker } from "./useDroneMarker";
import { storeToRefs } from 'pinia';
import { GPS2GCJ } from '../../utils/helpers';
const { markers, rotate, circles, createCircle, showEight, polygons, setCallBack, polyline, distanceText } = useDroneMarker();
const { getExamList, getEnvList } = useStandardStore()
const { wsDroneData } = useSupervisionStore();
const { position, attitude, battery, gps, tip, deviation, connectLoading, connectDrone, droneOnLine } = storeToRefs(useSupervisionStore());
const { getAirFieldsOfStudent } = useAirFieldsStore();
const { formData } = storeToRefs(useAirFieldsStore());
const { examList, envList } = storeToRefs(useStandardStore());
const envItem = computed(() => {
return envList.value.find((item) => item.id === formData.value.envGradeId) || {};
});
const standardData = computed(() => {
return examList.value.find((item) => item.name === '8字圆圈半径' && item.licenseLevelId === formData.value.licenseGradeId && item.envGrade === envItem.value.gradeName) || {};
});
const standardDiffData = computed(() => {
return examList.value.find((item) => item.name === '8字水平偏差阈值' && item.licenseLevelId === formData.value.licenseGradeId && item.envGrade === envItem.value.gradeName) || {};
});
const point3standardData = computed(() => {
return examList.value.find((item) => item.name === '点3中心筒范围-内' && item.licenseLevelId === formData.value.licenseGradeId && item.envGrade === envItem.value.gradeName) || {};
});
getExamList().catch(({ msg }) => {
if (msg) openToast('warn', msg);
});
const { params } = Taro.useRouter();
console.log('params', params);
// 地图上下文
let mapContext = null;
const show = ref(true);
// 初始化地图
onMounted(() => {
mapContext = Taro.createMapContext('map');
show.value = false;
connect();
// init();
// showEight();
});
onUnmounted(() => {
// eventBus.off('show-teaching-track-replay')
if (ws) {
confirmClose.value = true;
ws.close();
ws = null;
}
})
// 多边形配置
// const polygons = ref([]);
// 圆形标记配置
// const circles = ref([]);
// 标记点配置
const markerPoints = ref([]);
// 地图旋转角度
const bearing = ref(0);
let ws;
const confirmClose = ref(false);
function connect() {
// if (!params?.droneSn) {
// openToast('warn', '未获取到无人机编号,请重新选择无人机。');
// return;
// }
wsDroneData(params?.droneSn).then(wsTask => {
ws = wsTask;
wsTask.onMessage( () => {
if (!center.value.lat || !center.value.lng) {
center.value.lat = position.value.lat;
center.value.lng = position.value.lng;
}
// if (firstMarker.value && position.value?.lng) {
// initDevice({ ...position.value, ...attitude.value }, bearing.value);
// firstMarker.value = false;
// } else {
// moveDevice({ ...position.value, ...attitude.value }, bearing.value)
// }
});
wsTask.onError(() => {
// clearDevice()
// setTimeout(() => {
// sum += 1;
// connect();
// }, 3000);
ws.close()
});
wsTask.onClose(() => {
// initDevice();
if (confirmClose.value) return;
ws.close();
setTimeout(() => {
// sum += 1;
connect();
}, 3000);
})
});
}
const enableRotate = ref(false);
// function init() {
// // 获取飞行详情和轨迹数据
// Promise.all([
// getExamList(),
// getEnvList(),
// // getAirFieldsDetail('9' || '10'),
// // getAirFieldsOfStudent(),
// ]).then(([examlist, envlist, airFieldsData]) => {
// console.log('air', airFieldsData);
// // const airfield = airFieldsData?.data || {};
// const { records = [] } = examlist || {}
// const envItem = (envlist || []).find((item) => item.id === airfield.envGradeId) || {}
// const standardData = records.find(
// (item) =>
// item.name === '8字圆圈半径' &&
// item.licenseLevelId === airfield.licenseGradeId &&
// item.envGrade === envItem.gradeName,
// )
// const standardDiffData = records.find(
// (item) =>
// item.name === '8字水平偏差阈值' &&
// item.licenseLevelId === airfield.licenseGradeId &&
// item.envGrade === envItem.gradeName,
// )
// const point3standardData = records.find(
// (item) =>
// item.name === '点3中心筒范围-内' &&
// item.licenseLevelId === airfield.licenseGradeId &&
// item.envGrade === envItem.gradeName,
// );
//
// const center1 = GPS2GCJ([airfield.circle1Lng, airfield.circle1Lat]);
// const center2 = GPS2GCJ([airfield.circle2Lng, airfield.circle2Lat]);
//
// const { polygons: shapePolygons, circles: shapeCircles, markers: shapeMarkers } = creatEightShaped(
// {
// center: center1,
// radius: standardData.value,
// radiusDiff: standardDiffData.value,
// centerWidth: 0.1,
// },
// {
// center: center2,
// radius: standardData.value,
// radiusDiff: standardDiffData.value,
// centerWidth: 0.1,
// },
// [6, 0, 1, 3, 4, 5, 2],
// { radius: point3standardData.value },
// );
//
// // // 更新地图显示数据
// // polygons.value = shapePolygons;
// // setTimeout(() => {
// // circles.value = shapeCircles;
// // markerPoints.value = shapeMarkers;
// // }, 500);
//
// // 设置地图视野
// mapContext.includePoints({
// points: [
// { latitude: center1[1], longitude: center1[0] },
// { latitude: center2[1], longitude: center2[0] }
// ],
// // padding: [130, 50, 130, 10],
// success: (res) => {
// setTimeout(() => {
// // 计算两个圆心之间的方位角并转换为地图旋转角度
// const angle = turf.bearing(center1, center2);
// // 调整偏移量使八字飞行路径保持垂直显示
// rotate.value = 90 - angle;
// bearing.value = 90 - angle;
// connect();
// }, 500);
// // console.log('地图视野设置成功', res);
// },
// fail: (err) => {
// enableRotate.value = true;
// console.error('地图视野设置失败', err);
// }
// });
// }).catch(({ msg }) => {
// if (msg) openToast('warn', msg);
// })
// }
const center = ref({
lat: 0,
lng: 0,
})
setCallBack((index) => {
openToast('success', `成功打点圆${index}`);
})
const state = reactive({
msg: '错误提示',
type: 'warn',
show: false,
cover: true,
// title: '',
// bottom: '',
center: true,
});
function openToast(type = 'warn', msg = '错误提示') {
state.msg = msg;
state.type = type;
state.show = true;
}
function onHandleCreateCircle(index) {
if (gps.value.fixType !== 'GPS_FIX_TYPE_RTK_FIXED' && gps.value.fixType !== 'GPS_FIX_TYPE_RTK_FLOAT') {
openToast('warn', '请确保无人机处于RTK模式下');
return;
}
// let next;
if (index === 2 && formData.value.circle1Lat) {
// const center1 = [position.value.lng, position.value.lat];
// const center2 = GPS2GCJ([formData.value.circle2Lng, formData.value.circle2Lat]);
const center1 = turf.point([position.value?.lng, position.value?.lat]);
const center2 = turf.point(GPS2GCJ([formData.value.circle1Lng, formData.value.circle1Lat]));
const dis = turf.distance(center1, center2, { units: 'meters' }).toFixed(1);
const tmp = (standardData.value?.value || 0) * 2;
console.log('ada', dis, tmp);
if (Math.abs(tmp - dis) > 0.5) {
openToast('warn', '请确保误差处于50公分内');
return;
}
}
if (index === 1 && formData.value.circle2Lat) {
// const center1 = [position.value.lng, position.value.lat];
// const center2 = GPS2GCJ([formData.value.circle2Lng, formData.value.circle2Lat]);
const center1 = turf.point([position.value?.lng, position.value?.lat]);
const center2 = turf.point(GPS2GCJ([formData.value.circle2Lng, formData.value.circle2Lat]));
const dis = turf.distance(center1, center2, { units: 'meters' }).toFixed(1);
const tmp = (standardData.value?.value || 0) * 2;
if (Math.abs(tmp - dis) > 0.5) {
openToast('warn', '请确保误差处于50公分内');
return;
}
}
createCircle(index);
const { circle1Lat, circle1Lng, circle2Lat, circle2Lng } = formData.value;
if (circle1Lat && circle1Lng && circle2Lng && circle2Lat) {
const center1 = GPS2GCJ([formData.value.circle1Lng, formData.value.circle1Lat]);
const center2 = GPS2GCJ([formData.value.circle2Lng, formData.value.circle2Lat]);
bearing.value = 90 - turf.bearing(center1, center2);
rotate.value = bearing.value;
showEight();
}
}
watch([() => formData.value.envGradeId, () => formData.value.licenseGradeId], () => {
const { circle1Lat, circle1Lng, circle2Lat, circle2Lng } = formData.value;
if (circle1Lat && circle1Lng && circle2Lng && circle2Lat) {
const center1 = GPS2GCJ([formData.value.circle1Lng, formData.value.circle1Lat]);
const center2 = GPS2GCJ([formData.value.circle2Lng, formData.value.circle2Lat]);
bearing.value = 90 - turf.bearing(center1, center2);
rotate.value = bearing.value;
showEight();
}
})
// function showEight() {
// const center1 = GPS2GCJ([formData.value.circle1Lng, formData.value.circle1Lat]);
// const center2 = GPS2GCJ([formData.value.circle2Lng, formData.value.circle2Lat]);
//
// // const center1 = [-122.3895127, 37.6280898];
// // const center2 = [-122.3894255, 37.6281725];
// console.log(center1, center2);
// const { polygons: shapePolygons, circles: shapeCircles, markers: shapeMarkers } = creatEightShaped({
// center: center1,
// radius: standardData.value.value,
// radiusDiff: standardDiffData.value.value,
// centerWidth: 0.1,
// }, {
// center: center2,
// radius: standardData.value.value,
// radiusDiff: standardDiffData.value.value,
// centerWidth: 0.1,
// },
// [6, 0, 1, 3, 4, 5, 2],
// { radius: point3standardData.value });
// extCircles.value = [...shapeCircles];
// polygons.value = [...shapePolygons];
// extMarker.value = [...shapeMarkers];
// // }
// }
const extCircles = ref([])
// const extCircles = ref([])
const extMarker = ref([])
</script>
<template>
<view :class="s.root">
<view class="mapBox">
<map
id="map"
:markers="[...markerPoints, ...markers, ...extMarker, ...distanceText]"
:longitude="center.lng"
:latitude="center.lat"
:polygons="polygons"
:polyline="[...polyline]"
:scale="20"
:circles="[...circles, ...extCircles]"
:enable-rotate="enableRotate"
:rotate="bearing"
:enable-satellite="true"
:show-compass="true"
/>
</view>
<RightSide @create="onHandleCreateCircle" />
<BottomSide :info="{ ...position, ...attitude, ...gps, ...battery, connectLoading, connectDrone, droneOnLine }"/>
</view>
<nut-toast :msg="state.msg" v-model:visible="state.show" :type="state.type" :cover="state.cover" :duration="2000" />
</template>
<style lang="less" module="s">
page {
height: 100%;
overflow: hidden;
}
.root {
position: relative;
width: 100%;
height: 100%;
:global {
.mapBox {
width: 100%;
height: 100%;
position: relative;
#map {
width: 100%;
height: 100%;
transform: scale(2);
}
.exam-result-modal {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: center;
align-items: center;
z-index: 1000;
.modal-content {
background-color: rgba(0, 0, 0, 0.8);
padding: 20px;
border-radius: 12px;
min-width: 280px;
position: relative;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
.close-btn {
position: absolute;
top: 10px;
right: 10px;
width: 24px;
height: 24px;
line-height: 24px;
text-align: center;
font-size: 20px;
color: #999;
cursor: pointer;
border-radius: 50%;
transition: all 0.3s;
&:hover {
background-color: #f5f5f5;
color: #666;
}
}
.result-status {
font-size: 20px;
font-weight: bold;
text-align: center;
margin-bottom: 16px;
color: #ff4d4f;
&.pass {
color: #52c41a;
}
}
.info-item {
margin: 8px 0;
display: flex;
align-items: center;
.label {
color: #838383;
margin-right: 8px;
font-size: 14px;
}
.value {
color: #ffffff;
font-weight: 500;
font-size: 14px;
}
}
}
}
}
.real-time-data {
z-index: 1;
}
}
}
</style>