提交 9975a12b 作者: 翁进城

feat: 机库操控开发,剩下定时任务与周期任务未完成

上级 12e16c26
流水线 #9278 已失败 于阶段
...@@ -2,21 +2,21 @@ ...@@ -2,21 +2,21 @@
<div class="nest_info_maxBox"> <div class="nest_info_maxBox">
<div class="infoBox cf"> <div class="infoBox cf">
<div class="dib title"> <div class="dib title">
{{ uavData.relativeAlt }} {{ _uavData.gps.relativeAlt }}
</div> </div>
m m
<div class="cf infor">飞行高度</div> <div class="cf infor">飞行高度</div>
</div> </div>
<div class="infoBox cf"> <div class="infoBox cf">
<div class="dib title"> <div class="dib title">
{{ uavData.absoluteAlt }} {{ _uavData.gps.absoluteAlt }}
</div> </div>
m m
<div class="cf">海拔高度</div> <div class="cf">海拔高度</div>
</div> </div>
<div class="infoBox cf"> <div class="infoBox cf">
<div class="dib title"> <div class="dib title">
{{ uavData.flyDistance }} {{ _uavData.flyDistance }}
</div> </div>
m m
<div class="cf">飞行里程</div> <div class="cf">飞行里程</div>
...@@ -24,28 +24,28 @@ ...@@ -24,28 +24,28 @@
<div class="infoBox cf"> <div class="infoBox cf">
<div class="dib title"> <div class="dib title">
{{ uavData.distanceToHome }} {{ _uavData.distanceToHome }}
</div> </div>
m m
<div class="cf">起点距离</div> <div class="cf">起点距离</div>
</div> </div>
<div class="infoBox cf"> <div class="infoBox cf">
<div class="dib title"> <div class="dib title">
{{ uavData.flyTime }} {{ _uavData.flyTime }}
</div> </div>
min min
<div class="cf">飞行时间</div> <div class="cf">飞行时间</div>
</div> </div>
<div class="infoBox cf"> <div class="infoBox cf">
<div class="dib title"> <div class="dib title">
{{uavData.groundSpeed }} {{_uavData.groundSpeed }}
</div> </div>
m/s m/s
<div class="cf">飞行速度</div> <div class="cf">飞行速度</div>
</div> </div>
<div class="infoBox cf"> <div class="infoBox cf">
<div class="dib title" :style="up ? 'color: #ff2626':'color: #00f5ff'"> <div class="dib title" :style="up ? 'color: #ff2626':'color: #00f5ff'">
{{ uavData.velocityZ }} {{ _uavData.velocityZ }}
</div> </div>
m/s m/s
<div class="cf">爬升率</div> <div class="cf">爬升率</div>
...@@ -62,10 +62,25 @@ export default { ...@@ -62,10 +62,25 @@ export default {
}, },
data() { data() {
return { return {
// stationType:0
up: false, up: false,
}; };
}, },
computed: {
_uavData() {
return {
...this.uavData,
gps: {
relativeAlt: Number(this.uavData?.gps?.relativeAlt || 0).toFixed(0),
absoluteAlt: Number(this.uavData?.gps?.absoluteAlt || 0).toFixed(0),
},
flyDistance: Number(this.uavData?.flyDistance || 0).toFixed(0),
distanceToHome: Number(this.uavData?.distanceToHome || 0).toFixed(0),
flyTime: Number(this.uavData?.flyTime || 0).toFixed(0),
groundSpeed: Number(this.uavData?.groundSpeed || 0).toFixed(0),
velocityZ: Number(this.uavData?.velocityZ || 0).toFixed(0),
};
},
},
watch: { watch: {
uavData: function (val, old) { uavData: function (val, old) {
if (!val) { if (!val) {
......
...@@ -26,7 +26,7 @@ export default { ...@@ -26,7 +26,7 @@ export default {
}, },
throttleValue: { throttleValue: {
type: Number, type: Number,
default: 500, default: 0,
}, },
}, },
}; };
......
<!-- 飞控新版鹰视1027 --> <!-- 飞控新版鹰视1027 -->
<template> <template>
<div class="nest_controlBox"> <div class="nest_controlBox">
<throttleGauge :uavData="uavData" :throttleValue="throttleValue" style="transform: translateX(35px);"></throttleGauge> <throttleGauge
v-if="uavData"
:uavData="uavData"
:throttleValue="uavData.accelerator || 0"
style="transform: translateX(35px);"
></throttleGauge>
<div class="nest_control"> <div class="nest_control">
<Info class="" :uav-data="uavData"></Info> <Info class :uav-data="uavData"></Info>
<div class="xian"></div> <div class="xian"></div>
<battery v-if="uavBattery" :uav-battery="uavBattery" :device="device"></battery> <battery :batteryList="uavData.batteryList"></battery>
</div> </div>
<obstacle :uav-data="uavData" style="transform: translateX(-35px);"></obstacle> <obstacle :uav-data="uavData" style="transform: translateX(-35px);"></obstacle>
</div> </div>
</template> </template>
<script> <script>
import throttleGauge from './components/throttleGauge'; import throttleGauge from "./components/throttleGauge";
import Info from "./components/info/index"; import Info from "./components/info/index";
import battery from "./components/battery/index"; import battery from "./components/battery/index";
import obstacle from "./components/obstacle"; import obstacle from "./components/obstacle";
export default { export default {
name: 'MMCDataTransferPanel', name: "MMCDataTransferPanel",
data() { data() {
return {}; return {};
}, },
props: { props: {
// 无人机实时数据
uavData: { uavData: {
type: Object, type: Object,
default: () => ({}) default: () => ({
gps: {
relativeAlt: 0, //相对地面高度
absoluteAlt: 0, //海拔
}, },
uavBattery: { flyDistance: 0, //飞行距离
type: Object, flyTime: 0, //飞行时间
default: () => ({}) groundSpeed: 0, //飞行速度
}, distanceToHome: 0, //离起飞点距离
throttleValue: { velocityX: 0, // 使用NED(北-东-下)坐标系,飞机在x方向上的当前速度,以米
type: Number, velocityY: 0, // 使用NED(北-东-下)坐标系,飞机在y方向上的当前速度,以米
default: 0 velocityZ: 0, //爬升率
accelerator: this.uavRealTimeData.accelerator, //油门值
batteryList: this.uavRealTimeData.batteryList, //电池列表
}),
}, },
// 无人机设备信息
device: { device: {
type: Object, type: Object,
default: () => ({}) default: () => ({}),
}, },
}, },
components: { Info, battery, obstacle, throttleGauge }, components: { Info, battery, obstacle, throttleGauge },
mounted(){ mounted() {},
},
computed: { computed: {
props_obj() { props_obj() {
let { data } = this; let { data } = this;
} },
} },
}; };
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
...@@ -64,7 +76,6 @@ export default { ...@@ -64,7 +76,6 @@ export default {
background: rgba(9, 32, 87, 0.7); background: rgba(9, 32, 87, 0.7);
padding: 0 60px 0 40px; padding: 0 60px 0 40px;
} }
} }
.xian { .xian {
width: 0.3px; width: 0.3px;
......
export { default as Control_API } from './modules/uav_control'; export { default as Control_API } from './modules/uav_control';
export { default as flightTaskAPI } from './modules/flightTask'; export { default as flightTaskAPI } from './modules/flightTask';
export { default as AirLine } from './modules/air-line';
\ No newline at end of file
import request from '../request';
class AirLine {
/**
* 航线列表
* @param {*} params
* @returns
*/
static lineList(params) {
return request({
url: '/dms/route/page',
method: 'get',
params
});
}
/**
* 航线规划
* @param {*} data
* @returns
*/
static Edit(data) {
return request({
url: '/dms/route/add',
method: 'post',
data
});
}
static routeDelete(id) {
return request({
url: `/dms/route/delete/${id}`,
method: 'delete'
});
}
/**
* 航线修改
* @param {*} data
* @returns
*/
static Change(data) {
return request({
url: '/dms/route/update',
method: 'put',
data
});
}
/**
* 航线详情
* @param {*} data
* @returns
*/
static details(params) {
return request({
url: `/tmj/route/getRouteDetail/${params}`,
method: 'get',
params
});
}
/**
* 上传航线
* @param {*} data
* @returns
*/
static upload(data) {
return request({
headers: {
'Content-Type': 'multipart/form-data'
},
url: '/dms/route/upload',
method: 'post',
data
});
}
/**
* 上传航线
* @param {*} data
* @returns
*/
static uploadFile(data) {
return request({
headers: {
'Content-Type': 'multipart/form-data'
},
url: '/crm/dimensionMark/uploadFile',
method: 'post',
data
});
}
/**
* 上传多条航线
* @param {*} data
* @returns
*/
static uploadRoutes(data) {
return request({
headers: {
'Content-Type': 'multipart/form-data'
},
url: '/dms/route/upload',
method: 'post',
data
});
}
/**
* 航线删除
* @param {*} data
* @returns
*/
static deleteRoute(params) {
return request({
url: `/dms/route/delete/${params}`,
method: 'delete'
});
}
/**
* 航线详情
* @param {*} params
* @returns
*/
static routeDetail(params) {
return request({
url: '/dms/route/id',
method: 'get',
params
});
}
/**
* 飞行日志
* @param {*} params
* @returns
*/
static getSorties(params) {
return request({
url: '/dms/route/id',
method: 'get',
params
});
}
/**
* 飞行日志-历史视频
* @param {*} params
* @returns
*/
static getSortiesHistoryVideo(params) {
return request({
url: '/dms/sortie/history-video',
method: 'get',
params
});
}
/**
* 飞行日志-架次-历史轨迹
* @param {*} params
* @returns
*/
static getSortiesTrajectory(params) {
return request({
url: '/dms/sortie/data',
method: 'get',
params
});
}
}
export default AirLine;
<?xml version="1.0" encoding="UTF-8"?>
<svg width="22px" height="22px" viewBox="0 0 22 22" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>编组 58</title>
<g id="鹰视子页面" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="无人机应用3" transform="translate(-437.000000, -91.000000)">
<g id="编组-44" transform="translate(424.000000, 84.000000)">
<g id="编组-58" transform="translate(13.000000, 7.000000)">
<rect id="矩形" x="0" y="0" width="22" height="22"></rect>
<g id="编组-24" transform="translate(1.000000, 0.000000)">
<g id="编组">
<path d="M3.88923078,2.41768162 L3.88923078,2.90699556 C3.89135237,3.71997902 4.54351573,4.37741013 5.34615385,4.37568669 L14.6538461,4.37568669 C15.0394305,4.37672127 15.409628,4.22256551 15.6829986,3.9471322 C15.9563693,3.67169889 16.1105197,3.2975503 16.1115385,2.90699556 L16.1115385,2.41768162 L18.0561538,2.41768162 C18.5702664,2.41624304 19.0638901,2.62171794 19.4284324,2.98891369 C19.7929747,3.35610944 19.9985739,3.85494697 20,4.37568669 L20,20.0419851 C19.9985741,20.5628602 19.7928693,21.0618161 19.4281605,21.4290343 C19.0634517,21.7962524 18.5696302,22.0016358 18.0553846,21.9999902 L1.94461539,21.9999902 C1.42923078,21.9999902 0.933846162,21.7942856 0.569230765,21.4265284 C0.205080492,21.0601733 0.000204616439,20.5618526 0,20.0419851 L0,4.37568669 C0.00142586731,3.85481157 0.207130678,3.35585567 0.57183949,2.98863751 C0.936548301,2.62141936 1.43036975,2.41603597 1.94461539,2.41768162 L3.88923078,2.41768162 Z M8.03089086,7.05007484 C7.25556571,7.05007484 6.50823684,7.43670355 5.98144997,8.10900158 C5.48894424,8.73770348 5.21812322,9.5643088 5.21812322,10.4345102 L5.21812322,13.5757252 L5.23069297,13.8051785 C5.22326539,14.8021528 6.753347,14.6570236 6.75220429,13.7460942 L6.7413486,13.5349973 L6.7413486,10.4345102 C6.7413486,9.42893139 7.33212692,8.57938074 8.03089086,8.57938074 C8.73022614,8.57938074 9.32100448,9.42835775 9.32100448,10.4345102 L9.32100448,15.6161382 C9.32100448,16.4863397 9.59182549,17.3117977 10.0849026,17.9404996 C10.6122608,18.6133713 11.358447,19 12.1337721,19 C12.9096686,19 13.6564261,18.6133713 14.1837844,17.9404996 C14.6762901,17.3117977 14.9476825,16.4863397 14.9476825,15.6161382 L14.9476825,13.7460942 C14.9476825,13.3237881 14.6066968,12.9814413 14.1860698,12.9814413 C13.7654427,12.9814413 13.4244571,13.3237881 13.4244571,13.7460942 L13.4244571,15.6161382 C13.4244571,16.6217171 12.8331074,17.4706941 12.1337721,17.4706941 C11.4344368,17.4706941 10.8442299,16.6217171 10.8442299,15.6161382 L10.8442299,10.4345102 C10.8442299,9.56373516 10.5728375,8.73885074 10.0803318,8.10900158 C9.55297353,7.43670356 8.80621601,7.05007484 8.03089086,7.05007484 Z M5.97516509,14.9455611 C4.88461082,14.9468261 4.00094457,15.8342765 4,16.9291844 C4.0018887,18.0248844 4.8855348,18.9115448 5.97573645,18.9128078 C7.06664416,18.9118582 7.95058664,18.0238736 7.95090153,16.9286108 C7.94995603,15.8335722 7.06585007,14.9461937 5.97516509,14.9455611 Z M5.97573645,15.8639477 C6.56202684,15.8639477 7.03730912,16.3411273 7.03730912,16.9297581 C7.03730912,17.5183889 6.56202684,17.9955684 5.97573645,17.9955684 C5.38944605,17.9955684 4.91416377,17.5183889 4.91416377,16.9297581 C4.91416377,16.3411273 5.38944605,15.8639477 5.97573645,15.8639477 Z M14.1032237,7 C13.9820029,7 13.8657981,7.04858666 13.7804096,7.13497254 L12.3286033,8.5925743 C12.2429834,8.6785294 12.1948821,8.79511348 12.1948821,8.91667701 C12.1948821,9.03824054 12.2429834,9.15482463 12.3286033,9.24077972 C12.4141875,9.32723452 12.5305812,9.37584903 12.6519887,9.37584903 C12.7733962,9.37584903 12.8897899,9.32723452 12.9753741,9.24077972 L13.3421824,8.87308089 L13.3421824,11.1498307 C13.3421824,11.5721369 13.683168,11.9144837 14.103795,11.9144837 C14.5244221,11.9144837 14.8654077,11.5721369 14.8654077,11.1498307 L14.8654077,8.87250726 L15.2327873,9.24077972 C15.4131049,9.40799186 15.692774,9.40235843 15.8662663,9.22801943 C16.0397585,9.05368044 16.0451222,8.77289011 15.8784155,8.59200067 L14.4260378,7.13497254 C14.3406493,7.04858666 14.2244445,7 14.1032237,7 Z M10,0 C10.8817357,0.000861025619 11.6408671,0.63065615 11.8153846,1.50609017 L14.44,1.50609017 C15.0560099,1.50609017 15.5553846,2.01190203 15.5553846,2.63585258 C15.5553846,3.25980313 15.0560099,3.76561499 14.44,3.76561499 L5.56000001,3.76561499 C4.9439901,3.76561499 4.4446154,3.25980313 4.4446154,2.63585258 C4.4446154,2.01190203 4.9439901,1.50609017 5.56000001,1.50609017 L8.18461538,1.50609017 C8.35913286,0.63065615 9.11826429,0.000861025619 10,0 Z" id="形状结合" fill="#FFFFFF" fill-rule="nonzero"></path>
<g id="编组-5" transform="translate(12.194882, 7.000000)"></g>
</g>
<path d="M8.18461538,1.50609017 C8.35913286,0.63065615 9.11826429,0.000861025619 10,3.40838469e-13 C10.8817357,0.000861025619 11.6408671,0.63065615 11.8153846,1.50609017 L14.44,1.50609017 C15.0560099,1.50609017 15.5553846,2.01190203 15.5553846,2.63585258 C15.5553846,3.25980313 15.0560099,3.76561499 14.44,3.76561499 L5.56000001,3.76561499 C4.9439901,3.76561499 4.4446154,3.25980313 4.4446154,2.63585258 C4.4446154,2.01190203 4.9439901,1.50609017 5.56000001,1.50609017 L8.18538463,1.50609017 L8.18461538,1.50609017 Z" id="路径" fill="#FFBD36"></path>
</g>
<path d="M8.03730912,16.9297581 C8.03730912,16.3411273 7.56202684,15.8639477 6.97573645,15.8639477 C6.38944605,15.8639477 5.91416377,16.3411273 5.91416377,16.9297581 C5.91416377,17.5183889 6.38944605,17.9955684 6.97573645,17.9955684 C7.56202684,17.9955684 8.03730912,17.5183889 8.03730912,16.9297581 Z" id="路径" fill="#FFBD36"></path>
</g>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<template>
<div class="car dialog1027">
<div class="dialog-header" v-interact>
<div class="dialog-header__icon" />
<div class="dialog-header__title">
快速建模
</div>
<div class="dialog-header_close" style="color:#fff" @click="() => $emit('close')">关闭</div>
</div>
<div class="dialog-content w267">
<el-cascader size="mini" filterable popper-class="cpt-observe-mspace-dashboard-airway_popper" v-model="taskCateId"
:options="airway_list" clearable :show-all-levels="false" placeholder="请选择任务" :props="{
children: 'children',
label: 'taskTitle',
value: 'id',
emitPath: false,
}">
<template slot-scope="{ data }">
<el-tooltip :disabled="data.taskTitle.length < 11" class="item" effect="dark" :content="data.taskTitle"
placement="top-start">
<span>{{ data.taskTitle }}</span>
</el-tooltip>
</template>
</el-cascader>
<el-select class="mt10" v-model="type" size="mini" placeholder="请选择类型">
<el-option label="图片" :value="0"></el-option>
<el-option label="视频" :value="1"></el-option>
</el-select>
<div class="jcsb w267 h30 mt30">
<div class="dec mt5">1</div><span class="dib cf ml10 lh30"> 快速建模</span>
<div class="btn fr cf h30 lh30 w80 cp" @click="jmFn(1)">启动</div>
</div>
<div class="jcsb mt18 w267 h30">
<div class="dec mt5">2</div><span class="dib cf lh30 ml10">数据处理</span>
<div class="btn fr cf h30 lh30 w80 cp" @click="jmFn(2)">启动</div>
</div>
</div>
</div>
</template>
<script>
// import API from '@/api';
export default {
props: {
device: {
type: Object,
default: () => ({})
},
},
data() {
return {
imgUrl: process.env.VUE_APP_IMG_URL,
list: [],
type: null,
taskCateId: null,
airway_list: []
}
},
created() {
this.list_airway();
},
methods: {
jmFn(num) {
let { deviceHardId } = this.device
if (num == 1) {
let a = document.createElement("a");
a.href = `MMCEagleEye:// `
a.click()
}
else {
if(!this.taskCateId) return this.$message.warning('请选择任务!')
if(this.type==null ) return this.$message.warning('请选择类型!')
let a = document.createElement("a");
a.href = `MMCPosTool://&deviceId=${deviceHardId}enddeviceId&taskId=${this.taskCateId}endtaskId&type=${this.type}endtype`
a.click()
}
},
async list_airway() {
/* let res = await API.AIRWAY.getApprovedTask();
if (res) {
let jqList = [],
ctList = [],
lsList = [];
for (let i = 0; i < res.length; i++) {
if (res[i].taskCateId == 1) {
jqList.push(res[i]);
}
if (res[i].taskCateId == 2) {
ctList.push(res[i]);
}
if (res[i].taskCateId == 3) {
lsList.push(res[i]);
}
}
let airway_list = [
{
id: "警情任务",
taskTitle: "警情任务",
children: jqList,
},
{
id: "常态任务",
taskTitle: "常态任务",
children: ctList,
},
{
id: "临时任务",
taskTitle: "临时任务",
children: lsList,
},
];
this.airway_list = airway_list;
} */
},
}
}
</script>
<style lang="scss" scoped>
.car {
width: 268px;
}
.dialog-content {
padding: 20px 14px 12px;
max-height: 461px;
overflow: auto;
.dec {
width: 20px;
height: 20px;
line-height: 20px;
text-align: center;
border-radius: 50%;
background: #06199b;
}
.btn {
text-align: center;
border: 1px #315ec7 solid;
border-radius: 3px;
background-color: #02173d;
font-size: 14px;
font-family: MicrosoftYaHei;
color: #D2D9FF;
cursor: pointer;
}
.btn:hover {
background: #06199b;
}
}
.car-img {
position: relative;
width: 100%;
height: 135px;
.car-img__img {
width: 100%;
height: 100%;
}
.car-img__label {
position: absolute;
bottom: 0;
width: 100%;
height: 28px;
display: flex;
justify-content: center;
align-items: center;
font-size: 14px;
color: #aee9ff;
font-family: MicrosoftYaHeiUI;
}
}
.car-form {
padding: 10px 0 0;
font-size: 14px;
font-family: MicrosoftYaHei;
color: #fff;
>div {
margin-bottom: 8px;
&:last-child {
margin-bottom: 0;
}
}
}
.car-item {
margin-bottom: 24px;
}
</style>
\ No newline at end of file
<template>
<div class="car dialog1027">
<div class="dialog-header" v-interact>
<div class="dialog-header__icon" />
<div class="dialog-header__title">
车辆识别
</div>
<div class="dialog-header_close" style="color:#fff" @click="()=>$emit('close')">关闭</div>
</div>
<div class="dialog-content" v-infinite-scroll="load">
<template v-if="list.length > 0" >
<div v-for="(item, i) in list" :key="i" class="car-item">
<div class="car-img">
<img class="car-img__img" :src="imgUrl + item.imageUrl" />
<div class="car-img__label">{{ item.plateNum || '暂无' }}</div>
</div>
<div class="car-form">
<div>地点:{{ item.addr || item.findAddress || '暂无' }}</div>
<div>时间:{{ item.findTime || '暂无' }}</div>
</div>
</div>
</template>
<template v-else>
<div style="text-align: center; width: 100%;">暂无数据</div>
</template>
</div>
</div>
</template>
<script>
// import API from '@/api';
export default {
props: {
uavId: {
type: String,
default: ''
}
},
data(){
return {
imgUrl: process.env.VUE_APP_IMG_URL,
list: [],
pageNo: 1,
pageSize: 3,
}
},
created(){
this.getCarList()
},
methods: {
async load(){
this.pageNo++
/* let res = await API.HOME.getflightvideoMsg({
uavId: this.uavId,
pageNo: this.pageNo,
pageSize: this.pageSize
})
for(let i = 0; i < res.length; i++){
let item = res[i];
if(item.lon){
let address = await API.MAP.AiRegeo({
location: `${item.lon},${item.lat}`
})
item.addr = address.province.value + address.city.value + address.dist.value + address.road.roadname + address.poi;
}
this.list.push(res[i])
}
console.log(this.list,"list"); */
},
async getCarList(){
if(!this.uavId){
this.$message.error('请选择无人机');
return;
}
let res = await API.HOME.getflightvideoMsg({
uavId: this.uavId,
pageNo: this.pageNo,
pageSize: this.pageSize
})
for(let i = 0; i < res.length; i++){
let item = res[i];
if(item.lon){
let address = await API.MAP.AiRegeo({
location: `${item.lon},${item.lat}`
})
item.addr = address.province.value + address.city.value + address.dist.value + address.road.roadname + address.poi;
}
this.list.push(res[i])
}
// this.list = res || [];
}
}
}
</script>
<style lang="scss" scoped>
.car{
width: 268px;
}
.dialog-content{
padding: 20px 14px 12px;
max-height: 461px;
overflow: auto;
}
.car-img{
position: relative;
width: 100%;
height: 135px;
.car-img__img {
width: 100%;
height: 100%;
}
.car-img__label {
position: absolute;
bottom: 0;
width: 100%;
height: 28px;
display: flex;
justify-content: center;
align-items: center;
font-size: 14px;
color: #aee9ff;
font-family: MicrosoftYaHeiUI;
}
}
.car-form{
padding: 10px 0 0;
font-size: 14px;
font-family: MicrosoftYaHei;
color: #fff;
>div {
margin-bottom: 8px;
&:last-child {
margin-bottom: 0;
}
}
}
.car-item{
margin-bottom: 24px;
}
</style>
\ No newline at end of file
<template>
<div class="face dialog1027">
<div class="dialog-header" v-interact>
<div class="dialog-header__icon" />
<div class="dialog-header__title">
人脸识别
</div>
<div class="dialog-header_close" style="color:#fff" @click="()=>$emit('close')">关闭</div>
</div>
<div class="dialog-content" v-infinite-scroll="load">
<template v-if="list.length > 0">
<div class="result" v-for="(item, i) in list" :key="i">
<div class="rate-box">
<div class="rate-img">
<img :src="imgUrl + item.recordImageUrl" />
</div>
<div class="rate-round">
<div class="rate-round__value">{{ Number(item.similarity).toFixed(2) }}%</div>
<div class="rate-routd__text" @click="onDetail(item)">详情</div>
</div>
<div class="rate-img rate-img--contrary">
<img :src="imgUrl + item.snapImageUrl" />
</div>
</div>
<div class="rate-form" v-if="item.show">
<div class="rate-form-item">
<div class="rate-form-item__label">
姓名:
</div>
<div class="rate=form-item__value">
{{ item.userName || '暂无' }}
</div>
</div>
<div class="rate-form-item">
<div class="rate-form-item__label">
出生年份:
</div>
<div class="rate=form-item__value">
{{ item.birthday || '暂无' }}
</div>
</div>
<div class="rate-form-item">
<div class="rate-form-item__label">
发现时间:
</div>
<div class="rate=form-item__value">
{{ item.occurTime || '暂无' }}
</div>
</div>
<div class="rate-form-item">
<div class="rate-form-item__label">
发现地点:
</div>
<div class="rate=form-item__value">
{{ item.addr || item.address || '暂无' }}
</div>
</div>
<div class="rate-form-item">
<div class="rate-form-item__label">
身份证号:
</div>
<div class="rate=form-item__value">
{{ item.idCard || '暂无' }}
</div>
</div>
<div class="rate-form-item">
<div class="rate-form-item__label">
AI识别:
</div>
<div class="rate=form-item__value">
<template v-if="item.labels && item.labels.length">
<div class="round-border" v-for="(label, j) in item.labels" :key="j" >
{{label}}
</div>
</template>
<template v-else>
暂无
</template>
</div>
</div>
</div>
</div>
</template>
<template v-else>
<div style="text-align: center; width: 100%;">暂无数据</div>
</template>
</div>
</div>
</template>
<script>
// import API from '@/api';
export default {
props: {
uavId: {
type: String,
default: ''
}
},
data(){
return {
imgUrl: process.env.VUE_APP_IMG_URL,
list: [
/* {
userName: '人热二',
birthday: '1888-02-11',
occurTime: '2022-02-30 08:22:14',
address: '深圳市南山区',
idCard: '112313123123',
labels: ['省内人员'],
similarity: '63',
img: '',
imgs: '',
show: true
} */
],
pageNo: 1,
pageSize: 4,
}
},
created(){
this.getFaceList();
},
methods: {
async load(){
this.pageNo++
/* let res = await API.HOME.getFaceuavvideoMsg({
uavId: this.uavId,
pageNo: this.pageNo,
pageSize: this.pageSize
})
for(let i = 0; i < res.length; i++){
let item = res[i];
if(item.longi){
let address = await API.MAP.AiRegeo({
location: `${item.longi},${item.lati}`
})
item.addr = address.province.value + address.city.value + address.dist.value + address.road.roadname + address.poi;
}
this.list.push(res[i])
}
console.log(this.list,"list"); */
},
async getFaceList(){
if(!this.uavId){
this.$message.error('请选择无人机');
return;
}
let res = await API.HOME.getFaceuavvideoMsg({
uavId: this.uavId,
pageNo: this.pageNo,
pageSize: this.pageSize
}) || [];
for(let i = 0; i < res.length; i++){
let item = res[i];
if(item.longi){
let address = await API.MAP.AiRegeo({
location: `${item.longi},${item.lati}`
})
item.addr = address.province.value + address.city.value + address.dist.value + address.road.roadname + address.poi;
}
this.list.push(res[i])
}
// this.list = res || [];
},
onDetail(item){
this.$set(item, 'show', !item.show);
}
}
}
</script>
<style lang="scss" scoped>
.face{
width: 268px;
}
.dialog-content{
padding: 14px;
cursor: initial;
max-height: 461px;
overflow-y: auto;
}
.result{
width: 100%;
margin-top: 27px;
&:first-child {
margin-top: 0;
}
}
.rate-box{
display: flex;
align-items: center;
position: relative;
width: 100%;
.rate-img{
flex: 1;
height: 75px;
background-image: url('../../assets/images/faceAI_border1.png');
background-size: 100% 100%;
padding: 7px;
display: flex;
align-items: center;
&.rate-img--contrary {
background-image: url('../../assets/images/faceAI_border2.png');
justify-content: right;
}
img {
width: 70px;
height: 70px;
border-radius: 7px;
overflow: hidden;
}
}
.rate-round{
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
.rate-round__value{
color: #fb799d;
font-size: 14px;
font-family: MicrosoftYaHei;
}
.rate-routd__text{
cursor: pointer;
font-size: 12px;
color: #b9d7f0;
font-family: MicrosoftYaHei;
transform: scale(0.9);
margin-top: 3px;
}
}
}
.rate-form{
margin-top: 10px;
font-size: 14px;
font-family: MicrosoftYaHei;
color: #fff;
.rate-form-item {
margin-bottom: 12px;
display: flex;
&:last-child {
margin-bottom: 0;
}
.rate-form-item__label {
width: 70px;
text-align: right;
flex-shrink: 0;
}
.rate-form-item__value {
}
}
}
.round-border{
padding: 2px 8px;
border-radius: 11px;
border: 1px solid #ff4a4a;
color: #ff4a4a;
font-size: 14px;
font-family: MicrosoftYaHei;
}
</style>
\ No newline at end of file
<template>
<div class="livenvr">
<LivePlayer
:dblclick-fullscreen="false"
aspect="fulllscreen"
ref="livePlayer"
:videoUrl="url"
:controls="false"
:live="true"
/>
</div>
</template>
<script>
import LivePlayer from "@liveqing/liveplayer";
export default {
name: 'liveNVRPlayer',
props: {
url: {
type: String,
default: '',
},
},
components: { LivePlayer },
data() {
return {};
},
watch: {
url: {
handler(newVal, oldVal) {
if (newVal == oldVal) {
return;
}
// console.log('livenvr', value)
if (newVal ) {
this.$nextTick(() => {
this.$refs["livePlayer"].play();
});
}
},
deep: true,
immediate: true,
},
},
mounted() {
},
methods: {
init() {
},
fullScreen(){
this.$refs.livePlayer.fullScreen();
}
},
};
</script>
<style lang="scss" scoped>
</style>
\ No newline at end of file
<template>
<div class="qingliu" :class="classNames" id="qinglliu" ref="qingliu">
<div :id="'qingliu_' + name" class="qingcanvas" ref="qingcanvas">
</div>
</div>
</template>
<script>
export default {
name: "QingLiuPlayer",
props: {
url: {
type: String,
default: ''
}
},
data() {
return {
name: "QingLiuPlayer" + Date.now(),
};
},
watch: {
},
created() {},
mounted() {
this.init();
},
beforeDestroy() {
window.kbt_player_destroy("qingliu_" + this.name);
window.removeEventListener("resize", this.handResize);
},
methods: {
/**
* 初始化
*/
init() {
// 新
window.kbt_sdk_load(this.url, "qingliu_" + this.name);
// 监听窗口大小变化事件
window.addEventListener("resize", this.handResize);
var canvas_qinliu = document.getElementById("qingliu_" + this.name);
var resizeObserver = new ResizeObserver((e) => {
for (let i of e) {
window.kbt_player_resize("qingliu_" + this.name);
}
});
resizeObserver.observe(canvas_qinliu);
},
handResize() {
// 获取 Canvas 元素
var canvas_qinliu = document.getElementById("qingliu_" + this.name);
// 获取 Canvas 的初始宽度和高度
var initialWidth = canvas_qinliu.width;
var initialHeight = canvas_qinliu.height;
// 获取当前 Canvas 的宽度和高度
var currentWidth = canvas_qinliu.clientWidth;
var currentHeight = canvas_qinliu.clientHeight;
// 检查 Canvas 的大小是否发生变化
if (currentWidth !== initialWidth || currentHeight !== initialHeight) {
// 执行适应新尺寸的操作
window.kbt_player_resize("qingliu_" + this.name);
}
},
fullScreen(flag) {
if (flag) {
let dom = document.querySelector("#qingliu_" + this.name);
dom.requestFullscreen();
} else {
document.exitFullscreen();
}
},
},
};
</script>
<style scoped lang="scss">
.qingliu ::v-deep {
width: 100%;
height: calc(100% - 46px);
.qingcanvas {
width: 100%;
height: 100%;
}
canvas {
width: 100% !important;
}
}
</style>
<template>
<div class="cpt-player-webrtc">
<video id="rtc_media_player" ref="webrtc" controls autoplay></video>
</div>
</template>
<script>
import $ from "./jquery-1.10.2.min";
import {
SrsRtcPublisherAsync,
SrsRtcPlayerAsync,
SrsRtcFormatSenders,
} from "./srs.sdk";
window.$ = $;
export default {
props: {
data: {
type: Object,
default: () => ({}),
},
},
data() {
return {
sdk: null,
};
},
watch: {
data: {
handler(value) {
this.$nextTick(() => {
this.init();
});
},
deep: true,
immediate: true,
},
},
beforeDestroy() {
this.sdk.close();
},
methods: {
pause() {
if (this.$refs["webrtc"]) {
this.$refs["webrtc"].pause();
}
},
play() {
if (this.$refs["webrtc"]) {
this.$refs["webrtc"].play();
}
},
init() {
let _this = this;
if (this.$refs["webrtc"]) {
if (this.sdk) {
this.sdk.close();
}
this.sdk = new SrsRtcPlayerAsync();
this.$refs["webrtc"].srcObject = this.sdk.stream;
this.sdk
.play(this.data.vUrl)
.then(function (session) {})
.catch(function (reason) {
console.log('srs err', reason)
_this.sdk.close();
});
}
},
fullScreen() {
let video = this.$refs["webrtc"];
if (video.webkitRequestFullScreen) {
video.webkitRequestFullScreen();
} else if (video.requestFullscreen) {
video.requestFullscreen();
} else if (video.mozRequestFullScreen)
setTimeout(() => {
video.play();
}, 200);
},
},
};
</script>
<style lang="scss" scoped>
.cpt-player-webrtc {
height: 100%;
width: 100%;
background-color: #000;
video {
width: 100%;
height: 100%;
object-fit: fill;
}
}
</style>
\ No newline at end of file
<template>
<div class="video-wrap" @dblclick="screen" ref="video">
<div class="cpt_video">
<div class="video-header">
<div class="title">
<span class="title-scroll">{{ name }}</span>
<span class="title-scroll">{{ name }}</span>
</div>
<span class="label">{{ label }}</span>
<div class="el-icon-close close" @click="close"></div>
</div>
<components :is="playerCom" ref="player" :url="url" :className="'fkLivePlayer'" />
<slot></slot>
</div>
</div>
</template>
<script>
import LiveNVRPlayer from "./components/livenvr/index.vue";
import QingLiuPlayer from "./components/qingliu";
import SRSPlayer from "./components/srs";
export default {
name: "Player",
components: {
QingLiuPlayer,
LiveNVRPlayer,
SRSPlayer,
},
props: {
url: {
type: String,
default: "",
},
brand: {
type: String,
default: "qingliu",
},
// 持续滚动的文字
name: {
type: String,
default: "",
},
// 关闭图标旁边的文字
label: {
type: String,
default: "",
},
},
data() {
return {
isFullScreen: false, //是否全屏
};
},
computed: {
/**
* 播放器组件名
*/
playerCom() {
switch (this.brand.toLowerCase()) {
case "flv":
return "LiveNVRPlayer";
case "srs":
return "SRSPlayer";
case "livenvr":
return "LiveNVRPlayer";
case "qingliu":
return "QingLiuPlayer";
case "webrtc":
// return "LiveNVRPlayer";
return "SRSPlayer";
default:
return "LiveNVRPlayer";
}
},
},
watch: {},
async mounted() {},
beforeDestroy() {},
methods: {
close(data) {
this.$emit("close");
},
screen() {
this.isFullScreen = !this.isFullScreen;
if (this.playerCom === "LiveNVRPlayer") {
this.$refs.player.fullScreen(this.isFullScreen);
} else {
this.$refs.player.fullScreen(this.isFullScreen);
}
},
play() {
if (this.playerCom === "LiveNVRPlayer") {
this.$refs.player.$refs["livePlayer"].pause();
}
},
pause() {
if (this.playerCom === "LiveNVRPlayer") {
this.$refs.player.$refs["livePlayer"].play();
}
},
async reset() {
this.showPlayer = false;
this.$nextTick(() => {
this.showPlayer = true;
});
},
},
};
</script>
<style lang="scss" scoped>
.video-wrap {
}
.cpt_video {
width: 100%;
height: 100%;
background: #333;
align-items: center;
position: relative;
.video-header {
background: rgba(0, 0, 0, 0.6);
box-sizing: border-box;
display: flex;
align-items: center;
position: absolute;
top: 5px;
width: 100%;
z-index: 1;
background-color: rgba(0, 0, 0, 0.6);
display: flex;
.close {
cursor: pointer;
opacity: 0.6;
color: #ffffff;
}
.title {
font-family: Microsoft YaHei;
font-size: 14px;
color: #fff;
font-weight: 400;
white-space: nowrap;
line-height: 30px;
overflow: hidden;
.title-scroll {
display: inline-block;
animation: scrollTitle 15s linear infinite;
position: relative;
box-sizing: border-box;
padding-right: 50px;
}
}
.label {
white-space: nowrap;
margin-left: 5px;
color: #fff;
font-size: 12px;
}
}
}
@keyframes scrollTitle {
0% {
transform: translateX(0);
}
100% {
transform: translateX(-100%);
}
}
</style>
<template>
<div>
<Player @close="$emit('close')" :url="src.url" :brand="src.brand" :name="name" label="舱内" />
</div>
</template>
<script>
import Player from "../components/player";
import { mapState } from "vuex";
export default {
name: "InnerPlayer",
components: { Player },
data() {
return {};
},
computed: {
...mapState("MMCFlightControlCenter/hangar", ["hangar"]),
name() {
return `${this.hangar?.uav?.organizationName || ""}机库无人机`;
},
src() {
return (
this.hangar?.uav?.streamConfiguration
?.find((v) => v.videoType === 2)
?.streamUrlMessage.map((v) => ({
label: v.streamType.toLocaleLowerCase(),
url: v.streamUrl,
brand: v.streamType,
}))[0] || {
url: "",
brand: "",
}
);
},
},
};
</script>
<style lang="scss" scoped>
</style>
\ No newline at end of file
<template>
<div>
<Player @close="$emit('close')" :url="src.url" :brand="src.brand" :name="name" label="舱外" />
</div>
</template>
<script>
import Player from "../components/player";
import { mapState } from "vuex";
export default {
name: "OuterPlayer",
components: { Player },
data() {
return {};
},
computed: {
...mapState("MMCFlightControlCenter/hangar", ["hangar"]),
name() {
return `${this.hangar?.uav?.organizationName || ""}机库无人机`;
},
src() {
return (
this.hangar?.uav?.streamConfiguration
?.find((v) => v.videoType === 3)
?.streamUrlMessage.map((v) => ({
label: v.streamType.toLocaleLowerCase(),
url: v.streamUrl,
brand: v.streamType,
}))[0] || {
url: "",
brand: "",
}
);
},
},
methods: {},
};
</script>
<style lang="scss" scoped>
</style>
\ No newline at end of file
<template>
<div>
<Player @close="$emit('close')" :url="selectStream.url" :brand="selectStream.brand" :name="name" :label="label" />
<el-select v-model="selectUrl" class="select" popper-class="mmc">
<el-option
v-for="item in streamConfiguration"
:label="item.brand"
:value="item.url"
:key="item.url"
></el-option>
</el-select>
</div>
</template>
<script>
import Player from "../components/player";
import { mapState } from "vuex";
import { coverStreamUrl } from "../utils";
export default {
name: "UAVPlayer",
components: { Player },
props: {},
data() {
return {
selectUrl: "", //选择的流的url
};
},
computed: {
...mapState("MMCFlightControlCenter/hangar", ["hangar"]),
name() {
return `${this.hangar?.uav?.organizationName || ""}机库无人机`;
},
label() {
return this.hangar?.uav?.organizationName || "";
},
/**
* 可选流
*/
streamConfiguration() {
return (
this.hangar?.uav?.streamConfiguration
?.find((v) => v.videoType === 1)
?.streamUrlMessage.map((v) => ({
url: /* coverStreamUrl(v.streamUrl, this.hangar.uav.hardId) */ v.streamUrl,
brand: v.streamType,
})) || []
);
},
selectStream() {
return (
this.streamConfiguration.find(item => item.url === this.selectUrl) || {
url: "",
brand: "",
}
);
},
},
mounted() {
this.selectUrl = this.streamConfiguration[0]?.url || '';
},
methods: {},
};
</script>
<style lang="scss" scoped>
.select ::v-deep{
width: 95px;
margin-top: 5px;
input {
height: 30px;
}
.el-select__caret {
display: flex;
align-items: center;
width: initial;
}
}
</style>
\ No newline at end of file
import { Base64 } from "js-base64";
/**
* 转换流地址, 这样后端才可统计播放情况
* @param {*} url
* @param {*} hardId
* @returns
*/
export function coverStreamUrl(url, hardId) {
if (url.includes("https://live.mmcuav.cn")) {
const str = Base64.encode(
JSON.stringify({
token: localStorage.getItem("tmj_token"),
actionId: new Date().getTime().toString(),
deviceHardId: hardId,
environment: process.env.VUE_APP_ENV === "dev" ? "sit" : "prod",
})
);
return `${url}?${str}`;
} else {
return url;
}
}
<template>
<div class="normal-task">
<el-form label-width="60px">
<el-form-item label="任务库">
<el-select
v-model="selectedTaskId"
popper-class="mmc"
@change="onChangeTask"
placeholder="请选择任务"
clearable
>
<el-option v-for="item in taskListAll" :key="item.id" :label="item.name" :value="item.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="航线">
<el-button
v-if="selectedTaskId !== -1"
:disabled="selectedTaskId === ''"
@click="onStartTask"
>一键任务</el-button>
<el-button v-else @click="showFlywayDialog = true">请选择航线</el-button>
</el-form-item>
</el-form>
<LineList v-if="showFlywayDialog" @close="showFlywayDialog = false;" @change="onChangeLine"></LineList>
</div>
</template>
<script>
import { mapState, mapActions } from "vuex";
import LineList from "./components/lineList";
import { flightTaskAPI, AirLine } from "../../../../../../../../../../api";
import hangarStatusDict from "../../hangarStatusDict";
export default {
name: "normalTask",
components: {
LineList,
},
inject: ["rootNode"],
data() {
return {
// 选择的任务id
selectedTaskId: "",
// 选择的航线
selectedAirway: {
name: "",
id: -1,
},
// 航线选择窗口
showFlywayDialog: false,
};
},
computed: {
...mapState("MMCFlightControlCenter/hangar", [
"hangarRealTimeData",
"hangar",
"taskList",
]),
taskListAll() {
return [
{
id: -1,
name: "选择航线自动生成任务",
},
...this.taskList.normal,
];
},
/**
* 是否选择任务
*/
isSelectTask() {
return this.selectedTaskId[0] !== -1;
},
/**
* 选择的任务数据
*/
selectedTask() {
let find = this.taskList.normal.find((item) => {
return item.id === this.selectedTaskId;
});
return find;
},
},
watch: {
selectedAirway() {
this.clearAirwayEntities();
if (this.selectedAirway.id !== -1) {
try {
let airway = JSON.parse(this.selectedAirway.content);
this.createAirwayEntities({
polyline: airway.content,
id: airway.id,
});
} catch (e) {
console.log("绘制航线失败", e);
}
}
},
},
created() {
this.rootNode.$emit("changeHangarTaskTab", {
type: 1,
});
},
beforeDestroy(){
this.clearAirwayEntities();
},
methods: {
...mapActions("MMCFlightControlCenter", [
"createAirwayEntities",
"clearAirwayEntities",
]),
/**
* 更改任务事件
*/
async onChangeTask() {
if (this.selectedTask?.airwayId) {
let res = await AirLine.routeDetail({
id: this.selectedTask?.airwayId,
});
if (res.code === 200) {
this.selectedAirway = res.data;
}
} else {
this.selectedAirway = {
name: "",
id: -1,
};
}
},
/**
* 更改航线事件
*/
onChangeLine(data) {
this.selectedAirway = data;
if (data) {
this.rootNode.$emit("addHangarTask", {
type: 1, //1: 日常任务 2.定时任务 3.周期任务
airway: data, //航线数据
callback: (id) => {
// 返回新增任务后的任务id
this.selectedTaskId = id;
},
}); // 根节点发送机库任务新增事件
}
},
/**
* 一键任务事件
*/
async onStartTask() {
// 判断是否选择了航线
if (this.selectedAirway.id === -1) {
this.$message.warning("请选择航线");
return;
}
try {
await this.$confirm("请确认是否进行一键任务操作?", "安全确认", {
cancelButtonText: "取消",
confirmButtonText: "确定",
customClass: "uav_controlPane",
showClose: false,
});
// 当前机库状态是否空闲
if ([0, 8].includes(this.hangarRealTimeData.processStatus)) {
this.$store.commit("MMCFlightControlCenter/hangar/state", {
key: "airlineData",
value: this.selectedAirway,
});
this.$store.dispatch("MMCFlightControlCenter/hangar/takeOff", {
callback: (status) => {
if (status) {
this.$message.success("一键任务指令发送成功");
} else {
this.$message.error("一键任务指令发送失败");
}
},
});
this.rootNode.$emit("hangarStartTask", {
type: 1, //1: 日常任务 2:定时任务 3:周期任务
hangar: this.hangar,
task: this.selectedTask,
airway: this.selectedAirway,
});
} else {
// 获取当前机库状态
const statusItem = hangarStatusDict.find(
(item) => item.value === this.hangarRealTimeData.processStatus
);
this.$message.warning(statusItem?.label || "");
}
} catch (e) {}
},
},
};
</script>
<style lang="scss" scoped>
.normal-task ::v-deep {
padding: 32px 16px;
.el-form-item__label {
color: #fff;
}
.el-form-item__content {
> * {
width: 100%;
}
}
}
</style>
\ No newline at end of file
<template>
<div class="timed-task">
<div class="timed-task-header">
<div class="header__column flex2">名称</div>
<div class="header__column flex2">时间</div>
<div class="header__column">状态</div>
<div class="header__column flex2">操作</div>
</div>
<div class="timed-task-main">
<div class="row" v-for="item in taskListAll" :key="item.id">
<div class="row__column flex2">
<el-tooltip class="item" effect="dark" :content="item.name" placement="top-start">
<span>{{item.name}}</span>
</el-tooltip>
</div>
<div class="row__column flex2">{{item.time}}</div>
<div class="row__column" style="color: rgb(255, 189, 54);">{{item.status}}</div>
<div class="row__column flex2 ctrl">
<el-tooltip content="查看" placement="top">
<span
class="icon-chakan1 iconfont icon"
style="color: #ffffff; font-size: 10px;"
@click="onSwitchAirway(item)"
></span>
</el-tooltip>
<el-tooltip content="历史" placement="top">
<img class="icon" style="width: 15px;" src="../../assets/images/history.png" />
</el-tooltip>
<el-tooltip content="禁用" v-if="!item.enable" placement="top">
<img class="icon" style="width: 18px;" src="../../assets/images/enable.png" />
</el-tooltip>
<el-tooltip content="启用" v-if="item.enable" placement="top">
<img class="icon" style="width: 15px;" src="../../assets/images/able.png" />
</el-tooltip>
<el-tooltip content="删除" placement="top">
<span class="icon-shanchu iconfont icon"></span>
</el-tooltip>
</div>
</div>
</div>
</div>
</template>
<script>
import { mapState, mapActions } from "vuex";
import { AirLine } from "../../../../../../../../../../api";
export default {
name: "hangarTimedTask",
data() {
return {};
},
computed: {
...mapState("MMCFlightControlCenter", ["airwayEntities"]),
...mapState("MMCFlightControlCenter/hangar", [
"hangarRealTimeData",
"hangar",
"taskList",
]),
taskListAll() {
return this.taskList.timed || [];
},
},
beforeDestroy(){
this.clearAirwayEntities();
},
methods: {
...mapActions("MMCFlightControlCenter", [
"createAirwayEntities",
"clearAirwayEntities",
]),
/**
* 将任务中航线对象补充完整
*/
async getAirway(item){
if (!item.airway) {
let res = await AirLine.routeDetail({
id: item?.airwayId,
});
if (res.code === 200) {
item.airway = res.data;
}
}
},
/**
* 显示或隐藏航线
*/
async onSwitchAirway(item) {
await this.getAirway(item);
let find = this.airwayEntities.find((item1) => item1.airwayId === item.airwayId);
if (find) {
this.clearAirwayEntities({ id: find.airwayId });
} else {
let airway = JSON.parse(item.airway.content);
this.createAirwayEntities({
polyline: airway.content,
id: item.airwayId,
});
}
},
},
};
</script>
<style lang="scss" scoped>
.timed-task {
height: 100%;
display: flex;
flex-direction: column;
padding: 5px 10px 5px;
gap: 8px;
box-sizing: border-box;
.timed-task-header {
display: flex;
flex-shrink: 0;
font-family: MicrosoftYaHei-Bold;
font-size: 14px;
color: #b5e5ff;
padding: 5px 0;
letter-spacing: 0;
font-weight: 700;
background: rgba(87, 96, 138, 0.2);
border: 1px solid rgba(207, 234, 255, 0.33);
gap: 3px;
.header__column {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
&.flex2 {
flex: 2;
}
}
}
.timed-task-main {
color: #fff;
overflow-y: auto;
flex: 1;
.row {
display: flex;
color: #fff;
background: url("../../assets/images/listBg.png");
background-repeat: no-repeat;
background-size: 100% 100%;
height: 33px;
line-height: 33px;
padding-left: 4px;
margin-bottom: 16px;
gap: 3px;
.row__column {
flex: 1;
text-align: center;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
&.flex2 {
flex: 2;
}
&.ctrl {
display: flex;
justify-content: center;
align-items: center;
gap: 5px;
.icon {
cursor: pointer;
}
}
}
}
}
}
</style>
\ No newline at end of file
// 机库状态字典
export default [
{
value: 0,
label: "空闲 ",
},
{
value: 1,
label: "正在执行出仓待命 ",
},
{
value: 2,
label: "正在执行回收入仓 ",
},
{
value: 3,
label: "正在执行充电流程",
},
{
value: 4,
label: "正在结束充电流程",
},
{
value: 5,
label: "正在执行休眠流程",
},
{
value: 6,
label: "正在执行预热流程",
},
{
value: 7,
label: "正在执行初始化",
},
{
value: 8,
label: "未初始化",
},
{
value: 9,
label: "正在执行关舱流程 ",
},
{
value: 10,
label: "正在执行回中器操作 ",
},
{
value: 99,
label: "正在执行飞行任务",
},
];
<template>
<div class="task-list">
<div class="task-list-header">
<div
class="task-list-header__item"
:class="{active: tabIndex === 0}"
@click="tabIndex = 0"
>常态飞行</div>
<div
class="task-list-header__item"
:class="{active: tabIndex === 1}"
@click="tabIndex = 1"
>定时飞行</div>
<div
class="task-list-header__item"
:class="{active: tabIndex === 2}"
@click="tabIndex = 2"
>周期飞行</div>
</div>
<div class="task-list-main">
<!-- 常态任务 -->
<NormalTask v-if="tabIndex === 0"></NormalTask>
<!-- 定时任务 -->
<TimedTask v-else-if="tabIndex === 1"></TimedTask>
<!-- 周期任务 -->
<PeriodTask v-else-if="tabIndex === 2"></PeriodTask>
</div>
</div>
</template>
<script>
import NormalTask from './components/normalTask';
import TimedTask from './components/timedTask';
export default {
name: "hangarTaskList",
components: {
NormalTask,
TimedTask
},
data() {
return {
tabIndex: 0,
};
},
mounted(){
},
methods: {
}
};
</script>
<style lang="scss" scoped>
.task-list {
width: 416px;
height: 254px;
background: rgba(9, 32, 87, 0.7);
border-radius: 10px 10px 0 0;
display: flex;
flex-direction: column;
.task-list-header {
border-radius: 10px 10px 0 0;
height: 32px;
flex-shrink: 0;
display: flex;
.task-list-header__item {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
font-family: YouSheBiaoTiHei;
font-size: 16px;
color: #fff;
cursor: pointer;
&.active {
box-shadow: inset 0 0 10px 2px #3f9dff;
font-size: 20px;
font-family: YouSheBiaoTiHei;
color: #14faff;
line-height: 32px;
text-shadow: 0 1px 1px rgba(2, 32, 56, 0.2);
background: linear-gradient(
135deg,
#e3aa77,
#f5cda9 38%,
#f9ecd3 58%,
#fcdbb1 79%,
#edb07a
);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
}
}
.task-list-main {
flex: 1;
overflow: hidden;
}
}
</style>
\ No newline at end of file
<template>
<div class="traffic dialog1027">
<div class="dialog-header" v-interact>
<div class="dialog-header__icon" />
<div class="dialog-header__title">交通指引</div>
<div class="dialog-header_close" style="color:#fff" @click="()=>$emit('close')">关闭</div>
</div>
<div class="dialog-content">
<div class="step active">
<div class="step-box">
<div class="step-icon">1</div>
<div class="step-desc">无人机飞往交通事故现场进行拍摄取证</div>
</div>
<div class="btn-box1027">
<div class="btn1027" @click="onTakePhoto">取证</div>
</div>
<div class="imgList mt8" v-if="xcimg">
<el-image
style="width: 110px;height: 88px"
:src="imgApi + xcimg"
fit="cover"
:preview-src-list="[imgApi + xcimg]"
></el-image>
</div>
</div>
<div class="step">
<div class="step-box">
<div class="step-icon">2</div>
<div class="step-desc">激活事故绘制软件并上传事故图</div>
</div>
<div class="btn-box1027">
<div class="btn1027" @click="onActiveApp">激活软件</div>
<el-upload
class="dib"
accept=".png, .jpg, .image, .jpeg"
:action="upLoadApi + '/upload/v2_uploads'"
:on-success="onSuccess"
multiple
name="uploadFiles"
:show-file-list="false"
>
<div class="btn1027" style="margin-right: 0">上传事故图</div>
</el-upload>
</div>
<div class="imgList mt8" v-if="image">
<el-image
style="width: 110px;height: 88px"
:src="imgApi + image"
fit="cover"
:preview-src-list="[imgApi + image]"
></el-image>
</div>
</div>
<div class="step">
<div class="step-box">
<div class="step-icon">3</div>
<div class="step-desc">生成交通事故报告</div>
</div>
<div class="btn-box1027">
<div class="btn1027" @click="onExportReport">导出报告</div>
</div>
</div>
</div>
</div>
</template>
<script>
// import Bus from "@/assets/ligature.js";
import { saveAs } from "file-saver";
import Moment from "moment";
// import API from "@/api";
export default {
props: {
uavId: {
type: String,
default: ""
}
},
data() {
return {
upLoadApi: process.env.VUE_APP_UPLOADS_URL,
imgApi: process.env.VUE_APP_IMG_URL,
imageUrl: [],
imageName: [],
baseList: [],
image: null,
xcimg: null
};
},
computed: {
taskId() {
return this.$store.state.fckernel.taskId;
},
user_info() {
return this.$store.state.user.user_info;
}
},
methods: {
//拍照
async onTakePhoto() {
console.log("uav_take_photo emit");
Bus.$emit("uav_take_photo", {
callback: async blob => {
console.log("uav_take_photo callback");
const moment = new Moment();
const dateTime = moment.format("yyyyMMddhhmmss");
saveAs(blob, `${dateTime}.jpg`);
let fd2 = new FormData();
fd2.append("uploadFile", blob, `拍照.png`);
fd2.append("taskId", this.taskId);
fd2.append("deviceHardId", this.uavId);
let res2 = await API.FCKERNEL.Upload(fd2);
console.log(res2,"urlrel");
this.xcimg = '/uploads'+ res2.fileKey;
this.$message.success("取证成功!");
this.imageUrl.push(this.xcimg);
this.imageName.push('拍照.png');
let res1 = await API.ACCIDENT.createTaskWord({
imageUrl: this.imageUrl,
imageName: this.imageName,
taskId: this.taskId,
baseList: null
});
this.imageName = [];
this.imageUrl = [];
}
});
},
//激活程序
onActiveApp() {
window.open(`TrafficAccident://`, "_blank");
},
//导出报告
onExportReport() {
let url = `${process.env.VUE_APP_BASE_URL}/hawksystemserver/task/exportTaskWord?id=${this.taskId}&FLYINGSESSIONID=${this.user_info.FLYINGSESSIONID}&mmc-identity=${this.user_info["mmc-identity"]}`;
const fileName = url;
window.open(fileName);
},
//图片上传成功
async onSuccess(res, file, fileList) {
console.log("onSuccess", res);
if (res.status == 1) {
this.imageUrl.push(res.data[0].url);
this.imageName.push(res.data[0].name);
this.baseList.push(res.data[0].encode);
this.image = res.data[0].url;
let res1 = await API.ACCIDENT.createTaskWord({
imageUrl: this.imageUrl,
imageName: this.imageName,
taskId: this.taskId,
baseList: this.baseList
});
this.imageName = [];
this.imageUrl = [];
this.baseList = [];
this.$message.success("上传成功");
} else {
this.$message.error(res.msg || "上传失败");
}
}
}
};
</script>
<style lang="scss" scoped>
.traffic {
width: 268px;
}
.dialog-content {
padding: 16px !important;
height: initial !important;
}
.step {
font-size: 14px;
font-family: SourceHanSansCN-Medium, SourceHanSansCN;
font-weight: 500;
color: #fff;
width: 100%;
margin-bottom: 24px;
&:last-child {
margin-bottom: 0;
}
&.active {
.step-icon {
background: #1439ff;
}
}
.step-box {
display: flex;
// justify-content: space-between;
align-items: baseline;
}
.step-icon {
width: 18px;
height: 18px;
background: #515050;
display: flex;
justify-content: center;
align-items: center;
border-radius: 50%;
margin-right: 8px;
flex-shrink: 0;
}
.step-desc {
height: 40px;
line-height: 20px;
}
}
.btn-box1027 {
padding: 0 !important;
justify-content: right;
}
.btn1027 {
padding: 3px 8px;
min-width: 64px;
}
</style>
\ No newline at end of file
<template>
<div class="left-bar" :class="{ collapse: listCollapse }">
<div class="left-bar-item item" @click="onClickTask">
<img class="left-bar-item__icon" src="./assets/images/task.svg" />
<div class="left-bar-item__text">任务</div>
</div>
<TaskList class="task-list" v-if="openTask"></TaskList>
<div class="left-bar-item item" @click="onClickAI">
<img class="left-bar-item__icon" src="./assets/images/ai.png" />
<div class="left-bar-item__text">智能识别</div>
</div>
<div class="ai-list" :class="{ active: openAIList }">
<div class="left-bar-item item" @click.stop="switchAI(0)">
<img class="left-bar-item__icon" src="./assets/images/faceAI2.png" />
<div class="left-bar-item__text">人脸识别</div>
</div>
<div class="left-bar-item item" @click.stop="switchAI(1)">
<img class="left-bar-item__icon" src="./assets/images/carAI2.png" />
<div class="left-bar-item__text">车辆识别</div>
</div>
<Face v-if="openFace" class="ai-dialog" :uavId="uav.hardId" @close="openFace = false" />
<Car v-if="openPlate" class="ai-dialog" :uavId="uav.hardId" @close="openPlate = false" />
<Traffic
v-if="openTraffic"
class="ai-dialog"
:uavId="uav.hardId"
@close="openTraffic = false"
/>
<Jm v-if="openModeling" :device="device" class="jm-dialog" @close="openModeling = false"></Jm>
</div>
<!-- 展示视频 -->
<div class="left-video" :class="{collapse: playerCollapse}" v-if="showPanel && listCollapse">
<div class="collapse-btn" @click="playerCollapse = !playerCollapse">
<img src="./assets/images/hs.png" />
</div>
<div class="left-video-header">
<div class="left-video-header__title" @click="listCollapse = false">机库列表</div>
<div class="nest-name">
<span class="nest-name__text">{{ hangar.name }}</span>
<span class="nest-name__text">{{ hangar.name }}</span>
</div>
</div>
<div class="left-video-nest">
<div class="player1">
<PlayerInner />
</div>
<div class="player2">
<PlayerOuter />
</div>
<div class="player3">
<PlayerUav />
</div>
</div>
</div>
</div>
</template>
<script>
import { mapState } from "vuex";
import Car from "./components/car";
import Face from "./components/face";
import Jm from "./components/Jm";
import TaskList from "./components/taskList";
import Traffic from "./components/traffic";
import PlayerInner from "./components/player/inner";
import PlayerOuter from "./components/player/outer";
import PlayerUav from "./components/player/uav";
export default {
name: "ControlLeft",
components: {
Car,
Jm,
TaskList,
Traffic,
Face,
PlayerInner,
PlayerOuter,
PlayerUav,
},
data() {
return {
openTask: false, //打开任务
openAIList: false, //打开AI列表
openTraffic: false, //打开交通指引
openFace: false, //打开人脸识别
openPlate: false, //车牌识别
openModeling: false, //打开建模
playerCollapse: false, //收起播放器
};
},
computed: {
...mapState("MMCFlightControlCenter/hangar", ["hangar", "showPanel"]),
...mapState("MMCFlightControlCenter", ["listCollapse"]),
// 收起列表按钮
listCollapse: {
get() {
return this.$store.state.MMCFlightControlCenter.listCollapse;
},
set(val) {
this.$store.commit("MMCFlightControlCenter/setState", {
key: "listCollapse",
value: val,
});
},
},
},
methods: {
onClickTask() {
this.openTask = !this.openTask;
this.openAIList = false;
this.closeAI();
},
onClickAI() {
this.openTask = false;
this.openAIList = !this.openAIList;
this.closeAI();
},
/**
* 切换AI功能
*/
switchAI(type) {
this.openFace = false;
this.openPlate = false;
this.openTraffic = false;
this.openModeling = false;
switch (type) {
case 0:
this.openFace = !this.openFace;
break;
case 1:
this.openPlate = !this.openPlate;
break;
case 2:
if (this.taskId == null) {
return this.$message.error("暂无绑定任务!");
}
this.openTraffic = !this.openTraffic;
break;
case 3:
this.openModeling = !this.openModeling;
break;
}
},
/**
* 关闭所有ai
*/
closeAI() {
this.openFace = false;
this.openPlate = false;
this.openTraffic = false;
this.openModeling = false;
},
},
};
</script>
<style scoped lang="scss">
.task-list {
position: absolute;
left: 60px;
top: -30px;
cursor: initial;
}
.left-bar {
position: absolute;
left: 470px;
top: 13%;
transition: 0.3s;
&.collapse {
left: 10px;
}
.left-bar-item {
cursor: pointer;
position: relative;
width: 48px;
height: 48px;
background: rgba(9, 32, 87, 0.7);
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
margin-bottom: 2px;
.left-bar-item__icon {
width: 20px;
height: 20px;
margin-bottom: 2px;
}
.left-bar-item__text {
font-size: 16px;
transform: scale(0.6);
white-space: nowrap;
color: #fff;
}
}
.ai-list {
width: 0;
position: absolute;
left: 65px;
top: 62px;
display: none;
gap: 4px;
&.active {
display: flex;
}
.left-bar-item {
padding-top: 3px;
}
}
}
.ai-dialog {
position: absolute;
top: 56px;
left: 0;
}
.left-video {
width: 382px;
position: absolute;
left: -10px;
top: 308px;
z-index: 10;
background: rgba(12, 34, 73, 0.7);
border-radius: 10px;
border: 1px solid rgba(26, 92, 246, 0.5);
z-index: 1;
transition: 0.3s;
&.collapse {
transform: translateX(-100%);
}
.collapse-btn {
position: absolute;
top: 50%;
right: 0;
transform: translate(100%, -50%);
img {
transform: rotate(180deg);
cursor: pointer;
}
}
.left-video-header {
width: 100%;
height: 32px;
background-image: linear-gradient(
180deg,
#9198ff 0%,
rgba(45, 81, 153, 0.22) 40%,
#05091a 100%
);
border-radius: 10px 10px 0 0;
// border: 1px solid #70daf9;
box-shadow: inset 0 0 10px 2px #3f9dff;
box-sizing: inset 0px 0px 10px 2px #3f9dff;
background: url("./assets/images/line.png") no-repeat;
background-position: 60%;
font-size: 16px;
font-family: MicrosoftYaHei-Bold, MicrosoftYaHei;
font-weight: bold;
color: #70daf9;
display: flex;
// justify-content: center;
align-items: center;
.left-video-header__title {
cursor: pointer;
flex-shrink: 0;
margin-left: 16px;
width: 86px;
height: 22px;
line-height: 22px;
text-align: center;
font-size: 12px;
font-weight: 500;
font-family: SourceHanSansCN-Medium, SourceHanSansCN;
background: url("./assets/images/nestlist.png");
color: #fff;
}
.nest-name {
margin-left: 30px;
margin-right: 20px;
width: 250px;
overflow: hidden;
white-space: nowrap;
.nest-name__text {
display: inline-block;
white-space: nowrap;
animation: scrollTitle 15s linear infinite;
min-width: 100%;
padding-right: 50px;
box-sizing: border-box;
font-family: YouSheBiaoTiHei;
background-image: -webkit-linear-gradient(
right,
#e3aa77,
#f5cda9,
#f9ecd3,
#fcdbb1,
#edb07a
);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
font-size: 20px;
font-weight: 100;
}
}
}
@keyframes scrollTitle {
0% {
transform: translateX(0);
}
100% {
transform: translateX(-100%);
}
}
.left-video-nest::v-deep {
display: flex;
flex-wrap: wrap;
box-sizing: border-box;
gap: 10px;
padding: 16px 14px;
position: relative;
.player1,
.player2 {
flex: 1;
height: 96px;
}
.player3 {
width: 100%;
height: 240;
}
}
}
</style>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg width="164px" height="31px" viewBox="0 0 164 31" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>路径 3</title>
<defs>
<path d="M229.988757,97.4375536 L211.442082,124.702406 C211.131451,125.159054 211.249822,125.781055 211.706469,126.091686 C211.872338,126.204517 212.068308,126.264852 212.268916,126.264852 L352.929687,126.264852 C353.2531,126.264852 353.556546,126.108443 353.744181,125.845025 L373.165219,98.5801724 C373.485639,98.1303399 373.38073,97.5059266 372.930898,97.1855063 C372.761502,97.0648444 372.558701,97 372.350725,97 L230.815591,97 C230.484544,97 230.174953,97.1638333 229.988757,97.4375536 Z" id="path-1"></path>
<filter x="-3.4%" y="-22.2%" width="106.8%" height="144.4%" filterUnits="objectBoundingBox" id="filter-2">
<feMorphology radius="2" operator="erode" in="SourceAlpha" result="shadowSpreadInner1"></feMorphology>
<feGaussianBlur stdDeviation="5" in="shadowSpreadInner1" result="shadowBlurInner1"></feGaussianBlur>
<feOffset dx="0" dy="0" in="shadowBlurInner1" result="shadowOffsetInner1"></feOffset>
<feComposite in="shadowOffsetInner1" in2="SourceAlpha" operator="arithmetic" k2="-1" k3="1" result="shadowInnerInner1"></feComposite>
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0.482352941 0 0 0 0 1 0 0 0 0.5 0" type="matrix" in="shadowInnerInner1"></feColorMatrix>
</filter>
</defs>
<g id="鹰视子页面" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="路径-3" transform="translate(-210.000000, -96.000000)">
<use fill-opacity="0.498497596" fill="#000000" fill-rule="evenodd" xlink:href="#path-1"></use>
<use fill="black" fill-opacity="1" filter="url(#filter-2)" xlink:href="#path-1"></use>
<use stroke="#00B6FF" stroke-width="1" xlink:href="#path-1"></use>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg width="344px" height="38px" viewBox="0 0 344 38" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>路径 2备份</title>
<defs>
<radialGradient cx="50%" cy="0%" fx="50%" fy="0%" r="548.626887%" gradientTransform="translate(0.500000,0.000000),scale(0.096971,1.000000),rotate(82.515736),scale(1.000000,1.237046),translate(-0.500000,-0.000000)" id="radialGradient-1">
<stop stop-color="#00B6FF" offset="0%"></stop>
<stop stop-color="#00B6FF" offset="27.0225962%"></stop>
<stop stop-color="#00CAFF" stop-opacity="0" offset="73.0910044%"></stop>
<stop stop-color="#00D8FF" stop-opacity="0" offset="100%"></stop>
<stop stop-color="#00DCFF" stop-opacity="0" offset="100%"></stop>
</radialGradient>
</defs>
<g id="鹰视子页面" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="机库应用3" transform="translate(-18.000000, -89.000000)" stroke="url(#radialGradient-1)" stroke-width="2">
<polyline id="路径-2备份" points="6.83479976 92 6.83479976 125.264852 199.569948 125.264852 224.8348 90 370.5 90"></polyline>
</g>
</g>
</svg>
\ No newline at end of file
<template>
<ControlRight ref="controlRight" isHangar @switchCallback="showHangar = false; showMonitor = false;">
<div
slot="hangar"
class="control-item"
:class="showHangar ? 'active' : ''"
@click="onSwitchShow('showHangar')"
>
<!-- <img src="../../assets/images/hea.png" /> -->
<SymbolIcon icon="yingchao2" />
<span class="dib f8">机库</span>
</div>
<div slot="dialog">
<div class="hangar-ctrl" v-if="showHangar">
<div class="hangar-ctrl-header">
<span class="hangar-ctrl-header__title">
<img
class="hangar-ctrl-header__icon"
src="../../../../../../assets/images/mount_head.png"
/>操作区域
</span>
<span class="hangar-ctrl-header__close" @click="showHangar = false;">关闭</span>
</div>
<div class="hangar-ctrl-list">
<div
class="hangar-ctrl-item"
v-for="(item, i) in ctrlList"
:key="i"
@click="onClickCMD(i)"
>
<SymbolIcon v-if="item.icon" :icon="item.icon" class="hangar-ctrl-item__icon" />
<img v-else :src="item.img" class="hangar-ctrl-item__icon" />
<div class="hangar-ctrl-item__title">{{item.label}}</div>
</div>
</div>
</div>
<Logger :uavMsg="uavRealTimeData.msg" :hangarMsgList="hangarRealTimeData.msgList" :hangarData="hangarRealTimeData" class="logger" @exit="showLogger = false" @clearMsg="onClearMsg" v-if="showLogger"></Logger>
<HangarMonitor :uavMsg="uavRealTimeData.msg" :weatherStation="hangarRealTimeData.weatherStation" :hangarData="hangarRealTimeData" v-if="showMonitor"></HangarMonitor>
</div>
</ControlRight>
</template>
<script>
import ControlRight from "../../../../../uavApplications/components/controlPanel/components/controlRight";
import { mapActions, mapState } from "vuex";
import svgFXJJ from "./assets/images/fxjj.svg";
import Logger from './components/logger';
import HangarMonitor from './components/hangarMonitor';
export default {
name: "HangarControlRight",
components: {
ControlRight,
Logger,
HangarMonitor
},
data() {
return {
showHangar: false, // 显示机库列表
ctrlList: [
{
icon: "chucang1",
label: "出舱",
key: "out",
},
{
icon: "rucang1",
label: "入舱",
key: "in",
},
{
icon: "kaishichongdian",
label: "开始充电",
key: "chargeStart",
},
{
icon: "jieshuchongdian",
label: "结束充电",
key: "chargeEnd",
},
{
icon: "yure",
label: "预热",
key: "warmUp",
},
{
icon: "xiumian",
label: "休眠",
key: "dormancy",
},
{
icon: "yunhangrizhi2",
label: "运行日志",
key: "switchLogger",
noConfirm: true,
},
{
icon: "tuichuliucheng",
label: "退出流程",
key: "processExit",
},
{
icon: "guiji",
label: "运行监测",
key: "switchMonitor",
noConfirm: true,
},
{
img: svgFXJJ,
label: "飞行解禁",
key: "",
},
],
showLogger: true, // 显示日志
showMonitor: false, // 显示机库监测
};
},
computed: {
...mapState("MMCFlightControlCenter/uav", ['uavRealTimeData']),
...mapState('MMCFlightControlCenter/hangar', ['hangarRealTimeData'])
},
methods: {
...mapActions("MMCFlightControlCenter/hangar", [
"out",
"in",
"chargeStart",
"chargeEnd",
"warmUp",
"dormancy",
"processExit",
]),
/**
* 切换展示
*/
onSwitchShow(key) {
this.$refs.controlRight.hideAll(key);
this[key] = !this[key];
this.showMonitor = false;
},
/**
* 命令点击事件
* @param {number} i this.ctrlList被点击元素的索引
*/
async onClickCMD(i) {
let item = this.ctrlList[i];
let label = item.label;
let key = item.key;
let noConfirm = item.noConfirm;
try {
if (noConfirm) {
this[key]();
} else {
await this.$confirm(`请确认是否进行${label}操作?`, "安全确认", {
cancelButtonText: "取消",
confirmButtonText: "确定",
customClass: "uav_controlPane",
showClose: false,
});
this[key]();
}
} catch (e) {
console.log(e);
}
},
switchLogger(){
this.showLogger = !this.showLogger;
},
switchMonitor(){
this.showMonitor = !this.showMonitor;
if(this.showMonitor){
this.showHangar = false;
}
},
/**
* 清理日志
*/
onClearMsg(){
this.$store.commit('MMCFlightControlCenter/hangar/setState', {
key: 'hangarRealTimeData',
value: {
...this.hangarRealTimeData,
msgList: []
}
})
}
},
};
</script>
<style lang="scss" scoped>
.hangar-ctrl {
width: 416px;
min-height: 100px;
background: rgba(9, 32, 87, 0.7);
position: absolute;
right: 71px;
top: 50px;
bottom: auto !important;
width: 416px;
border-radius: 10px;
.hangar-ctrl-header {
display: flex;
justify-content: space-between;
height: 32px;
background: linear-gradient(
180deg,
#9198ff,
rgba(45, 81, 153, 0.45) 40%,
#05091a
);
box-shadow: inset 0 0 10px 2px #3f9dff;
border-radius: 10px 10px 0 0;
border: 1px solid #427dff;
.hangar-ctrl-header__title {
display: flex;
align-items: center;
font-size: 20px;
font-family: YouSheBiaoTiHei;
color: #14faff;
line-height: 26px;
text-shadow: 0 1px 1px rgba(2, 32, 56, 0.2);
background: linear-gradient(
135deg,
#e3aa77,
#f5cda9 38%,
#f9ecd3 58%,
#fcdbb1 79%,
#edb07a
);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.hangar-ctrl-header__close {
font-size: 14px;
font-family: MicrosoftYaHei;
color: #d2dfff;
margin-right: 8px;
cursor: pointer;
display: flex;
align-items: center;
}
}
.hangar-ctrl-list {
box-sizing: border-box;
justify-content: center;
padding: 10px 0px;
display: flex;
width: 100%;
gap: 15px;
flex-wrap: wrap;
.hangar-ctrl-item {
width: 48px;
height: 48px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 5px;
background-image: linear-gradient(
179deg,
#1773b6,
#3484c3 36%,
#2a7abd 56%,
#084681
);
box-shadow: 0 0 5px 0 #0c1c47;
border-radius: 4.5px;
cursor: pointer;
.hangar-ctrl-item__icon {
width: 28px;
height: 28px;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
color: #fff;
}
.hangar-ctrl-item__title {
font-size: 10px;
color: #fff;
}
}
}
}
.logger {
position: absolute;
left: -1200px;
}
</style>
\ No newline at end of file
<template>
<div>
<MMCDataTransferPanel class="data-panel" :device="uav" :uav-data="uavRealTimeData"></MMCDataTransferPanel>
<ControlLeft></ControlLeft>
<ControlBottom isHangar></ControlBottom>
<ControlRight></ControlRight>
</div>
</template>
<script>
import ControlLeft from "./components/controlLeft";
import ControlBottom from "../../../uavApplications/components/controlPanel/components/controlBottom";
import ControlRight from "./components/controlRight";
import { mapState } from "vuex";
export default {
name: "HangarControlPanel",
components: {
ControlLeft,
ControlBottom,
ControlRight,
},
computed: {
...mapState("MMCFlightControlCenter/uav", ["uavRealTimeData", "uav"]),
},
};
</script>
<style lang="scss" scoped>
.data-panel {
position: absolute;
bottom: 0;
left: 50%;
transform: translate(-50%, 0);
z-index: 100;
}
</style>
\ No newline at end of file
...@@ -15,11 +15,11 @@ ...@@ -15,11 +15,11 @@
</div> </div>
</div> </div>
<div class="nest-children" :class="{ collapse: data.collapse }"> <div class="nest-children" :class="{ collapse: listCollapse }">
<template v-if="data && data.nestList && data.nestList.length"> <template v-if="data && data.nests && data.nests.length">
<div class="nest-device-list"> <div class="nest-device-list">
<div <div
v-for="device in data.nestList" v-for="device in data.nests"
:key="`device_${device.id}`" :key="`device_${device.id}`"
class="nest-device-item" class="nest-device-item"
:class="{ online: device.online === 1 }" :class="{ online: device.online === 1 }"
...@@ -33,7 +33,7 @@ ...@@ -33,7 +33,7 @@
> >
<el-checkbox <el-checkbox
:disabled="device.online !== 1" :disabled="device.online !== 1"
:value="device.changestatus" :value="device.isCheck"
@change="(e) => handClick(e, device)" @change="(e) => handClick(e, device)"
></el-checkbox> ></el-checkbox>
</el-tooltip> </el-tooltip>
...@@ -59,36 +59,22 @@ ...@@ -59,36 +59,22 @@
</div> </div>
<div class="icon-box"> <div class="icon-box">
<el-popover <span class="type fr" v-if="device.status">{{ typeName(device.status) }}</span>
v-if="device.warnList && device.warnList.length > 0"
placement="right"
width="400"
trigger="hover"
>
<div style="display: flex; flex-direction: column">
<div
style="line-height: 20px; color: #fff; padding: 12px"
v-for="(warn, index) in device.warnList"
:key="index"
>{{ warn.content }}</div>
</div>
<span slot="reference" style="margin-right: 12px" class="iconfont icon-jiankang"></span>
</el-popover>
<span @click="itemLocation(device)" class="iconfont fr icon-dingwei1"></span> <span @click="itemLocation(device)" class="iconfont fr icon-dingwei1"></span>
<span class="type fr">{{ typeName(device.status) }}</span>
</div> </div>
</div> </div>
</div> </div>
</template> </template>
<div class="nest-child_group_box" v-if="data.child && data.child.length"> <div class="nest-child_group_box" v-if="data.childs && data.childs.length">
<Item v-for="item in data.child" :data="item" :key="`device_child_${item.id}`" /> <Item v-for="(item, i) in data.childs" :data="item" :key="`device_child_${i}`" />
</div> </div>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import { mapState } from "vuex";
export default { export default {
name: "Item", name: "Item",
props: { props: {
...@@ -97,37 +83,104 @@ export default { ...@@ -97,37 +83,104 @@ export default {
default: () => ({}), default: () => ({}),
}, },
}, },
inject: ['rootNode'],
data() { data() {
return { return {
device: {}, device: {},
}; };
}, },
computed: { computed: {
curr() { ...mapState("MMCFlightControlCenter", ["listCollapse"]),
return this.current(); ...mapState("MMCFlightControlCenter/hangar", ["showPanel", "hangar"]),
}, ...mapState("MMCFlightControlCenter/uav", ["uav"]),
}, },
methods: { methods: {
typeName(val) { typeName(val) {
let name = ""; let name = "";
if (val == 6) { switch (val) {
name = "充电中"; case 1:
} else if (val == 5) { name = "正常";
name = "飞行中"; break;
} else if (val == 2 || val == 3 || val == 4) {
name = "出仓中"; case 2:
} else if (val == 1) { name = "维修中";
name = "回收中"; break;
} else if (val == 0) {
name = "待机中"; case 3:
name = "损坏";
break;
case 4:
name = "保养中";
break;
} }
return name; return name;
}, },
handClick(e, device) { handClick(isCheck, device) {
this.itemClick(e, device); console.log("checkbox", isCheck, device);
this.data.nests.forEach((item) => {
this.$set(item, "isCheck", false);
});
if (isCheck) {
device.isCheck = true;
}
// 切换订阅的机库, 需要先取消订阅旧机库, 再重新订阅新机库
this.hangar &&
this.$store.dispatch("MMCFlightControlCenter/hangar/unsubscribe");
this.uav &&
this.$store.dispatch("MMCFlightControlCenter/uav/unsubscribe");
// todo 由于unsubscribe操作会将hangar设置为null, 所以unsubscribe操作要放在if判断之后再执行
if (isCheck) {
this.$store.commit("MMCFlightControlCenter/hangar/setState", {
key: "showPanel",
value: true,
});
this.$store.commit("MMCFlightControlCenter/hangar/setState", {
key: "hangar",
value: {
...device,
showPanel: true,
},
});
this.$store.dispatch("MMCFlightControlCenter/hangar/subscribe");
// 切换订阅的无人机, 需要先取消订阅旧无人机, 再重新订阅新无人机
this.uav &&
this.$store.dispatch("MMCFlightControlCenter/uav/unsubscribe");
if (device.uav) {
this.$store.commit("MMCFlightControlCenter/uav/setState", {
key: "uav",
value: device.uav,
});
this.$store.dispatch("MMCFlightControlCenter/uav/subscribe");
} else {
this.$message.error("该机库中没有无人机!");
}
this.rootNode.$emit('changeHangar', this.hangar); //根节点发出机库更换事件
} else {
this.$store.commit("MMCFlightControlCenter/hangar/setState", {
key: "showPanel",
value: false,
});
this.$store.commit("MMCFlightControlCenter/hangar/setState", {
key: "hangar",
value: null,
});
this.rootNode.$emit('changeHangar', null);
}
if (this.showPanel) {
this.$store.commit("MMCFlightControlCenter/setState", {
key: "listCollapse",
value: true,
});
}
}, },
}, },
inject: ["itemClick", "itemLocation"],
}; };
</script> </script>
...@@ -176,7 +229,7 @@ export default { ...@@ -176,7 +229,7 @@ export default {
} }
.line-box { .line-box {
width: 80px; display: flex;
flex-shrink: 0; flex-shrink: 0;
font-family: Arial, Helvetica, sans-serif; font-family: Arial, Helvetica, sans-serif;
font-size: 14px; font-size: 14px;
...@@ -202,7 +255,6 @@ export default { ...@@ -202,7 +255,6 @@ export default {
line-height: 30px; line-height: 30px;
box-sizing: border-box; box-sizing: border-box;
padding-left: 20px; padding-left: 20px;
cursor: pointer;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
...@@ -280,14 +332,8 @@ export default { ...@@ -280,14 +332,8 @@ export default {
} }
.icon-box { .icon-box {
.icon-jiankang { display: flex;
font-weight: bold; align-items: center;
color: #d54a15;
&.healthy {
color: #15d589;
}
}
} }
} }
} }
...@@ -309,6 +355,7 @@ export default { ...@@ -309,6 +355,7 @@ export default {
font-size: 16px; font-size: 16px;
} }
.type { .type {
cursor: default;
font-weight: 400; font-weight: 400;
font-size: 10px; font-size: 10px;
height: 22px; height: 22px;
......
<!-- 飞控中心机库列表 --> <!-- 飞控中心机库列表 -->
<template> <template>
<div style="height: 100%"> <div class="list" :class="{ collapse: listCollapse }">
<div class="uav-list-header"> <div class="list-header">
<div> <div>
<img <img class="list-header__icon" src="./assets/images/uav_list_header.png" />
class="uav-list-header__icon" <span class="list-header__text">机库列表</span>
src="./assets/images/uav_list_header.png"
/>
<span class="uav-list-header__text">机库列表</span>
</div> </div>
<div class="uav-list-header__count"> <div class="list-header__count">
{{ count.sumCount }}架 / {{ count.sumCount }}架 /
<span class="online">{{ count.onlineCount }}在线</span> / <span class="online">{{ count.onlineCount }}在线</span>
/
{{ count.offlineCount }}离线 {{ count.offlineCount }}离线
</div> </div>
</div> </div>
...@@ -24,72 +22,104 @@ ...@@ -24,72 +22,104 @@
</div> </div>
</div> </div>
</div> </div>
<img
@click="listCollapse = !listCollapse;"
style="transform: rotate(180deg)"
src="./assets/images/hs.png"
class="nsetLeftBox_btn"
/>
</div> </div>
<!-- </Dialog> --> <!-- </Dialog> -->
</template> </template>
<script> <script>
import { Control_API } from "../../../../api";
import Item from "./components/item"; import Item from "./components/item";
import { mapState } from "vuex";
export default { export default {
props: { name: "List",
value: { props: {},
type: Object,
default: () => ({}),
},
asyncList: {
type: Function,
default: () => () => {},
},
list: {
type: Array,
default: () => [],
},
},
components: { Item }, components: { Item },
data() { data() {
return { return {
name: null, list: [],
curr_value: null,
}; };
}, },
computed: { computed: {
...mapState("MMCFlightControlCenter", ["listCollapse"]),
count() { count() {
if (this.list.length == 0) { let countObj = {
return {
onlineCount: 0, onlineCount: 0,
offlineCount: 0, offlineCount: 0,
sumCount: 0, sumCount: 0,
}; };
} else { this.list.forEach((item) => {
return { countObj.onlineCount += item?.online || 0;
onlineCount: this.list[0].onLineCount, countObj.offlineCount += item?.offline || 0;
offlineCount: this.list[0].offLineCount, });
sumCount: this.list[0].onLineCount + this.list[0].offLineCount, countObj.sumCount = countObj.onlineCount + countObj.offlineCount;
}; return countObj;
}
},
},
watch: {
value: {
handler(value) {
this.curr_value = value;
}, },
immediate: true, // 收起列表按钮
deep: true, listCollapse: {
get(){
return this.$store.state.MMCFlightControlCenter.listCollapse;
}, },
set(val){
this.$store.commit('MMCFlightControlCenter/setState', {
key: 'listCollapse',
value: val
})
}
}
}, },
watch: {},
mounted() { mounted() {
this.asyncList(); this.getList();
},
methods: {
async getList() {
let res = await Control_API.getUavNestList({
name: "",
});
if (res.code === 200) {
this.list = res.data;
}
}, },
provide() {
}, },
}; };
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.list {
display: flex;
flex-direction: column;
position: absolute;
width: 460px;
height: 85%;
left: 0;
top: 60px;
// height: 86vh;
z-index: 99;
transition: 0.3s;
border-radius: 10px 10px 0px 0px;
overflow: visible;
&.collapse {
display: none;
}
.nsetLeftBox_btn {
position: absolute;
cursor: pointer;
right: -22px;
top: 50%;
transform: translate(0, -50%);
}
}
.healthy { .healthy {
box-sizing: border-box; box-sizing: border-box;
padding: 0 5px; padding: 0 5px;
...@@ -113,9 +143,10 @@ export default { ...@@ -113,9 +143,10 @@ export default {
} }
.cpt-observe-nest-list { .cpt-observe-nest-list {
display: flex; display: flex;
flex: 1;
flex-direction: column; flex-direction: column;
height: 87vh;
background: rgba(12, 34, 73, 0.7); background: rgba(12, 34, 73, 0.7);
overflow-y: auto;
.search-box { .search-box {
flex-shrink: 0; flex-shrink: 0;
...@@ -169,7 +200,6 @@ export default { ...@@ -169,7 +200,6 @@ export default {
.ctx-box { .ctx-box {
flex: 1; flex: 1;
overflow: auto; overflow: auto;
margin-bottom: 30px;
height: 100%; height: 100%;
/* backdrop-filter: blur(3px); */ /* backdrop-filter: blur(3px); */
position: relative; position: relative;
...@@ -186,7 +216,7 @@ export default { ...@@ -186,7 +216,7 @@ export default {
color: #70daf9 !important; color: #70daf9 !important;
font-weight: 700 !important; font-weight: 700 !important;
} }
.uav-list-header { .list-header {
box-sizing: border-box; box-sizing: border-box;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
...@@ -203,7 +233,7 @@ export default { ...@@ -203,7 +233,7 @@ export default {
border-radius: 10px 10px 0px 0px; border-radius: 10px 10px 0px 0px;
border: 1px solid #427dff; border: 1px solid #427dff;
.uav-list-header__text { .list-header__text {
vertical-align: bottom; vertical-align: bottom;
font-size: 20px; font-size: 20px;
font-family: YouSheBiaoTiHei; font-family: YouSheBiaoTiHei;
...@@ -221,12 +251,12 @@ export default { ...@@ -221,12 +251,12 @@ export default {
-webkit-text-fill-color: transparent; -webkit-text-fill-color: transparent;
} }
.uav-list-header__icon { .list-header__icon {
width: 26px; width: 26px;
margin-left: 9px; margin-left: 9px;
} }
.uav-list-header__count { .list-header__count {
color: #fff; color: #fff;
font-weight: 500; font-weight: 500;
margin-right: 16px; margin-right: 16px;
......
<template> <template>
<div> <div>
<List></List> <List></List>
<ControlPanel v-if="hangar && uav && showPanel"></ControlPanel>
</div> </div>
</template> </template>
<script> <script>
import List from './components/list'; import { mapState } from "vuex";
import List from "./components/list";
import ControlPanel from "./components/controlPanel";
import linkFusion from "./mixins/linkFusion";
export default { export default {
name: 'Hangar', name: "Hangar",
mixins: [linkFusion],
components: { components: {
List List,
ControlPanel,
},
data() {
return {};
},
computed: {
...mapState("MMCFlightControlCenter/hangar", ["showPanel", "hangar"]),
...mapState("MMCFlightControlCenter/uav", ["uav"]),
},
beforeDestroy() {
this.$store.commit('MMCFlightControlCenter/setState', {
key: 'listCollapse',
value: false
})
if (this.uav) {
this.$store.dispatch("MMCFlightControlCenter/uav/unsubscribe");
}
if (this.hangar) {
this.$store.dispatch("MMCFlightControlCenter/hangar/unsubscribe");
} }
} this.$store.dispatch('MMCFlightControlCenter/uav/end');
},
};
</script> </script>
<style> <style>
</style> </style>
\ No newline at end of file
// 无人机实时数据各链路融合
export default {
computed: {
// mqtt实时数据
mqttDataSet() {
return this.$store.state.MMCMQTT?.dataSet?.[this.hangar?.hardId];
},
mqttUrl() {
return this.$store.getters["MMCFlightControlCenter/mqttUrl"];
},
},
watch: {
mqttDataSet(newVal) {
if (newVal) {
this.$store.dispatch(
"MMCFlightControlCenter/hangar/updateByMQTT",
newVal
);
}
},
},
async created() {
// 启动mqtt服务
try {
this.$store
.dispatch("MMCMQTT/init", {
url: this.mqttUrl,
})
.then(() => {
console.log("mqtt连接成功");
});
} catch (e) {
console.log("mqtt失败", e);
}
},
};
...@@ -4,13 +4,15 @@ ...@@ -4,13 +4,15 @@
<SymbolIcon icon="yijianrenwu" /> <SymbolIcon icon="yijianrenwu" />
<span class="dib f8">一键任务</span> <span class="dib f8">一键任务</span>
</div> </div>
<!-- v-show="iconShow" -->
<div class="control-bottom-item" @click="onReturnFlight"> <div class="control-bottom-item" @click="onReturnFlight">
<SymbolIcon icon="yijianfanhang2" /> <SymbolIcon icon="yijianfanhang2" />
<span class="dib f8">一键返航</span> <span class="dib f8">一键返航</span>
</div> </div>
<!-- v-show="iconShow" --> <div class="control-bottom-item" @click="onLand" v-if="isHangar">
<div class="control-bottom-item" @click="onTaskEnd"> <SymbolIcon icon="anquanjiangla1" />
<span class="dib f8">紧急迫降</span>
</div>
<div class="control-bottom-item" @click="onTaskEnd" v-else>
<SymbolIcon icon="renwujieshu1" /> <SymbolIcon icon="renwujieshu1" />
<span class="dib f8">任务结束</span> <span class="dib f8">任务结束</span>
</div> </div>
...@@ -29,7 +31,6 @@ ...@@ -29,7 +31,6 @@
</div> </div>
</template> </template>
<!-- device.isPush =99 代表大疆 -->
<template v-else> <template v-else>
<div v-if="controlType === 0" class="control-bottom-item" @click="onModeManual"> <div v-if="controlType === 0" class="control-bottom-item" @click="onModeManual">
<SymbolIcon icon="zidong" /> <SymbolIcon icon="zidong" />
...@@ -39,7 +40,6 @@ ...@@ -39,7 +40,6 @@
<SymbolIcon icon="shoudong" /> <SymbolIcon icon="shoudong" />
<span class="dib f8">手动</span> <span class="dib f8">手动</span>
</div> </div>
</template> </template>
<!-- 键盘控制 --> <!-- 键盘控制 -->
<div class="key-control" v-if="controlType === 2"> <div class="key-control" v-if="controlType === 2">
...@@ -203,29 +203,39 @@ import { flightTaskAPI, Control_API } from "../../../../../../api"; ...@@ -203,29 +203,39 @@ import { flightTaskAPI, Control_API } from "../../../../../../api";
export default { export default {
name: "ControlBottom", name: "ControlBottom",
inject:['bus'], inject: ["bus"],
props: {
// 是否是机库组件
isHangar: {
type: Boolean,
default: false,
},
},
data() { data() {
return { return {
controlType: 0, //控制类型, 0: 自动 1: 摇杆 2: 键盘 controlType: 0, //控制类型, 0: 自动 1: 摇杆 2: 键盘
}; };
}, },
computed: { computed: {
...mapState("MMCFlightControlCenter/uav", [ ...mapState("MMCFlightControlCenter/uav", ["uav", "airlineData"]),
"uav",
"airlineData",
]),
}, },
methods: { methods: {
...mapActions("MMCFlightControlCenter/uav", [ /**
"isTakeOver", * 接管判断, 机库模块中不需要判断接管
]), */
async isTakeOver(){
if(this.isHangar){
return true;
}
return await this.$store.dispatch("MMCFlightControlCenter/uav/isTakeOver");
},
// 无人机接管更新状态 // 无人机接管更新状态
async updateTakeOver() { async updateTakeOver() {
await Control_API.updateTakeOver(this.uav.id); await Control_API.updateTakeOver(this.uav.id);
}, },
// 一键任务 // 一键任务
onStartTask() { onStartTask() {
this.bus.$emit('startTask'); this.bus.$emit("startTask");
}, },
// 一键返航 // 一键返航
async onReturnFlight() { async onReturnFlight() {
...@@ -242,14 +252,11 @@ export default { ...@@ -242,14 +252,11 @@ export default {
}).then((res) => { }).then((res) => {
this.updateTakeOver(); this.updateTakeOver();
this.$store.dispatch( this.$store.dispatch("MMCFlightControlCenter/uav/returnFlight", {
"MMCFlightControlCenter/uav/returnFlight",
{
callback: (isOk) => { callback: (isOk) => {
isOk && this.$message.success("发出返航指令成功"); isOk && this.$message.success("发出返航指令成功");
}, },
} });
);
}); });
}, },
// 任务结束 // 任务结束
...@@ -274,6 +281,28 @@ export default { ...@@ -274,6 +281,28 @@ export default {
}); });
}); });
}, },
// 紧急降落
async onLand() {
// 判断是否已接管
if (!(await this.isTakeOver())) {
this.$message.warning("请先接管无人机");
return;
}
this.$confirm("请确认是否进行紧急降落操作?", "安全确认", {
cancelButtonText: "取消",
confirmButtonText: "确定",
customClass: "uav_controlPane",
showClose: false,
}).then((res) => {
this.updateTakeOver();
this.$store.dispatch("MMCFlightControlCenter/uav/land", {
callback: (isOk) => {
isOk && this.$message.success("发出紧急降落指令成功");
},
});
});
},
/** /**
* 手动模式 * 手动模式
*/ */
...@@ -283,15 +312,13 @@ export default { ...@@ -283,15 +312,13 @@ export default {
this.$message.warning("请先接管无人机"); this.$message.warning("请先接管无人机");
return; return;
} }
this.$store.dispatch( this.$store.dispatch("MMCFlightControlCenter/uav/modeManual", {
"MMCFlightControlCenter/uav/modeManual",
{
callback: (isOk) => { callback: (isOk) => {
isOk && (this.controlType = 1); isOk && (this.controlType = 1);
}, },
} });
);
}, },
/** /**
* 自动模式 * 自动模式
*/ */
...@@ -301,45 +328,35 @@ export default { ...@@ -301,45 +328,35 @@ export default {
this.$message.warning("请先接管无人机"); this.$message.warning("请先接管无人机");
return; return;
} }
this.$store.dispatch( this.$store.dispatch("MMCFlightControlCenter/uav/modeAuto", {
"MMCFlightControlCenter/uav/modeAuto",
{
callback: (isOk) => { callback: (isOk) => {
isOk && (this.controlType = 0); isOk && (this.controlType = 0);
}, },
} });
);
}, },
/** /**
* 键盘模式 * 键盘模式
*/ */
async onModeKeyboard(){ async onModeKeyboard() {
// 判断是否已接管 // 判断是否已接管
if (!(await this.isTakeOver())) { if (!(await this.isTakeOver())) {
this.$message.warning("请先接管无人机"); this.$message.warning("请先接管无人机");
return; return;
} }
this.$store.dispatch( this.$store.dispatch("MMCFlightControlCenter/uav/modeKeyboard", {
"MMCFlightControlCenter/uav/modeKeyboard",
{
callback: (isOk) => { callback: (isOk) => {
isOk && (this.controlType = 2); isOk && (this.controlType = 2);
}, },
} });
);
}, },
/** /**
* 键盘控制 * 键盘控制
*/ */
clickControl(){ clickControl() {},
},
/** /**
* 停止键盘控制 * 停止键盘控制
*/ */
cancelControl(){ cancelControl() {},
}
}, },
}; };
</script> </script>
......
...@@ -8,7 +8,6 @@ ...@@ -8,7 +8,6 @@
</div> </div>
<el-form class="task-main" label-width="60px"> <el-form class="task-main" label-width="60px">
<el-form-item label="任务库"> <el-form-item label="任务库">
<el-tooltip :content="clew" placement="top">
<el-cascader <el-cascader
filterable filterable
popper-class="mmc" popper-class="mmc"
...@@ -33,7 +32,6 @@ ...@@ -33,7 +32,6 @@
</el-tooltip> </el-tooltip>
</template> </template>
</el-cascader> </el-cascader>
</el-tooltip>
</el-form-item> </el-form-item>
<el-form-item label="航线"> <el-form-item label="航线">
<el-tooltip content="航线名称" placement="top"> <el-tooltip content="航线名称" placement="top">
...@@ -78,9 +76,6 @@ export default { ...@@ -78,9 +76,6 @@ export default {
selectedTaskId: [], selectedTaskId: [],
// 航线数据 // 航线数据
flightList: [], flightList: [],
// 航线id
flightId: "",
flightIdv2: "",
// 选择的航线 // 选择的航线
selectedAirway: { selectedAirway: {
name: "", name: "",
...@@ -88,12 +83,11 @@ export default { ...@@ -88,12 +83,11 @@ export default {
}, },
// 航线选择窗口 // 航线选择窗口
showFlywayDialog: false, showFlywayDialog: false,
clew: "任务库", // 选中任务提示语
}; };
}, },
computed: { computed: {
...mapState("MMCFlightControlCenter", ["taskList", "cesiumViewer"]), ...mapState("MMCFlightControlCenter", ["cesiumViewer"]),
...mapState("MMCFlightControlCenter/uav", ["uav"]), ...mapState("MMCFlightControlCenter/uav", ["taskList", "uav"]),
taskListAll() { taskListAll() {
return [{ name: "选择航线自动生成任务", id: -1 }, ...this.taskList]; return [{ name: "选择航线自动生成任务", id: -1 }, ...this.taskList];
}, },
...@@ -161,26 +155,21 @@ export default { ...@@ -161,26 +155,21 @@ export default {
customClass: "uav_controlPane", customClass: "uav_controlPane",
showClose: false, showClose: false,
}); });
if (this.selectedAirway.id === -1) { this.$store.commit("MMCFlightControlCenter/uav/setState", {
this.$store.commit(
"MMCFlightControlCenter/uav/setState",
{
key: "airlineData",
value: null,
}
);
} else {
this.$store.commit(
"MMCFlightControlCenter/uav/setState",
{
key: "airlineData", key: "airlineData",
value: this.selectedAirway, value: this.selectedAirway,
});
this.$store.dispatch("MMCFlightControlCenter/uav/takeOff", {
callback(status) {
if (status) {
this.$message.success("一键任务指令发送成功");
} else {
this.$message.error("一键任务指令发送失败");
} }
); },
} });
this.$store.dispatch("MMCFlightControlCenter/uav/takeOff");
this.rootNode.$emit( this.rootNode.$emit(
"startTask", "uavStartTask",
this.uav, this.uav,
this.selectedTask, this.selectedTask,
this.selectedAirway this.selectedAirway
...@@ -245,11 +234,7 @@ export default { ...@@ -245,11 +234,7 @@ export default {
item.alt = Number(item.alt); item.alt = Number(item.alt);
pointPositions.push(item.longitude, item.latitude, item.alt); pointPositions.push(item.longitude, item.latitude, item.alt);
label_arr.push( label_arr.push(
Cesium.Cartesian3.fromDegrees( Cesium.Cartesian3.fromDegrees(item.longitude, item.latitude, item.alt)
item.longitude,
item.latitude,
item.alt
)
); );
point_entity = this.cesiumViewer.entities.add({ point_entity = this.cesiumViewer.entities.add({
position: Cesium.Cartesian3.fromDegrees( position: Cesium.Cartesian3.fromDegrees(
......
...@@ -10,6 +10,8 @@ ...@@ -10,6 +10,8 @@
<img src="../../assets/images/hea.png" /> <img src="../../assets/images/hea.png" />
<span class="dib f8">健康管理</span> <span class="dib f8">健康管理</span>
</div> </div>
<!-- 机库信息 -->
<slot name="hangar"></slot>
<div <div
class="control-item" class="control-item"
:class="showMount ? 'active' : ''" :class="showMount ? 'active' : ''"
...@@ -27,7 +29,7 @@ ...@@ -27,7 +29,7 @@
<span class="dib f8">无人机</span> <span class="dib f8">无人机</span>
</div> </div>
<div <div
v-if="uav.network === 1" v-if="!isHangar && uav.network === 1"
class="control-item" class="control-item"
:class="showAlarmLamp ? 'active' : ''" :class="showAlarmLamp ? 'active' : ''"
@click="onSwitchShow('showAlarmLamp')" @click="onSwitchShow('showAlarmLamp')"
...@@ -105,6 +107,7 @@ ...@@ -105,6 +107,7 @@
ref="MountControllerRef" ref="MountControllerRef"
/> />
<AlarmLamp v-if="showAlarmLamp" :uav="uav" @close="showAlarmLamp = false" /> <AlarmLamp v-if="showAlarmLamp" :uav="uav" @close="showAlarmLamp = false" />
<slot name="dialog"></slot>
</div> </div>
</template> </template>
...@@ -130,6 +133,13 @@ export default { ...@@ -130,6 +133,13 @@ export default {
ViewLib, ViewLib,
AlarmLamp, AlarmLamp,
}, },
props: {
// 是否机库页面使用
isHangar: {
type: Boolean,
default: false
}
},
data() { data() {
return { return {
showAlarmLamp: false, //展示警示灯面板 showAlarmLamp: false, //展示警示灯面板
...@@ -141,10 +151,7 @@ export default { ...@@ -141,10 +151,7 @@ export default {
}; };
}, },
computed: { computed: {
...mapState("MMCFlightControlCenter/uav", [ ...mapState("MMCFlightControlCenter/uav", ["uav", "airlineData"]),
"uav",
"airlineData",
]),
}, },
methods: { methods: {
hideAll(key) { hideAll(key) {
...@@ -166,6 +173,7 @@ export default { ...@@ -166,6 +173,7 @@ export default {
* 切换展示 * 切换展示
*/ */
onSwitchShow(key) { onSwitchShow(key) {
this.$emit("switchCallback");
this.hideAll(key); this.hideAll(key);
this[key] = !this[key]; this[key] = !this[key];
}, },
...@@ -180,7 +188,7 @@ export default { ...@@ -180,7 +188,7 @@ export default {
right: 30px; right: 30px;
z-index: 1; z-index: 1;
.control-list { .control-list::v-deep {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 3px; gap: 3px;
......
...@@ -2,10 +2,8 @@ ...@@ -2,10 +2,8 @@
<div> <div>
<MMCDataTransferPanel <MMCDataTransferPanel
class="data-panel" class="data-panel"
:device="device" :device="uav"
:throttleValue="throttleValue" :uav-data="uavRealTimeData"
:uav-battery="battery"
:uav-data="uavData"
></MMCDataTransferPanel> ></MMCDataTransferPanel>
<!-- 一键任务 返航 安全降落 手动 --> <!-- 一键任务 返航 安全降落 手动 -->
<ControlBottom></ControlBottom> <ControlBottom></ControlBottom>
...@@ -44,26 +42,7 @@ export default { ...@@ -44,26 +42,7 @@ export default {
}; };
}, },
computed: { computed: {
...mapState("MMCFlightControlCenter/uav", ["uavRealTimeData"]), ...mapState("MMCFlightControlCenter/uav", ["uavRealTimeData", "uav"]),
uavData() {
// console.log("this.uavRealTimeData", this.uavRealTimeData);
return {
relativeAlt:
Number(this.uavRealTimeData?.gps?.relativeAlt)?.toFixed(0) || "-",
absoluteAlt:
Number(this.uavRealTimeData?.gps?.absoluteAlt)?.toFixed(0) || "-",
flyDistance:
Number(this.uavRealTimeData?.flyDistance)?.toFixed(0) || "-",
flyTime: Number(this.uavRealTimeData?.flyTime)?.toFixed(0) || "-", //飞行时间
groundSpeed:
Number(this.uavRealTimeData?.groundSpeed)?.toFixed(0) || "-", //飞行速度
distanceToHome:
Number(this.uavRealTimeData?.distanceToHome)?.toFixed(0) || "-",
velocityX: this.uavRealTimeData?.velocityX || 0,
velocityY: this.uavRealTimeData?.velocityY || 0,
velocityZ: Number(this.uavRealTimeData?.velocityZ)?.toFixed(0) || "-", //爬升率
};
},
}, },
}; };
</script> </script>
......
...@@ -161,7 +161,6 @@ export default { ...@@ -161,7 +161,6 @@ export default {
) { ) {
if((value / 100).toFixed(2) == '0.00'){ if((value / 100).toFixed(2) == '0.00'){
// console.log('this.obstacle.distances', this.obstacle.distances) // console.log('this.obstacle.distances', this.obstacle.distances)
// debugger
} }
this.minDistance[block] = (value / 100).toFixed(2); this.minDistance[block] = (value / 100).toFixed(2);
} }
......
...@@ -284,8 +284,8 @@ ...@@ -284,8 +284,8 @@
<div class="search mr22" v-if="!isStatus"> <div class="search mr22" v-if="!isStatus">
<el-select class="video_type mr24" v-model="streamSelect" placeholder="切换源"> <el-select class="video_type mr24" v-model="streamSelect" placeholder="切换源">
<el-option <el-option
v-for="item in streamOptions" v-for="(item, i) in streamOptions"
:key="item.label" :key="i"
:label="item.label" :label="item.label"
:value="item.value" :value="item.value"
></el-option> ></el-option>
......
...@@ -5,13 +5,13 @@ ...@@ -5,13 +5,13 @@
v-if="listCollapse" v-if="listCollapse"
style="transform: rotate(180deg)" style="transform: rotate(180deg)"
src="./assets/images/hs.png" src="./assets/images/hs.png"
class="icon-collapse uav-list_btn" class="uav-list_btn"
/> />
<img <img
@click="collapseFlagfn" @click="collapseFlagfn"
v-else v-else
src="./assets/images/collapse.png" src="./assets/images/collapse.png"
class="icon-collapse uav-list_btn" class="uav-list_btn"
/> />
<div class="uav-list-header"> <div class="uav-list-header">
<img class="uav-list-header__icon" src="./assets/images/uav_list_header.png" /> <img class="uav-list-header__icon" src="./assets/images/uav_list_header.png" />
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
:mountDatas="selectMount" :mountDatas="selectMount"
@close="onPlayerClose" @close="onPlayerClose"
/> />
<ControlPanel v-if="showPanel"></ControlPanel> <ControlPanel v-if="uav && showPanel"></ControlPanel>
</div> </div>
</template> </template>
...@@ -44,26 +44,6 @@ export default { ...@@ -44,26 +44,6 @@ export default {
"showPanel", "showPanel",
"selectMount" "selectMount"
]), ]),
taskId() {
return this.$store.state.fckernel.taskId;
},
YJTaskInfo() {
return this.$store.state.fckernel.YJTaskInfo;
},
lineInfo() {
return this.$store.state.fckernel.lineInfo;
},
uav_mounts() {
let { mounts } = this.uav.control;
return mounts
.map((item) => {
let find_item = this.mount.list.find(
(m) => m.name === item.gimbalName
);
return find_item || undefined;
})
.filter((item) => item);
},
}, },
created() { created() {
// 等待航线上传成功在执行 // 等待航线上传成功在执行
...@@ -73,7 +53,16 @@ export default { ...@@ -73,7 +53,16 @@ export default {
}); */ }); */
}, },
mounted() {}, mounted() {},
beforeDestroy() {}, beforeDestroy() {
this.$store.commit('MMCFlightControlCenter/setState', {
key: 'listCollapse',
value: false
})
if(this.uav){
this.$store.dispatch('MMCFlightControlCenter/uav/unsubscribe');
}
this.$store.dispatch('MMCFlightControlCenter/uav/end');
},
methods: { methods: {
getcanvas(val, item) { getcanvas(val, item) {
let data = null; let data = null;
...@@ -342,12 +331,4 @@ export default { ...@@ -342,12 +331,4 @@ export default {
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.player {
/* position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: 0;
height: 0; */
}
</style> </style>
// 无人机实时数据各链路融合 // 无人机实时数据各链路融合
export default { export default {
computed: { computed: {
/* uav() {
return this.$store.state.MMCFlightControlCenter.uav.uav;
}, */
// mqtt实时数据 // mqtt实时数据
mqttDataSet() { mqttDataSet() {
return this.$store.state.MMCMQTT?.dataSet?.[this.uav?.hardId]; return this.$store.state.MMCMQTT?.dataSet?.[this.uav?.hardId];
...@@ -12,15 +9,6 @@ export default { ...@@ -12,15 +9,6 @@ export default {
gsDataSet() { gsDataSet() {
return this.$store.state.MMCGroundStation?.dataSet?.[this.uav?.hardId]; return this.$store.state.MMCGroundStation?.dataSet?.[this.uav?.hardId];
}, },
token() {
return this.$store.state.MMCFlightControlCenter.token;
},
userInfo() {
return this.$store.state.MMCFlightControlCenter.userInfo;
},
wsUrl() {
return this.$store.getters["MMCFlightControlCenter/wsUrl"];
},
mqttUrl() { mqttUrl() {
return this.$store.getters["MMCFlightControlCenter/mqttUrl"]; return this.$store.getters["MMCFlightControlCenter/mqttUrl"];
}, },
...@@ -63,27 +51,6 @@ export default { ...@@ -63,27 +51,6 @@ export default {
console.log("mqtt失败", e); console.log("mqtt失败", e);
} }
// 由于ws连接到地面站是使用广播形式获取无人机数据的,所以在组件创建时先连接ws,后续选择无人机时,通过广播数据,筛选出选择的无人机信息出来 // 由于地面站是广播形式的数据传输, 非常消耗性能, 把连接地面站ws的操作挪到了订阅中去, 取消订阅时就断开ws
try {
const username = this.userInfo.userName;
const token = this.token;
this.$store
.dispatch("MMCGroundStation/init", {
url: this.wsUrl,
userInfo: {
type: 100,
systemCode: "mmc",
state: 1,
username,
token,
appId: "40003",
},
})
.then(() => {
console.log("地面站连接成功");
});
} catch (e) {
console.log("地面站连接失败", e);
}
}, },
}; };
...@@ -17,6 +17,7 @@ import mapImageSwitch from "./components/mapImageSwitch"; ...@@ -17,6 +17,7 @@ import mapImageSwitch from "./components/mapImageSwitch";
import uavApplications from "./components/uavApplications"; import uavApplications from "./components/uavApplications";
import hangar from "./components/hangar"; import hangar from "./components/hangar";
import Vue from "vue"; import Vue from "vue";
import SymbolIcon from "../symbol-icon";
export default { export default {
name: "MMCFlightControlCenter", name: "MMCFlightControlCenter",
...@@ -37,8 +38,8 @@ export default { ...@@ -37,8 +38,8 @@ export default {
type: Object, type: Object,
default: null, default: null,
}, },
// 任务列表 // 无人机任务列表
taskList: { uavTaskList: {
type: Array, type: Array,
default() { default() {
return [ return [
...@@ -54,20 +55,51 @@ export default { ...@@ -54,20 +55,51 @@ export default {
]; ];
}, },
}, },
// 航线列表 // 机库任务列表
airwayList: { hangarTaskList: {
type: Array, type: Object,
default() { default() {
return [ return {
// 常态
normal: [
/* { /* {
name: '任务',
id: 1,
status: '', 任务状态
children: [],
airway: {
name: '航线名称', name: '航线名称',
id: 1
}
} */
],
// 定时
Timed: [
/* {
name: '任务',
id: 1, id: 1,
organizationName: '所属单位', time: '', //定时与周期的时间
status: 1 //空域状态 1: 可用 2: 待申请 3: 待审批 4: 通过 5: 驳回 status: '', 任务状态
isSafe: 1 //空域状态 1: 安全 2: 待确定 airway: {
labelName: '航线标签' name: '航线名称',
id: 1
}
} */ } */
]; ],
// 周期
period: [
/* {
name: '任务',
id: 1,
time: '', //定时与周期的时间
status: '', 任务状态
airway: {
name: '航线名称',
id: 1
}
} */
],
};
}, },
}, },
// 场景 0: 无人机 1: 机库 // 场景 0: 无人机 1: 机库
...@@ -83,10 +115,19 @@ export default { ...@@ -83,10 +115,19 @@ export default {
}; };
}, },
watch: { watch: {
taskList: { uavTaskList: {
immediate: true, immediate: true,
handler(newVal) { handler(newVal) {
this.$store.commit("MMCFlightControlCenter/setState", { this.$store.commit("MMCFlightControlCenter/uav/setState", {
key: "taskList",
value: newVal,
});
},
},
hangarTaskList: {
immediate: true,
handler(newVal) {
this.$store.commit("MMCFlightControlCenter/hangar/setState", {
key: "taskList", key: "taskList",
value: newVal, value: newVal,
}); });
...@@ -94,10 +135,11 @@ export default { ...@@ -94,10 +135,11 @@ export default {
}, },
}, },
beforeCreate() { beforeCreate() {
Vue.component("SymbolIcon", SymbolIcon);
if (!window.$mmc) { if (!window.$mmc) {
window.$mmc = {}; window.$mmc = {};
} }
window.$mmc.store = this.$store; window.$mmc.$store = this.$store;
window.$mmc.state = () => { window.$mmc.state = () => {
return this.$store.state; return this.$store.state;
}; };
...@@ -116,9 +158,7 @@ export default { ...@@ -116,9 +158,7 @@ export default {
value: this.userInfo, value: this.userInfo,
}); });
}, },
methods: { methods: {},
},
}; };
</script> </script>
...@@ -389,6 +429,11 @@ export default { ...@@ -389,6 +429,11 @@ export default {
background-color: #34466e !important; background-color: #34466e !important;
} }
} }
.el-select-dropdown__empty {
background: #02173d;
border: 1px solid #315ec7;
}
} }
&.el-cascader__dropdown { &.el-cascader__dropdown {
......
...@@ -34,11 +34,11 @@ export default function main(elementOrSelector, options = {}){ ...@@ -34,11 +34,11 @@ export default function main(elementOrSelector, options = {}){
if(!window.$mmc){ if(!window.$mmc){
window.$mmc = {}; window.$mmc = {};
} }
window.$mmc.store = new Vuex.Store(store); window.$mmc.$store = new Vuex.Store(store);
return new Vue({ return new Vue({
render: (h) => h(App), render: (h) => h(App),
router, router,
store: window.$mmc.store, store: window.$mmc.$store,
}).$mount(elementOrSelector); }).$mount(elementOrSelector);
} }
......
import Moment from "moment";
let hangarRealTimeData = {
chargerPower: 0, //充电电源,0-未知,1-打开,2-关闭
cover: 0, //舱盖,0-未知,1-关闭,2-打开,3-正在关闭,4-正在打开
driverPower: 0, // 伺服电源,0-未知,1-打开,2-关闭
folder: 0, // 回中器,0-未知,1-夹紧,2-放松,3-夹紧过程,4-放松过程
hangarHumid: 0, // 停机坪内湿度,单位:%
hangarMode: 0, // 停机坪模式,0-未知,1-正常模式,2-休眠模式
hangarPower: 0, // 停机坪电源,0-未知,1-打开,2-关闭
hangarTemp: 0, // 停机坪内温度,单位:度
inLamp: 0, // 内部灯,0-未知,1-打开,2-关闭
lifts: 0, // 起降台,0-未知,1-降下,2-升起,3-降下过程,4-升起过程
outCameraPower: 0, // 外置摄像头电源,0-未知,1-打开,2-关闭
outLamp: 0, // 外部灯,0-未知,1-打开,2-关闭
processStatus: 0, // 0-空闲 、1-正在执行出仓待命、2-正在执行回收入仓、3-正在执行充电流程 、4-正在结束充电流程、5-正在执行休眠流程、6-正在执行预热流程、7-正在执行初始化、8-未初始化 、9-正在执行关舱流程 、10-正在执行回中器操作、99-正在执行飞行任务
remotePower: 0, // 遥控电源,0-未知,1-打开,2-关闭
rfPower: 0, // 射频电源,0-未知,1-打开,2-关闭
rtkPower: 0, // RTK 基站电源,0-未知,1-打开,2-关闭
videoPower: 0, // 机载视频电源,0-未知,1-打开,2-关闭
waterWarn: 0, // 水浸报警,0-未知,1-报警,2-正常
msg: {
// 2063 飞控应答消息
number: 0, // 包序列号
text: "", // 文本内容
type: 1, // 系统消息数据:2063
},
msgList: [], //飞控应答消息记录
weatherStation: {
// 2066 气象站数据
rain: 0, // 雨量,0-无雨,1-有雨
homeLat: 0, // 停机坪纬度,单位 deg
homeLon: 0, // 停机坪经度,单位 deg
humidity: 0, // 湿度,单位:%
light: 0, // 光照,单位:lux
number: 0, // 包序列号
homesatellite: 0, // 停机坪卫星数
temp: 0, // 温度,单位:C
weatherHumid: 0, // 气象站湿度,单位:%
weatherTemp: 0, // 气象站温度,单位:度
windDirection: 0, // 风向,单位:deg
windSpeed: 0, // 风速,单位 m/s
},
};
const state = {
hangar: null, // 选择中的机库信息
showPanel: false, //显示数据面板
hangarRealTimeData, // 实时数据
airlineData: null, // 当前选择的航线数据
};
const mutations = {
/**
* 单纯的给state赋值
* @param {*} param0
* @param {*} data {key: '', value}
*/
setState(state, data) {
try {
state[data.key] = data.value;
} catch (e) {
console.log("setDate err", e);
}
},
};
const actions = {
// 通过mqtt更新实时采集数据
updateByMQTT({ commit, state, dispatch }, data) {
// mqtt链路
const type2065 = data[2065]?.data || {};
const type2063 = data[2063]?.data; //飞控应答消息
data[2063] && console.log("type2063", data[2063]);
const type2066 = data[2066]?.data || {}; //气象站数据
let msgList = state.hangarRealTimeData.msgList || [];
if (type2063) {
let moment = new Moment();
type2063.time = moment.format("yyyy-MM-DD hh:mm:ss");
msgList.push(type2063);
data[2063] = null;
}
commit("setState", {
key: "hangarRealTimeData",
value: {
...state.hangarRealTimeData,
...type2065,
msg: type2063,
msgList,
weatherStation: type2066,
},
});
},
/**
* 订阅机库数据
* @param {*} param0
* @param {object} data
*/
subscribe({ state, dispatch }) {
window.$mmc.$store.dispatch("MMCMQTT/subscribe", {
topic: "APRON/RECEIVE/" + state.hangar.hardId,
callback(ok) {
ok &&
console.log("mqtt订阅主题", "APRON/RECEIVE/" + state.hangar.hardId);
},
});
},
/**
* 取消订阅
* @param {} param0
*/
unsubscribe({ state, dispatch }) {
window.$mmc.$store.dispatch("MMCMQTT/unsubscribe", {
topic: "APRON/RECEIVE/" + state.hangar.hardId,
callback(ok) {
ok &&
console.log(
"mqtt取消订阅主题",
"APRON/RECEIVE/" + state.hangar.hardId
);
},
});
dispatch("destroy");
},
/**
* 销毁机库相关对象
* @param {} param0
* @param {*} data
*/
destroy({ commit, state, dispatch }, data) {
commit("setState", { key: "hangar", value: null });
commit("setState", {
key: "hangarRealTimeData",
value: hangarRealTimeData,
});
},
/**
* 显示面板
* @param {*} param0
* @param {Object} data 机库信息
*/
async showPanel({ state, commit, dispatch }, data) {
if (state.hangar?.id !== data.id) {
// 切换订阅的机库, 需要先取消订阅旧机库, 再重新订阅新机库
state.hangar && dispatch("unsubscribe");
commit("setState", {
key: "showPanel",
value: true,
});
commit("setState", {
key: "hangar",
value: {
...data,
showPanel: true,
},
});
dispatch("subscribe");
} else {
// 关闭机库订阅
dispatch("unsubscribe");
commit("setState", {
key: "showPanel",
value: false,
});
commit("setState", {
key: "hangar",
value: null,
});
}
},
/**
* 出库
* @param {*} param0
* @param {*} data
* @param {Function} data.callback
*/
out({ state, commit, dispatch }, data) {
window.$mmc.$store.dispatch("MMCMQTT/publish", {
topic: "APRON/RECEIVE/" + state.hangar.hardId,
data: {
cmdControlType: 2059,
},
callback() {
data?.callback && data.callback();
},
});
},
/**
* 入库
* @param {*} param0
* @param {*} data
*/
in({ state, commit, dispatch }, data) {
window.$mmc.$store.dispatch("MMCMQTT/publish", {
topic: "APRON/RECEIVE/" + state.hangar.hardId,
data: {
cmdControlType: 2073,
},
callback() {
data?.callback && data.callback();
},
});
},
/**
* 开始充电
* @param {*} param0
* @param {*} data
*/
chargeStart({ state, commit, dispatch }, data) {
window.$mmc.$store.dispatch("MMCMQTT/publish", {
topic: "APRON/RECEIVE/" + state.hangar.hardId,
data: {
cmdControlType: 2060,
},
callback() {
data?.callback && data.callback();
},
});
},
/**
* 结束充电
* @param {*} param0
* @param {*} data
*/
chargeEnd({ state, commit, dispatch }, data) {
window.$mmc.$store.dispatch("MMCMQTT/publish", {
topic: "APRON/RECEIVE/" + state.hangar.hardId,
data: {
cmdControlType: 2071,
},
callback() {
data?.callback && data.callback();
},
});
},
/**
* 预热
* @param {*} param0
* @param {*} data
*/
warmUp({ state, commit, dispatch }, data) {
window.$mmc.$store.dispatch("MMCMQTT/publish", {
topic: "APRON/RECEIVE/" + state.hangar.hardId,
data: {
cmdControlType: 2072,
},
callback() {
data?.callback && data.callback();
},
});
},
/**
* 休眠
* @param {*} param0
* @param {*} data
*/
dormancy({ state, commit, dispatch }, data) {
window.$mmc.$store.dispatch("MMCMQTT/publish", {
topic: "APRON/RECEIVE/" + state.hangar.hardId,
data: {
cmdControlType: 2061,
},
callback() {
data?.callback && data.callback();
},
});
},
/**
* 退出流程
* @param {*} param0
* @param {*} data
*/
processExit({ state, commit, dispatch }, data) {
window.$mmc.$store.dispatch("MMCMQTT/publish", {
topic: "APRON/RECEIVE/" + state.hangar.hardId,
data: {
cmdControlType: 100001,
},
callback() {
data?.callback && data.callback();
},
});
},
/**
* 一键起飞
* @param {function} data.callback //完成回调
*/
async takeOff({ state }, data) {
try {
let uavHardId =
window.$mmc.$store.state.MMCFlightControlCenter.uav.uav.hardId;
// 生成架次号
const getFlightSortic = await Control_API.getFlightSortic({
taskId: state.airlineData.id,
deviceHardId: uavHardId,
});
// 上传航线指令
const flightObj = JSON.parse(state.airlineData.content);
const waypointList = flightObj.map((v) => ({
altitude: v.alt,
coordinate: {
latitude: v.latitude,
longitude: v.longitude,
},
frame: 3,
stay: 0.0,
speed: v.speed,
waypointActions: v.actions,
}));
this.$store.dispatch("MMCMQTT/publish", {
topic: "PROCESS/OBTAIN/" + state.hangar.hardId,
data: {
cmdControlType: 100004,
uavDeviceId: uavHardId,
wayLineObj: {
taskId: state.airlineData.id,
flightSortiesID: getFlightSortic.data,
autoFlightSpeed: state.airlineData.line.baseSpeed,
waypointList,
finishedAction: "GO_HOME",
headingMode: "AUTO",
isExitMissionOnRCSignalLostEnabled: true,
maxFlightSpeed: 12,
},
},
callback() {
data.callback && data.callback(true);
},
});
} catch (e) {
console.log(e);
data.callback && data.callback(false, e);
}
},
};
export default {
namespaced: true,
name: "hangar",
state,
mutations,
actions,
};
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论