zhufu 2025-10-13 11:31:12 +08:00
commit 4c07f09b8f
47 changed files with 2287 additions and 281 deletions

View File

@ -129,6 +129,7 @@
"moment": "^2.30.1",
"monaco-editor": "^0.33.0",
"monaco-editor-core": "^0.46.0",
"mqtt": "^5.14.1",
"naive-ui": "2.34.3",
"nprogress": "^0.2.0",
"path-to-regexp": "^6.2.1",

View File

@ -0,0 +1,28 @@
import { defHttp } from '@/utils/http/axios';
interface AddOrUpdateRedisUserParams {
clientId?: string;
userId?: string;
userName?: string;
connectTime?: string;
isLock?: boolean;
}
enum Api {
GetRedisUser = '/api/AirportMaintenance/GetRedisUser',
GetLockedClients = '/api/AirportMaintenance/GetLockedClients',
AddOrUpdateRedisUser = '/api/AirportMaintenance/AddOrUpdateRedisUser',
}
export function getRedisUser(id) {
return defHttp.get({ url: Api.GetRedisUser + '?id=' + id });
}
export function getLockedClients(params?: any) {
return defHttp.get({ url: Api.GetLockedClients, params });
}
export const addOrUpdateRedisUser = (params: AddOrUpdateRedisUserParams) =>
defHttp.post({
url: Api.AddOrUpdateRedisUser,
params,
});

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 759 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 695 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -1,24 +1,33 @@
<template>
<div class="go-title-03">
<div class="go-title-03">
<div class="flex ai-c jc-sb max-w navsbox">
<div class="flex navsli ai-c jc-c" v-for="(item,index) in navsArr" :class="index==navsIndex?'navsliactive':''" @click="navsClick(item,index)">
<div
class="flex navsli ai-c jc-c"
v-for="(item, index) in navsArr"
:class="index == navsIndex ? 'navsliactive' : ''"
@click="navsClick(item, index)"
>
{{ item.label }}
<span class="navsNum" v-if="item.value!=0">{{item.value}}</span>
<span class="navsNum" v-if="item.value != 0">{{ item.value }}</span>
</div>
</div>
<div class="flex column sectionBox">
<div class="mt-1 sectionLi" v-for="(item,index) in sectionDatas" @click="handlerFireDetail(item)">
<div
class="mt-1 sectionLi"
v-for="(item, index) in sectionDatas"
@click="handlerFireDetail(item)"
>
<div class="flex jc-sb">
<div class="titleText">{{item.describe}}</div>
<div class="mr-2 desStyle">{{item.degreeType}}</div>
<div class="titleText">{{ item.describe }}</div>
<div class="mr-2 desStyle">{{ item.degreeType }}</div>
</div>
<div class="flex mt-1 ai-c">
<img class="mr-1" src="@/assets/images/chart/equipment/address.png" />
<div class="numStyle" :title="item.address">{{item.address}}</div>
<div class="numStyle" :title="item.address">{{ item.address }}</div>
</div>
<div class="flex mt-1 ai-c">
<img class="mr-1 timeicon" src="@/assets/images/chart/equipment/time.png" />
<div class="numStyle">{{item.reportTime}}</div>
<div class="numStyle">{{ item.reportTime }}</div>
</div>
</div>
</div>
@ -26,284 +35,276 @@
</template>
<script setup lang="ts">
import { PropType, toRefs, ref,onMounted } from 'vue'
import { CreateComponentType } from '@/packages/index.d'
import { useChartDataFetch } from '@/hooks';
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore';
import * as mars3d from "mars3d";
import { EventBus } from '@/utils/eventBus';
import { PropType, toRefs, ref, onMounted } from 'vue';
import { CreateComponentType } from '@/packages/index.d';
import { useChartDataFetch } from '@/hooks';
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore';
import * as mars3d from 'mars3d';
import { EventBus } from '@/utils/eventBus';
import { eventHandlerHook } from '@/hooks/eventHandler.hook';
const chartEditStore = useChartEditStore();
import { eventHandlerHook } from '@/hooks/eventHandler.hook';
const chartEditStore = useChartEditStore();
const props = defineProps({
chartConfig: {
type: Object as PropType<CreateComponentType>,
required: true
}
})
const props = defineProps({
chartConfig: {
type: Object as PropType<CreateComponentType>,
required: true,
},
});
const navsIndex = ref(0)
const { w, h } = toRefs(props.chartConfig.attr)
const {
navsArr,
navsSize,
navsColor,
navsCheckSize,
navsCheckColor,
navsCheckBackground,
navsBackground,
titleSize,
titleColor,
sectionDatas,
desColor,
desSize,
datasColor,
datasSize
} = toRefs(props.chartConfig.option)
const navsIndex = ref(0);
const { w, h } = toRefs(props.chartConfig.attr);
const {
navsArr,
navsSize,
navsColor,
navsCheckSize,
navsCheckColor,
navsCheckBackground,
navsBackground,
titleSize,
titleColor,
sectionDatas,
desColor,
desSize,
datasColor,
datasSize,
} = toRefs(props.chartConfig.option);
const navsClick = function (item, index) {
navsIndex.value = index;
props.chartConfig.request.requestSQLContent.sql = item.sql;
useChartDataFetch(props.chartConfig, useChartEditStore, (resData: any) => {
props.chartConfig.option.sectionDatas = resData;
});
};
// callback
useChartDataFetch(props.chartConfig, useChartEditStore, (resData: any[]) => {
props.chartConfig.option.sectionDatas = resData;
});
onMounted(() => {
//
setTimeout(function () {
handlerLoadFirePoint(sectionDatas.value);
}, 5000);
});
const navsClick = function(item,index){
navsIndex.value = index
props.chartConfig.request.requestSQLContent.sql = item.sql
useChartDataFetch(props.chartConfig, useChartEditStore, (resData: any) => {
props.chartConfig.option.sectionDatas = resData
})
}
// callback
useChartDataFetch(props.chartConfig, useChartEditStore, (resData: any[]) => {
props.chartConfig.option.sectionDatas = resData;
});
onMounted(()=>{
//
setTimeout(function(){
handlerLoadFirePoint(sectionDatas.value);
},5000)
})
//
const handlerLoadFirePoint = (points:[])=>{
points?.forEach((item,index)=>{
let graphicOptions = {
id:item.id,
attr:item,
position: [parseFloat(item.lng), parseFloat(item.lat)],
style: {
image: "/public/map/fire.png",
clampToGround: true,
scale: 0.8,
label: {
text: item.title,
font_size: 12,
color: "#ffffff",
pixelOffsetY: -36,
distanceDisplayCondition: true,
distanceDisplayCondition_far: 500000,
distanceDisplayCondition_near: 0,
//
const handlerLoadFirePoint = (points: []) => {
points?.forEach((item, index) => {
let graphicOptions = {
id: item.id,
attr: item,
position: [parseFloat(item.lng), parseFloat(item.lat)],
style: {
image: '/public/map/fire.png',
clampToGround: true,
scale: 0.8,
label: {
text: item.title,
font_size: 12,
color: '#ffffff',
pixelOffsetY: -36,
distanceDisplayCondition: true,
distanceDisplayCondition_far: 500000,
distanceDisplayCondition_near: 0,
},
},
},
popup: 'all',
// `<div class="marsTiltPanel marsTiltPanel-theme-red" style="font-size:12px;">
// <div class="marsTiltPanel-wrap">
// <div class="area">
// <div class="arrow-lt"></div>
// <div class="b-t"></div>
// <div class="b-r"></div>
// <div class="b-b"></div>
// <div class="b-l"></div>
// <div class="arrow-rb"></div>
// <div class="label-wrap">
// <div class="title"></div>
// <div class="label-content">
// <div class="data-li">
// <div class="data-label">${item.position}</div>
// </div>
// <div class="data-li">
// <div class="data-label"></div>
// <div class="data-value"><span id="lablYeWei" class="label-num">2025-2-11 12:00:00</span><span class="label-unit"></span>
// </div>
// </div>
// </div>
// </div>
// </div>
// <div class="b-t-l"></div>
// <div class="b-b-r"></div>
// </div>
// <div class="arrow" ></div>
// </div>`,
popupOptions: {
offsetY: -30,
template: "{content}",
horizontalOrigin: "Cesium.HorizontalOrigin.LEFT",
verticalOrigin: "Cesium.VerticalOrigin.CENTER",
},
}
popup: 'all',
// `<div class="marsTiltPanel marsTiltPanel-theme-red" style="font-size:12px;">
// <div class="marsTiltPanel-wrap">
// <div class="area">
// <div class="arrow-lt"></div>
// <div class="b-t"></div>
// <div class="b-r"></div>
// <div class="b-b"></div>
// <div class="b-l"></div>
// <div class="arrow-rb"></div>
// <div class="label-wrap">
// <div class="title"></div>
// <div class="label-content">
// <div class="data-li">
// <div class="data-label">${item.position}</div>
// </div>
// <div class="data-li">
// <div class="data-label"></div>
// <div class="data-value"><span id="lablYeWei" class="label-num">2025-2-11 12:00:00</span><span class="label-unit"></span>
// </div>
// </div>
// </div>
// </div>
// </div>
// <div class="b-t-l"></div>
// <div class="b-b-r"></div>
// </div>
// <div class="arrow" ></div>
// </div>`,
popupOptions: {
offsetY: -30,
template: '{content}',
horizontalOrigin: 'Cesium.HorizontalOrigin.LEFT',
verticalOrigin: 'Cesium.VerticalOrigin.CENTER',
},
};
let graphic = new mars3d.graphic.BillboardEntity(graphicOptions);
window.graphicLayer.addGraphic(graphic);
})
window.graphicLayer.on(mars3d.EventType.click,function(e){
handlerFireDetail(e.graphic.options.attr)
})
let graphic = new mars3d.graphic.BillboardEntity(graphicOptions);
window.graphicLayer.addGraphic(graphic);
});
}
window.graphicLayer.on(mars3d.EventType.click, function (e) {
handlerFireDetail(e.graphic.options.attr);
});
};
//
const handlerFireDetail = (item) => {
//
eventHandlerHook(
chartEditStore.getComponentList,
props.chartConfig.events.interactConfigEvents,
'click',
item
);
//
const handlerFireDetail = (item) => {
console.log(item);
//
eventHandlerHook(
chartEditStore.getComponentList,
props.chartConfig.events.interactConfigEvents,
'click',
item,
);
//
let bindEvents = props.chartConfig.events.interactConfigEvents
console.log("bindEvents",bindEvents);
for(let i=0;i<bindEvents.length;i++){
for(let j=0;j<bindEvents[i].movementList.length;j++){
EventBus.emit(bindEvents[i].movementList[j].elementId[j]+"dataupdate",item);
//
let bindEvents = props.chartConfig.events.interactConfigEvents;
console.log('bindEvents', bindEvents);
for (let i = 0; i < bindEvents.length; i++) {
for (let j = 0; j < bindEvents[i].movementList.length; j++) {
EventBus.emit(bindEvents[i].movementList[j].elementId[j] + 'dataupdate', item);
}
}
let graphic = window.graphicLayer.getGraphicById(item.id);
if(graphic){
window.globalMap.flyToGraphic(graphic,{radius:300});
}
}
}
let graphic = window.graphicLayer.getGraphicById(item.id);
if (graphic) {
window.globalMap.flyToGraphic(graphic, { radius: 300 });
}
};
</script>
<style lang="scss" scoped>
@include go('title-03') {
height: v-bind('h');
position: relative;
padding-top:10px;
scrollbar-width: none;
-ms-overflow-style: none;
.max-w{
width: 100%;
}
.column{
flex-direction: column;
}
.flex{
display: flex;
}
.jc-sb{
justify-content: space-between;
}
.jc-sa{
justify-content: space-around;
}
.jc-c{
justify-content: center;
}
.ai-c{
align-items: center;
}
.img{
width: 148px;
height: 16px;
}
.navsbox{
width: 92%;
margin-left: 4%;
height: 28px;
background: v-bind('navsBackground');
border-radius: 1px;
border: 1px solid #4FE985;
margin-bottom: 13px;
display: flex;
}
.navsli{
flex: 1;
height: 25px;
color: v-bind('navsColor');
font-size: v-bind('navsSize+"px"');
cursor: pointer;
@include go('title-03') {
height: v-bind('h');
position: relative;
}
.navsNum{
background: #F91B1B;
width: 20px;
height: 20px;
border-radius: 20px;
text-align: center;
line-height:20px;
color: #fff;
font-size: 8px;
position: absolute;
left: 60%;
top: 0;
margin-top: -10px;
}
.navsliactive{
color: v-bind('navsCheckColor');
font-size: v-bind('navsCheckSize+"px"');
background: v-bind('navsCheckBackground');
}
.sectionBox{
width: 92%;
height: calc(100% - 40px);
margin-left: 4%;
overflow: auto;
img{
width: 21px;
height: 21px;
padding-top: 10px;
scrollbar-width: none;
-ms-overflow-style: none;
.max-w {
width: 100%;
}
.timeicon{
width: 15px;
height: 15px;
margin-left: 3px;
.column {
flex-direction: column;
}
.flex {
display: flex;
}
.jc-sb {
justify-content: space-between;
}
.jc-sa {
justify-content: space-around;
}
.jc-c {
justify-content: center;
}
.ai-c {
align-items: center;
}
.img {
width: 148px;
height: 16px;
}
.navsbox {
width: 92%;
margin-left: 4%;
height: 28px;
background: v-bind('navsBackground');
border-radius: 1px;
border: 1px solid #4fe985;
margin-bottom: 13px;
display: flex;
}
.navsli {
flex: 1;
height: 25px;
color: v-bind('navsColor');
font-size: v-bind('navsSize+"px"');
cursor: pointer;
position: relative;
}
.navsNum {
background: #f91b1b;
width: 20px;
height: 20px;
border-radius: 20px;
text-align: center;
line-height: 20px;
color: #fff;
font-size: 8px;
position: absolute;
left: 60%;
top: 0;
margin-top: -10px;
}
.navsliactive {
color: v-bind('navsCheckColor');
font-size: v-bind('navsCheckSize+"px"');
background: v-bind('navsCheckBackground');
}
.sectionBox {
width: 92%;
height: calc(100% - 40px);
margin-left: 4%;
overflow: auto;
img {
width: 21px;
height: 21px;
}
.timeicon {
width: 15px;
height: 15px;
margin-left: 3px;
}
}
.sectionLi {
padding: 9px 12px;
height: 104px;
background: url('@/assets/images/chart/equipment/sectionbg.png');
background-size: 100% 100%;
}
.titleText {
color: v-bind('titleColor');
font-size: v-bind('titleSize+"px"');
}
.dataStyle {
font-size: 14px;
color: #cbe7cd;
}
.numStyle {
color: v-bind('datasColor');
font-size: v-bind('datasSize+"px"');
white-space: nowrap;
overflow: hidden; /* 隐藏溢出内容 :ml-search[overflow] */
text-overflow: ellipsis;
}
.desStyle {
color: v-bind('desColor');
font-size: v-bind('desSize+"px"');
}
.desImg {
margin-right: 10px;
}
.mr-2 {
margin-right: 20px;
}
.mr-1 {
margin-right: 6px;
}
.mt-1 {
margin-top: 8px;
}
}
.sectionLi{
padding: 9px 12px;
height: 104px;
background: url('@/assets/images/chart/equipment/sectionbg.png');
background-size: 100% 100%;
}
.titleText{
color: v-bind('titleColor');
font-size: v-bind('titleSize+"px"');
}
.dataStyle{
font-size: 14px;
color: #CBE7CD;
}
.numStyle{
color: v-bind('datasColor');
font-size: v-bind('datasSize+"px"');
white-space: nowrap;
overflow: hidden; /* 隐藏溢出内容 :ml-search[overflow] */
text-overflow: ellipsis;
}
.desStyle{
color: v-bind('desColor');
font-size: v-bind('desSize+"px"');
}
.desImg{
margin-right: 10px;
}
.mr-2{
margin-right: 20px;
}
.mr-1{
margin-right: 6px;
}
.mt-1{
margin-top: 8px;
}
}
</style>

View File

@ -0,0 +1,14 @@
import { PublicConfigClass } from '@/packages/public';
import { CreateComponentType } from '@/packages/index.d';
import { FlightControlConfig } from './index';
import cloneDeep from 'lodash/cloneDeep';
import { chartInitConfig } from '@/settings/designSetting';
export const option = {};
export default class Config extends PublicConfigClass implements CreateComponentType {
public key = FlightControlConfig.key;
public chartConfig = cloneDeep(FlightControlConfig);
public attr = { ...chartInitConfig, w: 370, h: 900, zIndex: -1 };
public option = cloneDeep(option);
}

View File

@ -0,0 +1,5 @@
<template>
<div> </div>
</template>
<script lang="ts" setup></script>
<style lang="scss" scoped></style>

View File

@ -0,0 +1,14 @@
import { ConfigType, PackagesCategoryEnum, ChartFrameEnum } from '@/packages/index.d';
import { ChatCategoryEnum, ChatCategoryEnumName } from '../../index.d';
export const FlightControlConfig: ConfigType = {
key: 'FlightControl',
chartKey: 'VFlightControl',
conKey: 'VCFlightControl',
title: '无人机',
category: ChatCategoryEnum.UAV,
categoryName: ChatCategoryEnumName.UAV,
package: PackagesCategoryEnum.UAVS,
chartFrame: ChartFrameEnum.STATIC,
image: 'text_gradient.png',
};

View File

@ -0,0 +1,850 @@
<template>
<div class="flight-control">
<div class="title"> 飞行控制 </div>
<div class="closeButton" @click="option.status.hide = true">
<img src="@/assets/images/chart/uav/close.png" alt="" />
</div>
<div class="button-group">
<button class="take-off" @click="takeOff"></button>
<button class="guided-flight" @click="flyTo"></button>
<button class="return-home" @click="returnVoyage"></button>
<button class="fly-to-point" @click="obtain"></button>
</div>
<div class="direction-control">
<div class="control-left">
<div class="control-left-center"> </div>
<div
class="control-left-top"
title="上升"
@mousedown="changeDRC('throttle', 'up', '上升')"
@mouseup="changeDRC('throttle', 'up', '')"
>
<img
src="@/assets/images/chart/uav/flight-top-active.png"
alt=""
v-if="selectName == '上升'"
/>
<img src="@/assets/images/chart/uav/flight-top.png" alt="" v-else />
</div>
<div
class="control-left-right"
title="右旋转"
@mousedown="changeDRC('yaw', 'up', '右旋转')"
@mouseup="changeDRC('yaw', 'up', '')"
>
<img
src="@/assets/images/chart/uav/flight-right-active.png"
alt=""
v-if="selectName == '右旋转'"
/>
<img src="@/assets/images/chart/uav/flight-right.png" alt="" v-else />
</div>
<div
class="control-left-bottom"
title="下降"
@mousedown="changeDRC('throttle', 'down', '下降')"
@mouseup="changeDRC('throttle', 'down', '')"
>
<img
src="@/assets/images/chart/uav/flight-bottom-active.png"
alt=""
v-if="selectName == '下降'"
/>
<img src="@/assets/images/chart/uav/flight-bottom.png" alt="" v-else />
</div>
<div
class="control-left-left"
title="左旋转"
@mousedown="changeDRC('yaw', 'down', '左旋转')"
@mouseup="changeDRC('yaw', 'down', '')"
>
<img
src="@/assets/images/chart/uav/flight-left-active.png"
alt=""
v-if="selectName == '左旋转'"
/>
<img src="@/assets/images/chart/uav/flight-left.png" alt="" v-else />
</div>
</div>
<div class="control-right">
<div class="control-left-center"> </div>
<div
class="control-left-top"
title="前进"
@mousedown="changeDRC('pitch', 'up', '前进')"
@mouseup="changeDRC('pitch', 'up', '')"
>
<img
src="@/assets/images/chart/uav/flight-top-active.png"
alt=""
v-if="selectName == '前进'"
/>
<img src="@/assets/images/chart/uav/flight-top.png" alt="" v-else />
</div>
<div
class="control-left-right"
title="右移"
@mousedown="changeDRC('roll', 'up', '右移')"
@mouseup="changeDRC('roll', 'up', '')"
>
<img
src="@/assets/images/chart/uav/flight-right-active.png"
alt=""
v-if="selectName == '右移'"
/>
<img src="@/assets/images/chart/uav/flight-right.png" alt="" v-else />
</div>
<div
class="control-left-bottom"
title="后退"
@mousedown="changeDRC('pitch', 'down', '后退')"
@mouseup="changeDRC('pitch', 'down', '')"
>
<img
src="@/assets/images/chart/uav/flight-bottom-active.png"
alt=""
v-if="selectName == '后退'"
/>
<img src="@/assets/images/chart/uav/flight-bottom.png" alt="" v-else />
</div>
<div
class="control-left-left"
title="左移"
@mousedown="changeDRC('roll', 'down', '左移')"
@mouseup="changeDRC('roll', 'down', '')"
>
<img
src="@/assets/images/chart/uav/flight-left-active.png"
alt=""
v-if="selectName == '左移'"
/>
<img src="@/assets/images/chart/uav/flight-left.png" alt="" v-else />
</div>
</div>
</div>
<div class="camera-title">
<button @click="cameraObtain"></button>
<button @click="singleShot">
<img src="@/assets/images/chart/uav/camera.png" alt="" />
单拍</button
>
</div>
<div class="camera-control">
<div class="camera-control-top">
<img class="camera-center" src="@/assets/images/chart/uav/camera-center.png" alt="" />
<div
class="control-left-top"
title="仰视"
@mousedown="changeCameraDRC('pitch_speed', 'up', '仰视')"
@mouseup="changeCameraDRC('pitch_speed', 'up', '')"
>
<img
src="@/assets/images/chart/uav/camera-top-active.png"
alt=""
v-if="selectCameraName == '仰视'"
/>
<img src="@/assets/images/chart/uav/camera-top.png" alt="" v-else />
</div>
<div
class="control-left-right"
title="右移"
@mousedown="changeCameraDRC('yaw_speed', 'up', '右移')"
@mouseup="changeCameraDRC('yaw_speed', 'up', '')"
>
<img
src="@/assets/images/chart/uav/camera-right-active.png"
alt=""
v-if="selectCameraName == '右移'"
/>
<img src="@/assets/images/chart/uav/camera-right.png" alt="" v-else />
</div>
<div
class="control-left-bottom"
title="俯视"
@mousedown="changeCameraDRC('pitch_speed', 'down', '俯视')"
@mouseup="changeCameraDRC('pitch_speed', 'down', '')"
>
<img
src="@/assets/images/chart/uav/camera-bottom-active.png"
alt=""
v-if="selectCameraName == '俯视'"
/>
<img src="@/assets/images/chart/uav/camera-bottom.png" alt="" v-else />
</div>
<div
class="control-left-left"
title="左移"
@mousedown="changeCameraDRC('yaw_speed', 'down', '左移')"
@mouseup="changeCameraDRC('yaw_speed', 'down', '')"
>
<img
src="@/assets/images/chart/uav/camera-left-active.png"
alt=""
v-if="selectCameraName == '左移'"
/>
<img src="@/assets/images/chart/uav/camera-left.png" alt="" v-else />
</div>
<div class="zoom">
<a-slider
v-model:value="zoomVale"
:max="maxval"
:min="2"
:marks="marks"
@change="cameraZoom"
/>
</div>
</div>
</div>
<div class="ai-title">
<button>开启AI智能巡检</button>
</div>
<div class="ai-control">
<div class="no-picture">
<img src="@/assets/images/chart/uav/no-picture.png" alt="" />
<span>暂无画面 请您耐心等待</span>
<span>......</span>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import {
computed,
PropType,
toRefs,
watch,
reactive,
ref,
onMounted,
onUnmounted,
createVNode,
} from 'vue';
import { CreateComponentType } from '@/packages/index.d';
import {
getClient,
createConnection,
clientSubscribe,
destroyConnection,
createSeizeConnection,
} from '@/utils/mqtt';
import {
servicesTopic,
services_replyTopic,
drcDownTopic,
eventsTopicSubscribe,
drcUpTopic,
errorName,
setTopic,
} from '@/utils/debugging/remote';
import { buildGUID } from '@/utils/uuid';
import { airPortStore } from '@/store/modules/airport';
import { useMessage } from '@/hooks/web/useMessage';
import {
drcDownTopicReize,
eventsTopicSubscribeReize,
servicesTopicReize,
services_replyTopicReize,
} from '@/utils/debugging/events';
import { EventBus } from '@/utils/eventBus';
import {
getRedisUser,
addOrUpdateRedisUser,
getLockedClients,
} from '@/api/demo/airportMaintenance';
import { useUserStore } from '@/store/modules/user';
import { timestampToFormattedDate } from '@/utils/index';
const { createMessage } = useMessage();
const userStore = useUserStore();
const userInfo = userStore.getUserInfo;
const props = defineProps({
chartConfig: {
type: Object as PropType<CreateComponentType>,
required: true,
},
});
const option = reactive({
status: props.chartConfig.status,
});
const airPortStoreVal = airPortStore();
const uav = airPortStoreVal.getUAV;
const bid = buildGUID();
const selectName = ref('');
const selectCameraName = ref('');
const seq = ref(1);
const longPressTimer = ref();
const longPressInterval = ref();
const longPressDuration = ref(1000); //
const uavStatus = ref();
const { w, h, x, y } = toRefs(props.chartConfig.attr);
const zoomVale = ref(2);
const maxval = ref(20);
const marks = ref<Record<number, any>>({
2: {
style: {
color: '#f50',
},
label: createVNode('strong', {}, '2'),
},
10: {
style: {
color: '#f50',
},
label: createVNode('strong', {}, '10'),
},
20: {
style: {
color: '#f50',
},
label: createVNode('strong', {}, '20'),
},
});
const flightGrab = ref(false);
const redisUser = ref({});
const cameraZoom = () => {};
//
const takeOff = () => {};
//
const flyTo = () => {};
//
const returnVoyage = () => {
servicesTopic({
bid: buildGUID(),
method: 'return_home',
tid: buildGUID(),
timestamp: new Date().getTime(),
data: {},
});
};
//
const obtain = () => {
//
servicesTopic({
bid: bid,
method: 'flight_authority_grab',
tid: buildGUID(),
timestamp: new Date().getTime(),
data: {},
});
//
servicesTopic({
bid: bid,
method: 'payload_authority_grab',
tid: buildGUID(),
timestamp: new Date().getTime(),
data: {
payload_index: uav.camera_index,
},
});
services_replyTopic();
changeRedisUser(true);
};
//
const changeDRC = (type, value, name) => {
selectName.value = name;
if (name !== '') {
console.log('鼠标按下');
if (!flightGrab.value) {
createMessage.warning('请先获取飞行器控制权');
return;
}
let isLongPress = false;
longPressTimer.value = setTimeout(() => {
console.log('长按事件触发!');
isLongPress = true;
longPressInterval.value = setInterval(() => {
seq.value = seq.value + 1;
let querys = getDRCFlightQuery(type, value, seq);
drcDownTopicReize(querys);
createMessage.info(name + '指令已发送');
}, 1000);
}, longPressDuration.value);
if (isLongPress) {
isLongPress = false;
return;
}
seq.value = seq.value + 1;
let querys = getDRCFlightQuery(type, value, seq);
drcDownTopicReize(querys);
createMessage.info(name + '指令已发送');
} else {
if (longPressTimer.value) {
clearTimeout(longPressTimer.value);
longPressTimer.value = null;
console.log('清除延时器');
}
if (longPressInterval.value) {
clearTimeout(longPressInterval.value);
longPressInterval.value = null;
console.log('清除定时器');
}
console.log('鼠标松开');
}
};
const getDRCFlightQuery = (type, value, seq) => {
let data = {
roll: 1024,
pitch: 1024,
throttle: 1024,
yaw: 1024,
gimbal_pitch: 1024,
};
if (value == 'up') {
data[type] = 1684;
} else {
data[type] = 364;
}
const querys = {
seq: seq.value,
method: 'stick_control',
data: data,
bid: buildGUID(),
tid: buildGUID(),
timestamp: new Date().getTime(),
};
console.log(querys);
return querys;
};
//
const changeCameraDRC = (type, val, name) => {
selectCameraName.value = name;
if (name !== '') {
if (!flightGrab.value) {
createMessage.warning('请先获取相机控制权');
return;
}
let isLongPress = false;
longPressTimer.value = setTimeout(() => {
console.log('长按事件触发!');
isLongPress = true;
longPressInterval.value = setInterval(() => {
let querys = getCameraDRCFlightQuery(type, val);
servicesTopicReize(querys);
createMessage.info(name + '指令已发送');
}, 2000);
}, longPressDuration.value);
if (isLongPress) {
isLongPress = false;
return;
}
//
let querys = getCameraDRCFlightQuery(type, val);
servicesTopicReize(querys);
createMessage.info(name + '指令已发送');
} else {
if (longPressTimer.value) {
clearTimeout(longPressTimer.value);
longPressTimer.value = null;
console.log('清除延时器');
}
if (longPressInterval.value) {
clearTimeout(longPressInterval.value);
longPressInterval.value = null;
console.log('清除定时器');
}
console.log('鼠标松开');
}
};
const getCameraDRCFlightQuery = (type, val) => {
let data = {
payload_index: uav.camera_index,
locked: true,
pitch_speed: 0,
yaw_speed: 0,
};
if (val == 'up') {
data[type] = 8;
} else {
data[type] = -8;
}
const querys = {
bid: buildGUID(),
method: 'camera_screen_drag',
tid: buildGUID(),
timestamp: new Date().getTime(),
data: data,
};
console.log(querys);
return querys;
};
//
const cameraObtain = () => {
//
servicesTopic({
bid: bid,
method: 'flight_authority_grab',
tid: buildGUID(),
timestamp: new Date().getTime(),
data: {},
});
//
servicesTopic({
bid: bid,
method: 'payload_authority_grab',
tid: buildGUID(),
timestamp: new Date().getTime(),
data: {
payload_index: uav.camera_index,
},
});
services_replyTopic();
changeRedisUser(true);
};
//
const singleShot = () => {
if (!flightGrab.value) {
createMessage.warning('请先获取相机控制权');
return;
}
//
servicesTopicReize({
bid: buildGUID(),
method: 'camera_photo_take',
tid: buildGUID(),
timestamp: new Date().getTime(),
data: {
payload_index: uav.camera_index,
},
});
services_replyTopicReize();
};
//redis
const changeRedisUser = (val: boolean) => {
const querys = redisUser.value;
querys.isLock = val;
querys.connectTime = timestampToFormattedDate(new Date().getTime());
addOrUpdateRedisUser(querys);
};
onMounted(() => {
// mqtt
createConnection();
// mqtt
getRedisUser(userInfo.id).then((res) => {
if (res) {
redisUser.value = res;
}
});
setTimeout(() => {
//
getClient().on('message', (topic, message) => {
const rs = JSON.parse(message);
if (rs.data.sub_device) {
uavStatus.value = rs.data.sub_device.device_online_status;
}
if (rs.method == 'camera_photo_take') {
if (rs.data.result == 0) {
createMessage.success('拍照成功');
} else {
flightGrab.value = false;
createMessage.error('拍照失败,' + errorName(rs.data.result));
}
}
if (rs.method == 'flight_authority_grab' && rs.bid == bid) {
if (rs.data.result == 0) {
flightGrab.value = true;
createSeizeConnection();
createMessage.success('相机控制权获取成功');
} else {
flightGrab.value = false;
createMessage.error('相机控制权获取失败,' + errorName(rs.data.result));
}
}
});
}, 1000);
//
EventBus.on(props.chartConfig.id + 'dataupdate', (data) => {
console.log('dataupdate', data);
});
});
</script>
<style lang="scss" scoped>
.flight-control {
width: v-bind('`${w}px`');
height: v-bind('`${h}px`');
//
-webkit-user-select: none; /* Safari */
-moz-user-select: none; /* Firefox */
-ms-user-select: none; /* IE/Edge */
user-select: none;
background-image: url('@/assets/images/chart/uav/flight-bg.png');
background-size: 100% 100%;
overflow: hidden;
}
.title {
color: #58ff95;
font-size: 20px;
position: absolute;
top: 16px;
left: 16px;
}
.closeButton {
position: absolute;
right: 10px;
top: 10px;
img {
width: 30px;
}
}
.button-group {
margin-top: 13%;
margin-left: 10%;
button {
margin: 10px;
width: 120px;
height: 36px;
color: #fff;
display: inline-block;
}
.take-off {
background: #00b155;
box-shadow: 0px 10px 30px 0px rgba(0, 0, 6, 0.15);
border-radius: 15px 15px 0px 15px;
border: 1px solid #00ae4a;
}
.guided-flight {
background: #ff9538;
box-shadow: 0px 10px 30px 0px rgba(0, 0, 6, 0.15);
border-radius: 15px 15px 15px 0px;
}
.return-home {
background: none;
box-shadow: 0px 10px 30px 0px rgba(0, 0, 6, 0.15);
border-radius: 15px 0px 15px 15px;
border: 1px solid #00ae4a;
}
.fly-to-point {
background: #0c29b2;
box-shadow: 0px 10px 30px 0px rgba(0, 0, 6, 0.15);
border-radius: 0px 15px 15px 15px;
border: none;
}
}
.direction-control {
width: 90%;
margin-left: 5%;
height: 160px;
background: #0c2e25;
box-shadow: 0px 10px 30px 0px rgba(0, 0, 6, 0.15);
border-radius: 10px;
display: flex;
}
.control-left {
width: 40%;
height: 100%;
margin-left: 10%;
position: relative;
.control-left-center {
width: 46px;
height: 46px;
border-radius: 50%;
// background: linear-gradient(148deg, #374249 0%, #151c20 100%);
// box-shadow:
// 0px 10px 30px 0px rgba(0, 0, 6, 0.15),
// 0px 2px 4px 0px rgba(0, 0, 0, 0.5);
// border-image: linear-gradient(134deg, rgba(0, 177, 85, 1), rgba(2, 87, 43, 1)) 1 1;
border: 1px solid #00b155;
position: absolute;
top: 36%;
left: 29%;
}
img {
width: 68px;
}
.control-left-top {
position: absolute;
left: 20%;
top: 12%;
}
.control-left-bottom {
position: absolute;
left: 20%;
bottom: 11%;
}
.control-left-left {
position: absolute;
left: -1%;
top: 30%;
img {
width: 40px;
}
}
.control-left-right {
position: absolute;
right: 6%;
top: 30%;
img {
width: 40px;
}
}
}
.control-right {
width: 40%;
height: 100%;
margin-left: 2%;
position: relative;
.control-left-center {
width: 46px;
height: 46px;
border-radius: 50%;
// background: linear-gradient(148deg, #374249 0%, #151c20 100%);
// box-shadow:
// 0px 10px 30px 0px rgba(0, 0, 6, 0.15),
// 0px 2px 4px 0px rgba(0, 0, 0, 0.5);
// border-image: linear-gradient(134deg, rgba(0, 177, 85, 1), rgba(2, 87, 43, 1)) 1 1;
border: 1px solid #00b155;
position: absolute;
top: 36%;
left: 29%;
}
img {
width: 68px;
}
.control-left-top {
position: absolute;
left: 20%;
top: 12%;
}
.control-left-bottom {
position: absolute;
left: 20%;
bottom: 11%;
}
.control-left-left {
position: absolute;
left: -1%;
top: 30%;
img {
width: 40px;
}
}
.control-left-right {
position: absolute;
right: 6%;
top: 30%;
img {
width: 40px;
}
}
}
.camera-title {
display: flex;
align-items: center;
justify-content: space-between;
margin: 16px 4%;
button:first-child {
border: 1px solid #00ae4a;
background: none;
color: #fff;
border-radius: 10px;
padding: 6px 10px;
}
button:last-child {
background: #00b155;
color: #fff;
border-radius: 10px;
padding: 6px 14px;
display: flex;
align-items: center;
justify-content: space-between;
img {
width: 16px;
}
}
}
.camera-control {
width: 90%;
margin-left: 5%;
background: #0c2e25;
box-shadow: 0px 10px 30px 0px rgba(0, 0, 6, 0.15);
border-radius: 10px;
padding-bottom: 30px;
.camera-control-top {
position: relative;
height: 180px;
.camera-center {
position: absolute;
top: 4%;
left: 25%;
width: 40%;
}
img {
width: 54px;
}
.control-left-top {
position: absolute;
left: 37%;
top: 20%;
}
.control-left-bottom {
position: absolute;
left: 37%;
bottom: 38%;
}
.control-left-left {
position: absolute;
left: 34%;
top: 28%;
img {
width: 24px;
}
}
.control-left-right {
position: absolute;
right: 43.5%;
top: 28%;
img {
width: 24px;
}
}
}
.zoom {
position: absolute;
bottom: -6%;
left: 5%;
width: 90%;
height: 20px;
}
}
::v-deep .ant-slider-rail {
background: #0f4c2d;
}
::v-deep .ant-slider-track {
background: #07b35a;
}
::v-deep .ant-slider-mark-text {
color: #fff !important;
}
.ai-title {
display: flex;
align-items: center;
justify-content: space-between;
margin: 16px 4%;
button:first-child {
border: 1px solid #00ae4a;
background: none;
color: #fff;
border-radius: 10px;
padding: 6px 10px;
}
}
.ai-control {
width: 90%;
background: #0c2e25;
box-shadow: 0px 10px 30px 0px rgba(0, 0, 6, 0.15);
border-radius: 10px;
border: 1px solid #00611a;
margin-left: 5%;
.no-picture {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
color: #fff;
margin-top: 6%;
}
}
</style>

View File

@ -0,0 +1,14 @@
import { PublicConfigClass } from '@/packages/public';
import { CreateComponentType } from '@/packages/index.d';
import { PatrolConfig } from './index';
import cloneDeep from 'lodash/cloneDeep';
import { chartInitConfig } from '@/settings/designSetting';
export const option = {};
export default class Config extends PublicConfigClass implements CreateComponentType {
public key = PatrolConfig.key;
public chartConfig = cloneDeep(PatrolConfig);
public attr = { ...chartInitConfig, w: 110, h: 30, zIndex: -1 };
public option = cloneDeep(option);
}

View File

@ -0,0 +1,5 @@
<template>
<div> </div>
</template>
<script lang="ts" setup></script>
<style lang="scss" scoped></style>

View File

@ -0,0 +1,14 @@
import { ConfigType, PackagesCategoryEnum, ChartFrameEnum } from '@/packages/index.d';
import { ChatCategoryEnum, ChatCategoryEnumName } from '../../index.d';
export const PatrolConfig: ConfigType = {
key: 'Patrol',
chartKey: 'VPatrol',
conKey: 'VCPatrol',
title: '无人机巡查',
category: ChatCategoryEnum.UAV,
categoryName: ChatCategoryEnumName.UAV,
package: PackagesCategoryEnum.UAVS,
chartFrame: ChartFrameEnum.STATIC,
image: 'text_gradient.png',
};

View File

@ -0,0 +1,151 @@
<template>
<div
class="patrol-container"
@click="clickBtn"
@dblclick="dblclickBtn"
@contextmenu="rightclickBtn"
@mouseenter="mouseenterBtn"
@mouseleave="mouseleaveBtn"
>
<img src="@/assets/images/chart/uav/uav.png" alt="" />
<span>无人机巡查</span>
</div>
</template>
<script lang="ts" setup>
import {
computed,
PropType,
toRefs,
watch,
reactive,
ref,
onMounted,
onUnmounted,
createVNode,
} from 'vue';
import { CreateComponentType } from '@/packages/index.d';
import { eventHandlerHook } from '@/hooks/eventHandler.hook';
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore';
import { EventBus } from '@/utils/eventBus';
import { uuid, buildGUID } from '@/utils/uuid';
import { servicesTopic, services_replyTopic } from '@/utils/debugging/remote';
import {
getClient,
createConnection,
clientSubscribe,
destroyConnection,
createSeizeConnection,
} from '@/utils/mqtt';
const props = defineProps({
chartConfig: {
type: Object as PropType<CreateComponentType>,
required: true,
},
});
const { w, h, x, y } = toRefs(props.chartConfig.attr);
const chartEditStore = useChartEditStore();
// 线
const deliveryData = ref();
const clickBtn = (val) => {
console.log('value000', val);
eventHandlerHook(
chartEditStore.getComponentList,
props.chartConfig.events.interactConfigEvents,
'click',
val,
);
console.log(deliveryData.value);
//
const data = {
flight_id: uuid(14, 14),
target_latitude: Number(deliveryData.value.lat),
target_longitude: Number(deliveryData.value.lng),
target_height: 200,
security_takeoff_height: 100,
rth_altitude: 115,
rth_mode: 1,
max_speed: 10,
commander_flight_mode: 1,
rc_lost_action: 2,
commander_mode_lost_action: 1,
commander_flight_height: 115.0,
flight_safety_advance_check: 1,
};
const querys = {
bid: buildGUID(),
data: data,
tid: buildGUID(),
timestamp: new Date().getTime(),
method: 'takeoff_to_point',
};
console.log(querys);
//
// servicesTopicReize(querys);
// services_replyTopicReize();
//
servicesTopic(querys);
services_replyTopic();
};
const dblclickBtn = (val) => {
eventHandlerHook(
chartEditStore.getComponentList,
props.chartConfig.events.interactConfigEvents,
'dblclick',
val,
);
};
const rightclickBtn = (event) => {
event.preventDefault(); //
eventHandlerHook(
chartEditStore.getComponentList,
props.chartConfig.events.interactConfigEvents,
'rightclick',
);
};
const mouseenterBtn = (val) => {
eventHandlerHook(
chartEditStore.getComponentList,
props.chartConfig.events.interactConfigEvents,
'mousein',
val,
);
};
const mouseleaveBtn = (val) => {
eventHandlerHook(
chartEditStore.getComponentList,
props.chartConfig.events.interactConfigEvents,
'mouseout',
val,
);
};
onMounted(() => {
//
EventBus.on(props.chartConfig.id + 'dataupdate', (data) => {
console.log('dataupdate', data);
deliveryData.value = data;
});
createConnection();
});
</script>
<style lang="scss" scoped>
.patrol-container {
width: v-bind('`${w}px`');
height: v-bind('`${h}px`');
background: linear-gradient(180deg, #182b20 0%, #136c3d 100%);
border-radius: 2px;
border: 1px solid #8ff4b1;
display: flex;
align-items: center;
justify-content: center;
font-size: 14px;
img {
width: 20px;
}
span {
margin-left: 6px;
color: #fff;
}
}
</style>

View File

@ -0,0 +1,4 @@
import { FlightControlConfig } from './FlightControl/index';
import { PatrolConfig } from './Patrol/index';
export default [FlightControlConfig, PatrolConfig];

View File

@ -0,0 +1,7 @@
export enum ChatCategoryEnum {
UAV = 'Uav',
}
export enum ChatCategoryEnumName {
UAV = '无人机',
}

View File

@ -0,0 +1,3 @@
import Uav from './Uav';
export const UAVList = [...Uav];

View File

@ -171,11 +171,11 @@ export interface PublicConfigType {
}[];
interactConfigEvents: {}[];
};
mouseSetting:{
mouseSetting: {
mouseEventClose: boolean;
mouseSelectClose: boolean;
mouseCursor: string;
}
};
}
export interface CreateComponentType extends PublicConfigType, requestConfig {
@ -213,7 +213,8 @@ export enum PackagesCategoryEnum {
ZHIKU = 'Zhiku',
EQUIPMENT = 'Equipment',
TASKS = 'Tasks',
XUNCHAGUIJI= 'XunChaGuiJi'
XUNCHAGUIJI = 'XunChaGuiJi',
UAVS = 'Uav',
}
// 包分类名称
@ -233,7 +234,8 @@ export enum PackagesCategoryName {
ZHIKU = '智库',
EQUIPMENT = '设备',
TASKS = '任务',
XUNCHAGUIJI = '巡查'
XUNCHAGUIJI = '巡查',
UAVS = '无人机',
}
// 获取组件
@ -260,4 +262,5 @@ export type PackagesType = {
[PackagesCategoryEnum.EQUIPMENT]: ConfigType[];
[PackagesCategoryEnum.TASKS]: ConfigType[];
[PackagesCategoryEnum.XUNCHAGUIJI]: ConfigType[];
[PackagesCategoryEnum.UAVS]: ConfigType[];
};

View File

@ -13,7 +13,7 @@ import { ZhikuList } from '@/packages/components/Zhiku/index';
import { EquipmentList } from '@/packages/components/Equipment/index';
import { TasksList } from '@/packages/components/Tasks/index';
import { XunChaGuiJiList } from '@/packages/components/XunChaGuiJi/index';
import { UAVList } from '@/packages/components/Uav/index';
import {
PackagesCategoryEnum,
@ -60,18 +60,21 @@ export let packagesList: PackagesType = {
[PackagesCategoryEnum.ZHIKU]: ZhikuList,
[PackagesCategoryEnum.EQUIPMENT]: EquipmentList,
[PackagesCategoryEnum.TASKS]: TasksList,
[PackagesCategoryEnum.UAVS]: UAVList,
};
// 组件缓存, 可以大幅度提升组件加载速度
const componentCacheMap = new Map<string, any>();
const loadConfig = (packageName: string, categoryName: string, keyName: string) => {
const key = packageName + categoryName + keyName;
console.log('loadConfig', key);
if (!componentCacheMap.has(key)) {
componentCacheMap.set(
key,
import(`./components/${packageName}/${categoryName}/${keyName}/config.ts`),
);
}
console.log('loadConfig', componentCacheMap.get(key));
return componentCacheMap.get(key);
};
@ -88,6 +91,7 @@ export const createComponent = async (targetData: ConfigType) => {
return new redirectChart.default();
}
const chart = await loadConfig(targetData.package, category, key);
console.log('chart', chart);
return new chart.default();
};

View File

@ -0,0 +1,67 @@
import { defineStore } from 'pinia';
export const airPortStore = defineStore({
id: 'airport',
state: () => ({
airport: {
sn: null,
camera_index: '165-0-7',
video_index: 'normal-0',
video_id: '8UUXN5400A079H/165-0-7/normal-0',
},
uav: {
sn: null,
camera_index: '99-0-0',
video_index: 'normal-0',
video_id: '1581F8HGX254V00A0BUY/99-0-0/normal-0',
},
liveInfo: {
rtmp: 'rtmp://175.27.168.120:6019/live/',
url: 'http://175.27.168.120:6012/live/',
// rtmp: 'rtmp://box.wisestcity.com:1935/live/',
// url: 'http://box.wisestcity.com:8081/live/',
// rtmp: 'http://175.27.168.120:5005/rtc/v1/whip/?app=live&stream=',
// url: 'http://175.27.168.120:5005/rtc/v1/whep/?app=live&stream=',
},
gateway: null,
project: null,
taskId: null,
}),
getters: {
getAirport(state) {
return state.airport;
},
getUAV(state) {
return state.uav;
},
getLiveInfo(state) {
return state.liveInfo;
},
getGateway(state) {
return state.gateway;
},
getProject(state) {
return state.project;
},
getTaskId(state) {
return state.taskId;
},
},
actions: {
setAirPort(item: any, value: any) {
this.airport[item] = value;
},
setUAV(item: any, value: any) {
this.uav[item] = value;
},
setGateway(value: any) {
this.gateway = value;
},
setProject(value: any) {
this.project = value;
},
setTaskId(value: any) {
this.taskId = value;
},
},
});

View File

@ -0,0 +1,447 @@
{
"error_code": {
"312014": "设备升级中,请勿重复操作",
"312015": "机场:{dock_org_name} 业务繁忙无法进行设备升级,请等待机场处于空闲中后再试",
"312016": "升级失败,机场和飞行器图传链路异常,请重启机场和飞行器后重试",
"312022": "飞行器开机失败或未连接,请检查飞行器是否在舱内,是否安装电池,机场和飞行器是否已对频",
"312023": "推杆闭合失败无法升级飞行器,请检查急停按钮是否被按下,推杆是否有异物卡住",
"312027": "升级失败,机场未检测到飞行器",
"312028": "升级失败,设备升级过程中设备被重启",
"312029": "设备重启中无法进行设备升级,请等待设备重启完成后重试",
"312030": "升级失败,飞行器增强图传开启后无法升级,请关闭飞行器增强图传后重试",
"312704": "设备电量过低请充电至20%以上后重试",
"314000": "设备当前无法支持该操作,建议检查设备当前工作状态",
"314001": "飞行任务下发失败,请稍后重试",
"314002": "飞行任务下发失败,请稍后重试",
"314003": "航线文件格式不兼容,请检查航线文件是否正确",
"314005": "飞行任务下发失败,请稍后重试或重启机场后重试",
"314006": "飞行器初始化失败,请重启机场后重试",
"314007": "机场传输航线至飞行器失败,请重启机场后重试",
"314008": "飞行器起飞前准备超时,请重启机场后重试",
"314009": "飞行器初始化失败,请重启机场后重试",
"314010": "航线执行失败,请重启机场后重试",
"314011": "机场系统异常,无法获取飞行任务执行结果",
"314012": "飞行器起飞前准备失败,无法执行飞行任务,请重启机场后重试",
"314013": "飞行任务下发失败,机场无法获取到本次飞行任务的航线,无法执行飞行任务,请稍后重试",
"314014": "机场系统异常,飞行任务执行失败,请稍后重试",
"314015": "机场传输精准复拍航线至飞行器失败,无法执行飞行任务,请稍后重试或重启机场后重试",
"314016": "航线文件解析失败,无法执行飞行任务,请检查航线文件",
"314017": "航线文件解析失败,请检查航线后再试",
"314018": "飞行器 RTK 定位异常,无法执行飞行任务,请稍后重试或重启机场后重试",
"314019": "飞行器 RTK 收敛失败,无法执行飞行任务,请稍后重试或重启机场后重试",
"314020": "飞行器不在停机坪正中间或飞行器朝向不正确,无法执行飞行任务,请检查飞行器位置和朝向",
"314021": "飞行器 RTK 定位异常,无法执行飞行任务,请稍后重试或重启机场后重试",
"314024": "进离场航线下发失败,请稍后重试或重启机场后重试",
"314025": "RTK收敛超时用户手动取消任务",
"314200": "任务失败,由于机场网络断开,飞行器已自动返航,请确保机场已连接网络后再试",
"315000": "机场通信异常,请重启机场后重试",
"315001": "机场通信异常,请远程开启飞机并等待 1min 后,再次下发任务重试",
"315002": "机场通信异常,请重启机场后重试",
"315003": "机场通信异常,请重启机场后重试",
"315004": "任务失败,请等待两个机场都空闲后,再次下发任务重试",
"315005": "机场通信异常,请重启机场后重试",
"315006": "机场通信异常,请重启机场后重试",
"315007": "机场通信异常,请将机场升级到最新版本或重启机场后重试",
"315008": "降落机场和起飞机场标定信息不一致,请确认两个机场均链路通畅且使用了相同的网络信息标定",
"315009": "机场通信异常,请重启机场后重试",
"315010": "无法停止飞行任务,请稍后重试,如果仍报错请联系大疆售后",
"315011": "无法停止飞行任务,请稍后重试,如果仍报错请联系大疆售后",
"315012": "无法停止飞行任务,请稍后重试,如果仍报错请联系大疆售后",
"315013": "飞行任务下发失败,请稍后重试,如果仍报错请联系大疆售后",
"315014": "当前任务类型不支持设置返航点",
"315015": "返航点设置失败,请稍后重试,如果仍报错请联系大疆售后",
"315016": "飞行任务下发失败,请稍后重试,如果仍报错请联系大疆售后",
"315017": "飞行任务下发失败,请稍后重试,如果仍报错请联系大疆售后",
"315018": "任务失败,请等待两个机场都空闲后,再次下发任务重试",
"315019": "设备部署位置不佳,无法执行蛙跳任务,请选择其它机场再试",
"315050": "机场系统异常,请重启机场后重试",
"315051": "任务失败,请重启机场并再次下发任务后重试,如果仍报错请联系大疆售后",
"315052": "机场位置未收敛,请等待一段时间后重试",
"315053": "任务失败,请重启机场并再次下发任务后重试,如果仍报错请联系大疆售后",
"315054": "任务失败,请重启机场并再次下发任务后重试,如果仍报错请联系大疆售后",
"315055": "任务失败,请重启机场并再次下发任务后重试,如果仍报错请联系大疆售后",
"315056": "任务失败,请重启机场并再次下发任务后重试,如果仍报错请联系大疆售后",
"315057": "任务失败,请重启机场并再次下发任务后重试,如果仍报错请联系大疆售后",
"315058": "任务失败,请重启机场并再次下发任务后重试,如果仍报错请联系大疆售后",
"315059": "任务失败,请重启机场并再次下发任务后重试,如果仍报错请联系大疆售后",
"315060": "任务失败,请重启机场并再次下发任务后重试,如果仍报错请联系大疆售后",
"315061": "任务失败,请重启机场并再次下发任务后重试,如果仍报错请联系大疆售后",
"315062": "任务失败,请重启机场并再次下发任务后重试,如果仍报错请联系大疆售后",
"315063": "任务失败,请重启机场并再次下发任务后重试,如果仍报错请联系大疆售后",
"315064": "任务失败,请重启机场并再次下发任务后重试,如果仍报错请联系大疆售后",
"315065": "任务失败,请重启机场并再次下发任务后重试,如果仍报错请联系大疆售后",
"316001": "飞行器参数配置失败,请重启机场后重试",
"316002": "飞行器参数配置失败,请重启机场后重试",
"316003": "飞行器参数配置失败,请重启机场后重试",
"316004": "飞行器参数配置失败,请重启机场后重试",
"316005": "飞行器 RTK 收敛失败,无法执行飞行任务,请重启机场后重试",
"316006": "任务超时,飞行器已丢失或降落时机场未开启舱盖或展开推杆,飞行器无法降落回机场,请尽快至机场部署现场检查飞行器状况",
"316007": "飞行器初始化失败,请重启机场后重试",
"316008": "机场获取飞行器控制权失败,无法执行飞行任务,请确认遥控器未锁定控制权",
"316009": "飞行器电量低于30%无法执行飞行任务请充电后重试建议电量≥50%",
"316010": "机场未检测到飞行器,无法执行飞行任务,请检查舱内是否有飞行器,机场与飞行器是否已对频,或重启机场后重试",
"316011": "飞行器降落位置偏移过大,请检查飞行器是否需要现场摆正",
"316012": "飞行器起飞前准备失败,无法执行飞行任务,请重启机场后重试",
"316013": "飞行器起飞前准备失败,无法执行飞行任务,请重启机场后重试",
"316014": "飞行器起飞前准备失败,无法执行飞行任务,请重启机场后重试",
"316015": "飞行器 RTK 收敛位置距离机场过远,无法执行飞行任务,请重启机场后重试",
"316016": "飞行器降落至机场超时,可能是机场与飞行器断连导致,请通过直播查看飞行器是否降落至舱内",
"316017": "获取飞行器媒体数量超时,可能是机场与飞行器断连导致,请通过直播查看飞行器是否降落至舱内",
"316018": "飞行任务执行超时,可能是机场与飞行器断连导致,请通过直播查看飞行器是否降落至舱内",
"316019": "机场系统错误,无法执行飞行任务,请稍后重试",
"316020": "飞行器使用的 RTK 信号源错误,请稍后重试",
"316021": "飞行器 RTK 信号源检查超时,请稍后重试",
"316022": "飞行器无法执行返航指令,请检查飞行器是否已开机,机场与飞行器是否已断连,请确认无以上问题后重试",
"316023": "飞行器无法执行返航指令,飞行器已被 B 控接管,请在 B 控操控飞行器,或关闭 B 控后重试",
"316024": "飞行器执行返航指令失败,请检查飞行器是否已起飞,确认飞行器已起飞后请重试",
"316025": "飞行器参数配置失败,请稍后重试或重启机场后重试",
"316026": "机场急停按钮被按下,无法执行飞行任务,请释放急停按钮后重试",
"316027": "飞行器参数配置超时,请稍后重试或重启机场后重试",
"316029": "机场急停按钮被按下,飞行器将飞往备降点降落,请立即检查飞行器是否已安全降落并将飞行器放回至机场",
"316032": "获取电池数据超时,请稍后重试或重启飞行器后重试",
"316033": "飞行器电池循环次数过高,为保证飞行安全,已自动终止任务,建议更换该电池",
"316034": "无法起飞,飞行器固件版本与机场固件版本不匹配,为保证飞行安全请升级固件后再试",
"316035": "进离场航线下发失败,请确保设备固件为最新版本后重新下发任务,如果持续报错,请联系大疆售后。",
"316050": "飞行器因电量过低在舱外降落,请立即检查飞行器是否已安全降落并将飞行器放回至机场",
"316051": "飞行任务异常,飞行器在舱外降落,请立即检查飞行器是否已安全降落并将飞行器放回至机场",
"316052": "飞行任务异常,飞行器将飞往备降点降落,请立即检查飞行器是否已安全降落并将飞行器放回至机场",
"316053": "用户已操控飞行器降落,请立即检查飞行器是否已安全降落并将飞行器放回至机场",
"316100": "获取相机概要信息失败,请重试",
"316101": "设置相机为单拍模式失败,请重试",
"316102": "关闭相机水印失败,请重试",
"316103": "设置测光模式到平均测光失败,请重试",
"316104": "切换镜头到广角镜头失败,请重试",
"316105": "设置相机存储照片失败,请重试",
"316106": "红外变焦倍数设置失败,请重试",
"316107": "照片尺寸设置4k失败请重试",
"316108": "设置照片存储格式为jpeg格式失败请重试",
"316109": "关闭相机畸变矫正失败,请重试",
"316110": "打开相机机械快门失败,请重试",
"316111": "设置对焦模式失败,请重试",
"317001": "获取飞行器媒体文件数量失败,请重启机场后重试",
"317002": "飞行器存储格式化失败,飞行器未开机、未连接或未检测到相机,请确认无以上问题后重试,或重启飞行器后重试",
"317003": "飞行器存储格式化失败,请重启飞行器后重试",
"317004": "机场媒体文件格式化失败,请稍后重试或重启机场后重试",
"317005": "飞行器结束录像失败,本次飞行任务的媒体文件可能无法上传",
"317006": "无法格式化,请等待当前飞行器媒体文件下载完成后再试",
"317007": "获取媒体文件数量失败,请稍后重试,如本架次任务有媒体文件且持续报错可联系大疆售后",
"319001": "机场作业中或设备异常反馈上传日志中,无法执行飞行任务,请等待当前飞行任务或操作执行完成后重试",
"319002": "机场系统运行异常,请重启机场后重试",
"319003": "机场系统运行异常,请重新下发任务",
"319004": "飞行任务执行超时,已自动终止本次飞行任务",
"319005": "云端与机场通信异常,无法执行飞行任务",
"319006": "取消飞行任务失败,飞行任务已经在执行中",
"319007": "修改飞行任务失败,飞行任务已经在执行中",
"319008": "机场时间与云端时间不同步,机场无法执行飞行任务",
"319009": "飞行任务下发失败,请稍后重试或重启机场后重试",
"319010": "机场固件版本过低,无法执行飞行任务,请升级机场固件为最新版本后重试",
"319015": "机场正在初始化中,无法执行飞行任务,请等待机场初始化完成后重试",
"319016": "机场正在执行其他飞行任务,无法执行本次飞行任务",
"319017": "机场正在处理上次飞行任务媒体文件,无法执行本次飞行任务,请稍后重试",
"319018": "机场正在自动导出日志中(设备异常反馈),无法执行飞行任务,请稍后重试",
"319019": "机场正在拉取日志中(设备异常反馈),无法执行飞行任务,请稍后重试",
"319020": "航线中断失败,请稍后重试",
"319021": "退出远程控制失败,请稍后重试",
"319022": "指点飞行失败,请稍后重试",
"319023": "指点飞行停止失败,请稍后重试",
"319024": "一键起飞失败,请稍后重试",
"319025": "机场未准备完成,无法执行云端下发的飞行任务,请稍后重试",
"319026": "飞行器电池电量低于用户设置的任务开始执行的电量,请等待充电完成后再执行飞行任务",
"319027": "机场或飞行器剩余存储容量过低,无法执行飞行任务,请等待媒体文件上传,机场和飞行器存储容量释放后再执行飞行任务",
"319028": "正在更新自定义飞行区",
"319029": "正在更新离线地图",
"319030": "操作失败,无飞行器控制权",
"319031": "控制权异常,请刷新重试",
"319032": "指点飞行失败,请稍后重试",
"319033": "虚拟摇杆操作失败,请稍后重试",
"319034": "虚拟摇杆操作失败,请稍后重试",
"319035": "急停失败,请稍后重试",
"319036": "设备远程调试中,请稍后重试",
"319037": "设备本地调试中,请稍后重试",
"319038": "设备正在升级,请稍后重试",
"319042": "航线恢复失败,请稍后重试",
"319043": "取消返航失败,请稍后重试",
"319044": "航线任务已结束,无法恢复",
"319045": "急停成功,请重新按键操作",
"319046": "无法暂停航线,飞行器尚未进入航线或已退出航线",
"319999": "机场系统运行异常,请重启机场后重试",
"321000": "航线执行异常,请稍后重试或重启机场后重试",
"321004": "航线文件解析失败,无法执行飞行任务,请检查航线文件",
"321005": "航线缺少断点信息,机场无法执行飞行任务",
"321257": "飞行任务已在执行中,请勿重复执行",
"321258": "飞行任务无法终止,请检查飞行器状态",
"321259": "飞行任务未开始执行,无法终止飞行任务",
"321260": "飞行任务未开始执行,无法中断飞行任务",
"321513": "航线规划高度已超过飞行器限高,机场无法执行飞行任务",
"321514": "任务失败,起点或终点位于限远区域的缓冲区内或超过了限远距离",
"321515": "航线穿过限飞区,机场无法执行飞行任务",
"321516": "飞行器飞行高度过低,飞行任务执行被终止",
"321517": "飞行器触发避障,飞行任务执行被终止。为保证飞行安全,请勿用当前航线执行断点续飞任务",
"321519": "飞行器接近限飞区或限远距离自动返航,无法完成航线飞行",
"321523": "飞行器起飞失败,请稍后重试,如果仍报错请联系大疆售后。",
"321524": "飞行器起飞前准备失败,可能是飞行器无法定位或档位错误导致,请检查飞行器状态",
"321528": "触碰自定义飞行区边界,航线任务已暂停",
"321529": "目标点位于禁飞区域或者障碍物内,无法到达,航线任务已暂停,请重新规划后再试",
"321530": "飞行器飞行航线过程中轨迹规划失败,航线任务已暂停",
"321531": "进离场航线执行失败,请联系大疆售后。",
"321532": "进离场航线执行失败,请联系大疆售后。",
"321533": "进离场航线执行失败,请联系大疆售后。",
"321769": "飞行器卫星定位信号差,无法执行飞行任务,请重启机场后重试",
"321770": "飞行器挡位错误,无法执行飞行任务,请重启机场后重试",
"321771": "飞行器返航点未设置,无法执行飞行任务,请重启机场后重试",
"321772": "飞行器电量低于30%无法执行飞行任务请充电后重试建议电量≥50%",
"321773": "飞行器执行飞行任务过程中低电量返航,无法完成航线飞行",
"321775": "飞行器航线飞行过程中失联,无法完成航线飞行",
"321776": "飞行器 RTK 收敛失败,无法执行飞行任务,请重启机场后重试",
"321777": "飞行器未悬停,无法开始执行飞行任务",
"321778": "用户使用 B 控操控飞行器起桨,机场无法执行飞行任务",
"321784": "任务过程中遇到大风紧急返航",
"322281": "任务失败,机场执行飞行任务过程被手动打断或异常终止",
"322282": "机场执行飞行任务过程中被中断,飞行器被云端用户或遥控器接管",
"322283": "机场执行飞行任务过程中被用户触发返航,无法完成航线飞行",
"322539": "航线的断点信息错误,机场无法执行飞行任务",
"322563": "航线轨迹生成失败,请检查飞行器视觉镜头是否存在脏污或重启飞行器后再试,如果仍报错请联系大疆售后",
"324012": "日志压缩过程超时,所选日志过多,请减少选择的日志后重试",
"324013": "设备日志列表获取失败,请稍后重试",
"324014": "设备日志列表为空,请刷新页面或重启机场后重试",
"324015": "飞行器已关机或未连接,无法获取日志列表,请确认飞行器在舱内,通过远程调试将飞行器开机后重试",
"324016": "机场存储空间不足,日志压缩失败,请清理机场存储空间或稍后重试",
"324017": "日志压缩失败,无法获取所选飞行器日志,请刷新页面或重启机场后重试",
"324018": "日志文件拉取失败,导致本次设备异常反馈上传失败,请稍后重试或重启机场后重试",
"324019": "因机场网络异常,日志上传失败,请稍后重试。如果连续多次出现该问题,请联系代理商或大疆售后进行网络排障",
"324021": "因机场断电或重启导致日志导出中断,日志导出失败,请稍后重试",
"324030": "因机场网络异常、飞行器图传链路异常等原因,媒体文件暂时无法上传或文件已上传但云端读取失败",
"325001": "云端下发命令不符合格式要求,设备无法执行",
"325003": "指令响应失败,请重试",
"325004": "设备端命令请求已超时,请重试",
"325005": "当前机场无法响应任务,请稍后重试",
"325006": "当前机场启动检查中,请稍后重试",
"325007": "当前机场执行作业任务中,请稍后重试",
"325008": "当前机场处理作业任务结果中,请稍后重试",
"325009": "当前机场执行远程日志导出中,请稍后重试",
"325010": "当前机场更新自定义飞行区中,请稍后重试",
"325011": "当前机场更新离线地图中,请稍后重试",
"325012": "当前飞机未连接,请稍后重试",
"326002": "飞行器未安装 DJI Cellualr 模块",
"326003": "飞行器 DJI Cellualr 模块中未安装 SIM 卡",
"326004": "飞行器 DJI Cellualr 模块需要强制升级,否则无法使用",
"326005": "操作失败,增强图传无法建立连接,请检查 4G 信号强度,或咨询运营商查询套餐流量和 APN 设置",
"326006": "增强图传开关切换失败,请稍后重试",
"326008": "机场未安装 DJI Cellualr 模块",
"326009": "机场 DJI Cellualr 模块中未安装 SIM 卡",
"326010": "机场 DJI Cellualr 模块需要强制升级,否则无法使用",
"326103": "当前 eSIM 正在激活中,请稍后再试",
"326104": "当前 eSIM 正在切换运营商中,请稍后再试",
"326105": "DJI 增强图传模块正在切换模式中,请稍后再试",
"326106": "DJI 增强图传模块异常,请重启设备后再试,如果仍报错请联系大疆售后",
"326107": "请在设备管理 > 机场 > 设备运维中激活DJI增强图传模块的 eSIM 或插入 SIM 卡后再试",
"327000": "参数设置失败,请稍后重试",
"327001": "参数设置失败,请稍后重试",
"327002": "获取控制权失败,请稍后重试",
"327003": "获取控制权失败,请稍后重试",
"327004": "画面拖动失败,请重试",
"327005": "双击画面归中失败",
"327006": "拍照失败",
"327007": "开始录像失败",
"327008": "停止录像失败",
"327009": "切换相机模式失败",
"327010": "ZOOM相机变焦失败",
"327011": "IR相机变焦失败",
"327012": "获取控制权失败,请稍后重试",
"327013": "参数设置失败,请稍后重试",
"327014": "云台已达限位",
"327015": "直播启动失败,建议刷新直播或重新打开设备小窗",
"327016": "失联动作设置失败,请重试",
"327017": "指点飞行高度设置失败,请重试",
"327018": "指点飞行模式切换失败,请重试",
"327019": "当前状态无法看向标注点",
"327020": "全景拍照停止命令超时",
"327050": "当前设备状态不支持播放音频",
"327051": "下载音频文件失败",
"327052": "喊话器处理模式切换失败",
"327053": "上传音频文件失败",
"327054": "播放音频失败",
"327055": "设置工作模式失败",
"327056": "上传文本失败",
"327057": "停止播放失败",
"327058": "设置播放模式失败",
"327059": "设置音量失败",
"327060": "设置控件值失败",
"327061": "发送文本值失败",
"327062": "切换系统语言失败",
"327063": "获取设备功能列表失败",
"327064": "获取设备配置文件失败",
"327065": "获取设备图片文件失败",
"327066": "设备文件压缩失败",
"327067": "设备文件上传失败",
"327068": "上传音频文件失败md5校验失败",
"327069": "上传音频文件失败",
"327070": "上传音频文件失败,异常终止",
"327071": "上传TTS文本失败md5校验失败",
"327072": "上传TTS文本失败",
"327073": "上传TTS文本失败异常终止",
"327074": "喊话器重播失败",
"327075": "喊话器编码失败",
"327201": "全景拍照失败",
"327202": "全景拍摄终止",
"327203": "当前设备不支持全景拍照",
"327204": "系统繁忙,无法全景拍照",
"327205": "请求失败,无法全景拍照",
"327206": "飞机未起飞,无法开始全景拍摄",
"327207": "控制权获取失败,全景拍摄终止",
"327208": "未知相机错误,无法开始全景拍摄",
"327209": "相机超时,全景拍摄终止",
"327210": "无法全景拍照",
"327211": "存储空间不足,全景拍摄终止",
"327212": "飞机运动中,无法开始全景拍摄",
"327213": "云台运动中,无法开始全景拍摄",
"327214": "用户操作摇杆,全景拍摄终止",
"327215": "碰到限飞区,全景拍摄终止",
"327216": "触发距离限制,全景拍摄终止",
"327217": "云台受阻,全景拍摄终止",
"327218": "拍照失败,全景拍摄终止",
"327219": "全景图片拼接失败",
"327220": "加载标定参数失败,全景拍摄终止",
"327221": "调整相机参数失败,全景拍摄终止",
"327500": "飞行器镜头除雾失败,请稍后重试",
"328051": "飞机未完成实名登记,请连接遥控器,按照指引完成、实名登记后飞行",
"328052": "飞机实名登记状态已注销,请连接遥控器,按照指引完成实名登记后飞行",
"336000": "指点飞行命令发送失败,请重试",
"336001": "飞行器数据异常,无法响应指令",
"336002": "飞行器GPS信号差",
"336003": "飞行器定位失效,无法响应指令",
"336004": "指点飞行自主规划失败",
"336005": "飞行器返航点未更新",
"336006": "飞行器已失联,已退出指点飞行",
"336017": "飞行器电量不足以完成当前任务",
"336018": "已切换飞行器规划模式",
"336019": "指点飞行因限高自动调整飞行高度",
"336513": "目标点在禁飞区内",
"336514": "目标点超出飞行器限远",
"336515": "目标点在禁飞区内",
"336516": "目标点超出飞行器限高",
"336517": "目标点超出飞行器限低",
"337025": "飞行器无法起飞",
"337026": "目标点异常,请重试",
"337027": "飞行器速度设置异常,请重试",
"337028": "飞行器版本异常,请检查飞行器版本",
"337029": "飞行器无法响应当前任务,请稍后重试",
"337030": "指令飞行安全离场高过低",
"337537": "已触碰禁飞区",
"337538": "已触碰飞行器限远",
"337539": "已触碰禁飞区",
"337540": "已触碰飞行器限高或限高区",
"337541": "已触碰飞行器限低",
"337542": "飞行器起飞失败,请重试",
"337543": "目标点可能在障碍物内,请检查周边环境",
"337544": "检测到障碍物,请检查周边环境",
"337545": "飞行器规划异常,请重试",
"337546": "已触碰自定义飞行区边界",
"338001": "飞行器通信异常,无法执行飞行任务,请重启飞行器与机场后重试",
"338002": "飞行器通信异常,无法执行飞行任务,请重启飞行器与机场后重试",
"338003": "飞行器通信异常,无法执行飞行任务,请重启飞行器与机场后重试",
"338004": "飞行器通信异常,无法执行飞行任务,请重启飞行器与机场后重试",
"338005": "起飞机场与降落机场部署距离超出限制,无法执行飞行任务,请选择两个部署距离不超过 15km 的机场执行任务",
"338006": "无法执行飞行任务,请检查降落机场是否已申请解禁证书、是否位于自定义禁飞区或是否位于自定义飞行区外",
"338007": "目标降落机场部署突破限高区限高,无法执行任务,请申请解禁证书后再试",
"338008": "目标降落机场部署突破飞行器设置的限高,无法执行任务,请调整限高后重试",
"338009": "飞行器 GPS 定位信号差,无法执行任务,请重启飞行器后重试",
"338010": "飞行器定位失效,无法执行任务,请重启飞行器后重试",
"338011": "任务失败,目标机场处于地理鸟笼作业区域外,请重新规划任务后再试",
"338017": "飞行器数据更新失败,无法执行任务,请重启飞行器后重试",
"338018": "飞行器数据更新失败,无法执行任务,请重启飞行器后重试",
"338019": "飞行器到目标机场的返航路线正在规划中,无法执行任务,请重启飞行器后重试",
"338020": "飞行器无法根据规划的路径到达目标降落机场,无法执行任务,请重新选择降落机场后再试",
"338021": "飞行器当前电量不足以到达目标降落机场,无法执行任务,请给飞行器充电后重试",
"338049": "响应遥控器杆量,已退出指点飞行",
"338050": "响应终止指令,已退出指点飞行",
"338051": "飞行器低电量返航,已退出指点飞行",
"338052": "飞行器低电量降落,已退出指点飞行",
"338053": "附近有载人机,已退出指点飞行",
"338054": "响应其他高优先级任务,已退出指点飞行",
"338255": "飞行器通信异常,无法执行飞行任务,请重启飞行器与机场后重试",
"386535": "航线执行异常,请稍后重试或重启机场后重试",
"513002": "直播失败,相机不存在或相机类型错误",
"513003": "相机已经在直播中,请勿重复开启直播",
"513005": "直播失败,直播参数(清晰度)设置错误",
"513006": "直播启动失败,请刷新重试",
"513008": "直播失败,设备端图传数据异常",
"513010": "直播失败,设备无法联网",
"513011": "操作失败,设备未开启直播",
"513012": "操作失败,设备已在直播中,不支持切换镜头",
"513013": "直播失败,直播使用的视频传输协议不支持",
"513014": "直播失败,直播参数错误或者不完整",
"513015": "直播异常,网络卡顿, 请刷新后重试",
"513016": "直播异常,视频解码失败",
"513017": "直播已暂停,请等待当前飞行器媒体文件下载完成后再试",
"513099": "直播失败,请稍后重试",
"514100": "机场运行异常,请重启机场后重试",
"514101": "推杆闭合失败,请检查停机坪上是否存在异物,飞行器方向是否放反,或重启机场后重试",
"514102": "推杆展开失败,请检查停机坪上是否存在异物,或重启机场后重试",
"514103": "飞行器电量低于30%无法执行飞行任务请充电后重试建议电量≥50%",
"514104": "飞行器电池开始充电失败,请重启机场后重试",
"514105": "飞行器电池停止充电失败,请重启机场后重试",
"514106": "飞行器电源控制异常,请重启机场后重试",
"514107": "舱盖开启失败,请检查舱盖周围是否存在异物,或重启机场后重试",
"514108": "舱盖关闭失败,请检查舱盖周围是否存在异物,或重启机场后重试",
"514109": "飞行器开机失败,请检查飞行器是否在舱和飞机电量是否正常,或重启机场后重试",
"514110": "飞行器关机失败,请重启机场后重试",
"514111": "飞行器慢转收桨控制异常,请重启机场后重试",
"514112": "飞行器慢转收桨控制异常,请重启机场后重试",
"514113": "机场推杆与飞行器无法连接,请检查飞行器是否在舱内,推杆闭合时是否被卡住,充电连接器是否脏污或损坏",
"514114": "获取飞行器电源状态失败,请重启机场后重试",
"514116": "无法执行当前操作,机场正在执行其他控制指令,请稍后重试",
"514117": "舱盖开启或关闭未到位,请重启机场后重试",
"514118": "推杆展开或闭合未到位,请重启机场后重试",
"514120": "机场与飞行器断连,请重启机场后重试或重新对频",
"514121": "机场急停按钮被按下,请释放急停按钮",
"514122": "获取飞行器充电状态失败,请重启机场后重试",
"514123": "飞行器电池电量过低无法开机",
"514124": "获取飞行器电池信息失败,无法执行飞行任务,请重启机场后重试",
"514125": "飞行器电池电量已接近满电状态无法开始充电请使用至95%以下再进行充电",
"514134": "雨量过大,机场无法执行飞行任务,请稍后重试",
"514135": "风速过大,机场无法执行飞行任务,请稍后重试",
"514136": "机场供电断开,机场无法执行飞行任务,请恢复机场供电后重试",
"514137": "环境温度过低于-20℃ (-4°F),机场无法执行飞行任务,请稍后重试",
"514138": "飞行器电池正在保养中,机场无法执行飞行任务,请等待保养结束后重试",
"514139": "飞行器电池无法执行保养指令,飞行器电池无需保养",
"514140": "飞行器电池无法执行保养指令,飞行器电池无需保养",
"514141": "机场系统运行异常,请重启机场后重试",
"514142": "飞行器起飞前,机场推杆与飞行器无法连接,请检查飞行器是否在舱内,推杆闭合时是否被卡住,充电连接器是否脏污或损坏",
"514143": "推杆未闭合或闭合不到位,请稍后重试或重启机场后重试",
"514144": "舱盖未关闭或关闭不到位,请稍后重试或重启机场后重试",
"514145": "机场处于现场调试中,无法执行当前操作或执行飞行任务,请断开遥控器和机场的数据线连接后重试",
"514146": "机场处于远程调试中,无法执行飞行任务,请退出远程调试后重试",
"514147": "设备升级中,无法进行远程调试或执行飞行任务,请等待升级完成后重试",
"514148": "机场已经在作业中,无法进行远程调试或再次执行飞行任务,请等待当前任务执行完成后重试",
"514149": "机场系统运行异常,无法执行飞行任务,请重启机场后重试",
"514150": "设备重启中,无法执行飞行任务,请等待重启完成后重试",
"514151": "设备升级中,无法执行设备重启指令,请等待升级完成后重试",
"514153": "机场已退出远程调试模式,无法执行当前操作",
"514154": "获取内循环出风口温度失败,请稍后再试",
"514156": "飞机不在舱内,请立即检查飞行器是否已安全降落并将飞行器放回至机场",
"514157": "执行开机失败,无线充电线圈业务繁忙,请重启机场后再试复",
"514158": "无法起飞,机场 RTK 业务异常,请重启机场后再试",
"514159": "任务失败,降落机场检测到飞行器,请确保降落机场没有飞行器后再试",
"514162": "飞行器和机场连接失败,请关闭机场舱盖或重启机场后再试",
"514163": "电池功能异常,请确保飞行器电池插入到位或重启飞行器后再试",
"514164": "设备重启失败,请稍后重试,如果仍报错请联系大疆售后",
"514165": "设备重启失败,请稍后重试,如果仍报错请联系大疆售后",
"514170": "机场系统初始化中,无法执行当前操作或指令,请等待机场系统初始化完成后重试",
"514171": "云端下发给机场的命令不符合格式要求,机场无法执行",
"514172": "飞行器无法关机,蓝牙连接状态为未连接,请尝试重启飞行器和机场,或去现场重新对频飞行器与机场后再试",
"514173": "由于天气原因环境温度低于5度并且降雨大于等于中雨可能导致桨叶结冰影响作业安全暂无法执行任务",
"514174": "飞行器充电失败,机场舱盖开启或关闭未到位,请关闭舱盖后再试",
"514180": "停止空调制冷或停止空调制热失败,请稍后重试",
"514181": "开启空调制冷失败,请稍后重试",
"514182": "开启空调制热失败,请稍后重试",
"514183": "开启空调除湿失败,请稍后重试",
"514184": "当前温度低于 0 ℃32°F无法开启空调制冷",
"514185": "当前温度高于 45 ℃115°F无法开启空调制热",
"514300": "网关异常",
"514301": "请求超时,连接断开",
"514302": "网络证书异常,连接失败",
"514303": "网络异常,连接断开",
"514304": "请求被拒,连接失败"
}
}

View File

@ -0,0 +1,40 @@
import { clientReizePublish, clientReizeSubscribe } from '@/utils/mqtt';
import { airPortStore } from '@/store/modules/airport';
const airPortStoreVal = airPortStore();
export const return_home_status = {
canceled: '取消或终止',
failed: '失败',
in_progress: '执行中',
ok: '执行成功',
paused: '暂停',
rejected: '拒绝',
sent: '已下发',
timeout: '超时',
};
export const eventsTopicReize = (data) => {
// 发送消息
clientReizePublish('thing/product/' + airPortStoreVal.getGateway + '/events', data);
};
export const events_replyTopicReize = () => {
// 订阅消息
clientReizeSubscribe('thing/product/' + airPortStoreVal.getGateway + '/events_reply');
};
export const servicesTopicReize = (data) => {
// 发送消息
clientReizePublish('thing/product/' + airPortStoreVal.getGateway + '/services', data);
};
export const services_replyTopicReize = () => {
// 订阅消息
clientReizeSubscribe('thing/product/' + airPortStoreVal.getGateway + '/services_reply');
};
export const drcDownTopicReize = (data) => {
// 发送消息thing/product/{gateway_sn}/drc/down
clientReizePublish('thing/product/' + airPortStoreVal.getGateway + '/drc/down', data);
};
export const eventsTopicSubscribeReize = () => {
// 发送消息
clientReizeSubscribe('thing/product/' + airPortStoreVal.getGateway + '/events');
};

View File

@ -0,0 +1,73 @@
import { getClient, createConnection, clientPublish, clientSubscribe } from '@/utils/mqtt';
import { airPortStore } from '@/store/modules/airport';
import errorCode from './error_code.json';
const airPortStoreVal = airPortStore();
export const debug_mode_openOptions = {
canceled: '取消或终止',
failed: '失败',
in_progress: '执行中',
ok: '执行成功',
paused: '暂停',
rejected: '拒绝',
sent: '已下发',
timeout: '超时',
};
export const cover_stateOptions = { '0': '关闭', '1': '打开', '2': '半开', '3': '舱盖状态异常' };
export const cover_opensStatus = {
canceled: '取消或终止',
failed: '失败',
in_progress: '执行中',
ok: '执行成功',
paused: '暂停',
rejected: '拒绝',
sent: '已下发',
timeout: '超时',
};
export const errorName = (code) => {
const error_code = errorCode.error_code;
if (error_code[code]) {
return error_code[code];
} else {
return '错误码' + code;
}
};
export const servicesTopic = (data) => {
console.log(airPortStoreVal.getGateway);
// 发送消息
clientPublish('thing/product/' + airPortStoreVal.getGateway + '/services', data);
};
export const services_replyTopic = () => {
// 订阅消息
clientSubscribe('thing/product/' + airPortStoreVal.getGateway + '/services_reply');
};
export const eventsTopic = (data) => {
// 发送消息
clientPublish('thing/product/' + airPortStoreVal.getGateway + '/events', data);
};
export const events_replyTopic = () => {
// 订阅消息
clientSubscribe('thing/product/' + airPortStoreVal.getGateway + '/events_reply');
};
export const drcDownTopic = (data) => {
// 发送消息thing/product/{gateway_sn}/drc/down
clientPublish('thing/product/' + airPortStoreVal.getGateway + '/drc/down', data);
};
export const eventsTopicSubscribe = () => {
// 发送消息
clientSubscribe('thing/product/' + airPortStoreVal.getGateway + '/events');
};
export const drcUpTopic = () => {
clientSubscribe('thing/product/' + airPortStoreVal.getGateway + '/drc/up');
};
export const setTopic = (data) => {
// 发送消息
clientPublish('thing/product/' + airPortStoreVal.getGateway + '/property/set', data);
};
export const set_replyTopic = () => {
// 订阅消息
clientSubscribe('thing/product/' + airPortStoreVal.getGateway + '/services_reply');
};

View File

@ -162,3 +162,8 @@ export const getAssetsImg = (url: string) => {
const data = url.split('@/')[1];
return new URL(`../${data}`, import.meta.url).href;
};
// 时间戳转时间
export const timestampToFormattedDate = (timestamp) => {
const date = new Date(timestamp);
return `${date.getFullYear()}-${('0' + (date.getMonth() + 1)).slice(-2)}-${('0' + date.getDate()).slice(-2)} ${('0' + date.getHours()).slice(-2)}:${('0' + date.getMinutes()).slice(-2)}:${('0' + date.getSeconds()).slice(-2)}`;
};

221
src/utils/mqtt.ts Normal file
View File

@ -0,0 +1,221 @@
import mqtt from 'mqtt';
import { useMessage } from '@/hooks/web/useMessage';
import { getRedisUser, addOrUpdateRedisUser } from '@/api/demo/airportMaintenance';
import { useUserStore } from '@/store/modules/user';
import { timestampToFormattedDate } from '@/utils/index';
const userStore = useUserStore();
const userInfo = userStore.getUserInfo;
const { createMessage } = useMessage();
const seizeClientId = 'mqtt_client_1581F8HGX254V00A0BUY_seize';
const connection = {
protocol: 'ws',
host: '175.27.168.120',
// server less服务器只有两种协议mqtts: 8883; wss: 8084
port: 6010,
endpoint: '/mqtt',
// for more options, please refer to https://github.com/mqttjs/MQTT.js#mqttclientstreambuilder-options
clean: true,
connectTimeout: 30 * 1000, // ms
reconnectPeriod: 4000, // ms
clientId: '',
// clientId: 'mqtt_client_1581F8HGX254V00A0BUY',
// auth
username: 'sdhc',
password: '',
};
let client: any = {
connected: false,
};
let retryTimes = 0;
const initData = () => {
client = {
connected: false,
};
retryTimes = 0;
};
// 重新连接
const handleOnReConnect = () => {
retryTimes += 1;
if (retryTimes > 5) {
try {
client.end();
initData();
createMessage.error('连接的最大重连次数限制,停止重试');
} catch (error) {
createMessage.error(error.toString());
}
}
};
// 创建连接函数
const createConnection = (callback?) => {
console.log('创建连接');
// 连接mqtt的时候先用GetRedisUser查一下有没有
// 然后AddOrUpdateRedisUser更新或添加
// 控制的时候先查一下有没有锁定的用户GetLockedClients
try {
getRedisUser(userInfo.id).then((res) => {
console.log(res);
if (res) {
connection.clientId = res.clientId;
} else {
const clientId = 'mqttx_' + Math.random().toString(16).substring(2, 8);
connection.clientId = clientId;
const querys = {
clientId: clientId,
userId: userInfo.id,
userName: userInfo.name,
isLock: false,
connectTime: timestampToFormattedDate(new Date().getTime()),
};
addOrUpdateRedisUser(querys);
}
const { protocol, host, port, endpoint, ...options } = connection;
const connectUrl = `${protocol}://${host}:${port}${endpoint}`;
client = mqtt.connect(connectUrl, options);
client.on('connect', () => {
if (callback) {
callback();
}
});
});
const clientId = 'mqttx_' + Math.random().toString(16).substring(2, 8);
connection.clientId = clientId;
} catch (error) {
console.log('mqtt.connect error', error);
}
};
const getClient = () => {
// if (!client || !client.connected) {
// createConnection();
// }
return client;
};
// 断开连接
const destroyConnection = () => {
if (client.connected) {
try {
client.end(false, () => {
initData();
console.log('Successfully disconnected!');
});
} catch (error) {
console.log('Disconnect failed', error.toString());
}
}
};
// 订阅事件
const clientSubscribe = (topic: string, options?: any) => {
// if (!client || !client.connected) {
// createConnection();
// }
getClient().subscribe(topic, { qos: 0 }, (error, res) => {});
};
// 发送消息
const clientPublish = (topic: string, querys: any) => {
// if (!client || !client.connected) {
// createConnection();
// }
getClient().publish(topic, JSON.stringify(querys), { qos: 0 }, (err) => {
// if(err == undefined){
// createMessage.error('指令执行失败,请检查设备连接状态');
// }
if (err) {
console.error('Publish error:', err);
}
});
};
// 获取连接状态
const getConnectStatus = () => {
if (!client.connected) {
return false;
}
return true;
};
// on 事件
// connect 连接
// reconnect 重新连接
// error 错误
// message 监听消息
// end 事件 停止连接
// publish 事件 发送
// subscribe 事件 订阅
// unsubscribe 事件 取消订阅
// 抢夺负载权、飞行控制权的时候使用
let client_seize: any = {
connected: false,
};
const createSeizeConnection = () => {
const seizeConnection = connection;
seizeConnection.clientId = seizeClientId;
try {
const { protocol, host, port, endpoint, ...options } = seizeConnection;
const connectUrl = `${protocol}://${host}:${port}${endpoint}`;
client_seize = mqtt.connect(connectUrl, options);
if (client.on) {
}
} catch (error) {
console.log('mqtt.connect error', error);
}
};
const destroySeizeConnection = () => {
if (client_seize.connected) {
try {
client_seize.end(false, () => {
client_seize = {
connected: false,
};
console.log('Successfully disconnected!');
});
} catch (error) {
console.log('Disconnect failed', error.toString());
}
}
};
const getReizeClient = () => {
// if (!client_seize || !client_seize.connected) {
// createSeizeConnection();
// }
return client_seize;
};
// 订阅事件
const clientReizeSubscribe = (topic: string, options?: any) => {
// if (!client_seize || !client_seize.connected) {
// createSeizeConnection();
// }
getReizeClient().subscribe(topic, { qos: 0 }, (error, res) => {
console.log('订阅');
console.log(error, res);
});
};
// 发送消息
const clientReizePublish = (topic: string, querys: any) => {
// if (!client_seize || !client_seize.connected) {
// createSeizeConnection();
// }
getReizeClient().publish(topic, JSON.stringify(querys), { qos: 0 }, (err) => {
if (err) {
console.error('Publish error:', err);
}
});
};
export {
connection,
seizeClientId,
// 连接
createConnection,
destroyConnection,
getClient,
clientSubscribe,
clientPublish,
createSeizeConnection,
destroySeizeConnection,
getReizeClient,
clientReizeSubscribe,
clientReizePublish,
getConnectStatus,
};

View File

@ -40,3 +40,32 @@ export function buildShortUUID(prefix = ''): string {
unique++;
return prefix + '_' + random + unique + String(time);
}
export function uuid(len, radix) {
const chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('');
let uuid = [],
i;
radix = radix || chars.length;
if (len) {
// Compact form
for (i = 0; i < len; i++) uuid[i] = chars[0 | (Math.random() * radix)];
} else {
// rfc4122, version 4 form
let r;
// rfc4122 requires these characters
uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
uuid[14] = '4';
// Fill in random data. At i==19 set the high bits of clock sequence as
// per rfc4122, sec. 4.1.5
for (i = 0; i < 36; i++) {
if (!uuid[i]) {
r = 0 | (Math.random() * 16);
uuid[i] = chars[i == 19 ? (r & 0x3) | 0x8 : r];
}
}
}
return uuid.join('');
}

View File

@ -163,6 +163,7 @@
//
const dblclickHandle = async (item: ConfigType) => {
console.log('双击添加', item);
if (item.disabled) return;
// 使
if (item.key == 'GroupItem') {
@ -230,6 +231,7 @@
componentInstall(item.conKey, fetchConfigComponent(item));
//
let newComponent: CreateComponentType = await createComponent(item);
console.log(newComponent);
if (item.redirectComponent) {
item.dataset && (newComponent.option.dataset = item.dataset);
newComponent.chartConfig.title = item.title;

View File

@ -58,32 +58,36 @@ const packagesListObj = {
},
[PackagesCategoryEnum.ZHIGAN]: {
icon: renderIcon(AirPlaneOutlineIcon),
label: PackagesCategoryName.ZHIGAN
label: PackagesCategoryName.ZHIGAN,
},
[PackagesCategoryEnum.ZHILAN]: {
icon: renderIcon(AirPlaneOutlineIcon),
label: PackagesCategoryName.ZHILAN
label: PackagesCategoryName.ZHILAN,
},
[PackagesCategoryEnum.ZHICHU]: {
icon: renderIcon(AirPlaneOutlineIcon),
label: PackagesCategoryName.ZHICHU
label: PackagesCategoryName.ZHICHU,
},
[PackagesCategoryEnum.ZHIKU]: {
icon: renderIcon(AirPlaneOutlineIcon),
label: PackagesCategoryName.ZHIKU
label: PackagesCategoryName.ZHIKU,
},
[PackagesCategoryEnum.TASKS]: {
icon: renderIcon(AirPlaneOutlineIcon),
label: PackagesCategoryName.TASKS
label: PackagesCategoryName.TASKS,
},
[PackagesCategoryEnum.EQUIPMENT]: {
icon: renderIcon(AirPlaneOutlineIcon),
label: PackagesCategoryName.EQUIPMENT
label: PackagesCategoryName.EQUIPMENT,
},
[PackagesCategoryEnum.XUNCHAGUIJI]: {
icon: renderIcon(AirPlaneOutlineIcon),
label: PackagesCategoryName.XUNCHAGUIJI
}
label: PackagesCategoryName.XUNCHAGUIJI,
},
[PackagesCategoryEnum.UAVS]: {
icon: renderIcon(AirPlaneOutlineIcon),
label: PackagesCategoryName.UAVS,
},
};
export const useAsideHook = () => {