提交 47f051c4 作者: 温凯

合并分支 'v4_master' 到 'master'

V4 master

查看合并请求 !8
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -8,7 +8,8 @@
:scene="scene"
:useSTLAirway="useSTLAirway"
:useTimedTask="useTimedTask"
:useAirway="useAirway"
:useTask="useTask"
:showVideoPanel="showVideoPanel"
@tokenInvalid="dispatchEvent('tokenInvalid')"
@refreshToken="dispatchEvent('refreshToken', $event)"
@uavChange="dispatchEvent('uavChange', $event)"
......@@ -23,6 +24,11 @@
@airwayListGet="dispatchEvent('airwayListGet', $event)"
@airwayGet="dispatchEvent('airwayGet', $event)"
@taskListGet="dispatchEvent('taskListGet', $event)"
@leapFrogFlighGet="dispatchEvent('leapFrogFlighGet', $event)"
@apronUavSkipEvent="dispatchEvent('apronUavSkipEvent', $event)"
@taskRecordPageGet="dispatchEvent('taskRecordPageGet', $event)"
@taskInfoUpdateTime="dispatchEvent('taskInfoUpdateTime', $event)"
@taskInfoRecordDel="dispatchEvent('taskInfoRecordDel', $event)"
></MMCFlightControlCenter>
</template>
......@@ -35,7 +41,7 @@ export default {
baseUrl: "/",
wsUrl: "wss://tmj.mmcuav.cn/websocket",
mqttUrl: "wss://fkzx.mmcuav.cn:8884/mqtt",
mqttToken: '',
mqttToken: "",
},
scene: 0, // 场景类型 1: 无人机 2: 机库
account: "mmctest@admin",
......@@ -50,8 +56,9 @@ export default {
airwayPageChangeCB: null, //航线翻页时回调
airwayGetCB: null, //获取航线数据回调
taskListGetCB: null, //获取任务数据回调
useAirway: true, //使用航线而不使用任务起飞
useTask: false, //使用任务进行航线选择
callbackList: {},
showVideoPanel: false, //无人机是否展示视频面板
};
},
computed: {},
......@@ -69,7 +76,7 @@ export default {
* 给父窗口发送消息
*/
postTop(data) {
console.log('iframe postMessage', data);
console.log("iframe postMessage", data);
window.top.postMessage(
{
module: "MMCFlightControlCenter",
......@@ -85,9 +92,16 @@ export default {
window.addEventListener("message", (event) => {
if (event.data.module === "MMCFlightControlCenter") {
console.log("iframe收到数据", event.data);
this.paramHandler(event.data);
this.callbackHandler(event.data);
this.logHandler(event.data);
if (event.type === "window") {
this.postTop({
event: "window",
data: window,
});
} else {
this.paramHandler(event.data);
this.callbackHandler(event.data);
this.logHandler(event.data);
}
}
});
},
......@@ -123,6 +137,7 @@ export default {
if (i === arr.length - 1) {
switch (keyType) {
case "value":
console.log('event log', value);
this.postTop({
event: "log",
data: {
......@@ -146,32 +161,6 @@ export default {
*/
dispatchEvent(event, data) {
// 回调函数不能通过postMessage传递
/* switch (event) {
case "hangarTaskAdd":
this.hangarTaskAddCB = data.callback;
delete data.callback;
break;
case "uavTaskAdd":
this.uavTaskAddCB = data.callback;
delete data.callback;
break;
case "airwayPageChange":
this.airwayPageChangeCB = data.callback;
delete data.callback;
break;
case "airwayGet":
this.airwayGetCB = data.callback;
delete data.callback;
break;
case "taskListGet":
this.taskListGetCB = data.callback;
delete data.callback;
break;
} */
if (data?.callback) {
this.callbackList[event] = data.callback;
delete data.callback;
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -81,7 +81,7 @@ export default {
}
let data = JSON.parse(event.currentTarget.result).data;
window.$log('src/components/observe/fckernel/uav/control/controlMenu/mixins/joystick.js message', data)
if (data && this.wsShow) {
const yaw = data.channel01//偏航-1000-1000
const x = data.channel02//俯仰-1000-1000
......
import axios from "axios";
import request from "../request";
// const gddaiapi = 'https://hawk.mmcuav.cn/gddaiapi';
export default class AI_API {
// 获取当前的ai配置
static getAiconfig(data) {
return request({
url: `/admin-api/system/ai-config/getconfig`,
method: "post",
data,
});
}
// 人脸
static face(data){
// return axios.post("http://api.user.mmcuav.cn/aidemo/facedetect", data); // 百度的ai
return axios.post("https://hawk.mmcuav.cn/faceaiapi/detect/imageface", data);
static face(data) {
return axios.post(
"https://hawk.mmcuav.cn/faceaiapi/detect/imageface",
data
);
}
// 车牌
static plate(data) {
return axios.post("https://hawk.mmcuav.cn/gddaiapi/api/inflet/v1/tasks/e01d1d01-52e2-4883-a5de-0ae268764db0/predict", data); // 共达地
// return axios.post("https://hawk.mmcuav.cn/plateaiapi/detect/image", data); // 自研
return axios.post(
"/gddaiapi/api/inflet/v1/tasks/e01d1d01-52e2-4883-a5de-0ae268764db0/predict",
data
); // 共达地
}
// 人流
static crowd(data){
return axios.post("https://hawk.mmcuav.cn/gddaiapi/api/inflet/v1/tasks/18493235-4dd0-4f54-ab55-c1856ca7e3a5/predict", data);
static crowd(data) {
return axios.post(
"/gddaiapi/api/inflet/v1/tasks/18493235-4dd0-4f54-ab55-c1856ca7e3a5/predict",
data
);
}
// 烟雾
static smoke(data){
return axios.post("https://hawk.mmcuav.cn/gddaiapi/api/inflet/v1/tasks/fca2eb65-8b99-4109-9f9e-a9f7fd06ac1f/predict", data);
static smoke(data) {
return axios.post(
"/gddaiapi/api/inflet/v1/tasks/fca2eb65-8b99-4109-9f9e-a9f7fd06ac1f/predict",
data
);
}
// 漏油识别
static oilLeak(data){
static oilLeak(data) {
return axios.post("https://hawk.mmcuav.cn/oilaiapi/detect/image", data);
}
// 裸土识别
static bareSoil(data){
return axios.post("https://hawk.mmcuav.cn/gddaiapi/api/inflet/v1/tasks/05a9d657-8339-4575-bced-04b60b74c690/predict", data);
static bareSoil(data) {
return axios.post(
"/gddaiapi/api/inflet/v1/tasks/05a9d657-8339-4575-bced-04b60b74c690/predict",
data
);
}
// 其余ai
static kbtAi(data) {
return axios.post("https://hawk.mmcuav.cn/detect/image", data);
}
}
\ No newline at end of file
}
......@@ -12,6 +12,16 @@ export default class TaskInfo {
});
}
// 通过任务生成架次号
static createTaskRecord(data) {
return request({
url: `/admin-api/bpm/task-info-record/createTaskRecord`,
method: "post",
data
});
}
// 获取航线
static getRoute(data) {
return request({
......
import request from "../request";
import request_uav from "../request_uav";
import store from "../../store";
class Control_API {
// 获取无人机树结构列表
......@@ -30,26 +30,26 @@ class Control_API {
data,
});
}
// 获取1小时短时天气预报
static getUavShortForEcast(params) {
return request_uav({
url: `/whapi/json/aliweather/shortforecast`,
method: "post",
params,
// 是否同意接管
static updateControlUav(data) {
return request({
url: `/admin-api/uas/device-take/updateControlUav`,
method: 'post',
data
});
}
// 获取24小时短时天气预报(详细)包含风向等等...
static getUavShortForEcast24(params) {
return request_uav({
url: `/whapi/json/aliweather/forecast24hours`,
method: "post",
params,
// 录入设备操控人
static updateCurrentOperator(params) {
return request({
url: `/admin-api/uas/device-take/updateCurrentOperator`,
method: 'post',
params
});
}
// 接管无人机
static setUavControlOn(params) {
// 申请接管无人机
static applyControlUav(params) {
return request({
url: `/admin-api/uas/device-take/updateCurrentOperator`,
url: `/admin-api/uas/device-take/controlUav`,
method: 'post',
params
});
......@@ -96,6 +96,13 @@ class Control_API {
});
}
/**
* 获取websocket连接地址
* @returns
*/
static getWebsocketUrl(){
return `/infra/ws?token=${store.state.token}`;
}
}
export default Control_API;
......@@ -29,6 +29,7 @@ $axios.interceptors.request.use(
config.headers["Tenant-Id"] = TenantId;
config.headers["terminal"] = 2; // 1 为管理后台 2 为前端项目
config.headers["p-id"] = projectId;
console.log(config, store.state, "token信息验证");
return config;
},
(error) => {
......@@ -73,11 +74,14 @@ $axios.interceptors.response.use(
isRefreshToken = false;
if (data.code === 0) {
const token = data.token;
console.log('store', store);
window.$mmc_stl.app.$store.commit('MMCFlightControlCenter/setState', {
key: 'token',
value: token
})
window.$mmc_stl.app.$store.commit(
"MMCFlightControlCenter/setState",
{
key: "token",
value: token,
}
);
config.headers.Authorization = "Bearer " + token;
requestList.forEach((cb) => {
cb();
......
import axios from 'axios';
// import store from "../store";
// import router from "../router";
import Vue from 'vue';
// 引用element-ui的加载和消息提示组件
// import { Loading } from "element-ui";
import { resetMessage } from './message';
import store from '../store';
let prodUrl = 'https://tmj.mmcuav.cn/flight_control';
let devUrl = 'https://test.tmj.mmcuav.cn/flight_control'
const $axios = axios.create({
// 设置超时时间
// timeout: 30000,
// 基础url,会在请求url中自动添加前置链接
// baseURL: process.env.VUE_APP_BASE_UAV_API
});
Vue.prototype.$http = axios;
const loading = null;
/**
* 请求拦截器
* 用于处理请求前添加loading、判断是否已保存token,并在每次请求头部添加token
*/
$axios.interceptors.request.use(
(config) => {
// let FLYINGSESSIONID = localStorage.getItem("FLYINGSESSIONID");
// let mmcIdentity = localStorage.getItem("mmcIdentity");
// let token = localStorage.getItem("tmj_token")
// loading = Loading.service({ text: "Loading", background: "transparent" });
// if (FLYINGSESSIONID && mmcIdentity) {
// 请求头部添加token
// config.headers["FLYINGSESSIONID"] = FLYINGSESSIONID;
// config.headers["mmc-identity"] = mmcIdentity;
// config.headers["token"] = token; //测试token用例:607753147d46ba48b1ac30a4ad3d60cd
// }
if(store.state.devMode){
config.baseURL = devUrl;
} else {
config.baseURL = prodUrl;
}
return config;
},
(error) => {
return Promise.reject(error);
}
);
/**
* 响应拦截器
* 用于处理loading状态关闭、请求成功回调、响应错误处理
*/
$axios.interceptors.response.use(
(response) => {
if (loading) {
loading.close();
}
const code = response.status;
const res = response.data;
// 请求成功返回response.data
if ((code >= 200 && code < 300) || code === 304) {
if (res.status == 621) {
resetMessage.error(res.message);
// store.commit("user/LOGIN_OUT");
// router.push("/login");
}
return Promise.resolve(response.data);
} else {
return Promise.reject(response);
}
},
(error) => {
if (loading) {
loading.close();
}
console.log(error);
if (error.response) {
switch (error.response.status) {
case 401:
// 返回401 清除token信息并跳转到登陆页面
// store.commit("user/LOGIN_OUT");
// router.replace({
// path: "/login",
// query: {
// redirect: router.currentRoute.fullPath,
// },
// });
break;
case 404:
resetMessage.error('网络请求不存在');
break;
case 403:
if (store.state.isIframe) {
resetMessage.error('授权组件已被禁用,请联系管理员');
}
break;
default:
resetMessage.error(error.response.data.message);
}
} else {
// 请求超时或者网络有问题
if (error.message.includes('timeout')) {
resetMessage.error('请求超时!请检查网络是否正常');
} else {
resetMessage.error('请求失败,请检查网络是否已连接');
}
}
return Promise.reject(error);
}
);
export default $axios;
<template>
<el-dialog :visible.sync="localVisible" :close-on-click-modal="false" :modal-append-to-body="false"
:show-close="showClose" @close="handleClose" :width="width">
<div slot="title" class="dialog-header">
<div >
<img src="../../../../../../assets/images/mount_head.png" />
<span class="title vas">{{ title }}</span>
</div>
</div>
<div class="stl-timed-task">
<div class="timed-task-header">
<div class="header__column flex2">序号</div>
<div class="header__column flex2">机库名称</div>
<div class="header__column status">状态</div>
<div class="header__column flex2">距离(km)</div>
</div>
<div class="timed-task-main" v-loading="loading" element-loading-background="rgba(0, 0, 0, 0.8)">
<div class="row" :class="{ single: i % 2 != 0 }" v-for="(item, i) in taskListAll" :key="item.id">
<div class="row__column flex2">
<span class="f12">
<span class="mr10">
<el-checkbox v-model="item.active" :label="item.id"
:disabled="item.type === '忙碌'"></el-checkbox>
</span>{{ i + 1 }}
</span>
</div>
<div class="row__column flex2">
<el-tooltip class="item" effect="dark" :content="item.name" placement="top-start">
<span class="f12">{{ item.name }}</span>
</el-tooltip>
</div>
<div class="row__column flex2">
<el-tooltip class="item" effect="dark" :content="item.descText" placement="top-start">
<span class="f12"
:class="{ 'text-red': item.type === '忙碌', 'text-green': item.type == '空闲' }">{{
item.type
}}</span>
</el-tooltip>
</div>
<div class="row__column status" style="color: rgb(255, 189, 54)">
<el-tooltip class="item" effect="dark" :content="String(item.distance)" placement="top-start">
<span class="f12">{{ item.distance }}</span>
</el-tooltip>
</div>
</div>
</div>
<div class="task-add-btn">
<div class="task-add__btn">生成航线</div>
<div class="task-add__btn">一键任务</div>
</div>
</div>
</el-dialog>
</template>
<script>
export default {
name: 'leapFrogDialog',
props: {
title: {
type: String,
default: ''
},
showClose: {
type: Boolean,
default: true
},
visible: {
type: Boolean,
default: false
},
width: {
type: String,
default: '30%'
}
},
data() {
return {
loading: false,
taskListAll: [{
active: true,
name: "机库1",
type: "空闲",
distance: 10
},
{
active: true,
name: "机库2",
type: "忙碌",
distance: 12
}],
localVisible: this.visible // 根据 prop 初始化本地状态
};
},
watch: {
visible(newVal) {
this.localVisible = newVal; // 监听 prop 的变化
}
},
methods: {
handleClose() {
this.localVisible = false;
this.$emit('update:visible', false); // 通知父组件
},
confirm() {
this.$emit('confirm');
this.handleClose();
}
}
}
</script>
<style scoped lang="scss">
::v-deep {
.el-dialog__header {
padding: 5px;
}
.el-dialog__headerbtn {
top: 12px;
}
.el-dialog__footer {
text-align: center;
}
}
.dialog-header {
.title {
font-size: 20px;
font-family: YouSheBiaoTiHei;
color: #14faff;
line-height: 26px;
text-shadow: 0px 1px 1px rgba(2, 32, 56, 0.2);
background: linear-gradient(135deg, #e3aa77 0%, #f5cda9 38%, #f9ecd3 58%, #fcdbb1 79%, #edb07a 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
}
.dialog-footer {
.btn {
color: #fff;
background-color: #222222;
}
}
.stl-timed-task {
height: 230px;
display: flex;
flex-direction: column;
padding: 16px 4px;
gap: 0px;
box-sizing: border-box;
position: relative;
&::before {
position: absolute;
content: "";
width: calc(100% - 5px);
height: calc(100% - 24px);
border-radius: 4px;
border: 1px solid #4b4b4b;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
.timed-task-header {
display: flex;
flex-shrink: 0;
font-size: 14px;
height: 42px;
background: #343434;
font-family: YouSheBiaoTiHei;
font-size: 16px;
color: #ebf9ff;
.header__column {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
&.flex2 {
flex: 2;
}
&.status {
flex: initial;
width: 70px;
}
}
}
.timed-task-main {
color: #fff;
overflow-y: auto;
flex: 1;
z-index: 1;
.row {
display: flex;
color: #fff;
min-height: 52px;
background-color: #222222;
align-items: center;
gap: 3px;
&.single {
background-color: #343434;
}
.row__column {
font-size: 14px;
flex: 1;
text-align: center;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
.text-red {
color: red
}
.text-green {
color: green;
}
&.col-2 {
text-overflow: initial;
font-size: 14px;
}
&.flex2 {
flex: 2;
}
&.ctrl {
display: flex;
justify-content: center;
align-items: center;
gap: 5px;
i {
cursor: pointer;
font-size: 20px;
&.loading {
opacity: 0.5;
}
}
}
&.status {
flex: initial;
width: 70px;
font-size: 14px;
}
}
}
}
.task-add-btn {
display: flex;
z-index: 1;
.task-add__btn {
cursor: pointer;
width: 100px;
height: 28px;
background: #3388ff;
border-radius: 2px;
text-align: center;
line-height: 28px;
margin: 0 auto;
margin-bottom: 10px;
color: #fff;
}
}
}
</style>
\ No newline at end of file
<template>
<el-dialog :modal='modal' :visible.sync="localVisible" :close-on-click-modal="false" :modal-append-to-body="false" :show-close="showClose" @close="handleClose"
:width="width">
<div slot="title" class="dialog-header">
<div v-if="dialogType == 1">
<img src="../../../../../../assets/images/mount_head.png" />
<span class="title vas">{{ title }}</span>
</div>
<span v-else class="dialog-header">
<div class="cf tc vas">{{ title }}</div>
</span>
</div>
<div>
<slot></slot>
</div>
<span slot="footer" class="dialog-footer">
<el-button class="btn" @click="handleClose">取消</el-button>
<el-button type="primary" @click="confirm">确定</el-button>
</span>
</el-dialog>
</template>
<script>
export default {
name: 'LeapFrogFlighDialog',
props: {
modal: {
type: Boolean,
default: true
},
title: {
type: String,
default: ''
},
dialogType: {
type: Number,
default: 1
},
showClose: {
type: Boolean,
default: true
},
visible: {
type: Boolean,
default: false
},
width: {
type: String,
default: '30%'
}
},
data() {
return {
localVisible: this.visible // 根据 prop 初始化本地状态
};
},
watch: {
visible(newVal) {
this.localVisible = newVal; // 监听 prop 的变化
}
},
methods: {
handleClose() {
this.localVisible = false;
this.$emit('update:visible', false); // 通知父组件
},
confirm() {
this.$emit('confirm');
this.handleClose();
}
}
}
</script>
<style scoped lang="scss">
::v-deep {
.el-dialog__header {
padding: 5px;
}
.el-dialog__headerbtn {
top: 12px;
}
.el-dialog__footer{
text-align: center;
}
}
.dialog-header {
.title {
font-size: 20px;
font-family: YouSheBiaoTiHei;
color: #14faff;
line-height: 26px;
text-shadow: 0px 1px 1px rgba(2, 32, 56, 0.2);
background: linear-gradient(135deg, #e3aa77 0%, #f5cda9 38%, #f9ecd3 58%, #fcdbb1 79%, #edb07a 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
}
.dialog-footer {
.btn {
color: #fff;
background-color: #222222;
}
}
</style>
\ No newline at end of file
<template>
<div class="stl-timed-task">
<div class="cf m5 f12">
主机库状态:<span :class="apronInfo.masterStatus ? 'green' : ' red'">{{
apronInfo.masterStatus ? "正常" : apronInfo.descText
}}</span>
</div>
<div class="timed-task-header">
<div class="header__column flex2">序号</div>
<div class="header__column flex2">机库名称</div>
<div class="header__column status">状态</div>
<div class="header__column flex2">距离(km)</div>
</div>
<div
class="timed-task-main"
v-loading="loading"
element-loading-background="rgba(0, 0, 0, 0.8)"
>
<div
class="row"
:class="{ single: i % 2 != 0 }"
v-for="(item, i) in skipList"
:key="i"
>
<div class="row__column flex2">
<span class="f12">
<span class="mr10">
<el-checkbox
@change="changeFn(item)"
v-model="item.active"
:label="item.i"
:disabled="!item.slaveStatus"
></el-checkbox> </span
>{{ i + 1 }}
</span>
</div>
<div class="row__column flex2">
<el-tooltip
class="item"
effect="dark"
:content="item.name"
placement="top-start"
>
<span class="f12">{{ item.name }}</span>
</el-tooltip>
</div>
<div class="row__column flex2">
<el-tooltip
:content="item.descText"
class="item"
effect="dark"
placement="top-start"
>
<span
class="f12"
:class="{
'text-red': !item.slaveStatus,
'text-green': item.slaveStatus,
}"
>{{ item.slaveStatus ? "空闲" : "忙碌" }}</span
>
</el-tooltip>
</div>
<div class="row__column status" style="color: rgb(255, 189, 54)">
<el-tooltip
class="item"
effect="dark"
:content="String(item.targetDistance / 1000)"
placement="top-start"
>
<span class="f12">{{
(item.targetDistance / 1000)?.toFixed(2)
}}</span>
</el-tooltip>
</div>
</div>
</div>
<div class="task-add-btn" v-if="skipList.length > 0">
<div class="task-add__btn" @click="creareLine">生成航线</div>
<div class="task-add__btn" @click="oneClickTask">一键任务</div>
</div>
<div class="overlay" v-if="dialogVisible" v-interact>
<div class="dialog-header">
<div>
<img src="../../../../assets/images/mount_head.png" />
<span class="title vas">航线信息</span>
</div>
<span class="cp w40 h40 cf pt15" @click="handleClose">X</span>
</div>
<div class="p10">
<div class="stl-timed-task-ht wih100 f12 ml13 stl-timed-task-jk">
<div class="wih100 tr">
<div class="dib">
{{ uav.uav && uav.uav.name }} --- {{ activeItem.name }}
</div>
<span style="color: #3388ff" class="ml56 cp pr130" @click="showLine"
>预览</span
>
</div>
</div>
<div class="stl-timed-task-ht mt16 cf">
<div class="lh34 f12">飞行高度设置:</div>
<div class="bg">
<el-input
@blur="isEditing.height = false"
size="mini"
v-if="isEditing.height"
v-model="flightHeight"
type="number"
/>
<span v-else class="indent">{{ flightHeight }} m</span>
</div>
<div class="text ml10 cp lh34" @click="toggleEdit('height')">
编辑
</div>
</div>
<div class="stl-timed-task-ht mt16">
<div class="lh34 f12">飞行速度设置:</div>
<div class="bg">
<el-input
@blur="isEditing.speed = false"
size="mini"
v-if="isEditing.speed"
v-model="flightSpeed"
type="number"
/>
<span class="indent" v-else>{{ flightSpeed }} m/s</span>
</div>
<div class="text ml10 cp lh34" @click="toggleEdit('speed')">编辑</div>
</div>
<div class="mt16">
飞行总距离:{{ activeItem.targetDistance?.toFixed(2) }}公里
</div>
</div>
<div class="tc mt50">
<el-button size="mini" @click="handleClose">取消</el-button>
<el-button type="primary" size="mini" @click="handleConfirm"
>确定</el-button
>
</div>
</div>
<!-- <leapFrogFlighDialog :showClose="false" :dialogType="2" width="420px" title="低电量预警" :visible.sync="dialogVisible" @confirm="handleConfirm">
<p class="tc">警告;低电量!!后续后续航程无法完成,当前未找到 合适机场充电,请确认是否进行返航!!</p>
<div class="tc mt20">
<span>30s</span><span class="cred ml15"> 强制返航</span>
</div>
</leapFrogFlighDialog>
<leapFrogFlighDialog :showClose="false" :dialogType="2" width="420px" title="低电量预警" :visible.sync="dialogVisible" @confirm="handleConfirm">
<p class="tc">警告;低电量!!当前已有合适机场充电,请确认
是否进行返航!!</p>
<div class="tc mt20">
<span>30s</span><span class="cred ml15"> 前往>></span>
</div>
</leapFrogFlighDialog> -->
<leapFrogDialog
title="蛙跳飞行"
:visible.sync="leapFrogDialogVisible"
@confirm="handleConfirm"
></leapFrogDialog>
</div>
</template>
<script>
import { mapState, mapActions } from "vuex";
import leapFrogFlighDialog from "./components/leapFrogFlighDialog";
import leapFrogDialog from "./components/leapFrogDialog";
let EntityList = [];
export default {
name: "hangarTimedTask",
components: {
leapFrogFlighDialog,
leapFrogDialog,
},
inject: ["rootNode", "bus"],
props: {
type: {
type: Number,
default: 1,
},
},
data() {
return {
dialogVisible: false,
// 当前选中要跳转的机
activeItem: {},
descCodeList: {
0: "ok!",
4401: "降落点位置未设置!",
4402: "目标机库有无人机在舱内!",
4403: "主跳转机库无人机不在舱内!",
4404: "当前正在执行流程,非可跳跃状态!",
4405: "天气不宜飞行!",
4406: "电量不足已飞至目标机库!",
},
apronInfo: {
// chargeRemaining: 0,
// computeDistance: 0,
// descCode: 0,
// descText: "",
// deviceId: "",
// height: 0,
// latitude: 22.709333137094063,
// longitude: 113.90762329101564,
// masterStatus: true,
// slaveStatus: true,
// targetDistance: 0,
// uavDeviceId: "",
// name: "当前鹰巢11"
},
leapFrogDialogVisible: false,
dialogVisible: false,
selectedItems: [], // 选中的项目
loading: false,
skipList: [
// {
// active: false,
// name: "鹰巢1",
// chargeRemaining: 0,
// computeDistance: 0,
// descCode: 0,
// descText: "",
// deviceId: "LMMC3X2KUAV202311063",
// height: 120,
// latitude: 22.545458392873208,
// longitude: 113.88856887817384,
// masterStatus: true,
// slaveStatus: true,
// targetDistance: 123,
// uavDeviceId: "LMMC3X2KUAV202501112",
// },
// {
// active: false,
// name: "鹰巢2",
// chargeRemaining: 0,
// computeDistance: 0,
// descCode: 0,
// descText: "",
// deviceId: "LMMC3X2KUAV20231106311",
// height: 120,
// latitude: 23.4551254223,
// longitude: 120.2155112,
// masterStatus: false,
// slaveStatus: true,
// targetDistance: 123,
// uavDeviceId: "LMMC3X2KUAV202501112",
// },
],
flightHeight: 100,
flightSpeed: 5,
isEditing: {
height: false,
speed: false,
},
intervalId: null,
};
},
watch: {
"uavRealTimeData.isFlying": {
handler: function (newVal, oldVal) {
if (oldVal === false && newVal === true) {
console.log("飞行状态");
}
},
deep: true,
immediate: true,
},
},
computed: {
...mapState("MMCFlightControlCenter", [
"uav",
"uavRealTimeData",
"airwayEntities",
]),
...mapState("MMCFlightControlCenter/hangar", [
"hangarRealTimeData",
"hangar",
"taskList",
]),
// 选中的任务的飞行计划
selectTaskFlightPlan() {
return [];
},
},
methods: {
isTakeOverHangar() {
return this.$store.dispatch("MMCFlightControlCenter/hangar/isTakeOver");
},
async oneClickTask() {
if (!(await this.isTakeOverHangar())) {
this.$message.warning("请先接管设备");
return;
}
if (!this.apronInfo.masterStatus) {
return this.$message.warning(this.apronInfo.descText);
}
// 执行前先校验主机库状态 0 未正常
if (this.apronInfo && this.apronInfo.descCode != 0) {
let { descCode } = this.apronInfo;
return this.$message.warning(this.descCodeList[descCode]);
}
// 选择了调点再执行
let data = this.skipList.filter((item) => item.active);
if (data.length > 0) {
this.activeItem = data[0];
}
if (!this.activeItem.deviceId) return this.$message.warning("请选择跳点");
let { flightSpeed, flightHeight } = this;
this.rootNode.$emit("apronUavSkipEvent", {
// 主机库序列号
masterDeviceId: this.hangar.deviceId,
// 从机库设备序列号
slaveDeviceId: this.activeItem.deviceId,
altitude: flightHeight,
speed: flightSpeed,
callback: (res) => {
resolve();
},
});
},
// 改变飞行日志弹框状态
changeflyLogStatus(falg) {
this.$store.commit("MMCFlightControlCenter/setState", {
key: "flyLogStatus",
value: falg,
});
},
showLine() {
let { height, latitude, longitude, name } = this.activeItem;
let apronPosition = Cesium.Cartesian3.fromDegrees(
this.apronInfo.longitude,
this.apronInfo.latitude,
this.apronInfo.height
);
// 创建一个带有图片的实体
const apronEntity = window.$mmc_stl.viewer.entities.add({
position: apronPosition, // 设置图片的位置(经纬度和高度)
label: {
text: this.apronInfo.name,
font: "14pt monospace",
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
outlineWidth: 2,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
pixelOffset: new Cesium.Cartesian3(0.0, 32, 0.0),
distanceDisplayCondition: new Cesium.DistanceDisplayCondition(
0.0,
5000
),
disableDepthTestDistance: Number.POSITIVE_INFINITY,
zIndex: 5000,
},
billboard: {
image: require("../../assets/images/无人机库.png"), // 图片资源路径
width: 50, // 图片宽度(可选,单位为像素)
height: 60, // 图片高度(可选,单位为像素)
eyeOffset: new Cesium.Cartesian3(0, 0, -10), // 图片与位置坐标的偏移量(可选)
scale: 1, // 图片缩放比例(可选)
},
});
EntityList.push(apronEntity);
let imageEntityPosition = Cesium.Cartesian3.fromDegrees(
longitude,
latitude,
height
);
// 创建一个带有图片的实体
const imageEntity = window.$mmc_stl.viewer.entities.add({
position: imageEntityPosition, // 设置图片的位置(经纬度和高度)
label: {
text: name,
font: "14pt monospace",
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
outlineWidth: 2,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
pixelOffset: new Cesium.Cartesian3(0.0, 32, 0.0),
distanceDisplayCondition: new Cesium.DistanceDisplayCondition(
0.0,
10000
),
disableDepthTestDistance: Number.POSITIVE_INFINITY,
zIndex: 5000,
},
polyline: new Cesium.PolylineGraphics({
positions: [apronPosition, imageEntityPosition],
width: 4,
material: Cesium.Color.RED,
clampToGround: true,
zIndex: 5000,
}),
billboard: {
image: require("../../assets/images/无人机库.png"), // 图片资源路径
width: 50, // 图片宽度(可选,单位为像素)
height: 60, // 图片高度(可选,单位为像素)
eyeOffset: new Cesium.Cartesian3(0, 0, -10), // 图片与位置坐标的偏移量(可选)
scale: 1, // 图片缩放比例(可选)
},
});
EntityList.push(imageEntity);
const polyCenter = Cesium.BoundingSphere.fromPoints([
apronPosition,
imageEntityPosition,
]).center;
console.log("PolyCenter:", polyCenter); // 调试信息
let entityLabel = window.$mmc_stl.viewer.entities.add({
position: polyCenter,
label: {
text: this.activeItem.targetDistance + "km",
font: "14pt monospace",
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
outlineWidth: 4,
eyeOffset: new Cesium.Cartesian3(0.0, 0.0, -10),
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
pixelOffset: new Cesium.Cartesian2(0, 0),
},
});
EntityList.push(entityLabel);
// 飞入到该实体位置
window.$mmc_stl.viewer.camera.flyTo({
destination: Cesium.Cartesian3.fromDegrees(longitude, latitude, 20000), // 设置相机目标位置
duration: 2, // 飞行动画持续时间(秒)
});
},
changeFn(item) {
this.skipList.forEach((data) => {
if (data.deviceId != item.deviceId) {
data.active = false;
}
});
this.activeItem = item;
},
getTaskList(deviceId) {
return new Promise((resolve) => {
this.rootNode.$emit("leapFrogFlighGet", {
deviceId,
callback: (res) => {
if (res.skipList) {
this.skipList = res.skipList.map((item) => {
return {
...item,
active: this.activeItem.deviceId == item.deviceId,
};
});
}
if (res.apronInfo) {
this.apronInfo = res.apronInfo;
}
this.$nextTick(() => {
resolve();
});
},
});
});
},
toggleEdit(type) {
this.isEditing[type] = !this.isEditing[type];
},
async creareLine() {
if (!(await this.isTakeOverHangar())) {
this.$message.warning("请先接管设备");
return;
}
let data = this.skipList.filter((item) => item.active);
if (data.length > 0) {
this.activeItem = data[0];
this.changeflyLogStatus(true);
this.dialogVisible = true;
} else {
this.$message.warning("请选择跳点");
}
},
handleConfirm() {
this.clearEntity();
this.dialogVisible = false;
},
handleClose() {
this.dialogVisible = false;
this.flightHeight = 100;
this.flightSpeed = 5;
this.clearEntity();
},
clearEntity() {
if (EntityList.length > 0) {
EntityList.forEach((item) => {
window.$mmc_stl.viewer.entities.remove(item);
});
}
},
},
created() {
this.intervalId = setInterval(() => {
this.getTaskList(this.hangar.deviceId);
}, 3000);
},
beforeDestroy() {
clearInterval(this.intervalId); // 清除定时器
this.clearEntity();
},
};
</script>
<style lang="scss">
.stl-timed-task {
height: 230px;
display: flex;
flex-direction: column;
padding: 16px 4px;
gap: 0px;
box-sizing: border-box;
position: relative;
.green {
color: green;
}
.red {
color: red;
}
.overlay {
position: fixed;
top: 20%;
left: 50%;
width: 526px;
height: 300px;
color: #fff;
background-color: #222222;
transform: translate(-50%, -20%);
.dialog-header {
background: #3c3c3c;
text-indent: 1rem;
height: 40px;
display: flex;
justify-content: space-between;
.title {
font-size: 20px;
font-family: YouSheBiaoTiHei;
color: #14faff;
line-height: 40px;
text-shadow: 0px 1px 1px rgba(2, 32, 56, 0.2);
background: linear-gradient(
135deg,
#e3aa77 0%,
#f5cda9 38%,
#f9ecd3 58%,
#fcdbb1 79%,
#edb07a 100%
);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
}
}
.timed-task-header {
display: flex;
flex-shrink: 0;
font-size: 14px;
height: 42px;
background: #343434;
font-family: YouSheBiaoTiHei;
font-size: 16px;
color: #ebf9ff;
.header__column {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
&.flex2 {
flex: 2;
}
&.status {
flex: initial;
width: 70px;
}
}
}
.timed-task-main {
color: #fff;
overflow-y: auto;
flex: 1;
z-index: 1;
.row {
display: flex;
color: #fff;
min-height: 52px;
background-color: #222222;
align-items: center;
gap: 3px;
&.single {
background-color: #343434;
}
.row__column {
font-size: 14px;
flex: 1;
text-align: center;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
.text-red {
color: red;
}
.text-green {
color: green;
}
&.col-2 {
text-overflow: initial;
font-size: 14px;
}
&.flex2 {
flex: 2;
}
&.ctrl {
display: flex;
justify-content: center;
align-items: center;
gap: 5px;
i {
cursor: pointer;
font-size: 20px;
&.loading {
opacity: 0.5;
}
}
}
&.status {
flex: initial;
width: 70px;
font-size: 14px;
}
}
}
}
.task-add-btn {
display: flex;
z-index: 1;
.task-add__btn {
cursor: pointer;
width: 100px;
height: 28px;
background: #3388ff;
border-radius: 2px;
text-align: center;
line-height: 28px;
margin: 0 auto;
margin-bottom: 10px;
color: #fff;
}
}
}
.cred {
color: #f42e2e;
}
.stl-timed-task-jk {
overflow-x: auto;
overflow-y: hidden;
}
.stl-timed-task-ht {
display: flex;
color: "#fff";
.bg {
background: #191919;
width: 364px;
height: 28px;
line-height: 28px;
color: #86909c;
.indent {
text-indent: 1rem;
border: 1px solid #4b4b4b;
border-radius: 5px;
width: 100%;
display: inline-block;
}
}
.text {
font-family: SourceHanSansCN, SourceHanSansCN;
font-weight: 400;
font-size: 12px;
color: #3388ff;
text-align: center;
font-style: normal;
}
}
</style>
......@@ -53,7 +53,7 @@
<el-input-number :min="-145" :max="145" v-model="item.param3"></el-input-number>(度)
</div>
</div>
<i class="el-icon-delete rm-as-item__del" v-hover @click="selectActions.splice()"></i>
<i class="el-icon-delete rm-as-item__del" v-hover @click="selectActions1.splice(i,1)"></i>
</div>
</div>
<div class="rm-rp-btns">
......
......@@ -335,8 +335,8 @@ export default {
flightName: airway.name || `${this.userInfo.username}-巡查}`,
pointCount: airway.content.length,
distance: airway.distance,
sourceType: 2,
departmentId: airway.departmentId,
sourceType: 1,
flyTime:airway.flyTime,
linePointSaveReqVOS: airway.content.map((point) => ({
latitude: point.coordinate.latitude,
......@@ -345,10 +345,14 @@ export default {
speed: point.speed,
pointActionSaveReqVOS: point.waypointActions.map((action) => {
let actionValue = [];
action.param1 && actionValue.push(`param1:${action.param1 || ""}`);
action.param2 && actionValue.push(`param2:${action.param2 || ""}`);
action.param3 && actionValue.push(`param3:${action.param3 || ""}`);
action.param4 && actionValue.push(`param4:${action.param4 || ""}`);
action.param1 &&
actionValue.push(`param1:${action.param1 || ""}`);
action.param2 &&
actionValue.push(`param2:${action.param2 || ""}`);
action.param3 &&
actionValue.push(`param3:${action.param3 || ""}`);
action.param4 &&
actionValue.push(`param4:${action.param4 || ""}`);
return {
actionType: action.actionType,
actionValue: actionValue.join(";"),
......@@ -689,6 +693,7 @@ export default {
top: 0px;
width: 351px;
z-index: 2;
left: 0px;
.dialog-content {
display: flex;
......@@ -698,8 +703,8 @@ export default {
flex-shrink: 0;
display: flex;
justify-content: space-around;
margin-bottom: 16px;
margin-top: 16px;
margin-bottom: 5px;
margin-top: 5px;
}
.ae-form {
......
<template>
<div class="taskListBox">
<el-form class="task-main" label-width="70px">
<el-form-item label="航线选择">
<el-form-item label="任务库:" v-if="useTask">
<el-select v-model="selectedTaskId" clearable>
<el-option v-for="(item, i) in taskList" :label="item.name" :value="item.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="航线:">
<el-select v-model="selectedAirwayId">
<el-option v-for="(item , i) in airwayList" :label="item.name" :value="item.id"></el-option>
<el-option v-for="(item, i) in airwayList" :label="item.name" :value="item.id"></el-option>
</el-select>
</el-form-item>
<div class="btn" @click="onStartTask" v-hover>一键任务</div>
<div class>
<span class="btn__add-line" @click="showAirwayEdit = true">
<span class="f8"></span> 创建航线
</span>
</div>
</el-form>
<div class="btn" @click="onStartTask" v-hover>一键任务</div>
<div class>
<span class="btn__add-line" @click="showAirwayEdit = true">
<i class="el-icon-circle-plus-outline"></i>
<span class="f8"></span> 创建航线
</span>
</div>
<AirwayEdit v-if="showAirwayEdit" @close="showAirwayEdit = false" @addDone="getAirwayList"></AirwayEdit>
</div>
</template>
......@@ -32,16 +38,35 @@ export default {
inject: ["rootNode", "bus"],
data() {
return {
//航线列表
airwayList: [],
// 选择的航线
selectedAirwayId: "",
airwayList: [], //航线列表
selectedAirwayId: "", // 选择的航线
taskList: [], //任务列表
selectedTaskId: "", //选择的任务
airwaySelectDisabled: false, //选择任务后, 禁用航线选择
};
},
computed: {
...mapState("MMCFlightControlCenter", ["cesiumViewer", "useSTLAirway"]),
...mapState("MMCFlightControlCenter", [
"cesiumViewer",
"useSTLAirway",
"useTask",
]),
...mapState("MMCFlightControlCenter/uav", ["uav", "uavRealTimeData"]),
...mapState("MMCFlightControlCenter/hangar", ["hangar"]),
// 选择的任务
selectedTask() {
let find = this.taskList.find((item) => {
return item.id == this.selectedTaskId;
});
if (find) {
return find;
} else {
return {
name: "",
id: -1,
};
}
},
showAirwayEdit: {
get() {
return this.$store.state.MMCFlightControlCenter.showAirwayEdit;
......@@ -69,6 +94,25 @@ export default {
},
},
watch: {
'uavRealTimeData.isFlying': {
handler: function (newVal,oldVal) {
if (oldVal === false && newVal === true) {
this.getTaskInfoRecord()
}
},
deep: true,
immediate: true,
},
selectedTask() {
if (this.selectedTask.id !== -1) {
this.airwaySelectDisabled = true;
} else {
this.airwaySelectDisabled = false;
}
// 任务改变则修改航线选择为任务中的航线
this.selectedAirwayId = this.selectedTask?.airwayId;
},
selectedAirway() {
this.clearAirwayEntities();
if (this.selectedAirway.id !== -1) {
......@@ -81,66 +125,23 @@ export default {
} catch (e) {
console.log("绘制航线失败", e);
}
} else {
if (this.selectedTaskId && this.selectedAirwayId == "") {
this.$message.warning("未找到相应的航线");
}
this.selectedAirwayId = "";
this.airwaySelectDisabled = false;
}
},
},
async created() {
this.bus.$on("startTask", this.onStartTask);
/* if (this.useSTLAirway) {
let res = await Control_API.getUavRouteList({
pageNo: 1,
pageSize: 100,
nestId: this.hangar.id,
});
if (res?.code === 0) {
let airwayList = [];
for (let i = 0; i < res.data.list.length; i++) {
let item = res.data.list[i];
let flightCourseJson;
try {
flightCourseJson = JSON.parse(item.flightCourseJson);
} catch (e) {
console.log(e);
}
// 转换成飞控中心能接受的数据协议
let content = flightCourseJson
? await this.$store.dispatch(
"MMCFlightControlCenter/apiPointsToFKZXPoints",
{
list: flightCourseJson?.linePointSaveReqVOS || [],
actionListKey: "pointActionSaveReqVOS",
}
)
: null;
airwayList.push({
name: item.flightName,
id: item.id,
content: content,
});
}
this.airwayList = airwayList;
}
} else {
this.rootNode.$emit("airwayListGet", {
pageNo: this.airwayData.pageNo,
pageSize: this.airwayData.pageSize,
callback: (data) => {
this.airwayList = airwayData?.records || [];
},
});
} */
await this.getTaskList();
await this.getAirwayList();
// 获取正在飞行的航线
console.log('当前飞行状态', this.uavRealTimeData?.isFlying);
if (this.uav && this.uavRealTimeData?.isFlying) {
let res = await TaskInfo.getTaskInfoRecord({
deviceId: this.uav.deviceId,
});
if (res.code === 0) {
this.selectedAirwayId = res.data.reouteId;
}
if(this.uavRealTimeData.isFlying){
this.getTaskInfoRecord()
}
},
beforeDestroy() {
this.showAirwayEdit = false;
......@@ -154,8 +155,45 @@ export default {
"apiPointsToFKZXPoints",
]),
...mapActions("MMCFlightControlCenter/hangar", ["isTakeOver"]),
async getTaskInfoRecord() {
let res = await TaskInfo.getTaskInfoRecord({
deviceId: this.uav && this.uav.deviceId,
});
if (res.code === 0) {
console.log("getTaskInfoRecord", res.data);
this.selectedTaskId = res.data.taskInfoId;
setTimeout(() => {
this.selectedAirwayId = res.data.reouteId;
},1000)
}
},
/**
* 更新任务列表
* 获取任务列表
*/
getTaskList(id) {
return new Promise((resolve) => {
this.rootNode.$emit("taskListGet", {
pageNo: 1,
pageSize: 100,
type: 0,
putDevice: 2,
// isHangar: true,
hangar: this.hangar,
// taskStatus: 1,
callback: (res) => {
this.taskList =res?.records.filter(item => item.status != "已完成");
this.$nextTick(() => {
if (id) {
this.selectedTaskId = id;
}
resolve();
});
},
});
});
},
/**
* 获取航线列表
*/
getAirwayList(id) {
return new Promise((resolve) => {
......@@ -203,6 +241,7 @@ export default {
value: this.selectedAirway,
});
this.$store.dispatch("MMCFlightControlCenter/hangar/takeOff", {
taskInfoId: this.selectedTaskId,
callback: (status) => {
if (status) {
this.$message.success("一键任务指令发送成功");
......@@ -213,10 +252,10 @@ export default {
});
this.rootNode.$emit("taskStart", {
uav: this.uav,
task: this.selectedTask,
task: this.selectedTaskId,
airway: this.selectedAirway,
});
} catch (e) {}
} catch (e) { }
},
},
};
......@@ -230,6 +269,7 @@ export default {
transition: 0.3s;
display: flex;
flex-direction: column;
padding: 35px 16px 16px;
.header {
flex-shrink: 0;
......@@ -238,35 +278,34 @@ export default {
height: 32px;
background: #3c3c3c;
border-radius: 12px 12px 0px 0px;
.title {
display: flex;
align-items: center;
margin-left: 10px;
.font {
font-size: 20px;
font-family: YouSheBiaoTiHei;
color: #14faff;
line-height: 26px;
text-shadow: 0px 1px 1px rgba(2, 32, 56, 0.2);
background-image: -webkit-linear-gradient(
right,
#e3aa77,
#f5cda9,
#f9ecd3,
#fcdbb1,
#edb07a
);
background-image: -webkit-linear-gradient(right,
#e3aa77,
#f5cda9,
#f9ecd3,
#fcdbb1,
#edb07a);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
}
.active {
background-image: linear-gradient(
180deg,
#9198ff 0%,
rgba(45, 81, 153, 0.22) 40%,
#05091a 100%
);
background-image: linear-gradient(180deg,
#9198ff 0%,
rgba(45, 81, 153, 0.22) 40%,
#05091a 100%);
border: 1px solid #70daf9;
box-shadow: inset 0 0 10px 2px #3f9dff;
font-family: MicrosoftYaHei-Bold;
......@@ -277,12 +316,10 @@ export default {
}
.default {
background-image: linear-gradient(
180deg,
#9198ff 0%,
rgba(45, 81, 153, 0.22) 40%,
#05091a 100%
);
background-image: linear-gradient(180deg,
#9198ff 0%,
rgba(45, 81, 153, 0.22) 40%,
#05091a 100%);
border: 1px solid #70daf9;
font-family: MicrosoftYaHei-Bold;
font-size: 14px;
......@@ -291,33 +328,43 @@ export default {
font-weight: 700;
}
}
.task-main::v-deep {
flex: auto;
padding: 38px 16px 16px;
position: relative;
display: flex;
flex-direction: column;
flex-grow: 1;
.el-form-item__label {
color: #fff;
}
.el-form-item {
flex-grow: 0;
margin-bottom: 16px;
$line-height: 32px;
.btn__add-line {
position: absolute;
bottom: 20px;
right: 20px;
font-size: 10px;
color: #43deff;
cursor: pointer;
}
.el-form-item__label {
line-height: 1;
color: #fff;
line-height: $line-height;
}
.el-form-item {
flex-grow: 1;
.el-form-item__content {
line-height: 1;
line-height: $line-height;
}
.el-select {
width: 100%;
}
.el-input__inner {
height: $line-height;
}
}
}
.btn {
width: 122px;
width: 110px;
height: 32px;
text-align: center;
line-height: 32px;
......@@ -328,11 +375,27 @@ export default {
font-weight: 400;
font-size: 14px;
cursor: pointer;
border-radius: 4px;
}
.btn__add-line {
position: absolute;
bottom: 24px;
right: 16px;
cursor: pointer;
font-family: MicrosoftYaHei;
font-size: 12px;
color: #3388ff;
}
}
.select-airway__btn {
width: 100%;
height: 30px;
padding: 0;
}
::v-deep.el-tooltip__popper {
margin-top: 20px;
}
</style>
<template>
<div class="task-add dialog1027" v-interact>
<div class="dialog-header">
<div class="dialog-header__title">飞行编辑</div>
<div class="dialog-header__close" @click="close">关闭</div>
</div>
<div class="dialog-content">
<el-form ref="form" :model="form" :rules="rules" label-width="90px">
<el-date-picker
v-model="form.time"
:type="task.taskType == 1 ? 'datetime' : 'datetimerange'"
range-separator="至"
start-placeholder="请选择任务开始时间"
end-placeholder="请选择任务结束时间"
placeholder="选择日期时间"
size="mini"
popper-class="mmc"
value-format="yyyy-MM-dd HH:mm:ss"
:picker-options="pickerOptions"
style="margin-bottom: 24px; width: 100%"
></el-date-picker>
<el-form-item label="任务库:" prop="taskId">
{{ task.name }}
</el-form-item>
<el-form-item label="航线名称:" prop="airwayId">
{{ task.airwayName }}
</el-form-item>
</el-form>
<div class="task-add-btn">
<el-button
type="danger"
size="medium"
class="btn btn--cancel"
@click="close"
>取消</el-button
>
<el-button
type="primary"
size="medium"
:loading="confirmLoading"
class="btn btn--ok"
@click="onConfirm"
>确认</el-button
>
</div>
</div>
</div>
</template>
<script>
import { mapState, mapActions } from "vuex";
import { Control_API } from "../../../../../../../../../../../../api";
import Moment from "moment";
export default {
name: "TaskAdd",
inject: ["rootNode"],
props: {
task: {
type: Object,
default() {
return {};
},
},
},
data() {
return {
form: {
time: [],
},
rules: {},
pickerOptions: {
disabledDate: (time) => {
// 日期选择限制
return time.getTime() < Date.now() - 8.64e7;
},
},
confirmLoading: false,
};
},
computed: {},
watch: {},
async mounted() {
if (this.task.taskType == 1) {
if (this.task.taskStartTime == "/") {
this.form.time = null;
} else if (this.task.taskStartTime) {
// 定时
this.form.time = Moment(this.task.taskStartTime).format(
"YYYY-MM-DD HH:mm:ss"
);
}
} else {
if (this.task.taskStartTime == "/" || this.task.taskEndTime == "/") {
this.form.time = null;
} else if (this.task.taskStartTime && this.task.taskEndTime) {
// 周期
this.form.time = [
Moment(this.task.taskStartTime).format("YYYY-MM-DD HH:mm:ss"),
Moment(this.task.taskEndTime).format("YYYY-MM-DD HH:mm:ss"),
];
}
}
},
methods: {
/**
* 确认事件
*/
onConfirm() {
this.$refs["form"].validate((valid) => {
let params = {
id: this.task.id,
};
if (this.task.taskType == 1) {
params.taskStartTime = Moment(this.form.time).valueOf();
params.taskEndTime = null;
} else {
params.taskStartTime = Moment(this.form.time[0]).valueOf();
params.taskEndTime = Moment(this.form.time[1]).valueOf();
}
if (valid) {
this.confirmLoading = true;
this.rootNode.$emit("taskInfoUpdateTime", {
data: params,
callback: (res) => {
console.log("taskInfoUpdateTime res", res);
this.confirmLoading = false;
if (res.code === 0) {
this.$message.success("更改时间完成");
this.$emit("close");
} else {
this.$message.warning(res.error.msg);
}
},
});
} else {
return false;
}
});
},
close() {
this.$emit("close");
},
},
};
</script>
<style lang="scss" scoped>
.task-add::v-deep {
width: 526px;
height: 268px;
background: #222;
position: fixed;
top:25%;
left: 50%; /* 水平居中 */
transform: translate(-50%, -25%); /* 使用 transform 进行精确居中 */
z-index: 1;
display: flex;
flex-direction: column;
gap: 5px;
&.more {
height: 376px;
}
.dialog-header {
padding-left: 16px !important;
flex-shrink: 0;
}
.dialog-content {
flex-direction: column;
flex-grow: 1;
flex-shrink: 1;
}
.task-add-main {
padding: 20px 20px 0 10px;
}
.task-add-btn {
flex-shrink: 0;
display: flex;
justify-content: center;
.btn {
box-sizing: border-box;
width: 112px;
height: 32px;
border-radius: 4px;
display: flex;
justify-content: center;
align-items: center;
font-family: SourceHanSansCN, SourceHanSansCN;
font-weight: 500;
font-size: 14px;
&.btn--cancel {
color: #ff4040;
border: 1px #ff4040 solid;
background-color: transparent;
}
&.btn--ok {
margin-left: 23px;
}
}
}
.task-add-more {
background-color: rgba(13, 82, 143, 0.6);
height: 24px;
cursor: pointer;
display: flex;
justify-content: center;
align-items: center;
}
$height: 32px;
.el-form-item__content {
line-height: $height;
height: $height;
}
.el-form-item__label {
line-height: $height;
}
}
</style>
<template>
<div class="task-add dialog1027" v-interact>
<div class="task-add-header dialog-header">
<img class="dialog-header__icon" src="../../../../../../assets/images/mount_head.png" />
<div class="header__title dialog-header__title">飞行计划</div>
<div class="header-right dialog-header__close">
<el-select placeholder="请选择任务场景" v-model="selectedTask" class="select" popper-class="mmc">
<el-option v-for="item in taskList" :label="item.name" :value="item.id"></el-option>
</el-select>
<div class="header-right__close" @click="$emit('close')">关闭</div>
</div>
</div>
<div class="stl-timed-task">
<div class="timed-task-header">
<div class="header__column flex2">时间</div>
<div class="header__column flex2">航线名</div>
<div class="header__column flex2">状态</div>
<div class="header__column flex2">异常状态</div>
<div class="header__column">操作</div>
</div>
<div class="timed-task-main">
<div class="row" :class="{ single: i % 2 != 0 }" v-for="(item, i) in flightPlan" :key="item.id">
<div class="row__column flex2 col-2">
<el-tooltip class="item" effect="dark" :content="item.putStartTime" placement="top-start">
<span>{{ item.putStartTime }}</span>
</el-tooltip>
</div>
<div class="row__column flex2">
<el-tooltip class="item" effect="dark" :content="item.reouteName" placement="top-start">
<span>{{ item.reouteName }}</span>
</el-tooltip>
</div>
<div class="row__column flex2">
<el-tooltip class="item" effect="dark" :content="item.status" placement="top-start">
<span v-if="item.abnormal == 1 || item.abnormal == 0">{{
abnormalType[item.abnormal]
}}</span>
<span v-else> 暂无 </span>
</el-tooltip>
</div>
<div class="row__column flex2">
<el-tooltip class="item" effect="dark" :content="item.abnormalName" placement="top-start">
<span style="color: red" v-if="item.abnormal > 1 ">{{ item.abnormalName }}</span>
<span v-else>暂无</span>
</el-tooltip>
</div>
<div class="row__column ctrl">
<el-tooltip content="删除" placement="top">
<i class="el-icon-delete" @click="onDel(item)"></i>
</el-tooltip>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { mapState, mapActions } from "vuex";
import { AirLine } from "../../../../../../../../../../../../api";
import Moment from "moment";
export default {
name: "TaskAdd",
inject: ["rootNode"],
props: {
taskId: {
type: Number,
default: 0,
},
/**
* 任务列表
*/
taskList: {
type: Array,
default() {
return [];
},
},
},
data() {
return {
abnormalType: {
0: "完成",
1: "待执行",
},
flightPlan: [
/* {
id: 30616,
deviceId: "TMJ",
deviceName: "无人机",
flightSortieName: "TMJ", // 架次名称
taskInfoId: 21480, // 任务id
taskInfoName: "任务123",
reouteId: 16462, // 航线id
reouteName: "航线123",
projectId: 12, // 项目Id
projectName: "",
status: 2, // 默认0 表示架次未结束;1表示架次完整。
sequence: 0, // 周期任务有多次执行,执行顺序
putStartTime: "", // 任务执行开始时间
putEndTime: "",
createTime: "",
}, */
], // 飞行计划列表
selectedTask: "", // 当前选择的任务
};
},
computed: {
...mapState("MMCFlightControlCenter/hangar", ["hangar"]),
...mapState("MMCFlightControlCenter", ["airwayEntities", "useTask"]),
},
watch: {
taskId: {
immediate: true,
handler() {
this.selectedTask = this.taskId;
},
},
selectedTask: {
immediate: true,
handler() {
this.getList();
},
},
},
mounted() { },
methods: {
...mapActions("MMCFlightControlCenter", []),
getList() {
this.rootNode.$emit("taskRecordPageGet", {
id: this.selectedTask,
callback: (res) => {
console.log("taskRecordPageGet res", res);
if (res.code === 0) {
this.flightPlan = res.records.map((item) => {
return {
...item,
putStartTime: Moment(item.putStartTime).format(
"YYYY-MM-DD HH:mm:ss"
),
};
});
}
},
});
},
/**
* 删除的任务
*/
async onDel(item) {
await this.$confirm("请确认是否删除该飞行计划?", "安全确认", {
cancelButtonText: "取消",
confirmButtonText: "确定",
customClass: "uav_controlPane",
showClose: false,
});
this.rootNode.$emit("taskInfoRecordDel", {
id: item.id,
callback: () => {
this.getList();
},
});
},
},
};
</script>
<style lang="scss" scoped>
.task-add::v-deep {
min-height: 232px;
position: fixed;
max-height: 400px;
top: -24%;
overflow-y: auto;
left: 0;
right: 0;
bottom: 0;
margin: auto;
width: 660px;
z-index: 1;
display: flex;
flex-direction: column;
gap: 5px;
.task-add-header {
flex-shrink: 0;
display: flex;
justify-content: space-between;
align-items: center;
height: 32px;
padding: 0 20px 0 0;
.header__title {
font-family: MicrosoftYaHei-Bold;
font-size: 16px;
color: #70daf9;
letter-spacing: 0;
font-weight: 700;
}
.header-right {
display: flex;
gap: 20px;
font-family: MicrosoftYaHei;
font-size: 16px;
color: #70daf9;
letter-spacing: 0;
font-weight: 400;
.select {
border-radius: 2px;
border: 1px solid #4b4b4b;
width: 150px;
$height: 24px;
.el-input__inner {
height: $height;
font-size: 14px;
color: #86909c;
}
.el-input__suffix {
top: 0px;
display: flex;
align-items: center;
}
}
.header-right__close {
font-size: 16px;
cursor: pointer;
}
}
}
.stl-timed-task {
height: 340px;
flex-grow: 1;
}
.task-add-btn {
flex-shrink: 0;
text-align: center;
.task-add__btn {
width: 92px;
height: 36px;
background: #3388ff;
border-radius: 2px;
text-align: center;
line-height: 32px;
margin: 0 auto;
margin-bottom: 10px;
cursor: pointer;
color: #fff;
}
}
.task-add-more {
background-color: #191919;
height: 24px;
cursor: pointer;
display: flex;
justify-content: center;
align-items: center;
}
}
</style>
<template>
<div class="timed-task">
<div class="stl-timed-task">
<div class="timed-task-header">
<div class="header__column flex2">名称</div>
<div class="header__column flex2">时间</div>
<div class="header__column status">状态</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="timed-task-main" v-loading="loading" element-loading-background="rgba(0, 0, 0, 0.8)">
<div class="row" :class="{ single: i % 2 != 0 }" v-for="(item, i) 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>
<span class="f12">{{ item.name }}</span>
</el-tooltip>
</div>
<div class="row__column flex2">
<el-tooltip
class="item"
effect="dark"
:content="item.taskStartTime"
placement="top-start"
>
<span>{{item.taskStartTime}}</span>
<div class="row__column flex2 col-2">
<el-tooltip class="item" effect="dark" placement="top-start">
<template #content>
<div>
{{ item.taskStartTime }}
<div v-if="type == 2 &&item.taskEndTime != '/'">
{{ item.taskEndTime }}
</div>
</div>
</template>
<div v-if="type == 2" class="f9">
<div v-if="item.taskStartTime == '/'">
/
</div>
<div v-else>
<div>
{{ item.taskStartTime }}
</div>
{{ item.taskEndTime }}
</div>
</div>
<span class="f9" v-else>{{ item.taskStartTime }}</span>
</el-tooltip>
</div>
<div class="row__column status" style="color: rgb(255, 189, 54);">
<div class="row__column status" style="color: rgb(255, 189, 54)">
<el-tooltip class="item" effect="dark" :content="item.status" placement="top-start">
<span>{{item.status}}</span>
<span class="f12">{{ item.status }}</span>
</el-tooltip>
</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>
<i class="el-icon-position" style @click="onSwitchAirway(item, true)"></i>
</el-tooltip>
<el-tooltip content="计划安排" placement="top">
<i class="el-icon-date" @click="onOpenPlan(item)"></i>
</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 content="编辑" placement="top" v>
<i class="el-icon-edit" @click="onOpenEdit(item)" v-if="item.status !== '执行中' && item.status !== '已完成'"></i>
</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">
<i class="el-icon-turn-off"></i>
</el-tooltip> -->
<el-tooltip content="删除" placement="top">
<span class="icon-shanchu iconfont icon" @click="onDelAirway(item)"></span>
<i v-if="item.status !== '执行中' && item.status !== '已完成'" class="el-icon-delete"
@click="onDelAirway(item)"></i>
</el-tooltip>
</div>
</div>
</div>
<div class="task-add-btn">
<div class="task-add__btn" @click="showTaskAdd = true">创建定时任务</div>
</div>
<!-- <div class="task-add-btn">
<div class="task-add__btn" @click="showFlightPlan = true">创建定时任务</div>
</div>-->
<TaskAdd v-if="showTaskAdd" @close="onTaskAddClose" @addDone="onAddDone"></TaskAdd>
<FlightPlan v-if="showFlightPlan" :taskId="selectedTask.id" :taskList="taskListAll" @close="showFlightPlan = false">
</FlightPlan>
<FlightEdit v-if="showFlightEdit" :task="selectedTask" @close="showFlightEdit = false"></FlightEdit>
</div>
</template>
<script>
import { mapState, mapActions } from "vuex";
import { AirLine } from "../../../../../../../../../../api";
import TaskAdd from "./components/taskAdd";
import FlightPlan from "./components/flightPlan";
import FlightEdit from "./components/flightEdit";
export default {
name: "hangarTimedTask",
components: {
TaskAdd,
FlightPlan,
FlightEdit,
},
inject: ["rootNode", "bus"],
props: {
type: {
type: Number,
default: 1,
},
},
data() {
return {
showTaskAdd: false,
showFlightPlan: false,
showFlightEdit: false,
taskListAll: [],
timeHandle: null,
selectedTask: null, //选中的任务
loading: false,
executeFlightRouteId: null,
airwayId: null,
};
},
computed: {
......@@ -84,13 +111,45 @@ export default {
"hangar",
"taskList",
]),
// 选中的任务的飞行计划
selectTaskFlightPlan() {
return [];
},
},
watch: {
type: {
immediate: true,
handler() {
// 切换任务列表时清空航线
this.clearAirwayEntities();
this.airwayId = null;
this.executeFlightRouteId = null;
this.rootNode.$emit("hangarTaskTabChange", {
type: this.type,
});
this.getTaskList();
},
},
showFlightEdit: {
handler(val) {
if (!val && !this.showFlightPlan) {
this.changeflyLogStatus(false);
} else {
this.changeflyLogStatus(true);
}
},
},
showFlightPlan: {
handler(val) {
if (!val && !this.showFlightEdit) {
this.changeflyLogStatus(false);
} else {
this.changeflyLogStatus(true);
}
},
},
},
watch: {},
created() {
this.rootNode.$emit("hangarTaskTabChange", {
type: 2,
});
this.getTaskList();
this.timeHandle = setInterval(() => {
this.getTaskList();
}, 5000);
......@@ -104,21 +163,45 @@ export default {
"createAirwayEntities",
"clearAirwayEntities",
]),
// 改变飞行日志弹框状态
changeflyLogStatus(falg) {
this.$store.commit("MMCFlightControlCenter/setState", {
key: "flyLogStatus",
value: falg,
});
},
/**
* 更新任务列表
*/
getTaskList() {
console.log("getTaskList", this.taskListAll);
this.rootNode.$emit("taskListGet", {
const params = {
pageNo: 1,
pageSize: 100,
taskStatus: 11,//筛选掉审核未通过的
type: 2, // 1: 日常任务 2: 定时任务 3:周期任务
type: this.type, // 0: 日常任务, 1: 定时任务, 2: 周期任务
taskStatus: 11, // 筛选掉审核未通过的
hangar: this.hangar,
callback: (res) => {
this.taskListAll = res.records || [];
},
putDevice: 2,
callback: this.handleTaskListResponse.bind(this),
};
this.rootNode.$emit("taskListGet", params);
},
handleTaskListResponse(res) {
if (res.taskType !== this.type || res.records.length === 0) {
this.taskListAll = [];
return;
}
this.taskListAll = res.records.sort((a, b) => {
const aIsExecuting = a.status === "执行中";
const bIsExecuting = b.status === "执行中";
return aIsExecuting === bIsExecuting ? 0 : (aIsExecuting ? -1 : 1);
});
const executeFlightRoute = this.taskListAll.find(item => item.status === "执行中");
if (executeFlightRoute && this.executeFlightRouteId !== executeFlightRoute.airwayId) {
this.executeFlightRouteId = executeFlightRoute.airwayId;
this.onSwitchAirway(executeFlightRoute);
}
},
/**
* 显示或隐藏航线
......@@ -132,69 +215,96 @@ export default {
);
if (find) {
this.clearAirwayEntities({ id: airway.id });
if (this.airwayId != airway.id) {
this.createAirwayEntities({
polyline: airway.content,
id: airway.id,
});
this.airwayId = airway.id;
}
} else {
this.createAirwayEntities({
polyline: airway.content,
id: airway.id,
});
this.airwayId = airway.id;
}
},
});
},
async onDelAirway(item) {
try {
if (item.loading) {
return;
}
await this.$confirm("请确认是否删除该任务?", "安全确认", {
cancelButtonText: "取消",
confirmButtonText: "确定",
customClass: "uav_controlPane",
showClose: false,
});
item.loading = true;
this.loading = true;
this.rootNode.$emit("taskDel", {
task: item,
type: 2, // 1: 日常任务 2: 定时任务 3:周期任务
type: 0, // 0: 日常任务 1.定时任务 2.周期任务
callback: () => {
this.getTaskList();
this.loading = false;
},
});
} catch (e) {
console.log(e);
}
},
onTaskAddClose() {
this.showTaskAdd = false;
/**
* 打开飞行计划
*/
onOpenPlan(item) {
this.selectedTask = item;
this.showFlightPlan = true;
this.showFlightEdit = false;
},
onAddDone() {
this.getTaskList();
/**
* 打开飞行编辑
*/
onOpenEdit(item) {
this.selectedTask = item;
this.showFlightEdit = true;
this.showFlightPlan = false;
},
},
};
</script>
<style lang="scss" scoped>
.timed-task {
height: 100%;
<style lang="scss">
.stl-timed-task {
height: 230px;
display: flex;
flex-direction: column;
padding: 5px 10px 5px;
gap: 8px;
padding: 16px 4px;
gap: 0px;
box-sizing: border-box;
position: relative;
&::before {
position: absolute;
content: "";
width: calc(100% - 5px);
height: calc(100% - 24px);
border-radius: 4px;
border: 1px solid #4b4b4b;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
.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;
height: 42px;
background: #343434;
font-family: YouSheBiaoTiHei;
font-size: 16px;
color: #ebf9ff;
.header__column {
flex: 1;
......@@ -217,26 +327,33 @@ export default {
color: #fff;
overflow-y: auto;
flex: 1;
z-index: 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;
min-height: 52px;
background-color: #222222;
align-items: center;
gap: 3px;
&.single {
background-color: #343434;
}
.row__column {
font-size: 14px;
flex: 1;
text-align: center;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
&.col-2 {
text-overflow: initial;
font-size: 14px;
}
&.flex2 {
flex: 2;
}
......@@ -247,8 +364,9 @@ export default {
align-items: center;
gap: 5px;
.icon {
i {
cursor: pointer;
font-size: 20px;
&.loading {
opacity: 0.5;
......@@ -259,6 +377,7 @@ export default {
&.status {
flex: initial;
width: 70px;
font-size: 14px;
}
}
}
......@@ -281,4 +400,4 @@ export default {
}
}
}
</style>
\ No newline at end of file
</style>
......@@ -3,27 +3,46 @@
<div class="task-list-header">
<div
class="task-list-header__item"
:class="{active: tabIndex === 0 && useTimedTask}"
:class="{ active: tabIndex === 0 && useTimedTask }"
@click="tabIndex = 0"
>
<label>常态飞行</label>
</div>
<template v-if="useTimedTask">
<div class="task-list-header__item" :class="{active: tabIndex === 1}" @click="tabIndex = 1">
<div
class="task-list-header__item"
:class="{ active: tabIndex === 1 }"
@click="tabIndex = 1"
>
<label>定时飞行</label>
</div>
<div class="task-list-header__item" :class="{active: tabIndex === 2}" @click="tabIndex = 2">
<div
class="task-list-header__item"
:class="{ active: tabIndex === 2 }"
@click="tabIndex = 2"
>
<label>周期飞行</label>
</div>
<div
v-if="isLeapFrogFligh"
class="task-list-header__item"
:class="{ active: tabIndex === 3 }"
@click="tabIndex = 3"
>
<label>蛙跳飞行</label>
</div>
</template>
</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>
<!-- 定时任务 --><!-- 周期任务 -->
<TimedTask
v-else-if="tabIndex === 1 || tabIndex === 2"
:type="tabIndex"
></TimedTask>
<!-- 蛙跳飞行 -->
<leapFrogFligh v-else></leapFrogFligh>
</div>
</div>
</template>
......@@ -31,7 +50,8 @@
<script>
import NormalTask from "./components/normalTask";
import TimedTask from "./components/timedTask";
import PeriodTask from "./components/periodTask";
import leapFrogFligh from "./components/leapFrogFligh";
import { mapState } from "vuex";
export default {
......@@ -39,11 +59,12 @@ export default {
components: {
NormalTask,
TimedTask,
PeriodTask,
leapFrogFligh,
},
data() {
return {
tabIndex: 0,
isLeapFrogFligh: false,
};
},
computed: {
......@@ -56,17 +77,45 @@ export default {
}
},
},
created() {
let tmjData = JSON.parse(localStorage.getItem("tmj"));
if (tmjData) {
const userList = this.handleGetMenuList(tmjData.user.menuList);
// 获取蛙跳权限
let leapFrogFlighFlag = userList.find((item) => item.id == 3096);
if (leapFrogFlighFlag) {
this.isLeapFrogFligh = true;
}
}
},
mounted() {},
methods: {},
methods: {
handleGetMenuList(menuList) {
const collector = [];
const flattenMenu = (items) => {
items.forEach((item) => {
if (item.children && item.children.length > 0) {
flattenMenu(item.children);
} else {
collector.push(item);
}
});
};
flattenMenu(menuList);
return collector;
},
},
};
</script>
<style lang="scss" scoped>
.task-list {
width: 350px;
width: 352px;
height: 254px;
background: #222222;
border-radius: 10px 10px 0 0;
border-radius: 10px 10px 10px 10px;
display: flex;
flex-direction: column;
......@@ -76,6 +125,7 @@ export default {
height: 32px;
flex-shrink: 0;
display: flex;
overflow: hidden;
.task-list-header__item {
flex: 1;
......@@ -119,7 +169,7 @@ export default {
.task-list-main {
flex: 1;
overflow: hidden;
// overflow: hidden;
}
}
</style>
\ No newline at end of file
<template>
<div class="cpt-command-airway-list" v-interact>
<div class="hd">
<div class="left ml8">
<!-- <img src="../../../../../../assets/images/mount_head.png" /> -->
<div class="title">航空航线</div>
</div>
<div @click="close" class="close">关闭</div>
</div>
<div class="list-box">
<div class="tb-box">
<div class="tb-hd-box">
<div class="tb-hd">航线ID</div>
<div class="tb-hd">航线名称</div>
<div class="tb-hd">所属单位</div>
<div class="tb-hd">空域状态</div>
<div class="tb-hd">安全状态</div>
<div class="tb-hd">航线标签</div>
<div class="tb-hd last-tb-hd">操作</div>
</div>
<div class="tb-bd-box">
<div class="tb-tr" v-for="item in airwayData.records" :key="item.id">
<div class="td">{{ item.id || "暂无" }}</div>
<div class="td">
<div>{{ item.name || "暂无" }}</div>
</div>
<div class="td">{{ item.organizationName || "暂无" }}</div>
<!-- 空域状态 -->
<div class="td">
<div v-if="item.status == 1" class="status">可用</div>
<div v-else-if="item.status == 2" class="status" style="color: #2ca1e2">待申请</div>
<div v-else-if="item.status == 3" class="status" style="color: #ffbd36">待审批</div>
<div v-else-if="item.status == 4" class="status" style="color: #2bfdf1">通过</div>
<div v-else-if="item.status == 5" class="status" style="color: #fb4a2d">驳回</div>
<div v-else>暂无</div>
</div>
<!-- 模式 -->
<!-- <div class="td">{{ item.distance || "暂无" }}</div> -->
<!-- 安全状态 -->
<div
class="td"
:style="{ color: item.safe == 1 ? '#19D864' : '' }"
>{{ item.safe == 1 ? "安全" : "待确定" }}</div>
<!-- 航线标签 -->
<div class="td">
<!-- <span v-for="item2 in item.labelList"
:key="item2.labelId">{{ item2.labelName }}</span>-->
{{ item.labelName ||"暂无" }}
</div>
<div class="td last-td" style="width: 15%">
<div @click="changeLine(item)">选择航线</div>
</div>
</div>
</div>
</div>
</div>
<el-pagination
layout="prev, pager, next"
:total="airwayData.total"
:pageSize="airwayData.pageSize"
:currentPage.sync="airwayData.pageNo"
@current-change="getAirway"
></el-pagination>
</div>
</template>
<script>
import { mapState } from "vuex";
import { Control_API } from "../../../../../../../../../../../../api";
export default {
inject: ["rootNode"],
data() {
return {
keyword: null,
airwayData: {
pageNo: 1,
records: [],
pageSize: 10,
total: 0,
},
};
},
computed: {
...mapState("MMCFlightControlCenter", ["useSTLAirway"]),
...mapState("MMCFlightControlCenter/hangar", ["hangar"]),
},
mounted() {
this.getAirway();
},
methods: {
async changeLine(item) {
try {
if (item.safe != 1) {
await this.$confirm(
"此航线为非安全航线,开始任务前请确认航线安全!",
"安全确认",
{ customClass: "uav_controlPane", showClose: false }
);
}
this.$emit("change", item);
this.close();
} catch (e) {}
},
close() {
this.$emit("close");
},
async getAirway() {
if (this.useSTLAirway) {
let res = await Control_API.getUavRouteList({
pageNo: this.airwayData.pageNo,
pageSize: this.airwayData.pageSize,
// nestId: this.hangar.id, // TODO 目前还没有新增航线操作
});
if (res?.code === 0) {
let statusMap = {
1: "可用",
2: "待申请",
3: "待审批",
4: "通过",
5: "驳回",
};
this.airwayData = (res.data.list && {
pageNo: this.airwayData.pageNo,
records: res.data.list,
pageSize: this.airwayData.pageSize,
total: res.data.total,
}) || {
pageNo: this.airwayData.pageNo,
records: [],
pageSize: this.airwayData.pageSize,
total: this.airwayData.total,
};
this.airwayData.records = this.airwayData.records?.map((item) => {
let content = [];
try {
content = JSON.parse(item.content).content; // TODO 待确认字段
} catch (e) {
console.log(e);
}
return {
...item,
status: statusMap[item.status],
content,
};
});
}
} else {
this.rootNode.$emit("airwayListGet", {
pageNo: this.airwayData.pageNo,
pageSize: this.airwayData.pageSize,
callback: (data) => {
this.airwayData = data || {
pageNo: 1,
records: [],
pageSize: 10,
total: 0,
};
},
});
}
},
},
};
</script>
<style lang="scss" scoped>
.cpt-command-airway-list {
width: 600px;
position: absolute;
right: -213px;
top: 300px;
box-sizing: border-box;
background: #222222;
box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.1);
border-radius: 2px;
.hd {
flex-shrink: 0;
display: flex;
justify-content: space-between;
align-items: center;
height: 32px;
background: #3c3c3c;
border-radius: 2px 2px 0px 0px;
.left {
display: flex;
align-items: center;
.title {
font-family: PingFangSC, PingFang SC;
font-weight: 500;
font-size: 14px;
color: #ffffff;
}
}
.close {
font-size: 14px;
font-family: MicrosoftYaHei;
color: #d2dfff;
margin-right: 8px;
cursor: pointer;
}
}
.list-box {
// width: 1132px;
height: calc(100% - 56px);
box-sizing: border-box;
padding: 0 16px 0 16px;
.search-box {
margin-left: 0 !important;
// height: 80px;
height: auto;
margin: 24px 0 24px 0;
box-sizing: border-box;
display: flex;
align-items: center;
.item-plan {
width: 79px;
height: 32px;
background: rgba(28, 67, 191, 0.6) !important;
box-shadow: 0px 2px 4px 0px rgba(23, 33, 60, 0.5),
inset 0px 0px 16px 0px rgba(33, 137, 255, 0.4),
inset 0px 0px 4px 0px #00a7ff;
border: 1px solid;
border-image: linear-gradient(
180deg,
rgba(138, 218, 255, 1),
rgba(82, 179, 255, 0)
)
1 1;
border-radius: 0px;
font-size: 12px;
font-family: MicrosoftYaHei;
color: #43deff;
line-height: 16px;
}
.item-plan:hover {
opacity: 0.5;
}
.item-input {
width: 168px;
height: 40px;
margin-left: 10px;
// margin-right: 10px;
color: #08c2d1;
::v-deep .el-input__inner {
background: rgba(2, 31, 51, 0);
border: 0px solid #06b6e0;
border-radius: 4px;
font-family: MicrosoftYaHeiUI;
font-size: 16px;
color: #08c2d1;
font-weight: 400;
padding-left: 0;
&::placeholder {
font-size: 14px;
font-family: MicrosoftYaHei;
color: #397c8b;
line-height: 19px;
}
}
}
.andLinlineBtn {
position: absolute;
top: 65px;
right: 160px;
width: 130px;
cursor: pointer;
height: 32px;
opacity: 0.8;
font-family: PangMenZhengDao;
font-size: 22px;
color: #00ffff;
text-align: center;
font-weight: 400;
line-height: 40px;
}
.routeLabelBtn {
position: absolute;
top: 65px;
right: 20px;
width: 130px;
cursor: pointer;
height: 40px;
opacity: 0.8;
font-family: PangMenZhengDao;
font-size: 22px;
color: #00ffff;
text-align: center;
font-weight: 400;
line-height: 40px;
}
.routeLabelBtnDefault {
background: rgba(0, 3, 36, 0.8);
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.5),
inset 0 0 15px 0 rgba(0, 182, 255, 0.9);
border-radius: 6px;
}
.routeLabelBtnActive {
background: rgba(0, 34, 140, 0.2);
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.5), inset 0 0 10px 0 #00b6ff;
border-radius: 6px;
}
}
.tb-box {
// overflow-x: scroll;
// overflow-y: hidden;
padding: 0 !important;
.tb-hd-box {
display: flex;
background: #303133;
// width: 1415.62px;
border-top: 1px solid rgba(207, 234, 255, 0.33);
border-bottom: 1px solid rgba(207, 234, 255, 0.33);
height: 37.6px;
.tb-hd {
flex: 1;
line-height: 37.6px;
width: calc(100% / 8);
white-space: nowrap;
height: 100%;
text-align: center;
font-family: MicrosoftYaHei-Bold;
font-size: 16px;
color: #b5e5ff;
letter-spacing: 0;
font-weight: 700;
}
}
.tb-bd-box {
width: 570px;
max-height: 280px;
overflow: hidden;
overflow-y: auto;
.tb-tr {
display: flex;
color: #fff;
align-items: center;
font-size: 14px;
width: 560px;
margin: 5px 0 0 0;
// border: 1px solid;
background: #081a3a;
cursor: pointer;
// background-image: url("~@/assets/newImage/tiaokaung.png") !important;
background-size: 100% 100%;
// &:hover {
// // background: rgba(2, 19, 96, 0.2);
// box-shadow: inset 0px 0px 10px 2px #3fcbff;
// // border: 1px solid #70f6f9;
// }
&:nth-of-type(2n - 1) {
background: #3c3c3c;
}
.td {
// width: calc(100% / 7);
flex: 1;
text-align: center;
overflow: hidden;
text-overflow: ellipsis;
}
.last-td {
width: 80px;
height: 32px;
text-align: center;
line-height: 32px;
margin: 0 auto;
color: #fff;
background: #3388ff;
font-family: SourceHanSansCN, SourceHanSansCN;
font-weight: 400;
font-size: 14px;
}
}
}
}
}
}
.toubu {
display: flex;
.tiao {
width: 3px !important;
height: 15px;
background: #ffbd36;
margin: 6px 5px 0 16px;
}
.hd-box {
font-size: 18px;
font-family: MicrosoftYaHei-Bold, MicrosoftYaHei;
font-weight: bold;
color: #ffffff;
line-height: 24px;
text-shadow: 0px 2px 4px #136791;
}
}
.cpt-command-airway-list .tb-box {
height: 100%;
}
.flex {
display: flex;
}
.uavImg {
width: 20px;
height: 20px;
margin: 0 6px 0 6px;
img {
width: 100%;
height: 100%;
}
}
.fangkuai {
border: 1px solid #43deff;
height: 32px;
background: rgba(13, 50, 92, 0.7);
}
.duanxian {
width: 1px;
height: 22px;
border-left: 1px solid;
border-image: linear-gradient(
180deg,
rgba(67, 222, 255, 0),
rgba(67, 222, 255, 1),
rgba(67, 222, 255, 0)
)
1 1;
}
.el-input__suffix-inner::v-deep {
i {
color: #43deff;
}
}
// 滚动动画
.animate {
padding-left: 20px;
// font-size: 12px;
// color: #000;
display: inline-block;
white-space: nowrap;
animation: 5s wordsLoop linear infinite normal;
}
@keyframes wordsLoop {
0% {
transform: translateX(100%);
-webkit-transform: translateX(100%);
}
100% {
transform: translateX(-100%);
// -webkit-transform: translateX(-100%);
}
}
// @-webkit-keyframes wordsLoop {
// 0% {
// transform: translateX(100%);
// -webkit-transform: translateX(100%);
// }
// 100% {
// transform: translateX(-100%);
// -webkit-transform: translateX(-100%);
// }
// }
.tb-tr::v-deep .td {
// padding: 18px 0 !important;
}
// 提示框样式
.td::v-deep .el-tooltip {
background: rgba(2, 19, 96, 0);
border: 0px solid rgba(207, 234, 255, 0.33);
font-family: MicrosoftYaHei;
color: #ffffff;
line-height: 19px;
}
// 空域状态
.status {
font-size: 14px;
font-family: MicrosoftYaHei;
color: #00d45c;
line-height: 19px;
}
//操作状态
.el-tooltip {
opacity: 0.7;
}
.el-tooltip:hover {
opacity: 1;
}
// 页签样式
.zongji {
font-size: 12px;
font-family: MicrosoftYaHei;
color: #b5e5ff;
line-height: 16px;
.tiaoshu {
color: #43deff;
}
}
.douhao {
margin: 0 5px 0 5px;
}
.dangqianye {
margin: 0 20px 0 0;
}
.el-pager::v-deep .number:hover {
background: #00b6ff !important;
border-radius: 2px;
color: #000 !important;
width: 14px;
height: 22px;
line-height: 22px;
}
.el-pagination--small::v-deep .el-pager .number {
font-size: 12px;
font-family: MicrosoftYaHei;
color: #889fb2;
}
.active::v-deep {
color: #000 !important;
}
.btnqueding {
margin: 0 0 0 8px;
width: 79px;
height: 32px;
background: rgba(28, 67, 191, 0.6) !important;
box-shadow: 0px 2px 4px 0px rgba(23, 33, 60, 0.5),
inset 0px 0px 16px 0px rgba(33, 137, 255, 0.4),
inset 0px 0px 4px 0px #00a7ff;
border-radius: 0px;
border: 1px solid;
border-image: linear-gradient(
180deg,
rgba(138, 218, 255, 1),
rgba(82, 179, 255, 0)
)
1 1;
line-height: 1px;
color: #43deff;
}
.btnqueding:hover {
opacity: 0.5 !important;
}
.tb-pagination {
margin: 0 0 19px 0;
}
.zhuan {
font-size: 12px;
font-family: MicrosoftYaHei;
color: #889fb2;
line-height: 16px;
input {
width: 48px;
min-width: 48px;
max-width: auto;
text-align: center;
height: 28px;
background: rgba(12, 13, 20, 0.5);
border-radius: 2px;
border: 1px solid rgba(36, 146, 252, 0.3);
margin: 0 5px 0 5px;
color: #fff;
outline: 0px solid;
}
}
// 说明
.shuo {
margin: 0 0 29px 0;
}
.shuoming {
font-size: 12px;
font-family: MicrosoftYaHei;
color: #43deff;
line-height: 16px;
}
.maohao {
font-size: 12px;
font-family: MicrosoftYaHei;
color: #43deff;
line-height: 16px;
margin: 0 14px 0 5px;
}
.icons {
font-size: 12px;
font-family: MicrosoftYaHei;
color: #b3bbc5;
line-height: 16px;
margin: 0 12px 0 0;
}
.cpt-command-flight-task-explain {
display: flex;
align-items: center;
margin-left: 4px;
// margin-top: 8px;
padding: 0;
margin: 28px 0 29px 0;
.explain_title {
font-family: MicrosoftYaHei;
font-size: 14px;
color: #08c2d1;
}
.explain_box {
display: flex;
}
.explain_box_detail {
margin-right: 15px;
font-size: 12px;
font-family: MicrosoftYaHei;
color: #b3bbc5;
}
}
.waixian {
// border-radius: 6px;
// border: 1px solid #8adaff;
}
.el-tooltip__popper::v-deep .is-dark {
z-index: -100;
}
.el-pagination::v-deep {
text-align: center;
.btn-prev,
.btn-next {
color: #fff;
background-color: transparent;
}
.el-pager {
color: #fff;
li {
background-color: transparent;
}
}
}
</style>
\ No newline at end of file
<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
>
<template v-if="showTaskList">
<el-option
v-for="item in taskListAll"
:key="item.id"
:label="item.name"
:value="item.id"
></el-option>
</template>
</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 { AirLine } from "../../../../../../../../../../api";
import hangarStatusDict from "../../hangarStatusDict";
export default {
name: "normalTask",
components: {
LineList,
},
inject: ["rootNode", "bus"],
data() {
return {
// 选择的任务id
selectedTaskId: "",
// 选择的航线
selectedAirway: {
name: "",
id: -1,
},
// 航线选择窗口
showFlywayDialog: false,
showTaskList: true, //用于任务列表更改时强制刷新组件
taskListAll: [],
};
},
computed: {
...mapState("MMCFlightControlCenter", ["useSTLAirway"]),
...mapState("MMCFlightControlCenter/hangar", [
"hangarRealTimeData",
"hangar",
"taskList",
]),
...mapState("MMCFlightControlCenter/uav", ["uav"]),
/**
* 是否选择任务
*/
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 = this.selectedAirway.content;
this.createAirwayEntities({
polyline: airway,
id: airway.id,
});
} catch (e) {
console.log("绘制航线失败", e);
}
}
},
},
created() {
this.rootNode.$emit("hangarTaskTabChange", {
type: 1,
});
this.updateTaskList();
//todo 通过iframe嵌入时, 不知道为什么无法监听this.$store.state.MMCFlightControlCenter.hangar.taskList的变化, 会导致任务列表不更新, 通过事件方式强制更新
this.bus.$on("updateHangarTaskList", this.updateTaskList);
},
beforeDestroy() {
this.clearAirwayEntities();
this.bus.$off("updateHangarTaskList", this.updateTaskList);
},
methods: {
...mapActions("MMCFlightControlCenter", [
"createAirwayEntities",
"clearAirwayEntities",
]),
/**
* 更新任务列表
*/
updateTaskList() {
console.log("updateTaskList");
this.taskListAll = [
{
id: -1,
name: "选择航线自动生成任务",
},
...(this.$store.state.MMCFlightControlCenter.hangar.taskList.normal ||
[]),
];
},
/**
* 更改任务事件
*/
async onChangeTask() {
if (!this.selectedTask?.airwayId) {
this.selectedAirway = {
name: "",
id: -1,
};
} else if (this.useSTLAirway) {
let res = await AirLine.routeDetail({
id: this.selectedTask?.airwayId,
});
if (res.code === 0) {
this.selectedAirway = res.data;
}
} else {
this.rootNode.$emit('airwayGet', {
airwayId: this.selectedTask?.airwayId,
callback: (airway) => {
this.selectedAirway = airway;
}
})
}
},
/**
* 更改航线事件
*/
onChangeLine(data) {
this.selectedAirway = data;
if (data) {
this.rootNode.$emit("hangarTaskAdd", {
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/setState", {
key: "airlineData",
value: this.selectedAirway,
});
this.$store.dispatch("MMCFlightControlCenter/hangar/takeOff", {
uav: this.uav,
callback: (status) => {
if (status) {
this.$message.success("一键任务指令发送成功");
} else {
this.$message.error("一键任务指令发送失败");
}
},
});
this.rootNode.$emit("taskStart", {
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="task-add dialog1027" v-interact>
<div class="dialog-header">
<div class="dialog-header__title">定时任务</div>
<div class="dialog-header__close" @click="$emit('close')">关闭</div>
</div>
<div class="dialog-content">
<el-form ref="form" :model="form" :rules="rules" label-width="100px">
<el-form-item label="执行日期" prop="date" required>
<el-date-picker
v-model="form.date"
type="daterange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
size="mini"
popper-class="mmc"
value-format="yyyy-MM-dd"
:picker-options="pickerOptions"
></el-date-picker>
</el-form-item>
<el-form-item label="执行时间" prop="time" required>
<el-time-picker
is-range
v-model="form.time"
range-separator="至"
start-placeholder="开始时间"
end-placeholder="结束时间"
placeholder="选择时间范围"
size="mini"
popper-class="mmc"
value-format="HH:mm:ss"
></el-time-picker>
</el-form-item>
<el-form-item label="任务名称" required>
<el-select v-model="form.normalTaskId" size="mini" popper-class="mmc" style="width:100%">
<el-option :label="item.name" :value="item.id" v-for="(item, index) in taskList.normal"></el-option>
</el-select>
</el-form-item>
</el-form>
</div>
<div class="task-add-btn">
<div class="task-add__btn" @click="onConfirm">确认</div>
</div>
</div>
</template>
<script>
import { mapState, mapActions } from "vuex";
import { AirLine } from "../../../../../../../../../../../../api";
export default {
name: "TaskAdd",
inject: ["rootNode"],
data() {
return {
form: {
date: [],
time: ["00:00:00", "23:59:59"],
normalTaskId: "",
},
rules: {
date: [{ required: true, message: "请选择日期", trigger: "blur" }],
time: [{ required: true, message: "请选择时间", trigger: "blur" }],
normalTaskId: [
{ required: true, message: "请选择任务", trigger: "blur" },
],
},
pickerOptions: {
disabledDate: (time) => {
// 日期选择限制
return time.getTime() < Date.now() - 8.64e7;
},
},
};
},
computed: {
...mapState("MMCFlightControlCenter/hangar", ["taskList"]),
...mapState("MMCFlightControlCenter", ["airwayEntities"]),
/**
* 选择的日常任务数据
*/
selectedTask() {
let find = this.taskList.normal.find((item) => {
return item.id === this.form.normalTaskId;
});
return find;
},
},
watch: {
selectedTask: {
async handler(newVal, oldVal) {
//清除旧的航线并渲染新航线
let find = this.airwayEntities.find(
(item1) => oldVal?.airwayId === item1.airwayId
);
if (find) {
this.clearAirwayEntities({ id: find.airwayId });
}
//渲染新航线
if (newVal) {
await this.getAirway(newVal);
this.createAirwayEntities({
polyline: newVal.airway.content,
id: newVal.airwayId,
});
}
},
},
},
methods: {
...mapActions("MMCFlightControlCenter", [
"createAirwayEntities",
"clearAirwayEntities",
]),
/**
* 将任务中航线对象补充完整
*/
async getAirway(item) {
if (!item.airway) {
let res = await AirLine.routeDetail({
id: item?.airwayId,
});
if (res.code === 0) {
this.$set(item, "airway", res.data);
}
}
},
/**
* 确认事件
*/
onConfirm() {
this.$refs["form"].validate((valid) => {
if (valid) {
this.rootNode.$emit("hangarTaskAdd", {
type: 3, //1: 日常任务 2.定时任务 3.周期任务
taskList: [{ ...this.form, airway: this.selectedTask.airway }], //任务数据
}); // 根节点发送机库任务新增事件
this.$emit("close");
} else {
return false;
}
});
},
},
};
</script>
<style lang="scss" scoped>
.task-add {
height: 286px;
background: rgba(9, 32, 87, 0.7);
// border: 1px solid #70daf9;
position: absolute;
top: -5px;
left: 550px;
width: 512x;
z-index: 1;
display: flex;
flex-direction: column;
gap: 5px;
padding-bottom: 20px;
&.more {
height: 376px;
}
.dialog-header {
padding-left: 16px !important;
}
.task-add-main {
padding: 20px 20px 0 10px;
}
.task-add-btn {
flex-shrink: 0;
.task-add__btn {
margin: auto;
width: 92px;
height: 36px;
background: #3388ff;
border-radius: 2px;
cursor: pointer;
text-align: center;
color: #fff;
display: flex;
justify-content: center;
align-items: center;
}
}
.task-add-more {
background-color: rgba(13, 82, 143, 0.6);
height: 24px;
cursor: pointer;
display: flex;
justify-content: center;
align-items: center;
}
}
</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">
<el-tooltip class="item" effect="dark" :content="item.time" placement="top-start">
<span>{{item.time}}</span>
</el-tooltip>
</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" @click="onDelAirway(item)"></span>
</el-tooltip>
</div>
</div>
</div>
<div class="task-add-btn">
<div class="task-add__btn" @click="showTaskAdd = true">创建周期任务</div>
</div>
<TaskAdd v-if="showTaskAdd" @close="showTaskAdd = false"></TaskAdd>
</div>
</template>
<script>
import { mapState, mapActions } from "vuex";
import { AirLine } from "../../../../../../../../../../api";
import TaskAdd from "./components/taskAdd";
export default {
name: "hangarPeriodTask",
components: {
TaskAdd,
},
inject: ["rootNode", "bus"],
data() {
return {
showTaskAdd: false,
taskListAll: [],
};
},
computed: {
...mapState("MMCFlightControlCenter", ["airwayEntities"]),
...mapState("MMCFlightControlCenter/hangar", [
"hangarRealTimeData",
"hangar",
"taskList",
]),
},
created() {
this.rootNode.$emit("hangarTaskTabChange", {
type: 3,
});
this.updateTaskList();
//todo 通过iframe嵌入时, 不知道为什么无法监听this.$store.state.MMCFlightControlCenter.hangar.taskList的变化, 会导致任务列表不更新, 通过事件方式强制更新
this.bus.$on("updateHangarTaskList", this.updateTaskList);
},
beforeDestroy() {
this.clearAirwayEntities();
this.bus.$off("updateHangarTaskList", this.updateTaskList);
},
methods: {
...mapActions("MMCFlightControlCenter", [
"createAirwayEntities",
"clearAirwayEntities",
]),
/**
* 更新任务列表
*/
updateTaskList() {
this.taskListAll = [
...(this.$store.state.MMCFlightControlCenter.hangar.taskList.period ||
[]),
];
console.log("updateTaskList", this.taskListAll);
},
/**
* 将任务中航线对象补充完整
*/
async getAirway(item) {
if (!item.airway) {
let res = await AirLine.routeDetail({
id: item?.airwayId,
});
if (res.code === 0) {
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 {
this.createAirwayEntities({
polyline: item.airway.content,
id: item.airwayId,
});
}
},
async onDelAirway(item) {
try {
await this.$confirm("请确认是否删除该任务?", "安全确认", {
cancelButtonText: "取消",
confirmButtonText: "确定",
customClass: "uav_controlPane",
showClose: false,
});
this.rootNode.$emit("hangarTaskDel", {
task: item,
type: 3, // 1: 日常任务 2: 定时任务 3:周期任务
});
} catch (e) {
console.log(e);
}
},
},
};
</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;
}
}
}
}
}
.task-add-btn {
text-align: center;
.task-add__btn {
width: 124px;
height: 36px;
background: #3388ff;
border-radius: 2px;
text-align: center;
line-height: 32px;
margin: 0 auto;
margin-bottom: 10px;
cursor: pointer;
color: #fff;
}
}
}
</style>
\ No newline at end of file
<template>
<div class="task-add dialog1027" :class="{more: showMore}" v-interact>
<div class="task-add-header dialog-header">
<div class="header__title dialog-header__title">定时任务</div>
<div class="header-right dialog-header__close">
<div class="header-right__add" @click="onTaskAdd">
<span class="iconfont icon-zengjia"></span>添加任务
</div>
<div class="header-right__close" @click="$emit('close')">关闭</div>
</div>
</div>
<div class="task-add-main dialog-content">
<div class="main-item" v-for="(item, index) in list" :key="index">
<el-date-picker
v-model="item.time"
size="mini"
popper-class="mmc"
type="datetime"
placeholder="选择时间"
value-format="yyyy-MM-dd HH:mm:ss"
:picker-options="pickerOptions"
></el-date-picker>
<el-select
v-model="item.normalTaskId"
size="mini"
popper-class="mmc"
@change="onChangeTask(item, index)"
placeholder="请选择任务"
>
<el-option
:label="item1.name"
:value="item1.id"
v-for="(item1, index) in taskList.normal"
></el-option>
</el-select>
<el-input
placeholder="航线名称"
class="input"
size="mini"
:value="item.airway ? item.airway.name : ''"
disabled
/>
<el-tooltip content="删除" placement="top">
<span class="icon-shanchu iconfont" @click="onDelTask(index)"></span>
</el-tooltip>
<el-tooltip content="查看" placement="top">
<span
class="icon-chakan1 iconfont"
style="font-size: 10px;"
@click="onSwitchAirway(item)"
></span>
</el-tooltip>
</div>
</div>
<div class="task-add-btn">
<div class="task-add__btn" @click="onConfirm">确认</div>
</div>
<div class="task-add-more" @click="showMore = !showMore">
<img src="../../../../assets/images/xb.png" width="15" />
</div>
</div>
</template>
<script>
import { mapState, mapActions } from "vuex";
import { AirLine } from "../../../../../../../../../../../../api";
export default {
name: "TaskAdd",
inject: ["rootNode"],
data() {
return {
list: [
/* {
time: '',
normalTaskId: '',
airwayId: ''
} */
],
showMore: false,
pickerOptions: {
disabledDate: (time) => {
// 日期选择限制
return time.getTime() < Date.now() - 8.64e7;
},
},
};
},
computed: {
...mapState("MMCFlightControlCenter/hangar", ["taskList"]),
...mapState("MMCFlightControlCenter", ["airwayEntities"]),
},
methods: {
...mapActions("MMCFlightControlCenter", [
"createAirwayEntities",
"clearAirwayEntities",
]),
/**
* 将任务中航线对象补充完整
*/
async getAirway(id) {
let res = await AirLine.routeDetail({
id: id,
});
if (res.code === 0) {
return res.data;
}
},
/**
* 显示或隐藏航线
*/
async onSwitchAirway(item) {
let find = this.airwayEntities.find(
(item1) => item1.airwayId === item.airwayId
);
if (find) {
this.clearAirwayEntities({ id: find.airwayId });
} else {
this.createAirwayEntities({
polyline: item.airway.content,
id: item.airwayId,
});
}
},
/**
* 添加新任务
*/
onTaskAdd(item) {
this.list.push({
time: "",
normalTaskId: "",
airwayId: "",
});
},
/**
* 任务内容更改
*/
async onChangeTask(item, i) {
let normalTask = this.selectedTask(item.normalTaskId);
item.airwayId = normalTask.airwayId;
let find = this.taskList.normal.find(
(task) => task.airwayId === item.airwayId
);
if (find) {
item.airway = find.airway;
}
if (!find.airway) {
item.airway = await this.getAirway(item.airwayId);
}
this.$set(this.list, i, item);
},
/**
* 删除的任务
*/
onDelTask(index) {
this.list = this.list.filter((item, i) => i !== index);
},
/**
* 选择的日常任务数据
*/
selectedTask(normalTaskId) {
let find = this.taskList.normal.find((item) => {
return item.id === normalTaskId;
});
return find;
},
/**
* 确认事件
*/
onConfirm() {
let isOk = true;
this.list.some((item) => {
if (!item.time) {
this.$message.warning("请选择时间")
isOk = false;
return true;
}
if (!item.normalTaskId) {
this.$message.warning("请选择任务")
isOk = false;
return true;
}
});
if (isOk) {
this.rootNode.$emit("hangarTaskAdd", {
type: 2, //1: 日常任务 2.定时任务 3.周期任务
taskList: this.list, //任务数据
}); // 根节点发送机库任务新增事件
this.$emit("close");
}
},
},
};
</script>
<style lang="scss" scoped>
.task-add {
height: 250px;
position: absolute;
top: -5px;
left: 550px;
width: 620px;
z-index: 1;
display: flex;
flex-direction: column;
gap: 5px;
&.more {
height: 376px;
}
.task-add-header {
flex-shrink: 0;
display: flex;
justify-content: space-between;
align-items: center;
height: 32px;
padding: 0 20px 0 0;
.header__title {
font-family: MicrosoftYaHei-Bold;
font-size: 16px;
color: #70daf9;
letter-spacing: 0;
font-weight: 700;
}
.header-right {
display: flex;
gap: 20px;
font-family: MicrosoftYaHei;
font-size: 16px;
color: #70daf9;
letter-spacing: 0;
font-weight: 400;
.header-right__add {
font-size: 12px;
display: flex;
align-items: center;
cursor: pointer;
}
.header-right__close {
font-size: 16px;
cursor: pointer;
}
}
}
.task-add-main {
padding: 20px 20px 0 10px;
flex: 1;
overflow-y: auto;
.main-item::v-deep {
margin-bottom: 20px;
display: flex;
align-items: center;
font-size: 15px;
color: #fff;
gap: 5px;
height: fit-content;
.el-date-editor {
width: 188px;
}
.el-select {
width: 200px;
}
.input {
width: 150px;
}
.iconfont {
color: rgb(67, 222, 255);
cursor: pointer;
}
}
}
.task-add-btn {
flex-shrink: 0;
.task-add__btn {
width: 92px;
height: 36px;
background: #3388ff;
border-radius: 2px;
text-align: center;
line-height: 32px;
margin: 0 auto;
margin-bottom: 10px;
cursor: pointer;
color: #fff;
}
}
.task-add-more {
background-color: #191919;
height: 24px;
cursor: pointer;
display: flex;
justify-content: center;
align-items: center;
}
}
</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">
<el-tooltip class="item" effect="dark" :content="item.time" placement="top-start">
<span>{{item.time}}</span>
</el-tooltip>
</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" @click="onDelAirway(item)"></span>
</el-tooltip>
</div>
</div>
</div>
<div class="task-add-btn">
<div class="task-add__btn" @click="showTaskAdd = true">创建定时任务</div>
</div>
<TaskAdd v-if="showTaskAdd" @close="showTaskAdd = false"></TaskAdd>
</div>
</template>
<script>
import { mapState, mapActions } from "vuex";
import { AirLine } from "../../../../../../../../../../api";
import TaskAdd from "./components/taskAdd";
export default {
name: "hangarTimedTask",
components: {
TaskAdd,
},
inject: ["rootNode", "bus"],
data() {
return {
showTaskAdd: false,
taskListAll: [],
};
},
computed: {
...mapState("MMCFlightControlCenter", ["airwayEntities"]),
...mapState("MMCFlightControlCenter/hangar", [
"hangarRealTimeData",
"hangar",
"taskList",
]),
},
created() {
this.rootNode.$emit("hangarTaskTabChange", {
type: 2,
});
this.updateTaskList();
//todo 通过iframe嵌入时, 不知道为什么无法监听this.$store.state.MMCFlightControlCenter.hangar.taskList的变化, 会导致任务列表不更新, 通过事件方式强制更新
this.bus.$on("updateHangarTaskList", this.updateTaskList);
},
beforeDestroy() {
this.clearAirwayEntities();
this.bus.$off("updateHangarTaskList", this.updateTaskList);
},
methods: {
...mapActions("MMCFlightControlCenter", [
"createAirwayEntities",
"clearAirwayEntities",
]),
/**
* 更新任务列表
*/
updateTaskList() {
this.taskListAll = [
...(this.$store.state.MMCFlightControlCenter.hangar.taskList.timed ||
[]),
];
console.log("updateTaskList", this.taskListAll);
},
/**
* 将任务中航线对象补充完整
*/
async getAirway(item) {
if (!item.airway) {
let res = await AirLine.routeDetail({
id: item?.airwayId,
});
if (res.code === 0) {
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 {
this.createAirwayEntities({
polyline: item.airway.content,
id: item.airwayId,
});
}
},
async onDelAirway(item) {
try {
await this.$confirm("请确认是否删除该任务?", "安全确认", {
cancelButtonText: "取消",
confirmButtonText: "确定",
customClass: "uav_controlPane",
showClose: false,
});
this.rootNode.$emit("hangarTaskDel", {
task: item,
type: 2, // 1: 日常任务 2: 定时任务 3:周期任务
});
} catch (e) {
console.log(e);
}
},
},
};
</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;
}
}
}
}
}
.task-add-btn {
text-align: center;
.task-add__btn {
width: 124px;
height: 36px;
background: #3388ff;
border-radius: 2px;
text-align: center;
line-height: 32px;
margin: 0 auto;
margin-bottom: 10px;
cursor: pointer;
color: #fff;
}
}
}
</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: "正在执行飞行任务",
},
];
......@@ -8,11 +8,12 @@
<!-- 展示视频 -->
<div class="left-video" :class="{collapse: playerCollapse}" v-if="hangar && showPanel && listCollapse">
<div class="collapse-btn" @click="playerCollapse = !playerCollapse">
<img src="./assets/images/collapse.svg" />
<img style="width:23px" src="./assets/images/collapse.svg" />
</div>
<div class="left-video-header">
<div class="left-video-header__title" @click="openList">机库列表</div>
<!-- @click="openList" -->
<div class="left-video-header__title" >视频列表</div>
<div class="nest-name">
<span class="nest-name__text">{{ hangar.name }}</span>
<span class="nest-name__text">{{ hangar.name }}</span>
......@@ -107,7 +108,7 @@ export default {
position: absolute;
z-index: 2;
left: 430px;
top: 28px;
top: 68px;
transition: 0.3s;
&.collapse {
......@@ -189,7 +190,7 @@ export default {
.collapse-btn {
position: absolute;
cursor: pointer;
right: -35px;
right: -22px;
top: 50%;
transform: translate(0, -50%);
z-index: 99;
......
<template>
<div class="cpt-nest-logger dialog1027" :class="{ chang: dakai == true, }" v-interact>
<div
class="cpt-nest-logger dialog1027"
:class="{ chang: dakai == true }"
v-interact
>
<div class="title-box dialog-header">
<div class="title">
<img src="../../../../../../../../assets/images/mount_head.png" />
<div class="dialog-header__title">运行监控日志</div>
<div effect="dark" class="status">{{ getProcessStatus(hangarRealTimeData.processStatus) }}</div>
<div effect="dark" class="status">
{{ getProcessStatus(hangarRealTimeData.processStatus) }}
</div>
</div>
<div style="display: flex">
<div class="icon-box" @click="onClear">
......@@ -45,9 +51,16 @@
<div class="time">时间</div>
</div>
<div class="list-box mt7">
<div class="item-box" v-for="(item, index) in hangarMsgList" :key="index">
<div
class="item-box"
v-for="(item, index) in hangarMsgList"
:key="index"
>
<div class="text-box">
<div class="type-box" :class="{ emerg: item.type == 1, ordinary: item.type == 8 }">
<div
class="type-box"
:class="{ emerg: item.type == 1, ordinary: item.type == 8 }"
>
<span class="type" v-if="item.type == 1">紧急</span>
<span class="type" v-else-if="item.type == 8">普通</span>
<span class="type" v-else>AUTO</span>
......@@ -288,8 +301,11 @@ export default {
position: fixed;
width: 670px;
height: 143px;
top: 21%;
left: 32%;
top:-50%; /* 设置为 0 */
left: 0; /* 设置为 0 */
right: 0; /* 设置为 0 */
bottom: 0; /* 设置为 0 */
margin: auto; /* 自动边距实现居中 */
display: flex;
// overflow-y: auto;
background: rgba(9, 32, 87, 0.7);
......
<template>
<ControlRight
ref="controlRight"
isHangar
@switchCallback="showHangar = false; showMonitor = false;"
>
<div
slot="hangar"
class="control-item"
:class="showHangar ? 'active' : ''"
@click="onSwitchShow('showHangar')"
>
<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/hangar.svg" />
<span class="dib">机库</span>
</div>
......@@ -21,25 +12,16 @@
<span class="dialog-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)"
>
<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 class="hangar-ctrl-item__title">{{ item.label }}</div>
</div>
</div>
</div>
<Logger class="logger" @exit="showLogger = false" v-if="showLogger"></Logger>
<HangarMonitor
:uavMsg="uavRealTimeData.msg"
:weatherStation="hangarRealTimeData.weatherStation"
:hangarData="hangarRealTimeData"
v-if="showMonitor"
></HangarMonitor>
<HangarMonitor :uavMsg="uavRealTimeData.msg" :weatherStation="hangarRealTimeData.weatherStation"
:hangarData="hangarRealTimeData" v-if="showMonitor"></HangarMonitor>
</div>
</ControlRight>
</template>
......@@ -120,11 +102,21 @@ export default {
};
},
computed: {
...mapState("MMCFlightControlCenter", ["showAirwayEdit"]),
...mapState("MMCFlightControlCenter", ["showAirwayEdit", "flyLogStatus"]),
...mapState("MMCFlightControlCenter/uav", ["uavRealTimeData"]),
...mapState("MMCFlightControlCenter/hangar", ["hangarRealTimeData"]),
},
watch: {
flyLogStatus: {
handler(val) {
if (val) {
this.showLogger = false
} else {
this.showLogger = true
}
},
immediate: true,
},
// 打开航线编辑时关闭所有窗口
showAirwayEdit(newVal) {
if (newVal) {
......@@ -149,7 +141,11 @@ export default {
/**
* 切换展示
*/
onSwitchShow(key) {
async onSwitchShow(key) {
if (!await this.isTakeOver()) {
this.$message.warning("请先接管设备");
return;
}
this.$refs.controlRight.hideAll(key);
this[key] = !this[key];
this.showMonitor = false;
......@@ -159,7 +155,7 @@ export default {
* @param {number} i this.ctrlList被点击元素的索引
*/
async onClickCMD(i) {
if(!await this.isTakeOver()){
if (!await this.isTakeOver()) {
this.$message.warning("请先接管设备");
return;
}
......@@ -217,8 +213,7 @@ export default {
justify-content: space-between;
height: 32px;
.hangar-ctrl-header__title {
}
.hangar-ctrl-header__title {}
.hangar-ctrl-header__close {
font-size: 14px;
......@@ -230,6 +225,7 @@ export default {
align-items: center;
}
}
.hangar-ctrl-list {
box-sizing: border-box;
padding: 8px 16px 14px;
......@@ -267,8 +263,4 @@ export default {
}
}
.logger {
position: absolute;
left: -1200px;
}
</style>
\ No newline at end of file
......@@ -7,10 +7,16 @@
</div>
<div class="line-box w210">
(
<span class="cf">{{ data.onLineCount + data.offLineCount }}</span>
<span class="healthy--un ml5" style="color: #31db24">{{ data.onLineCount }} 架在线</span>
<span class="cf"
>{{ data.onLineCount + data.offLineCount }}</span
>
<span class="healthy--un ml5" style="color: #31db24"
>{{ data.onLineCount }} 架在线</span
>
<span>/</span>
<span class="healthy--total" style="color: #cad8d9">{{ data.offLineCount }} 离线</span>)
<span class="healthy--total" style="color: #cad8d9"
>{{ data.offLineCount }} 离线</span
>)
</div>
</div>
</div>
......@@ -27,12 +33,16 @@
<!-- 最前面的选项框 -->
<div class="title-box">
<el-tooltip
:content="device.isOnline? '在线' : '离线'"
:content="device.isOnline ? '在线' : '离线'"
placement="top"
:enterable="false"
>
<el-checkbox
:value="hangar && device.deviceId === hangar.deviceId && device.isCheck"
:value="
hangar &&
device.deviceId === hangar.deviceId &&
device.isCheck
"
@change="(e) => handClick(e, device)"
></el-checkbox>
</el-tooltip>
......@@ -58,10 +68,25 @@
</div>
<div class="icon-box">
<span class="type fr" v-if="device.status">{{ typeName(device.status) }}</span>
<span @click="onLocation(device)" class="iconfont fr icon-dingwei1" v-hover></span>
<span class="takeover" title="接管" @click="onTakeOver(device)" v-hover>
<img src="./assets/images/jieguan_active.svg" v-if="device.currentOperator" />
<span class="type fr" v-if="device.status">{{
typeName(device.status)
}}</span>
<span
@click="onLocation(device)"
class="iconfont fr icon-dingwei1"
v-hover
></span>
<!-- 相同部门不需要接管 -->
<span
class="takeover"
title="接管"
@click="onTakeOver(device, data.name)"
v-hover
>
<img
src="./assets/images/jieguan_active.svg"
v-if="device.currentOperator === userInfo.id"
/>
<img src="./assets/images/jieguan.svg" v-else />
</span>
</div>
......@@ -69,9 +94,39 @@
</div>
</template>
<div class="nest-child_group_box" v-if="data.child && data.child.length">
<Item v-for="(item, i) in data.child" :data="item" :key="`device_child_${i}`" />
<Item
v-for="(item, i) in data.child"
:data="item"
:key="`device_child_${i}`"
/>
</div>
</div>
<el-dialog
title="接管确认"
:visible.sync="takeOverVisible"
width="20%"
:modal-append-to-body="false"
:append-to-body="false"
:close-on-click-modal="false"
@close="takeLoading = false"
>
<span>是否请求接管 {{ departmentName }} 下的 {{ takeDevice.name }}</span>
<span slot="footer" class="dialog-footer">
<el-button @click="takeOverVisible = false">取 消</el-button>
<el-button
@click="onForceTakeOver"
type="danger"
:loading="forceTakeLoading"
>强制接管</el-button
>
<el-button
type="primary"
@click="onApplyTakeOver"
:loading="takeLoading"
>确 认</el-button
>
</span>
</el-dialog>
</div>
</template>
......@@ -87,14 +142,27 @@ export default {
default: () => ({}),
},
},
inject: ["rootNode"],
inject: ["rootNode", "bus"],
data() {
return {
locationEntity: null,
takeOverVisible: false,
// 接管设备信息
takeDevice: {
name: "",
},
departmentName: "",
takeLoading: false, //接管等待中
forceTakeLoading: false, //强制接管等待
};
},
computed: {
...mapState("MMCFlightControlCenter", ["listCollapse", "cesiumViewer", "userInfo"]),
...mapState("MMCFlightControlCenter", [
"listCollapse",
"cesiumViewer",
"userInfo",
"deptId",
]),
...mapState("MMCFlightControlCenter/hangar", ["showPanel", "hangar"]),
...mapState("MMCFlightControlCenter/uav", ["uav"]),
},
......@@ -103,7 +171,84 @@ export default {
this.onLocation(this.hangar);
},
},
beforeDestroy() {
this.bus.$off("uas-device-take-agree-message", this.onTakeAgree);
this.bus.$off("uas-device-take-refuse-message", this.onTakeAgree);
},
methods: {
/**
* 同意接管事件
*/
onTakeAgree({ type, content, msg }) {
console.log("onTakeAgree");
//接管消息
if (content.isAgree) {
this.$notify.success({
title: "接管消息",
message: msg,
duration: 30000,
offset: 40,
});
this.$emit("refresh");
this.takeOverVisible = false;
} else {
this.$notify.warning({
title: "接管消息",
message: msg,
duration: 30000,
offset: 40,
});
this.$message.warning("申请接管拒绝");
}
this.takeLoading = false;
this.bus.$off("uas-device-take-agree-message", this.onTakeAgree);
this.bus.$off("uas-device-take-refuse-message", this.onTakeAgree);
},
/**
* 申请接管
*/
async onApplyTakeOver() {
this.takeLoading = true;
let res = await Control_API.applyControlUav({
deviceId: this.takeDevice.id,
});
setTimeout(() => {
if (this.takeLoading) {
this.$message.error(`接管失败,申请单位未同意`);
this.takeLoading = false;
}
}, 5500);
if (res.code === 0) {
this.bus.$on("uas-device-take-agree-message", this.onTakeAgree);
this.bus.$on("uas-device-take-refuse-message", this.onTakeAgree);
} else {
this.$message.warning("接管失败,申请单位未同意");
this.takeLoading = false;
}
setTimeout(() => {
if (this.takeLoading) {
this.$message.error(`接管失败,申请单位未同意`);
this.takeLoading = false;
}
}, 5500);
},
/**
* 强制接管
*/
async onForceTakeOver() {
this.forceTakeLoading = true;
try {
let res = await Control_API.setUavControlOnForce({
deviceId: this.takeDevice.id,
});
if (res.code === 0) {
this.$message.success(`请开始操作${this.takeDevice.name}`);
this.takeOverVisible = false;
this.$emit("refresh");
}
} catch (e) {}
this.forceTakeLoading = false;
},
typeName(val) {
let name = "";
switch (val) {
......@@ -176,7 +321,8 @@ export default {
});
}
} else {
this.$message.error("该机库中没有无人机!");
// this.$message.error("该机库中没有无人机!");
console.log(device, "该机库中没有无人机!");
}
//获取机库中视频
......@@ -250,14 +396,55 @@ export default {
/**
* 接管无人机
*/
async onTakeOver(hangar) {
if (!hangar.currentOperator) {
let res = await Control_API.setUavControlOn({
deviceId: hangar.id,
async onTakeOver(hangar, departmentName) {
console.log("onTakeOver:", hangar);
//upkeepStatus保养状态, upkeepErrorCode异常信息代码,upkeepTime保养时间
const { upkeepStatus, upkeepErrorCode, upkeepTime, countdown } = hangar;
//设备超过保养时间,不能起飞
if (!upkeepStatus) {
await this.$confirm(
`设备超三个月未进行保养,存在安全隐患,无法进行正常飞行!`,
"温馨提示",
{
cancelButtonText: "取消",
confirmButtonText: "确定",
showClose: false,
}
);
return;
}
//保养周期小于20天时,提示保养
if (countdown == 0 || (countdown && countdown <= 20)) {
this.$message({
type: "warning",
message: `需安排时间进行保养,上次保养时间为${upkeepTime},距离下次保养时间还有${countdown}日!超出时间将无法正常飞行!!!`,
duration: 2000,
});
if (res.code === 0) {
this.$message.success(`请开始操作${hangar.name}`);
this.$emit("refresh");
}
this.departmentName = departmentName;
if (!hangar.currentOperator) {
// 没有接管人的情况下该设备所属部门与用户一致则直接接管
if (this.deptId === hangar.departmentId) {
let res = await Control_API.updateCurrentOperator({
deviceId: hangar.id,
});
if (res.code === 0) {
this.$message.success(`请开始操作${hangar.name}`);
this.$emit("refresh");
}
} else {
// 不一致则申请接管
this.takeDevice = hangar;
this.takeOverVisible = true;
setTimeout(() => {
if (this.takeLoading) {
this.$message.error(`接管失败,申请单位未同意`);
this.takeLoading = false;
}
}, 5500);
}
} else if (
// 判断当前接管人是不是自已, 是则提示退出接管, 不是则提示是否强制接管
......@@ -279,25 +466,16 @@ export default {
}
} catch (e) {}
} else {
try {
await this.$confirm(
`${hangar.name}已被接管, 请确认是否强制接管?`,
"安全确认",
{
cancelButtonText: "取消",
confirmButtonText: "确定",
customClass: "uav_controlPane",
showClose: false,
}
);
let res = await Control_API.setUavControlOnForce({
deviceId: hangar.id,
});
if (res.code === 0) {
this.$message.success(`请开始操作${hangar.name}`);
this.$emit("refresh");
// 已被接管且接管人不是自已的情况下, 需要申请接管
this.takeDevice = hangar;
this.takeOverVisible = true;
// 5秒后没收到通知认定接管失败
setTimeout(() => {
if (this.takeLoading) {
this.$message.error(`接管失败,申请单位未同意`);
this.takeLoading = false;
}
} catch (e) {}
}, 5500);
}
},
},
......@@ -399,6 +577,7 @@ export default {
.title-box::v-deep {
height: 100%;
white-space: nowrap;
.el-checkbox {
&.is-checked {
.el-checkbox__input {
......@@ -444,6 +623,7 @@ export default {
font-weight: 400;
margin-left: 8px;
}
.status-icon {
margin-left: 12px;
font-size: 14px;
......@@ -477,16 +657,19 @@ export default {
}
}
}
.li {
font-size: 16px;
color: #9baaac;
font-weight: 400;
}
.zai {
color: #31db24;
font-weight: 400;
font-size: 16px;
}
.type {
cursor: default;
font-weight: 400;
......@@ -500,6 +683,7 @@ export default {
color: #fff;
background-color: #224563;
}
.el-checkbox__inner::v-deep {
background: transparent !important;
}
......
......@@ -35,8 +35,8 @@
<div
class="hangar-list_btn"
@click="listCollapse = !listCollapse;"
v-if="!hangar || (hangar && !listCollapse)"
>
<!-- v-if="!hangar || (hangar && !listCollapse)" -->
<img style src="./assets/images/collapse.svg" />
</div>
</div>
......@@ -101,12 +101,13 @@ export default {
mounted() {
this.getList();
this.timeHandle = setInterval(() => {
this.getList();
}, 10000);
this.bus.$on("uas-device-getTree-message", this.initList);
// this.timeHandle = setInterval(() => {
// this.getList();
// }, 10000);
},
beforeDestroy() {
clearInterval(this.timeHandle);
// clearInterval(this.timeHandle);
},
methods: {
async getList() {
......@@ -155,7 +156,7 @@ export default {
position: absolute;
cursor: pointer;
right: -35px;
top: 50%;
top: 23%;
transform: translate(0, -50%);
z-index: 99;
......
......@@ -29,7 +29,7 @@ export default {
"uavRealTimeData.isFlying"(newVal, oldVal) {
// 监听飞机降落然后进行任务结束的提示
if (oldVal === true && newVal === false) {
if (!this.uav.deviceId.include("mock")) {
if (!this.uav.deviceId.includes("mock")) {
this.$alert("当前任务已结束", "提示", {
type: "success ",
confirmButtonText: "确定",
......
......@@ -617,6 +617,9 @@ export default {
mountStatus: 0
});
},
mounted() {
this.clearRecord()
},
methods: {
resolve_payload(buff) {
const dataArray = new Uint8Array(buff);
......@@ -979,6 +982,25 @@ export default {
}
this.$emit('take_photo', streamData);
},
clearRecord(){
const streamData = {
data: {
data: {
videoID: 1
}
},
type: 528
};
if (this.isQingLiu) {
streamData.data.messageID = 1017;
streamData.data.data.status =false
} else {
streamData.data.messageID = 1006;
streamData.data.data.recordControl =false;
}
this.$emit('record', streamData);
},
handle_record() {
if (!this.keyFlag) return this.$message.error('录像失败,NX通信异常!');
this.record = !this.record;
......
<?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>编组 17</title>
<g id="套用鹰视改" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="驾驶中心-无人机应用4-AI人脸" transform="translate(-1072.000000, -923.000000)">
<g id="编组-25" transform="translate(1059.000000, 916.000000)">
<g id="编组-17" transform="translate(13.000000, 7.000000)">
<rect id="矩形" x="0" y="0" width="22" height="22"></rect>
<path d="M15.8851398,2.2006884 C18.4513254,2.2006884 20.5316299,4.34209967 20.5316299,6.98366435 C20.5316299,9.62522902 18.4513254,11.7666403 15.8851398,11.7666403 C13.3189542,11.7666403 11.2386497,9.62522902 11.2386497,6.98366435 C11.2386497,4.34209967 13.3189542,2.2006884 15.8851398,2.2006884 Z" id="路径" fill="#4E4E4E" fill-rule="nonzero"></path>
<path d="M4.07412626,9.38141381 C2.93497627,9.38141381 2.01151275,8.43082449 2.01151275,7.25821315 C2.01151275,6.08560181 2.93497627,5.1350125 4.07412626,5.1350125 C5.21327625,5.1350125 6.13673978,6.08560181 6.13673978,7.25821315 C6.13673978,8.43082449 5.21327625,9.38141381 4.07412626,9.38141381 L4.07412626,9.38141381 Z" id="路径" fill="#4E4E4E" fill-rule="nonzero"></path>
<path d="M7.78746356,5.5594665 C6.64837243,5.5594665 5.72493331,4.60897169 5.7248501,3.43642094 C5.72476689,2.2638702 6.6480711,1.31323655 7.78716221,1.31306522 C8.92625333,1.31289388 9.84982739,2.26324972 9.85007712,3.43580045 C9.850197,3.9989889 9.6329395,4.53915287 9.24611143,4.93743089 C8.85928337,5.33570892 8.33458102,5.5594665 7.78746356,5.5594665 L7.78746356,5.5594665 Z" id="路径" fill="#4E4E4E" fill-rule="nonzero"></path>
<path d="M11.4438326,19.3760946 C13.8976211,19.3567809 16.3492167,19.5318262 18.7769164,19.8996809 C18.6033789,20.1815037 18.4983837,20.5022294 18.4708249,20.8346897 C16.5583183,20.6652804 14.1154641,20.5628902 11.4438326,20.5628902 C5.69003612,20.5628902 0.963477237,21.0329544 0.420922173,21.6333333 C0.388765361,21.5789522 0.370130228,21.5172484 0.366666667,21.453685 C0.366666667,20.3064493 5.32607207,19.3760946 11.4438326,19.3760946 Z M17.0194901,1.27722864 C17.0425487,1.28327896 17.064703,1.29212177 17.0877616,1.29863749 C17.1108203,1.30515321 17.1270969,1.30468781 17.1465384,1.30980733 C20.2783269,2.07257018 22.2164465,5.30430294 21.4754496,8.52808447 C20.7344528,11.751866 17.59494,13.7469158 14.4631515,12.984153 L12.4837298,15.8157077 L13.0262848,15.8157077 C13.7778855,15.8859857 14.360153,16.5229174 14.3826725,17.299435 C14.3814616,17.4595724 14.3598772,17.6188566 14.3184701,17.7732224 C15.913582,18.0571225 16.9824155,18.5686082 16.9824155,19.154094 C16.9809982,19.2018663 16.9718291,19.2490583 16.9552878,19.293717 C16.7653935,18.96793 15.549618,19.154094 13.8518728,19.0172634 C13.6838982,19.1627519 13.4723007,19.2441235 13.2528016,19.2476414 L10.087897,19.2476414 C9.85125189,19.2442624 9.62405888,19.1515108 9.44949056,18.9870118 C7.53743608,19.1103455 6.13764401,18.9404708 5.93282951,19.2941824 C5.91631263,19.2495165 5.9071444,19.2023288 5.90570176,19.1545594 C5.90570176,18.5169476 7.17166356,17.9672984 9.00549968,17.7038763 C8.97481916,17.5710172 8.95859341,17.4350569 8.95712184,17.2985041 C8.95712184,16.478917 9.46305444,15.8147769 10.0874449,15.8147769 L11.6943121,15.8147769 L13.7044787,12.769599 C13.5472439,12.7129244 13.3924704,12.6492585 13.2405941,12.5787808 C13.2207004,12.5699381 13.2003546,12.5624915 13.1804609,12.5531833 C13.0389445,12.4866296 12.9028535,12.4135603 12.7685712,12.3353714 C12.7414434,12.3200129 12.7138635,12.3060506 12.6871879,12.2888304 C12.5599483,12.2120974 12.4356687,12.130278 12.3146335,12.0435593 C12.285245,12.0226158 12.2549524,12.0030686 12.2242076,11.9816597 C12.1075583,11.8960243 11.998143,11.8048039 11.8864671,11.7107911 C11.8566265,11.6851935 11.8258817,11.6600614 11.7960412,11.6339984 C11.6911915,11.5402607 11.5898414,11.442454 11.4922104,11.3407901 L11.4017846,11.2477081 C11.3081938,11.1467141 11.2209329,11.0424623 11.130507,10.935418 C11.1015708,10.8995814 11.0726345,10.8637448 11.0446025,10.8269774 C10.9626163,10.7205536 10.8845487,10.611958 10.8103995,10.5011904 L10.728112,10.3750643 C10.6584841,10.2646069 10.5923225,10.152288 10.5296273,10.0381074 C10.5034038,9.99156638 10.4780846,9.94083666 10.4527653,9.89150321 C10.3951623,9.77919803 10.3408818,9.66512011 10.2899988,9.54942682 C10.2655838,9.49357762 10.2447859,9.43679758 10.220823,9.38001758 C10.1756101,9.26738833 10.1303972,9.15429369 10.0942269,9.03840659 C10.0790966,8.97295723 10.0617544,8.90807069 10.042232,8.8438652 C10.0087156,8.73300435 9.97855909,8.62109664 9.95180615,8.50830457 C9.93462523,8.43430437 9.92106135,8.35937334 9.9065932,8.28444231 C9.88534312,8.17693259 9.86409307,8.06942287 9.84872069,7.95865529 C9.83696531,7.87348525 9.83018338,7.78738438 9.82204505,7.70174894 C9.81209822,7.60028954 9.80079497,7.49929557 9.79582157,7.39643994 C9.79084817,7.29358431 9.79356091,7.19817526 9.79582157,7.09857752 C9.79582157,7.0054955 9.79310879,6.91567137 9.79582157,6.82305478 C9.80124712,6.70297899 9.81571526,6.5824378 9.82837487,6.46189657 C9.83606108,6.38836177 9.83967809,6.31529241 9.85007707,6.24175761 C9.87765694,6.04675079 9.91427941,5.85081317 9.96130086,5.65534095 C10.3323119,4.11070926 11.2847264,2.78130799 12.6086737,1.96007893 C13.932621,1.13884986 15.5194489,0.89318879 17.0194901,1.27722864 Z M13.4784141,18.003135 L10.7656387,18.003135 C10.5159347,18.003135 10.3135095,18.2115061 10.3135095,18.468545 C10.3135095,18.7255839 10.5159347,18.9339551 10.7656387,18.9339551 L13.4784141,18.9339551 C13.7281181,18.9339551 13.9305433,18.7255839 13.9305433,18.468545 C13.9305433,18.2115061 13.7281181,18.003135 13.4784141,18.003135 Z M13.2523494,16.8735848 L10.0874449,16.8735848 C9.71308192,16.8735848 9.40925108,16.8065657 9.40925108,17.2985041 C9.40925108,17.7904425 9.71308192,17.7234235 10.0874449,17.7234235 L13.2523494,17.7234235 C13.6267124,17.7234235 13.9305433,17.7904426 13.9305433,17.2985041 C13.9305433,16.8065657 13.6267124,16.8735848 13.2523494,16.8735848 Z M5.56615269,13.8144445 C6.19041287,13.8144445 6.69647573,14.3353725 6.69647573,14.9779696 C6.69647573,15.6205668 6.19041287,16.1414947 5.56615269,16.1414947 C4.94189251,16.1414947 4.43582965,15.6205668 4.43582965,14.9779696 C4.43582965,14.3353725 4.94189251,13.8144445 5.56615269,13.8144445 Z M7.6007342,11.7200993 C8.22499437,11.7200993 8.73105725,12.2410272 8.73105725,12.8836244 C8.73105725,13.1922105 8.61197,13.4881576 8.3999933,13.7063609 C8.1880166,13.9245642 7.9005145,14.0471496 7.60073418,14.0471496 C6.97647401,14.0471496 6.47041117,13.5262216 6.47041117,12.8836244 C6.47041117,12.2410273 6.97647403,11.7200993 7.6007342,11.7200993 Z M3.53157122,11.7200993 C4.15583139,11.7200993 4.66189427,12.2410272 4.66189427,12.8836244 C4.66189427,13.1922105 4.54280701,13.4881576 4.33083032,13.7063609 C4.11885362,13.9245642 3.83135152,14.0471496 3.5315712,14.0471496 C2.90731103,14.0471496 2.40124819,13.5262216 2.40124819,12.8836244 C2.40124819,12.2410273 2.90731105,11.7200993 3.53157122,11.7200993 Z M15.6938472,2.07726852 C13.7371468,2.07726852 11.9731157,3.29057916 11.2243188,5.1514356 C10.475522,7.01229204 10.8894222,9.15423045 12.2730183,10.5784683 C13.6566145,12.0027062 15.737431,12.4287642 17.5451865,11.6579722 C19.352942,10.8871802 20.5316299,9.0713325 20.5316299,7.05715601 C20.5316299,4.30684009 18.3656808,2.07726852 15.6938472,2.07726852 Z M5.56615271,9.62575412 C6.19041288,9.62575412 6.69647576,10.146682 6.69647576,10.7892792 C6.69647576,11.0978652 6.57738851,11.3938124 6.36541181,11.6120157 C6.15343511,11.830219 5.86593301,11.9528043 5.56615269,11.9528043 C4.94189252,11.9528043 4.43582968,11.4318764 4.43582968,10.7892792 C4.43582968,10.146682 4.94189254,9.62575412 5.56615271,9.62575412 Z M12.0392868,7.02736978 L12.6483048,7.1953828 C12.551277,7.73410365 12.6749886,8.29014528 12.9901145,8.73170139 L12.5443151,9.19431897 C12.0726108,8.5845918 11.8876634,7.79102923 12.0392868,7.02736978 Z M14.545439,3.5875241 L14.545439,4.23909818 C13.5952179,4.31491998 12.8400303,5.09150061 12.7654063,6.0695559 L12.134686,6.0695559 C12.2108376,4.7327597 13.2468036,3.66616323 14.545439,3.5875241 Z" id="形状结合" fill="#4E4E4E" fill-rule="nonzero"></path>
</g>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1736152125143" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="32062" width="22" height="22" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M739.374545 102.4c119.435636 0 216.296727 99.700364 216.296728 222.673455 0 122.926545-96.814545 222.626909-216.296728 222.626909-119.435636 0-216.250182-99.700364-216.250181-222.626909 0-122.973091 96.814545-222.626909 216.250181-222.62691z" fill="#FF9600" p-id="32063"></path><path d="M362.449455 258.792727c-53.015273 0-95.976727-44.264727-95.976728-98.862545 0-54.551273 42.961455-98.816 95.976728-98.816 53.061818 0 96.023273 44.218182 96.023272 98.816 0 26.205091-10.100364 51.339636-28.113454 69.864727a94.626909 94.626909 0 0 1-67.909818 28.951273zM189.626182 436.642909c-53.015273 0-95.976727-44.218182-95.976727-98.816 0-54.551273 42.961455-98.816 95.976727-98.816 53.061818 0 96.023273 44.218182 96.023273 98.816 0 54.597818-43.008 98.816-96.023273 98.816z" fill="#FFFFFF" p-id="32064"></path><path d="M501.108364 837.957818h126.231272c11.636364 0 21.085091 9.728 21.085091 21.690182a21.364364 21.364364 0 0 1-21.085091 21.643636h-126.231272a21.364364 21.364364 0 0 1-21.038546-21.643636c0-11.962182 9.402182-21.690182 21.038546-21.690182z" fill="#22B3F1" p-id="32065"></path><path d="M673.186909 604.346182l-92.16 131.816727h25.274182c35.002182 3.258182 62.091636 32.907636 63.162182 69.026909-0.093091 7.447273-1.070545 14.894545-3.025455 22.062546 74.286545 13.218909 123.997091 37.050182 123.997091 64.279272a20.48 20.48 0 0 1-1.256727 6.516364c-8.843636-15.173818-65.396364-6.516364-144.430546-12.893091a43.659636 43.659636 0 0 1-27.927272 10.705455h-147.269819a44.218182 44.218182 0 0 1-29.742545-12.101819c-88.994909 5.725091-154.112-2.187636-163.653818 14.289455a20.526545 20.526545 0 0 1-1.256727-6.516364c0-29.649455 58.926545-55.249455 144.290909-67.490909a88.110545 88.110545 0 0 1-2.280728-18.850909c0-38.167273 23.552-69.073455 52.596364-69.073454h74.798545l93.556364-141.730909a263.819636 263.819636 0 0 1-21.550545-8.890182c-0.930909-0.465455-1.861818-0.791273-2.792728-1.210182a246.551273 246.551273 0 0 1-19.176727-10.146909c-1.303273-0.698182-2.56-1.349818-3.816727-2.141091a262.749091 262.749091 0 0 1-17.314909-11.403636c-1.396364-0.977455-2.792727-1.861818-4.189091-2.885819a301.521455 301.521455 0 0 1-15.778909-12.613818c-1.396364-1.210182-2.792727-2.327273-4.189091-3.584a258.234182 258.234182 0 0 1-14.149818-13.637818l-4.189091-4.328727c-4.375273-4.701091-8.424727-9.588364-12.613818-14.568728a280.762182 280.762182 0 0 1-27.927273-41.751272c-1.303273-2.141091-2.466909-4.514909-3.630546-6.795637a296.029091 296.029091 0 0 1-7.586909-15.965091c-1.117091-2.56-2.094545-5.213091-3.258182-7.866181a214.341818 214.341818 0 0 1-5.864727-15.918546 137.867636 137.867636 0 0 0-2.420363-9.029818 266.519273 266.519273 0 0 1-4.189091-15.639273c-0.791273-3.444364-1.396364-6.935273-2.094546-10.426182a267.264 267.264 0 0 1-2.699636-15.127272c-0.558545-4.002909-0.884364-8.005818-1.256727-11.962182-0.465455-4.747636-0.977455-9.448727-1.210182-14.242909-0.232727-4.747636-0.093091-9.216 0-13.824 0-4.375273-0.139636-8.517818 0-12.846546 0.232727-5.585455 0.930909-11.170909 1.489454-16.802909 0.372364-3.444364 0.558545-6.842182 1.024-10.24 1.303273-9.076364 2.978909-18.199273 5.166546-27.322182A278.481455 278.481455 0 0 1 586.938182 91.229091a264.378182 264.378182 0 0 1 205.265454-31.790546c1.117091 0.279273 2.141091 0.698182 3.211637 1.024 1.070545 0.279273 1.861818 0.279273 2.746182 0.465455 145.733818 35.560727 235.985455 185.949091 201.448727 336.058182-34.443636 150.016-180.596364 242.874182-326.376727 207.36z m-203.682909 181.061818c-17.408 0-31.557818-3.118545-31.557818 19.781818 0 22.853818 14.149818 19.735273 31.557818 19.735273h147.316364c17.454545 0 31.604364 3.118545 31.604363-19.735273 0-22.900364-14.149818-19.781818-31.604363-19.781818h-147.316364z m260.980364-688.733091c-91.089455 0-173.149091 56.506182-208.058182 143.080727-34.816 86.621091-15.592727 186.321455 48.826182 252.602182 64.418909 66.327273 161.233455 86.109091 245.387636 50.269091 84.154182-35.84 139.031273-120.413091 139.031273-214.109091 0-128.046545-100.817455-231.796364-225.186909-231.796363zM594.292364 282.530909h-29.463273c3.537455-62.231273 51.758545-111.895273 112.174545-115.525818v30.301091c-44.218182 3.537455-79.36 39.703273-82.850909 85.178182h0.139637z m10.519272 123.904l-20.945454 21.504a125.207273 125.207273 0 0 1-23.505455-100.864l28.392728 7.819636a94.487273 94.487273 0 0 0 15.872 71.540364h0.186181zM353.745455 653.824c-29.090909 0-52.596364-24.203636-52.596364-54.132364s23.505455-54.178909 52.596364-54.178909c29.044364 0 52.596364 24.250182 52.596363 54.178909 0 14.336-5.538909 28.113455-15.406545 38.260364-9.867636 10.193455-23.272727 15.872-37.236364 15.872z m-94.72-97.466182c-29.044364 0-52.596364-24.250182-52.596364-54.178909 0-29.882182 23.552-54.132364 52.596364-54.132364 29.044364 0 52.596364 24.203636 52.596363 54.132364 0 14.382545-5.538909 28.16-15.36 38.306909-9.914182 10.146909-23.272727 15.825455-37.236363 15.825455z m-94.673455 97.466182c-29.090909 0-52.596364-24.203636-52.596364-54.132364s23.505455-54.178909 52.596364-54.178909c29.044364 0 52.596364 24.250182 52.596364 54.178909 0 14.336-5.585455 28.113455-15.406546 38.260364-9.867636 10.193455-23.272727 15.872-37.236363 15.872z m94.673455-10.845091c29.044364 0 52.596364 24.250182 52.596363 54.178909 0 29.928727-23.552 54.132364-52.596363 54.132364-29.044364 0-52.596364-24.203636-52.596364-54.132364s23.552-54.178909 52.596364-54.178909z m614.865454 283.275636a98.536727 98.536727 0 0 0-14.196364 43.52c-89.041455-7.912727-202.752-12.660364-327.074909-12.660363-267.822545 0-487.796364 21.876364-513.070545 49.803636a18.385455 18.385455 0 0 1-2.513455-8.378182c0-53.387636 230.865455-96.674909 515.584-96.674909a2164.363636 2164.363636 0 0 1 341.317819 24.389818z" fill="#FF9600" p-id="32066"></path></svg>
\ No newline at end of file
<?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>编组 17</title>
<g id="套用鹰视改" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="驾驶中心-无人机应用4-AI人脸" transform="translate(-1072.000000, -923.000000)">
<g id="编组-25" transform="translate(1059.000000, 916.000000)">
<g id="编组-17" transform="translate(13.000000, 7.000000)">
<rect id="矩形" x="0" y="0" width="22" height="22"></rect>
<path d="M15.8851398,2.2006884 C18.4513254,2.2006884 20.5316299,4.34209967 20.5316299,6.98366435 C20.5316299,9.62522902 18.4513254,11.7666403 15.8851398,11.7666403 C13.3189542,11.7666403 11.2386497,9.62522902 11.2386497,6.98366435 C11.2386497,4.34209967 13.3189542,2.2006884 15.8851398,2.2006884 Z" id="路径" fill="#4E4E4E" fill-rule="nonzero"></path>
<path d="M4.07412626,9.38141381 C2.93497627,9.38141381 2.01151275,8.43082449 2.01151275,7.25821315 C2.01151275,6.08560181 2.93497627,5.1350125 4.07412626,5.1350125 C5.21327625,5.1350125 6.13673978,6.08560181 6.13673978,7.25821315 C6.13673978,8.43082449 5.21327625,9.38141381 4.07412626,9.38141381 L4.07412626,9.38141381 Z" id="路径" fill="#4E4E4E" fill-rule="nonzero"></path>
<path d="M7.78746356,5.5594665 C6.64837243,5.5594665 5.72493331,4.60897169 5.7248501,3.43642094 C5.72476689,2.2638702 6.6480711,1.31323655 7.78716221,1.31306522 C8.92625333,1.31289388 9.84982739,2.26324972 9.85007712,3.43580045 C9.850197,3.9989889 9.6329395,4.53915287 9.24611143,4.93743089 C8.85928337,5.33570892 8.33458102,5.5594665 7.78746356,5.5594665 L7.78746356,5.5594665 Z" id="路径" fill="#4E4E4E" fill-rule="nonzero"></path>
<path d="M11.4438326,19.3760946 C13.8976211,19.3567809 16.3492167,19.5318262 18.7769164,19.8996809 C18.6033789,20.1815037 18.4983837,20.5022294 18.4708249,20.8346897 C16.5583183,20.6652804 14.1154641,20.5628902 11.4438326,20.5628902 C5.69003612,20.5628902 0.963477237,21.0329544 0.420922173,21.6333333 C0.388765361,21.5789522 0.370130228,21.5172484 0.366666667,21.453685 C0.366666667,20.3064493 5.32607207,19.3760946 11.4438326,19.3760946 Z M17.0194901,1.27722864 C17.0425487,1.28327896 17.064703,1.29212177 17.0877616,1.29863749 C17.1108203,1.30515321 17.1270969,1.30468781 17.1465384,1.30980733 C20.2783269,2.07257018 22.2164465,5.30430294 21.4754496,8.52808447 C20.7344528,11.751866 17.59494,13.7469158 14.4631515,12.984153 L12.4837298,15.8157077 L13.0262848,15.8157077 C13.7778855,15.8859857 14.360153,16.5229174 14.3826725,17.299435 C14.3814616,17.4595724 14.3598772,17.6188566 14.3184701,17.7732224 C15.913582,18.0571225 16.9824155,18.5686082 16.9824155,19.154094 C16.9809982,19.2018663 16.9718291,19.2490583 16.9552878,19.293717 C16.7653935,18.96793 15.549618,19.154094 13.8518728,19.0172634 C13.6838982,19.1627519 13.4723007,19.2441235 13.2528016,19.2476414 L10.087897,19.2476414 C9.85125189,19.2442624 9.62405888,19.1515108 9.44949056,18.9870118 C7.53743608,19.1103455 6.13764401,18.9404708 5.93282951,19.2941824 C5.91631263,19.2495165 5.9071444,19.2023288 5.90570176,19.1545594 C5.90570176,18.5169476 7.17166356,17.9672984 9.00549968,17.7038763 C8.97481916,17.5710172 8.95859341,17.4350569 8.95712184,17.2985041 C8.95712184,16.478917 9.46305444,15.8147769 10.0874449,15.8147769 L11.6943121,15.8147769 L13.7044787,12.769599 C13.5472439,12.7129244 13.3924704,12.6492585 13.2405941,12.5787808 C13.2207004,12.5699381 13.2003546,12.5624915 13.1804609,12.5531833 C13.0389445,12.4866296 12.9028535,12.4135603 12.7685712,12.3353714 C12.7414434,12.3200129 12.7138635,12.3060506 12.6871879,12.2888304 C12.5599483,12.2120974 12.4356687,12.130278 12.3146335,12.0435593 C12.285245,12.0226158 12.2549524,12.0030686 12.2242076,11.9816597 C12.1075583,11.8960243 11.998143,11.8048039 11.8864671,11.7107911 C11.8566265,11.6851935 11.8258817,11.6600614 11.7960412,11.6339984 C11.6911915,11.5402607 11.5898414,11.442454 11.4922104,11.3407901 L11.4017846,11.2477081 C11.3081938,11.1467141 11.2209329,11.0424623 11.130507,10.935418 C11.1015708,10.8995814 11.0726345,10.8637448 11.0446025,10.8269774 C10.9626163,10.7205536 10.8845487,10.611958 10.8103995,10.5011904 L10.728112,10.3750643 C10.6584841,10.2646069 10.5923225,10.152288 10.5296273,10.0381074 C10.5034038,9.99156638 10.4780846,9.94083666 10.4527653,9.89150321 C10.3951623,9.77919803 10.3408818,9.66512011 10.2899988,9.54942682 C10.2655838,9.49357762 10.2447859,9.43679758 10.220823,9.38001758 C10.1756101,9.26738833 10.1303972,9.15429369 10.0942269,9.03840659 C10.0790966,8.97295723 10.0617544,8.90807069 10.042232,8.8438652 C10.0087156,8.73300435 9.97855909,8.62109664 9.95180615,8.50830457 C9.93462523,8.43430437 9.92106135,8.35937334 9.9065932,8.28444231 C9.88534312,8.17693259 9.86409307,8.06942287 9.84872069,7.95865529 C9.83696531,7.87348525 9.83018338,7.78738438 9.82204505,7.70174894 C9.81209822,7.60028954 9.80079497,7.49929557 9.79582157,7.39643994 C9.79084817,7.29358431 9.79356091,7.19817526 9.79582157,7.09857752 C9.79582157,7.0054955 9.79310879,6.91567137 9.79582157,6.82305478 C9.80124712,6.70297899 9.81571526,6.5824378 9.82837487,6.46189657 C9.83606108,6.38836177 9.83967809,6.31529241 9.85007707,6.24175761 C9.87765694,6.04675079 9.91427941,5.85081317 9.96130086,5.65534095 C10.3323119,4.11070926 11.2847264,2.78130799 12.6086737,1.96007893 C13.932621,1.13884986 15.5194489,0.89318879 17.0194901,1.27722864 Z M13.4784141,18.003135 L10.7656387,18.003135 C10.5159347,18.003135 10.3135095,18.2115061 10.3135095,18.468545 C10.3135095,18.7255839 10.5159347,18.9339551 10.7656387,18.9339551 L13.4784141,18.9339551 C13.7281181,18.9339551 13.9305433,18.7255839 13.9305433,18.468545 C13.9305433,18.2115061 13.7281181,18.003135 13.4784141,18.003135 Z M13.2523494,16.8735848 L10.0874449,16.8735848 C9.71308192,16.8735848 9.40925108,16.8065657 9.40925108,17.2985041 C9.40925108,17.7904425 9.71308192,17.7234235 10.0874449,17.7234235 L13.2523494,17.7234235 C13.6267124,17.7234235 13.9305433,17.7904426 13.9305433,17.2985041 C13.9305433,16.8065657 13.6267124,16.8735848 13.2523494,16.8735848 Z M5.56615269,13.8144445 C6.19041287,13.8144445 6.69647573,14.3353725 6.69647573,14.9779696 C6.69647573,15.6205668 6.19041287,16.1414947 5.56615269,16.1414947 C4.94189251,16.1414947 4.43582965,15.6205668 4.43582965,14.9779696 C4.43582965,14.3353725 4.94189251,13.8144445 5.56615269,13.8144445 Z M7.6007342,11.7200993 C8.22499437,11.7200993 8.73105725,12.2410272 8.73105725,12.8836244 C8.73105725,13.1922105 8.61197,13.4881576 8.3999933,13.7063609 C8.1880166,13.9245642 7.9005145,14.0471496 7.60073418,14.0471496 C6.97647401,14.0471496 6.47041117,13.5262216 6.47041117,12.8836244 C6.47041117,12.2410273 6.97647403,11.7200993 7.6007342,11.7200993 Z M3.53157122,11.7200993 C4.15583139,11.7200993 4.66189427,12.2410272 4.66189427,12.8836244 C4.66189427,13.1922105 4.54280701,13.4881576 4.33083032,13.7063609 C4.11885362,13.9245642 3.83135152,14.0471496 3.5315712,14.0471496 C2.90731103,14.0471496 2.40124819,13.5262216 2.40124819,12.8836244 C2.40124819,12.2410273 2.90731105,11.7200993 3.53157122,11.7200993 Z M15.6938472,2.07726852 C13.7371468,2.07726852 11.9731157,3.29057916 11.2243188,5.1514356 C10.475522,7.01229204 10.8894222,9.15423045 12.2730183,10.5784683 C13.6566145,12.0027062 15.737431,12.4287642 17.5451865,11.6579722 C19.352942,10.8871802 20.5316299,9.0713325 20.5316299,7.05715601 C20.5316299,4.30684009 18.3656808,2.07726852 15.6938472,2.07726852 Z M5.56615271,9.62575412 C6.19041288,9.62575412 6.69647576,10.146682 6.69647576,10.7892792 C6.69647576,11.0978652 6.57738851,11.3938124 6.36541181,11.6120157 C6.15343511,11.830219 5.86593301,11.9528043 5.56615269,11.9528043 C4.94189252,11.9528043 4.43582968,11.4318764 4.43582968,10.7892792 C4.43582968,10.146682 4.94189254,9.62575412 5.56615271,9.62575412 Z M12.0392868,7.02736978 L12.6483048,7.1953828 C12.551277,7.73410365 12.6749886,8.29014528 12.9901145,8.73170139 L12.5443151,9.19431897 C12.0726108,8.5845918 11.8876634,7.79102923 12.0392868,7.02736978 Z M14.545439,3.5875241 L14.545439,4.23909818 C13.5952179,4.31491998 12.8400303,5.09150061 12.7654063,6.0695559 L12.134686,6.0695559 C12.2108376,4.7327597 13.2468036,3.66616323 14.545439,3.5875241 Z" id="形状结合" fill="#4E4E4E" fill-rule="nonzero"></path>
</g>
</g>
</g>
</g>
</svg>
\ No newline at end of file
......@@ -17,13 +17,14 @@
<span class="dib">任务结束</span>
</div>
<template v-if="uav.network === 2">
<div v-if="controlType === 0" class="control-bottom-item" @click="onModeManual">
<div v-if="controlType === 0" class="control-bottom-item" @click="onInfieldControl">
<img src="./assets/images/auto.svg" />
<span class="dib">自动</span>
</div>
<div v-else-if="controlType === 1" class="control-bottom-item" @click="onModeKeyboard">
<img src="./assets/images/manual.svg" />
<span class="dib">摇杆</span>
<div v-else-if="controlType === 1"
:class="manualControlStatus ? 'active control-bottom-item' : 'control-bottom-item'" @click="onModeKeyboard">
<img :src="require(`./assets/images/${manualControlStatus ? 'manual' : 'manual1'}.svg`)" />
<span class="dib">摇杆 </span>
</div>
<div v-else-if="controlType === 2" class="control-bottom-item" @click="onModeAuto">
<img src="../../assets/images/keyboard.png" alt />
......@@ -43,6 +44,20 @@
</template>
<!-- 键盘控制 -->
<KeyControl v-if="controlType === 2" @close="onModeAuto"></KeyControl>
<!-- 强制切换外场权限 -->
<el-dialog title :visible.sync="showInfieldControlDialog" width="30%" :append-to-body="true" custom-class="mmc"
style="margin-top: 20vh">
<div class="endrenwu">
<div class="tishiyu">温馨提示</div>
<div class="queding" v-if="!isAcceleratorMedian">
当前油门值为
<span style="color: red">{{ throttleValue.toFixed(2) || 0 }}</span>,请调到中位(470-530)
</div>
<div class="queding" v-if="isAcceleratorMedian">
摇杆已处于中位,即将切换内场权限
</div>
</div>
</el-dialog>
</div>
</template>
......@@ -50,9 +65,11 @@
import { mapState, mapActions } from "vuex";
import { flightTaskAPI, Control_API } from "../../../../../../api";
import KeyControl from "./components/keyControl";
import joystick from "../../../../../../mixins/joystick";
export default {
name: "ControlBottom",
mixins: [joystick],
components: {
KeyControl,
},
......@@ -66,13 +83,127 @@ export default {
},
data() {
return {
showInfieldControlDialog: false, //强制切换状态为内场权限 提示框
isAcceleratorMedian: false, //油门是否在中位
YGPermissionsSend: false, //摇杆权限更改中
// 摇杆手动控制状态
manualControlStatus: false,
controlType: 0, //控制类型, 0: 自动 1: 摇杆 2: 键盘
};
},
watch: {
// 状态改变时摇杆会切换为手动模式并且抢权限
"onInfieldControlFn": {
handler(val) {
if (val) {
this.onInfieldControl()
}
}
},
throttleValue(val) {
// val = -1 代表摇杆已经建立连接 ,rcState为0 代表当前权限在外场需要去展示摇杆油门值
if (val == -1 &&this.uavRealTimeData.rcState == 0) {
this.showInfieldControlDialog = true;
}
// 判断是否为外场权限
if (this.uavRealTimeData.rcState == 0) {
// 判断油门是否处于中位
if (val >= 470 && val <= 530) {
console.log(this.uavRealTimeData, val, 'val');
this.isAcceleratorMedian = true;
if (!this.YGPermissionsSend) {
this.YGPermissionsSend = true;
// 发送抢权限指令
this.$store.dispatch(
"MMCFlightControlCenter/uav/changeYGPermissions",
{
callback: () => { },
}
);
setTimeout(() => {
if (this.uavRealTimeData.rcState == 1) {
// 摇杆切换为手动模式
if (!this.manualControlStatus) {
this.$message.success("已切换内场权限,摇杆即将切换为手动模式!");
// 切换为是手动模式
this.onModeManual();
} else {
this.$message.success("已切换内场权限,请使用摇杆控制!");
}
this.showInfieldControlDialog = false;
} else {
// this.$message.error("摇杆权限切换失败");
console.log("摇杆权限切换失败");
}
this.YGPermissionsSend = false;
}, 2000);
}
} else {
this.isAcceleratorMedian = false;
}
}
},
"manualControlStatus": {
handler(val) {
if (val) {
this.$message.success("手动模式已开启");
}
this.$store.commit("MMCFlightControlCenter/joystick/setState", {
key: "manualControlStatus",
value: val,
});
},
},
immediate: true,
},
computed: {
...mapState("MMCFlightControlCenter/uav", ["uav", "airlineData"]),
...mapState("MMCFlightControlCenter/uav", ["uav", "airlineData", "uavRealTimeData"]),
...mapState("MMCFlightControlCenter/joystick", ["onInfieldControlFn", "throttleValue"]),
},
methods: {
network() {
let { uavRealTimeData } = this;
let name = null;
if (uavRealTimeData && uavRealTimeData.link) {
for (let i = 0; i < uavRealTimeData.link.length; i++) {
const k = uavRealTimeData.link[i];
if (k.priority == 2 && k.using) {
return "专网";
} else if (k.priority == 3 && k.using) {
return "公网";
} else if (k.priority == 1 && k.using) {
return "图传";
}
}
}
return name || "离线";
},
async onInfieldControl() {
// 判断是否已接管
if (!(await this.isTakeOver())) {
this.$message.warning("请先接管设备");
return;
}
let networkType = this.network()
if (networkType == '离线') {
return this.$message.info('无人机不在线!');
}
// 如果是内场权限 且摇杆为手动模式就提示用户使用
if (this.uavRealTimeData.rcState == 1 && this.manualControlStatus) {
this.$message.success("当前处于内场模式,请使用摇杆控制!");
} else {
// 否则如果摇杆是手动模式没内场权限,则展示油门弹窗,油门值为中位时发起抢权限指令
if (this.manualControlStatus) {
this.showInfieldControlDialog = true;
} else {
this.$message.success("摇杆即将切换为手动模式,请稍等!");
// 切换为手动模式
this.onModeManual();
}
}
},
/**
* 接管判断, 机库模块中不需要判断接管
*/
......@@ -160,11 +291,20 @@ export default {
this.$message.warning("请先接管设备");
return;
}
this.$store.dispatch("MMCFlightControlCenter/uav/modeManual", {
callback: (isOk) => {
if (isOk) { }
isOk && (this.controlType = 1);
},
});
// 打开软件
let a = document.createElement("a");
a.href = "JoystickTools://";
a.click();
setTimeout(() => {
this.initJoystick();
}, 5000);
},
/**
......@@ -181,6 +321,7 @@ export default {
isOk && (this.controlType = 0);
},
});
this.closeJoystick();
},
/**
* 键盘模式
......@@ -196,11 +337,11 @@ export default {
/**
* 键盘控制
*/
clickControl() {},
clickControl() { },
/**
* 停止键盘控制
*/
cancelControl() {},
cancelControl() { },
},
};
</script>
......@@ -235,6 +376,10 @@ export default {
transform: scale(1.1);
}
}
.active {
background-color: #0cc81f;
}
}
.key-control {
......@@ -249,6 +394,7 @@ export default {
background: rgba(32, 32, 30, 0.8);
border-radius: 10px;
padding: 8px;
.head {
width: 360px;
color: #fff;
......@@ -256,15 +402,19 @@ export default {
line-height: 32px;
display: flex;
}
.content {
display: flex;
align-items: center;
> div {
>div {
flex-direction: column;
display: flex;
align-items: center;
> div {
>div {
display: flex;
div {
background: #333;
width: 32px;
......@@ -278,23 +428,61 @@ export default {
align-items: center;
justify-content: center;
}
.active {
background: #ead91b;
}
}
}
.line {
width: 1px;
height: 60px;
border: 1px solid;
border-image: linear-gradient(
180deg,
border-image: linear-gradient(180deg,
rgba(255, 255, 255, 0),
rgba(255, 255, 255, 1),
rgba(255, 255, 255, 0)
)
1 1;
rgba(255, 255, 255, 0)) 1 1;
}
}
}
.el-dialog__header {
margin-left: 0;
padding: 0;
background: #3c3c3c;
}
.el-dialog__body {
padding: 0;
z-index: 2023 !important;
}
.el-dialog {
z-index: 2022 !important;
background: transparent !important;
}
.endrenwu {
width: 100%;
height: 177px;
border: 1px solid #70daf9;
background: rgba(9, 32, 87, 0.7) !important;
}
.tishiyu {
color: #92d9ff;
font-size: 18px;
margin: 30px 0 0 0;
text-align: center;
width: 100%;
}
.queding {
color: #92d9ff;
text-align: center;
width: 100%;
font-size: 14px;
margin: 30px 0 0 0;
}
</style>
\ No newline at end of file
......@@ -53,7 +53,7 @@
<el-input-number :min="-145" :max="145" v-model="item.param3"></el-input-number>(度)
</div>
</div>
<i class="el-icon-delete rm-as-item__del" v-hover @click="selectActions.splice()"></i>
<i class="el-icon-delete rm-as-item__del" v-hover @click="selectActions1.splice(i,1)"></i>
</div>
</div>
<div class="rm-rp-btns">
......
......@@ -377,10 +377,14 @@ export default {
speed: point.speed,
pointActionSaveReqVOS: point.waypointActions.map((action) => {
let actionValue = [];
actionValue.push(`param1:${action.param1 || ""}`);
actionValue.push(`param2:${action.param2 || ""}`);
actionValue.push(`param3:${action.param3 || ""}`);
actionValue.push(`param4:${action.param4 || ""}`);
action.param1 &&
actionValue.push(`param1:${action.param1 || ""}`);
action.param2 &&
actionValue.push(`param2:${action.param2 || ""}`);
action.param3 &&
actionValue.push(`param3:${action.param3 || ""}`);
action.param4 &&
actionValue.push(`param4:${action.param4 || ""}`);
return {
actionType: action.actionType,
actionValue: actionValue.join(";"),
......@@ -731,8 +735,8 @@ export default {
flex-shrink: 0;
display: flex;
justify-content: space-around;
margin-bottom: 16px;
margin-top: 16px;
margin-bottom: 5px;
margin-top: 5px;
}
.ae-form {
......
......@@ -7,19 +7,40 @@
</div>
</div>
<el-form class="task-main" label-width="70px">
<el-form-item label="任务库" v-if="useTask">
<el-select v-model="selectedTaskId" clearable>
<el-option
v-for="(item, i) in taskList"
:label="item.name"
:value="item.id"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="航线选择">
<el-select v-model="selectedAirwayId">
<el-option v-for="(item , i) in airwayList" :label="item.name" :value="item.id"></el-option>
<el-select
v-model="selectedAirwayId"
:disabled="airwaySelectDisabled"
clearable
>
<el-option
v-for="(item, i) in airwayList"
:label="item.name"
:value="item.id"
></el-option>
</el-select>
</el-form-item>
<div class="btn" @click="onStartTask" v-hover>一键任务</div>
<div class>
<span class="btn__add-line" @click="showAirwayEdit = true">
<span class="f8"></span> 创建航线
<span class="f8"></span> 创建航线
</span>
</div>
</el-form>
<AirwayEdit v-if="showAirwayEdit" @close="showAirwayEdit = false" @addDone="getAirwayList"></AirwayEdit>
<AirwayEdit
v-if="showAirwayEdit"
@close="showAirwayEdit = false"
@addDone="getAirwayList"
></AirwayEdit>
</div>
</template>
<script>
......@@ -38,15 +59,34 @@ export default {
inject: ["rootNode", "bus"],
data() {
return {
//航线列表
airwayList: [],
// 选择的航线
selectedAirwayId: "",
airwayList: [], //航线列表
selectedAirwayId: "", // 选择的航线
taskList: [], //任务列表
selectedTaskId: "", //选择的任务
airwaySelectDisabled: false, //选择任务后, 禁用航线选择
};
},
computed: {
...mapState("MMCFlightControlCenter", ["cesiumViewer", "useSTLAirway"]),
...mapState("MMCFlightControlCenter/uav", ["uav"]),
...mapState("MMCFlightControlCenter", [
"cesiumViewer",
"useSTLAirway",
"useTask",
]),
...mapState("MMCFlightControlCenter/uav", ["uav","uavRealTimeData"]),
// 选择的任务
selectedTask() {
let find = this.taskList.find((item) => {
return item.id == this.selectedTaskId;
});
if (find) {
return find;
} else {
return {
name: "",
id: -1,
};
}
},
// 选择的航线
selectedAirway() {
let find = this.airwayList.find((item) => {
......@@ -86,11 +126,29 @@ export default {
},
},
watch: {
"uavRealTimeData.isFlying": {
handler: function (newVal, oldVal) {
if (oldVal === false && newVal === true) {
this.getTaskInfoRecord();
}
},
deep: true,
immediate: true,
},
showAirwayEdit(newVal) {
if (newVal) {
this.listCollapse = true;
}
},
selectedTask() {
if (this.selectedTask.id !== -1) {
this.airwaySelectDisabled = true;
} else {
this.airwaySelectDisabled = false;
}
// 任务改变则修改航线选择为任务中的航线
this.selectedAirwayId = this.selectedTask?.airwayId;
},
selectedAirway() {
this.clearAirwayEntities();
if (this.selectedAirway.id !== -1) {
......@@ -104,29 +162,24 @@ export default {
} catch (e) {
console.log("绘制航线失败", e);
}
} else {
if (this.selectedTaskId && this.selectedAirwayId == "") {
this.$message.warning("未找到相应的航线");
}
this.selectedAirwayId = "";
this.airwaySelectDisabled = false;
}
},
},
async created() {
this.bus.$on("startTask", this.onStartTask);
this.bus.$on("refreshAirway", this.getAirwayList);
await this.getTaskList();
await this.getAirwayList();
console.log(this.uavRealTimeData,'this.uavRealTimeData');
// 获取正在飞行的航线
console.log("当前飞行状态", this.uavRealTimeData?.isFlying);
if (this.uav && this.uavRealTimeData?.isFlying) {
let res = await TaskInfo.getTaskInfoRecord({
deviceId: this.uav.deviceId,
});
if (res.code === 0) {
this.selectedAirwayId = res.data.reouteId;
// 在一次时机中再取航线数据存进store中
this.$nextTick(() =>
this.$store.commit("MMCFlightControlCenter/uav/setState", {
key: "airlineData",
value: this.selectedAirway,
})
);
}
if (this.uavRealTimeData.isFlying) {
this.getTaskInfoRecord();
}
},
beforeDestroy() {
......@@ -142,7 +195,43 @@ export default {
]),
...mapActions("MMCFlightControlCenter/uav", ["isTakeOver"]),
/**
* 更新任务列表
* 获取任务列表
*/
async getTaskInfoRecord() {
let res = await TaskInfo.getTaskInfoRecord({
deviceId: this.uav && this.uav.deviceId,
});
if (res.code === 0) {
this.selectedTaskId = res.data.taskInfoId;
setTimeout(() => {
this.selectedAirwayId = res.data.reouteId;
}, 1000);
}
},
getTaskList(id) {
return new Promise((resolve) => {
console.log("getTaskList", this.taskListAll);
this.rootNode.$emit("taskListGet", {
pageNo: 1,
pageSize: 100,
type: 0,
// taskStatus: 1, // 任务状态 0:待审批 1:待执行 2:执行中 3:执行完成 4:审批不通过
callback: (res) => {
this.taskList = res?.records.filter(
(item) => item.status != "已完成"
);
this.$nextTick(() => {
if (id) {
this.selectedTaskId = id;
}
resolve();
});
},
});
});
},
/**
* 获取航线列表
*/
getAirwayList(id) {
return new Promise((resolve) => {
......@@ -177,6 +266,10 @@ export default {
this.$message.warning("请选择航线");
return;
}
let data = this.taskList.filter((item) => item.id == this.selectedTaskId);
if (data && data[0].status == "执行中") {
return this.$message.warning("当前任务执行中");
}
try {
await this.$confirm("请确认是否进行一键任务操作?", "安全确认", {
cancelButtonText: "取消",
......@@ -189,6 +282,7 @@ export default {
value: this.selectedAirway,
});
this.$store.dispatch("MMCFlightControlCenter/uav/takeOff", {
taskInfoId: this.selectedTaskId,
callback: (status) => {
if (status) {
this.$message.success("一键任务指令发送成功");
......@@ -209,7 +303,7 @@ export default {
</script>
<style lang="scss" scoped>
.taskListBox {
height: 200px;
min-height: 200px;
width: 350px;
background: #222222;
border-radius: 12px;
......
......@@ -553,8 +553,8 @@ export default {
flex-shrink: 0;
display: flex;
justify-content: space-around;
margin-bottom: 16px;
margin-top: 16px;
margin-bottom: 5px;
margin-top: 5px;
}
.ae-form {
......
......@@ -4,28 +4,25 @@
<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="!useAirway && openTask"></TaskList>
<AirwayList class="task-list" v-if="useAirway && openTask"></AirwayList>
<AirwayList class="task-list" v-if="openTask"></AirwayList>
<VideoMapSwitch ref="videoMapSwitch"></VideoMapSwitch>
</div>
</template>
<script>
import { mapState } from "vuex";
import TaskList from "./components/taskList";
import AirwayList from "./components/airwayList";
import VideoMapSwitch from './components/videoMapSwitch';
export default {
name: "ControlLeft",
components: {
TaskList,
AirwayList,
VideoMapSwitch
},
data() {
return {
openTask: true, //打开任务
openTask: true, //打开任务列表
openAIList: false, //打开AI列表
openTraffic: false, //打开交通指引
openFace: false, //打开人脸识别
......@@ -34,7 +31,7 @@ export default {
};
},
computed: {
...mapState("MMCFlightControlCenter", ["useAirway"]),
...mapState("MMCFlightControlCenter", []),
...mapState("MMCFlightControlCenter/uav", ["uav"]),
// 收起列表按钮
listCollapse: {
......
......@@ -2,7 +2,10 @@
<div>
<div class="nset_control_box dialog1027" v-if="show">
<div class="dialog-header">
<img class="dialog-header__icon" src="../../assets/images/mount_head.png" />
<img
class="dialog-header__icon"
src="../../assets/images/mount_head.png"
/>
<div class="dialog-header__title">操作区域</div>
<div class="dialog-header__close" @click="$emit('exit')">关闭</div>
</div>
......@@ -32,11 +35,19 @@
<SymbolIcon icon="yunhangrizhi2" />
<span class="txt">运行日志</span>
</div>
<div class="item" @click="guideFlight" v-if="uav && uav.network === 2">
<div
class="item"
@click="guideFlight"
v-if="uav && uav.network === 2"
>
<SymbolIcon icon="tiaozhuandaozuobiao" />
<span class="txt">指点飞行</span>
</div>
<div class="item" @click="onInfieldControl" v-if="uav && uav.network === 2">
<div
class="item"
@click="onInfieldControl"
v-if="uav && uav.network === 2"
>
<img class="dib mt3" src="./assets/images/1.svg" alt />
<span class="txt">内场控制</span>
</div>
......@@ -52,7 +63,9 @@
>
<div class="endrenwu">
<div class="tishiyu">紧急迫降</div>
<div class="queding">无人机即将原地降落,请确认无人机下方是否安全!</div>
<div class="queding">
无人机即将原地降落,请确认无人机下方是否安全!
</div>
<div class="btn_kuang">
<div class="btn btn_lan" @click="safetyNotice = false">取消</div>
<div style="width: 20px"></div>
......@@ -60,23 +73,7 @@
</div>
</div>
</el-dialog>
<!-- 强制切换外场权限 -->
<el-dialog
title
:visible.sync="showInfieldControlDialog"
width="30%"
:append-to-body="true"
style="margin-top: 20vh"
>
<div class="endrenwu">
<div class="tishiyu">温馨提示</div>
<div class="queding" v-if="!isAcceleratorMedian">
当前油门值为
<span style="color:red">{{uavRealTimeData.rcChannelState.toFixed(2)||0}}</span>,请调到中位(470-530)
</div>
<div class="queding" v-if="isAcceleratorMedian">摇杆已处于中位,即将切换内场权限</div>
</div>
</el-dialog>
<el-dialog
title
:visible.sync="guideFlightShow"
......@@ -92,8 +89,11 @@
<div class="queding">位置获取成功,请确认是否进行指点模式飞行</div>
<div class="fleSpeed">
指点飞行速度:
<el-input oninput="value=value.replace(/[^0-9.]/g,'')" v-model="flySpeed"></el-input>
<span style="opacity: 0;">1</span>(米/秒)
<el-input
oninput="value=value.replace(/[^0-9.]/g,'')"
v-model="flySpeed"
></el-input>
<span style="opacity: 0">1</span>(米/秒)
</div>
<div class="red" v-if="maxSpeed">指点飞行最大速度为8米/秒</div>
<div class="btn_kuang">
......@@ -139,11 +139,11 @@ export default {
},
data() {
return {
isAcceleratorMedian: false, //油门是否在中位
YGPermissionsSend: false, //摇杆权限更改中
// isAcceleratorMedian: false, //油门是否在中位
// YGPermissionsSend: false, //摇杆权限更改中
safetyNotice: false, //安全降落弹框
chargerPower: true,
showInfieldControlDialog: false, //强制切换状态为内场权限 提示框
flySpeed: 6, //指点飞行设置
maxSpeed: false,
showLogger: false, //显示日志
......@@ -161,39 +161,9 @@ export default {
"uavRealTimeData",
]),
...mapState("MMCFlightControlCenter", ["userInfo", "cesiumViewer"]),
},
watch: {
"uavRealTimeData.rcChannelState"(val) {
// 判断是否为外场权限
if (this.uavRealTimeData.rcState == 0) {
// 判断油门是否处于中位
if (val >= 470 && val <= 530) {
this.isAcceleratorMedian = true;
if (!this.YGPermissionsSend) {
this.YGPermissionsSend = true;
// 发送抢权限指令
this.$store.dispatch(
"MMCFlightControlCenter/uav/changeYGPermissions",
{
callback: () => {},
}
);
setTimeout(() => {
if (this.uavRealTimeData.rcState == 1) {
this.$message.success("已切换内场权限,请使用摇杆控制!");
this.showInfieldControlDialog = false;
} else {
// this.$message.error("摇杆权限切换失败");
console.log("摇杆权限切换失败");
}
this.YGPermissionsSend = false;
}, 2000);
}
} else {
this.isAcceleratorMedian = false;
}
}
},
...mapState("MMCFlightControlCenter/joystick", [
"manualControlStatus",
]),
},
beforeDestroy() {
if (Point) {
......@@ -208,9 +178,16 @@ export default {
"routeControl",
"isTakeOver",
]),
isTakeOverHangar() {
return this.$store.dispatch("MMCFlightControlCenter/hangar/isTakeOver");
},
async isTake() {
// 判断是否已接管
if (!this.isHangar && !(await this.isTakeOver())) {
let isTakeOver = this.isTakeOver;
if (this.isHangar) {
isTakeOver = this.isTakeOverHangar;
}
if (!(await isTakeOver())) {
this.$message.warning("请先接管设备");
return false;
}
......@@ -219,7 +196,16 @@ export default {
/**
* 显示隐藏航线
*/
onSwitchAirline() {
async onSwitchAirline() {
// 判断是否已接管
let isTakeOver = this.isTakeOver;
if (this.isHangar) {
isTakeOver = this.isTakeOverHangar;
}
if (!(await isTakeOver())) {
this.$message.warning("请先接管设备");
return false;
}
if (this.airlineEntity) {
this.airlineEntity.show = !this.airlineEntity.show;
}
......@@ -263,22 +249,17 @@ export default {
this.safetyNotice = false;
this.land();
},
changeOnInfieldControlFn() {
this.$store.commit("MMCFlightControlCenter/joystick/setState", {
key: "onInfieldControlFn",
value: new Date().getTime(),
});
},
/**
* 内场控制
*/
async onInfieldControl() {
// 判断是否已接管
if (!(await this.isTake())) {
return;
}
if (this.online === 0)
return this.$message.warning("处于离线状态,不可操作!");
// 自动切换摇杆权限
if (this.uavRealTimeData.rcState == 1) {
this.$message.success("当前处于内场模式,请使用摇杆控制!");
} else {
this.showInfieldControlDialog = true;
}
this.changeOnInfieldControlFn()
},
/**
* cesium添加目标点
......@@ -309,15 +290,15 @@ export default {
* 指点飞行
*/
async guideFlight() {
// 判断是否已接管
if (!(await this.isTake())) {
return;
}
if (this.uav.online === 0)
return this.$message.warning("处于离线状态,不可操作!");
if (!this.guideFlightDone) {
return this.$message.warning("指点飞行操作中!");
}
// // 判断是否已接管
// if (!(await this.isTake())) {
// return;
// }
// if (this.uav.online === 0)
// return this.$message.warning("处于离线状态,不可操作!");
// if (!this.guideFlightDone) {
// return this.$message.warning("指点飞行操作中!");
// }
let viewer = this.cesiumViewer;
// 指点飞行 wgs84
......
......@@ -2,10 +2,15 @@
<div class="mountBox">
<div class="main" v-if="show">
<div v-if="mountList.length > 0" class="list">
<div class="mount-item pr mt6" :class="{
active:
(selectMount && selectMount.gimbalName) === item.gimbalName,
}" v-for="(item, index) in mountList" :key="index">
<div
class="mount-item pr mt6"
:class="{
active:
(selectMount && selectMount.gimbalName) === item.gimbalName,
}"
v-for="(item, index) in mountList"
:key="index"
>
<div class="icon-box" @click="onSelectMount(item)">
<img class :src="item.icon" />
</div>
......@@ -13,9 +18,17 @@
</div>
</div>
<template v-if="selectMount">
<component :is="selectMount.gimbalName" v-if="selectMount" class="mount-panel" :keyFlag="nxNormal"
:payload_data="selectMountPayload" @directive="mountDirective" @take_photo="mountTakePhoto"
@record="mountRecord" @close="mountClose" />
<component
:is="selectMount.gimbalName"
v-if="selectMount"
class="mount-panel"
:keyFlag="nxNormal"
:payload_data="selectMountPayload"
@directive="mountDirective"
@take_photo="mountTakePhoto"
@record="mountRecord"
@close="mountClose"
/>
</template>
</div>
</template>
......@@ -35,11 +48,6 @@ export default {
...mountComponents,
},
props: {
// 是否机库页面使用
isHangar: {
type: Boolean,
default: false,
},
show: {
type: Boolean,
default: false,
......@@ -70,30 +78,11 @@ export default {
return this.uavRealTimeData?.healthData?.NX?.warningLevel === "NORMAL";
},
},
created() { },
mounted() { },
beforeDestroy() { },
created() {},
mounted() {},
beforeDestroy() {},
methods: {
/**
* 接管判断, 机库模块中不需要判断接管
*/
async isTakeOver() {
if (this.isHangar) {
return await this.$store.dispatch(
"MMCFlightControlCenter/hangar/isTakeOver"
);
} else {
return await this.$store.dispatch(
"MMCFlightControlCenter/uav/isTakeOver"
);
}
},
async onSelectMount(item) {
// 判断是否已接管
if (!(await this.isTakeOver())) {
this.$message.warning("请先接管设备");
return;
}
onSelectMount(item) {
this.$store.commit("MMCFlightControlCenter/uav/setState", {
key: "selectMount",
value: item,
......
......@@ -17,9 +17,9 @@
>
<el-option
v-for="item in aiTypeList"
:key="item.id"
:label="item.value"
:value="item.id"
:key="item.typeId"
:label="item.title"
:value="item.typeId"
></el-option>
</el-select>
<el-checkbox
......@@ -262,39 +262,118 @@ export default {
isIndeterminate: false,
selectAll: false, //全选
viewLibTab: 0, // 视图库tab索引, 0: 视图, 1: 机载
aiType: 0, // 图片类型
aiType: 1, // 图片类型
aiTypeList: [
// 普通图片或ai图片选项
{
id: 0,
value: "全部",
typeId: 1,
title: "人车识别",
},
{
id: 1,
value: "人脸识别",
typeId: 2,
title: "烟火识别",
},
{
id: 8,
// id: 2,
value: "车牌识别",
typeId: 4,
title: "行人识别",
},
{
id: 3,
value: "人流识别",
typeId: 5,
title: "机动车识别",
},
{
id: 4,
value: "烟雾识别",
typeId: 6,
title: "两轮车识别",
},
{
id: 5,
value: "漏油识别",
typeId: 7,
title: "三轮车识别",
},
{
id: 6,
value: "裸土识别",
typeId: 8,
title: "挖掘机识别",
},
], //视图库类型
{
typeId: 9,
title: "车牌识别",
},
{
typeId: 10,
title: "人脸识别",
},
{
typeId: 11,
title: "口罩识别",
},
{
typeId: 14,
title: "烟雾识别",
},
{
typeId: 15,
title: "火焰识别",
},
{
typeId: 17,
title: "占道经营",
},
{
typeId: 22,
title: "船舶识别",
},
{
typeId: 23,
title: "漏油识别",
},
{
typeId: 24,
title: "头盔识别",
},
{
typeId: 25,
title: "管线识别",
},
{
typeId: 26,
title: "路面裂缝",
},
{
typeId: 27,
title: "顶棚违建",
},
{
typeId: 28,
title: "门牌广告",
},
{
typeId: 29,
title: "井盖识别",
},
{
typeId: 30,
title: "搅拌车识别",
},
{
typeId: 31,
title: "油罐车识别",
},
{
typeId: 32,
title: "渣土车识别",
},
{
typeId: 33,
title: "排气口识别",
},
{
typeId: 34,
title: "人流识别",
},
{
title: "裸土识别",
typeId: 35,
},
],
//视图库类型
fileType: "图片", //视图文件类型 0:图片;1:视频
photoList: [], //资源列表对应的对象
photoListDate: null, //某日期的所有资源
......
......@@ -80,7 +80,7 @@ export default {
},
computed: {
...mapState("MMCFlightControlCenter", ["showAirwayEdit"]),
...mapState("MMCFlightControlCenter/uav", ["uav", "airlineData",'uavRealTimeData']),
...mapState("MMCFlightControlCenter/uav", ["uav", "airlineData", 'uavRealTimeData']),
},
watch: {
// 打开航线编辑时关闭所有窗口
......@@ -146,15 +146,15 @@ export default {
* 切换展示
*/
async onSwitchShow(key) {
let networkType = this.network()
if (key == 'showHealth' && networkType == '离线') {
return this.$message.info('无人机不在线!');
}
// 判断是否已接管
if (!(await this.isTakeOver())) {
if (!(await this.isTakeOver() )&& key != 'showViewLib') {
this.$message.warning("请先接管设备");
return;
}
let networkType = this.network()
if (key == 'showHealth' && networkType == '离线' && key != 'showViewLib') {
return this.$message.info('无人机不在线!');
}
this.$emit("switchCallback");
this.hideAll(key);
this[key] = !this[key];
......
......@@ -16,10 +16,11 @@
</div>
</template>
</el-table-column>
<el-table-column label="当前控制单位" align="center" prop="takeUserName"></el-table-column>
<el-table-column label="当前控制单位" align="center" prop="userDeptName"></el-table-column>
<el-table-column label="当前控制用户" align="center" prop="takeUserName"></el-table-column>
<el-table-column label="操作" align="center" prop="name">
<template slot-scope="scope">
<el-buttonclas @click="onExit(scope.row)" type="text" class="color-aqua" size="small" v-if="scope.row.takeStats">退出接管</el-buttonclas>
<el-buttonclas @click="onExit(scope.row)" type="text" class="color-aqua cp" size="small" v-if="scope.row.takeStats">退出接管</el-buttonclas>
</template>
</el-table-column>
</el-table>
......@@ -59,11 +60,13 @@ export default {
},
methods: {
async init() {
console.log(this.uav,'this.uav');
let res = await Control_API.getTakeRecord({
deviceType: this.hangar ? 2 : 1,
pageNo: this.page.pageNo,
pageSize: this.page.pageSize,
deviceId : this.uav? this.uav?.deviceId:this.hangar?.deviceId
deviceId : this.hangar? this.hangar?.deviceId:this.uav?.deviceId
});
this.list.splice(0, this.list.length, ...res.data?.list??[])
// this.list = res.data;
......@@ -78,6 +81,7 @@ export default {
await Control_API.setUavControlOff({
deviceId: item.deviceId,
});
this.init();
this.$message({
type: "success",
message: "操作完成",
......@@ -91,7 +95,7 @@ export default {
<style lang="scss" scoped>
.dialog1027::v-deep {
width: 700px;
width: 750px;
position: absolute !important;
left: 50%;
top: calc(100% + 25px);
......
......@@ -110,10 +110,11 @@
<script>
import dayjs from "dayjs";
import { mapState } from "vuex";
import { mapState, mapActions } from "vuex";
import TakeOverRecords from "./components/takeOverRecords";
import { System } from "../../../../../../api";
export default {
name: "ControlTop",
components: {
......@@ -339,6 +340,7 @@ export default {
clearInterval(this.timeWeather);
},
methods: {
...mapActions("MMCFlightControlCenter/hangar", ["isTakeOver"]),
updateTime() {
this.date = dayjs().format("YYYY/MM/DD");
this.time = dayjs().format("HH:mm:ss");
......@@ -391,17 +393,10 @@ export default {
*/
async onModeChange(data, flag) {
// 查看是否有权限接管无人机
let res = await this.$store.dispatch(
"MMCFlightControlCenter/uav/isTakeOver"
);
// 判断当前状态 true为一接管
if (res == false) {
return;
}
if (this.flightMode == "离线状态") {
return this.$message.warning("处于离线状态,不可切换模式!");
}
}
console.log( this.modeList,data,'data')
let mode = this.modeList.find((item) => item.data === data);
if (
mode.label == "定高模式" ||
......
......@@ -18,15 +18,16 @@ import Moment from "moment";
import ControlBottom from "./components/controlBottom";
import ControlRight from "./components/controlRight";
import ControlLeft from "./components/controlLeft";
import ControlTop from './components/controlTop';
import ControlTop from "./components/controlTop";
export default {
name: "ControlPanel",
mixins: ["joystick"],
components: {
ControlBottom,
ControlRight,
ControlLeft,
ControlTop
ControlTop,
},
data() {
return {
......
......@@ -5,21 +5,26 @@
<img src="./assets/images/car1.png" @click="aiVisible = !aiVisible" />
<div class="ai-list" v-show="aiVisible">
<el-tooltip
v-for="(item,index) in aiIdentifyList"
v-for="(item, index) in aiIdentifyList"
:key="index"
:content="item.title"
placement="bottom"
>
<div class="ai-item" @click="onAiIdentify(item.type)">
<img class="img_src" :src="item.img" />
<img class="img_src" crossorigin="anonymous" :src="item.img" />
</div>
</el-tooltip>
</div>
</div>
</el-tooltip>
<el-dialog :title="`${aiTitle}结果`" :visible.sync="aiResultShow" append-to-body width="700px">
<div style="text-align: center;">
<img style="width: 100%;" :src="aiResultImg" />
<el-dialog
:title="`${aiTitle}结果`"
:visible.sync="aiResultShow"
append-to-body
width="700px"
>
<div style="text-align: center">
<img style="width: 100%" crossorigin="anonymous" :src="aiResultImg" />
</div>
</el-dialog>
</div>
......@@ -46,44 +51,234 @@ export default {
data() {
return {
aiVisible: false,
aiIdentifyList: [
aiIdentifyList: [],
deAiIdentifyList: [
{
title: "人脸识别",
type: "face",
typeId: 1,
img: require("./assets/images/人脸识别.svg"),
type: "kbtAi",
img: "https://mmc-crm.oss-cn-shenzhen.aliyuncs.com/prod/tmj-icon/ai/person_car.png",
title: "人车识别",
},
{
typeId: 2,
type: "kbtAi",
img: "https://mmc-crm.oss-cn-shenzhen.aliyuncs.com/prod/tmj-icon/ai/fire.png",
title: "烟火识别",
},
{
typeId: 4,
type: "kbtAi",
img: "https://mmc-crm.oss-cn-shenzhen.aliyuncs.com/prod/tmj-icon/ai/person.png",
title: "行人识别",
},
{
typeId: 5,
type: "kbtAi",
img: "https://mmc-crm.oss-cn-shenzhen.aliyuncs.com/prod/tmj-icon/ai/car.png",
title: "机动车识别",
},
{
typeId: 6,
type: "kbtAi",
img: "https://mmc-crm.oss-cn-shenzhen.aliyuncs.com/prod/tmj-icon/ai/motor_bicycle.png",
title: "两轮车识别",
},
{
typeId: 7,
type: "kbtAi",
img: "https://mmc-crm.oss-cn-shenzhen.aliyuncs.com/prod/tmj-icon/ai/tricycle.png",
title: "三轮车识别",
},
{
typeId: 8,
type: "kbtAi",
img: "https://mmc-crm.oss-cn-shenzhen.aliyuncs.com/prod/tmj-icon/ai/excavator.png",
title: "挖掘机识别",
},
{
typeId: 9,
type: "kbtAi",
img: "https://mmc-crm.oss-cn-shenzhen.aliyuncs.com/prod/tmj-icon/ai/plate.png",
title: "车牌识别",
type: "plate",
typeId: 8,
img: require("./assets/images/车牌识别.svg"),
},
{
title: "人流识别",
type: "crowd",
typeId: 3,
img: require("./assets/images/人流识别.svg"),
typeId: 10,
type: "face",
img: "https://mmc-crm.oss-cn-shenzhen.aliyuncs.com/prod/tmj-icon/ai/face.png",
title: "人脸识别",
},
{
title: "烟雾识别",
typeId: 11,
type: "kbtAi",
img: "https://mmc-crm.oss-cn-shenzhen.aliyuncs.com/prod/tmj-icon/ai/mask.png",
title: "口罩识别",
},
{
typeId: 14,
type: "smoke",
typeId: 7,
img: require("./assets/images/烟雾识别.svg"),
img: "https://mmc-crm.oss-cn-shenzhen.aliyuncs.com/prod/tmj-icon/ai/smoke.png",
title: "烟雾识别",
},
{
title: "漏油识别",
typeId: 15,
type: "kbtAi",
img: "https://mmc-crm.oss-cn-shenzhen.aliyuncs.com/prod/tmj-icon/ai/fire.png",
title: "火焰识别",
},
{
typeId: 17,
type: "kbtAi",
img: "https://mmc-crm.oss-cn-shenzhen.aliyuncs.com/prod/tmj-icon/ai/zhandao.png",
title: "占道经营",
},
{
type: "kbtAi",
typeId: 22,
img: "https://mmc-crm.oss-cn-shenzhen.aliyuncs.com/prod/tmj-icon/ai/boat.png",
title: "船舶识别",
},
{
typeId: 23,
type: "oilLeak",
typeId: 5,
img: require("./assets/images/漏油识别.svg"),
img: "https://mmc-crm.oss-cn-shenzhen.aliyuncs.com/prod/tmj-icon/ai/oilspill.png",
title: "漏油识别",
},
{
typeId: 24,
type: "kbtAi",
img: "https://mmc-crm.oss-cn-shenzhen.aliyuncs.com/prod/tmj-icon/ai/helmet.png",
title: "头盔识别",
},
{
typeId: 25,
type: "kbtAi",
img: "https://mmc-crm.oss-cn-shenzhen.aliyuncs.com/prod/tmj-icon/ai/guanxian.png",
title: "管线识别",
},
{
typeId: 26,
type: "kbtAi",
img: "https://mmc-crm.oss-cn-shenzhen.aliyuncs.com/prod/tmj-icon/ai/lumianliefeng.png",
title: "路面裂缝",
},
{
typeId: 27,
type: "kbtAi",
img: "https://mmc-crm.oss-cn-shenzhen.aliyuncs.com/prod/tmj-icon/ai/dingpeng.png",
title: "顶棚违建",
},
{
typeId: 28,
type: "kbtAi",
img: "https://mmc-crm.oss-cn-shenzhen.aliyuncs.com/prod/tmj-icon/ai/guanggaopai.png",
title: "门牌广告",
},
{
typeId: 29,
type: "kbtAi",
img: "https://mmc-crm.oss-cn-shenzhen.aliyuncs.com/prod/tmj-icon/ai/jinggai.png",
title: "井盖识别",
},
{
typeId: 30,
type: "kbtAi",
img: "https://mmc-crm.oss-cn-shenzhen.aliyuncs.com/prod/tmj-icon/ai/jiaobanche.png",
title: "搅拌车识别",
},
{
typeId: 31,
type: "kbtAi",
img: "https://mmc-crm.oss-cn-shenzhen.aliyuncs.com/prod/tmj-icon/ai/youguanche.png",
title: "油罐车识别",
},
{
typeId: 32,
type: "kbtAi",
img: "https://mmc-crm.oss-cn-shenzhen.aliyuncs.com/prod/tmj-icon/ai/zhatuche.png",
title: "渣土车识别",
},
{
typeId: 33,
type: "kbtAi",
img: "https://mmc-crm.oss-cn-shenzhen.aliyuncs.com/prod/tmj-icon/ai/paiwukou.png",
title: "排气口识别",
type: "kbtAi",
},
{
typeId: 34,
img: require("./assets/images/人流识别.svg"),
title: "人流识别",
type: "kbtAi",
},
{
title: "裸土识别",
type: "bareSoil",
typeId: 6,
typeId: 35,
img: require("./assets/images/裸土识别.svg"),
},
],
// aiIdentifyList: [
// {
// title: "人脸识别",
// type: "face",
// typeId: 1,
// img: require("./assets/images/人脸识别.svg"),
// },
// {
// title: "车牌识别",
// type: "plate",
// typeId: 8,
// img: require("./assets/images/车牌识别.svg"),
// },
// {
// title: "人流识别",
// type: "crowd",
// typeId: 3,
// img: require("./assets/images/人流识别.svg"),
// },
// {
// title: "烟雾识别",
// type: "smoke",
// typeId: 7,
// img: require("./assets/images/烟雾识别.svg"),
// },
// {
// title: "漏油识别",
// type: "oilLeak",
// typeId: 5,
// img: require("./assets/images/漏油识别.svg"),
// },
// {
// title: "裸土识别",
// type: "bareSoil",
// typeId: 6,
// img: require("./assets/images/裸土识别.svg"),
// },
// ],
aiResultShow: false, //ai识别结果展示
aiTitle: "",
aiResultImg: "", //ai结果图
......@@ -91,9 +286,43 @@ export default {
},
computed: {
...mapState("MMCFlightControlCenter", ["cesiumViewer", "baseUrl"]),
...mapState("MMCFlightControlCenter/uav", ["uav"]),
...mapState("MMCFlightControlCenter/uav", ["uav", "userInfo"]),
},
mounted() {
this.getAiconfig();
},
methods: {
async getAiconfig() {
let formData = new FormData();
console.log(this.$store.state.MMCFlightControlCenter, "userInfo");
let { TenantId, projectId } = this.$store.state.MMCFlightControlCenter;
// formData.append("projectId", projectId);
// formData.append("tenantId", TenantId);
let res = await AI_API["getAiconfig"]({
tenantId: TenantId,
projectId: projectId,
});
if (res.data.configInfo) {
const configInfo = Object.entries(res.data.configInfo).map(
([key, value]) => ({
key,
...value,
})
);
let configInfoData = configInfo.filter((item) => item.status == 0);
// 使用 Set 存储数据1中的所有 title,提高查找效率
const titleSet = new Set(
configInfoData.map((item) => item.detectorType)
);
console.log(titleSet, "titleSet");
// 遍历数据2,检查每个 name 是否在 titleSet 中存在
const matchedData = this.deAiIdentifyList.filter((dataItem) =>
titleSet.has(dataItem.typeId)
);
this.aiIdentifyList = matchedData;
}
},
/**
* ai识别事件
*/
......@@ -200,7 +429,28 @@ export default {
}
}
break;
case "kbtAi":
{
let formData = new FormData();
formData.append("image", blob, `下载.jpeg`);
formData.append("iscount", 1);
let res = await AI_API[type](formData);
results =
res?.data?.data?.data?.map((item) => {
return {
x: item.bbox[0],
y: item.bbox[1],
width: item.bbox[2] - item.bbox[0],
height: item.bbox[3] - item.bbox[1],
label: item.label_cn,
prob: item.bbox.conf,
};
}) || [];
if (results.length > 0) {
isSuccess = true;
}
}
break;
// 共达地通用数据结构
default:
{
......@@ -371,11 +621,13 @@ export default {
position: absolute;
left: -124px;
top: 0;
width: 111px;
width: 123px;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
overflow-y: auto;
max-height: 142px;
gap: 4px;
.ai-item {
cursor: pointer;
width: 35px;
......
......@@ -2,20 +2,20 @@
<!-- 清流融合 -->
<div id="uavPlayerWrap" class="player" :class="big" v-interact>
<div ref="video" class="video-wrap" @dblclick="screen">
<div class="cpt_video" @click="lensControl" v-if="showPlayer">
<div class="cpt_video" @click.stop="lensControl" v-if="showPlayer">
<Obstacle v-if="!isStatus"></Obstacle>
<div class="video">
<div class="name" v-clipboard:copy="vUrl.vUrl">{{ uav.name }}</div>
<!-- <div class="type" v-if="networkType">{{ networkType }}</div> -->
<!-- <div class="types">{{ streamName }}</div> -->
<div v-show="!isStatus" class="close" @click="close()">关闭</div>
<div v-show="!isStatus" class="close" @click.stop="close()">关闭</div>
</div>
<!-- <videoModelChange
:data="data"
v-if="streamSelect == 'QINGLIU' && !isStatus"
class="cp pa cf modelStyle"
@click="VideoModelChange"
@click.stop="VideoModelChange"
:uavRealTimeData="uavRealTimeData"
:NXdata="NXdata"
></videoModelChange>-->
......@@ -125,7 +125,7 @@
</div>
<div style="display: flex">
<div class="icon-box"></div>
<div class="cf ml20 mr10 c70d cp" @click="showInfo = false">关闭</div>
<div class="cf ml20 mr10 c70d cp" @click.stop="showInfo = false">关闭</div>
</div>
</div>
<div class="content">
......@@ -239,11 +239,11 @@
</div>
</div>
<div class="iconBG" v-if="isStatus">
<div class="infop" @click="getInfo" alt />
<div class="infop" @click.stop="getInfo" alt />
<div
:class="type == 4 ? 'right17' : 'right23'"
class="reset iconfont icon-gengxin"
@click="reset"
@click.stop="reset"
/>
</div>
<div class="bottom-menu">
......@@ -257,13 +257,13 @@
<img
class="menu-item"
src="./assets/images/info.png"
@click="getInfo"
@click.stop="getInfo"
style="transform: scale(1.4)"
alt
/>
</el-tooltip>
<el-tooltip content="是否启动瞄准镜" placement="bottom" v-if="!isStatus">
<img class="menu-item" src="./assets/images/center.png" @click="showCenterFn" alt />
<img class="menu-item" src="./assets/images/center.png" @click.stop="showCenterFn" alt />
</el-tooltip>
<el-tooltip
v-if="!isStatus"
......@@ -301,44 +301,44 @@
></el-option>
</el-select>
</div>
<div class="pointer iconfont icon-gengxin menu-item" @click="reset"></div>
<div class="pointer iconfont icon-gengxin menu-item" @click.stop="reset"></div>
<!-- FPV切换 -->
<el-tooltip content="模式切换" placement="bottom">
<div
v-if="streamSelect.toUpperCase() !== 'QINGLIU'"
class="iconfont icon-moshiqiehuan modelStyle menu-item"
@click="change"
@click.stop="change"
></div>
</el-tooltip>
<div class="pointer iconfont icon-quanping menu-item" @click="screen" v-if="!isStatus"></div>
<div class="pointer iconfont icon-quanping menu-item" @click.stop="screen" v-if="!isStatus"></div>
</div>
</div>
<div class="right-menu">
<template v-if="uav.network === 2">
<el-tooltip content="拍照" placement="bottom">
<div class="menu-item plate" @click="photojz">
<div class="menu-item plate" @click.stop="photojz">
<img src="./assets/images/ai.png" />
</div>
</el-tooltip>
<el-tooltip v-if="!screenRecordingStatus" content="开始录像" placement="bottom">
<div class="record menu-item" @click="getRecord">
<div class="record menu-item" @click.stop="getRecord">
<img src="./assets/images/record.png" />
</div>
</el-tooltip>
<el-tooltip v-else content="停止录像" placement="bottom">
<div class="record menu-item" @click="getRecord">
<div class="record menu-item" @click.stop="getRecord">
<img src="./assets/images/stop.png" />
</div>
</el-tooltip>
</template>
<el-tooltip content="截图" placement="bottom">
<div class="photojz menu-item" @click="photo">
<div class="photojz menu-item" @click.stop="photo">
<img src="./assets/images/photojz.svg" />
</div>
</el-tooltip>
<AiList ref="aiList" @screenShot="onAiScreenShot"></AiList>
<div class="menu-item" @click="startLinePoint" content="航点动作">
<div class="menu-item" @click.stop="startLinePoint" content="航点动作">
<img src="./assets/images/point_small.svg" />
</div>
</div>
......@@ -364,7 +364,7 @@ import { to_moveMount } from "../../../../utils/to_moveMount.js";
import Obstacle from "./components/obstacle";
import PointList from "./components/pointList";
import videoModelChange from "./components/videoModelChange";
import { mapState } from "vuex";
import { mapState, mapActions } from "vuex";
import AiList from "./components/aiList";
export default {
......@@ -655,6 +655,22 @@ export default {
clearInterval(this.aiTimeHandle);
},
methods: {
...mapActions("MMCFlightControlCenter/uav", ["isTakeOver"]),
isTakeOverHangar() {
return this.$store.dispatch("MMCFlightControlCenter/hangar/isTakeOver");
},
async isTake(show=true) {
// 判断是否已接管
let isTakeOver = this.isTakeOver;
if (this.isHangar) {
isTakeOver = this.isTakeOverHangar;
}
if (!(await isTakeOver())) {
show && this.$message.warning("请先接管设备");
return false;
}
return true;
},
startLinePoint() {
let gps = {};
if (this.uavRealTimeData) {
......@@ -755,6 +771,9 @@ export default {
* 录像
*/
async getRecord() {
if (!(await this.isTake())) {
return;
}
if (this.healthData.NX.code !== "0x2110000") {
return this.$message.error("录像失败,NX通信异常!");
}
......@@ -784,6 +803,9 @@ export default {
* 拍照
*/
async photojz() {
if (!(await this.isTake())) {
return;
}
if (this.healthData.NX.code !== "0x2110000") {
return this.$message.error("拍照失败,NX通信异常!");
}
......@@ -799,6 +821,9 @@ export default {
});
},
async photo() {
if (!(await this.isTake())) {
return;
}
let blob = this.$refs.player.screenShot();
if (blob) {
console.log(blob, window.URL.createObjectURL(blob));
......@@ -854,6 +879,9 @@ export default {
* 挂载镜头控制
*/
async lensControl(el) {
if (!(await this.isTake(false))) {
return;
}
// let mountData =this.$store.state.device.move_data
let { mountData } = this;
// if mountStatus =1 代表启用 屏幕指点功能
......
......@@ -8,43 +8,27 @@
<img class="level-icon" src="./assets/images/uav_item2.svg" v-if="level === 2" />
<img class="level-icon" src="./assets/images/uav_item3.svg" v-if="level === 3" />
<div class="org-name" :title="data.name">{{ data.name }}</div>
<i
class="refresh-icon el-icon-refresh-right"
v-if="level === 1"
@click.stop="$emit('refresh')"
/>
<i class="refresh-icon el-icon-refresh-right" v-if="level === 1" @click.stop="$emit('refresh')" />
</div>
<div class="online-info">
(共 {{data.onLineCount + data.offLineCount}}
<span
class="ml10"
:class="{ online: data.onLineCount }"
>{{ data.onLineCount }} 在线</span>
(共 {{ data.onLineCount + data.offLineCount }}
<span class="ml10" :class="{ online: data.onLineCount }">{{ data.onLineCount }} 在线</span>
/
{{ data.offLineCount }} 离线)
</div>
</div>
<div class="uav-item-child-box" :class="{ collapse: data.collapse }">
<Item
v-for="child in data.child"
:key="child.deptId"
:data="child"
:level="level+1"
@refresh="$emit('refresh')"
/>
<div
class="device-item-box"
:class="{ online: device.isOnline }"
v-for="device in data.deviceDOList"
:key="`device_${device.deviceId}`"
>
<Item v-for="child in data.child" :key="child.deptId" :data="child" :level="level + 1"
@refresh="$emit('refresh')" />
<div class="device-item-box" :class="{ online: device.isOnline }" v-for="device in data.deviceDOList"
:key="`device_${device.deviceId}`">
<div class="device-name">
<!-- <span
style="margin-right:10px"
:class="device.status==1&&device.currentOperator==1? 'blue' : device.status==1&&device.currentOperator!=1 ?'yellow':'' "
:title="device.name"
>{{device.name}}</span>-->
<span style="margin-right:10px" :class="'blue'" :title="device.name">{{device.name}}</span>
<span class="device-name-text" style="margin-right:10px" :class="'blue'" :title="device.name">{{ device.name }}</span>
<span style="color:#31DB24 " class="dib" v-if="device.isOnline">(在线)</span>
<span v-else class="dib">(离线)</span>
<div class="symbol-icon-box">
......@@ -53,13 +37,13 @@
<img src="./assets/images/I.svg" />
</div>
</template>
<template v-if="device.modelName && device.modelName.includes('入云龙2')">
<template v-if="device.modelName && device.modelName.includes('入云龙2')">
<div class="uav_version status-icon cp">
<img src="./assets/images/I.svg" />
<img src="./assets/images/I.svg" />
</div>
</template>
<template v-if="device.modelName && device.modelName.includes('插翅虎')">
<template v-if="device.modelName && device.modelName.includes('插翅虎')">
<div class="uav_version status-icon cp">
<img src="./assets/images/cq.svg" />
</div>
......@@ -67,35 +51,36 @@
<template>
<div class="uav_version status-icon cp">
<!-- <img src="./assets/images/I.svg" />
<img src="./assets/images/I.svg" /> -->
<img src="./assets/images/I.svg" />-->
{{ device.modelName }}
</div>
</template>
</div>
</div>
<div class="device-fns">
<div
class="iconfont icon-luxiang_xianxing"
:class="{ active: uav && device.deviceId === uav.deviceId && uav.showPlayer }"
title="视频"
@click="onShowPlayer(device)"
v-hover
></div>
<div
class="iconfont icon-kongzhi_xianxing"
:class="{ active: uav && device.deviceId === uav.deviceId && uav.showPanel }"
title="控制面板"
@click="onShowPanel(device)"
v-hover
></div>
<div class="takeover" title="接管" @click="onTakeOver(device)" v-hover>
<img src="./assets/images/jieguan_active.svg" v-if="device.currentOperator" />
<div v-if="showVideoPanel" class="iconfont icon-luxiang_xianxing"
:class="{ active: uav && device.deviceId === uav.deviceId && uav.showPlayer }" title="视频"
@click="onShowPlayer(device)" v-hover></div>
<div class="iconfont icon-kongzhi_xianxing"
:class="{ active: uav && device.deviceId === uav.deviceId && uav.showPanel }" title="控制面板"
@click="onShowPanel(device)" v-hover></div>
<div class="takeover" title="接管" @click="onTakeOver(device, data.name)" v-hover>
<img src="./assets/images/jieguan_active.svg" v-if="device.currentOperator === userInfo.id" />
<img src="./assets/images/jieguan.svg" v-else />
</div>
</div>
</div>
</div>
</div>
<el-dialog title="接管确认" :visible.sync="takeOverVisible" width="20%" :modal-append-to-body="false"
:append-to-body="false" :close-on-click-modal="false" @close="takeLoading = false">
<span>是否请求接管 {{ departmentName }} 下的 {{ takeDevice.name }}</span>
<span slot="footer" class="dialog-footer">
<el-button @click="takeOverVisible = false">取 消</el-button>
<el-button @click="onForceTakeOver" type="danger" :loading="forceTakeLoading">强制接管</el-button>
<el-button type="primary" @click="onApplyTakeOver" :loading="takeLoading">确 认</el-button>
</span>
</el-dialog>
</div>
</template>
......@@ -106,9 +91,6 @@ import { Control_API } from "../../../../../../../../api";
export default {
name: "Item",
inject: ["rootNode", "bus"],
data() {
return {};
},
props: {
data: {
type: Object,
......@@ -119,13 +101,31 @@ export default {
default: -1,
},
},
data() {
return {
takeOverVisible: false,
// 接管设备信息
takeDevice: {
name: "",
},
departmentName: "",
takeLoading: false, //接管等待中
forceTakeLoading: false, //强制接管等待
};
},
computed: {
...mapState("MMCFlightControlCenter/uav", [
"uav",
"showPlayer",
"showPanel",
]),
...mapState("MMCFlightControlCenter", ["userInfo", "showAirwayEdit"]),
...mapState("MMCFlightControlCenter", [
"userInfo",
"showAirwayEdit",
"deptId",
'showVideoPanel',
]),
},
watch: {
showAirwayEdit(newVal) {
......@@ -138,25 +138,106 @@ export default {
key: "uav",
value: {
...this.uav,
showPlayer: false
showPlayer: false,
},
});
}
},
},
beforeDestroy() {
this.bus.$off("uas-device-take-agree-message", this.onTakeAgree);
this.bus.$off("uas-device-take-refuse-message", this.onTakeAgree);
},
methods: {
/**
* 接管无人机
* 同意接管事件
*/
async onTakeOver(uav) {
if (!uav.currentOperator) {
let res = await Control_API.setUavControlOn({
deviceId: uav.id,
onTakeAgree({ type, content, msg }) {
console.log("onTakeAgree");
//接管消息
if (content.isAgree) {
this.$notify.success({
title: "接管消息",
message: msg,
duration: 30000,
offset:40
});
this.$emit("refresh");
this.takeOverVisible = false;
} else {
this.$notify.warning({
title: "接管消息",
message: msg,
duration: 30000,
offset:40
});
this.$message.warning("申请接管拒绝");
}
this.takeLoading = false;
this.bus.$off("uas-device-take-agree-message", this.onTakeAgree);
this.bus.$off("uas-device-take-refuse-message", this.onTakeAgree);
},
/**
* 申请接管
*/
async onApplyTakeOver() {
this.takeLoading = true;
let res = await Control_API.applyControlUav({
deviceId: this.takeDevice.id,
});
console.log("申请接管");
if (res.code === 0) {
this.bus.$on("uas-device-take-agree-message", this.onTakeAgree);
this.bus.$on("uas-device-take-refuse-message", this.onTakeAgree);
} else {
this.$message.warning("接管失败,申请单位未同意");
this.takeLoading = false;
}
setTimeout(() => {
if (this.takeLoading) {
this.$message.error(`接管失败,申请单位未同意`);
this.takeLoading = false
}
}, 5500);
},
/**
* 强制接管
*/
async onForceTakeOver() {
this.forceTakeLoading = true;
try {
let res = await Control_API.setUavControlOnForce({
deviceId: this.takeDevice.id,
});
if (res.code === 0) {
this.$message.success(`请开始操作${uav.name}`);
this.$message.success(`请开始操作${this.takeDevice.name}`);
this.takeOverVisible = false;
this.$emit("refresh");
}
} catch (e) { }
this.forceTakeLoading = false;
},
/**
* 接管无人机
*/
async onTakeOver(uav, departmentName) {
this.departmentName = departmentName;
if (!uav.currentOperator) {
// 没有接管人的情况下该设备所属部门与用户一致则直接接管
if (this.deptId === uav.departmentId) {
let res = await Control_API.updateCurrentOperator({
deviceId: uav.id,
});
if (res.code === 0) {
this.$message.success(`请开始操作${uav.name}`);
this.$emit("refresh");
}
} else {
// 不一致则申请接管
this.takeDevice = uav;
this.takeOverVisible = true;
}
} else if (
// 判断当前接管人是不是自已, 是则提示退出接管, 不是则提示是否强制接管
uav.currentOperator === this.userInfo.id
......@@ -175,27 +256,11 @@ export default {
this.$message.success(`已退出接管${uav.name}`);
this.$emit("refresh");
}
} catch (e) {}
} catch (e) { }
} else {
try {
await this.$confirm(
`${uav.name}已被接管, 请确认是否强制接管?`,
"安全确认",
{
cancelButtonText: "取消",
confirmButtonText: "确定",
customClass: "uav_controlPane",
showClose: false,
}
);
let res = await Control_API.setUavControlOnForce({
deviceId: uav.id,
});
if (res.code === 0) {
this.$message.success(`请开始操作${uav.name}`);
this.$emit("refresh");
}
} catch (e) {}
// 已被接管且接管人不是自已的情况下, 需要申请接管
this.takeDevice = uav;
this.takeOverVisible = true;
}
},
/**
......@@ -455,10 +520,16 @@ export default {
.device-name {
display: flex;
align-items: center;
width: calc(100% - 150px);
width: calc(100% - 90px);
white-space: nowrap;
text-overflow: ellipsis;
font-size: 13px;
.device-name-text{
display: inline-block;
max-width: 100%;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden
}
}
&.online {
......@@ -483,6 +554,7 @@ export default {
height: 100%;
}
}
.iconfont {
font-size: 24px;
margin-right: 8px;
......@@ -496,40 +568,50 @@ export default {
}
}
}
.goodsName_two {
background-image: url("./assets/images/goodsName_two.svg");
background-size: 100% 100%;
}
.goodsName_one {
background-image: url("./assets/images/goodsName_one.svg");
background-size: 100% 100%;
}
}
.green {
color: #31db24;
}
.red {
color: red;
}
.item_items {
align-items: center;
}
.level-icon {
width: 16px;
margin-right: 6px;
}
.refresh-icon {
width: 16px;
margin-left: 34px;
}
.jcsb {
justify-content: left;
}
.status-icon {
margin-left: 12px;
font-size: 14px;
color: RGBA(251, 192, 1, 1);
}
.uav_version {
margin-top: 1px;
// width: 14px;
......@@ -543,6 +625,7 @@ export default {
color: #fff;
font-size: 8px;
}
.symbol-icon-box {
display: flex;
align-items: center;
......
......@@ -20,15 +20,16 @@
style="color: rgba(123, 181, 213, 1)"
></i>
</el-input>
<el-button class="uav-search__btn" @click="onUavSearch" v-hover>搜索</el-button>
<el-button class="uav-search__btn" @click="onUavSearch" v-hover
>搜索</el-button
>
</div>
<List
class="uav-list-main"
@exit
:containerStyle="{
width: '400PX',
height: '275px',
}"
width: '400PX',
height: '275px',
}"
:list="uavList"
@refresh="initList"
/>
......@@ -78,12 +79,13 @@ export default {
},
mounted() {
this.initList();
this.timeHandle = setInterval(() => {
this.initList();
}, 10000);
this.bus.$on("uas-device-getTree-message", this.initList);
// this.timeHandle = setInterval(() => {
// this.initList();
// }, 10000);
},
beforeDestroy() {
clearInterval(this.timeHandle);
// clearInterval(this.timeHandle);
},
methods: {
async initList() {
......@@ -135,7 +137,7 @@ export default {
position: absolute;
cursor: pointer;
right: -35px;
top: 50%;
top: 23%;
transform: translate(0, -50%);
z-index: 99;
......
......@@ -39,7 +39,7 @@ export default {
"uavRealTimeData.isFlying"(newVal, oldVal) {
// 监听飞机降落然后进行任务结束的提示
if (oldVal === true && newVal === false) {
if (!this.uav.deviceId.include("mock")) {
if (!this.uav.deviceId.includes("mock")) {
this.$alert("当前任务已结束", "提示", {
type: "success ",
confirmButtonText: "确定",
......
......@@ -21,6 +21,7 @@ import Hangar from "./components/hangar";
import Vue from "vue";
import SymbolIcon from "../symbol-icon";
import MapSearch from "./components/mapSearch";
import { Control_API } from "./api/index";
export default {
name: "MMCFlightControlCenter",
......@@ -68,11 +69,18 @@ export default {
type: Boolean,
default: false,
},
// 使用航线而不使用任务起飞
useAirway: {
// useAirway
// 使用任务
useTask: {
type: Boolean,
default: true,
default: false,
},
//使用视频面板
showVideoPanel: {
type: Boolean,
default: false,
},
userInfo: {
type: Object,
default() {
......@@ -89,6 +97,8 @@ export default {
data() {
return {
bus: new Vue(),
ws: null,
uavWs:null
};
},
provide() {
......@@ -98,6 +108,14 @@ export default {
};
},
watch: {
'scene': {
handler(newVal) {
if (newVal) {
this.reset()
}
},
},
userInfo: {
immediate: true,
handler() {
......@@ -114,6 +132,10 @@ export default {
value: this.userInfo.projectId,
});
this.$store.commit("MMCFlightControlCenter/setState", {
key: "deptId",
value: this.userInfo.deptId,
});
this.$store.commit("MMCFlightControlCenter/setState", {
key: "userInfo",
value: this.userInfo,
});
......@@ -146,6 +168,10 @@ export default {
key: "mqttToken",
value: newVal.mqttToken,
});
this.$store.commit("MMCFlightControlCenter/setState", {
key: "mqttIP",
value: newVal.mqttIP,
});
},
},
useSTLAirway: {
......@@ -166,15 +192,26 @@ export default {
});
},
},
useAirway: {
useTask: {
immediate: true,
handler(newVal) {
this.$store.commit("MMCFlightControlCenter/setState", {
key: "useAirway",
key: "useTask",
value: newVal,
});
},
},
showVideoPanel: {
immediate: true,
handler(newVal) {
this.$store.commit("MMCFlightControlCenter/setState", {
key: "showVideoPanel",
value: newVal,
});
},
},
},
beforeCreate() {
crashMonitor({
......@@ -189,6 +226,12 @@ export default {
window.$mmc_stl.state = () => {
return this.$store.state;
};
window.$debug = localStorage.getItem("$debug") == 1 ? true : false; //全局调试信息展示开关
window.$log = function (...args) {
if (window.$debug) {
console.info(...args);
}
};
},
created() {
if (this.cesiumViewer) {
......@@ -198,8 +241,156 @@ export default {
});
window.$mmc_stl.viewer = this.cesiumViewer;
}
// 连接ws监听接管请求数据
let url = this.url.wsUrl
let token = this.$store.state.MMCFlightControlCenter.token
const socket = new WebSocket(`${url}/infra/ws?token=${token}`);
const uavSocket = new WebSocket(`${url}/uav/ws?token=${token}`);
this.ws = socket;
this.uavWs = uavSocket;
socket.onopen = function () {
};
socket.onmessage = (event) => {
let data = JSON.parse(event.data || "{}");
const type = data.type;
const content = JSON.parse(data.content || "{}");
const msg = content.message;
switch (type) {
// 接管申请
case "uas-device-take-message":
//接管消息
this.$confirm(msg, "提示", {
confirmButtonText: "同意",
cancelButtonText: "拒绝",
type: "warning",
closeOnClickModal: false,
closeOnPressEscape: false,
showClose: false,
})
.then(async () => {
try {
let res = await Control_API.updateControlUav({
deviceId: content.deviceId,
applicantId: content.applicantId,
isAgree: 1,
});
if (res.code == 0) {
this.$message.success("已同意接管");
} else {
this.$message.warning("操作失败");
}
} catch (e) { }
})
.catch(async () => {
await Control_API.updateControlUav({
deviceId: content.deviceId,
applicantId: content.applicantId,
isAgree: 2,
});
this.$message.success("已拒绝接管");
});
// 5秒后自动关闭弹框
setTimeout(() => {
this.$confirm.close(); // 关闭弹框
}, 5000);
break;
// 接管申请同意
case "uas-device-take-agree-message":
console.log('同意接管')
this.bus.$emit("uas-device-take-agree-message", {
type,
content,
msg,
});
break;
// 接管申请拒绝
case "uas-device-take-refuse-message":
this.bus.$emit("uas-device-take-refuse-message", {
type,
content,
msg,
});
break;
// 退出接管消息
case "uas-device-take-quit-message":
this.$notify.info({
title: "接管消息",
message: msg,
duration: 30000,
offset:40
});
break;
// 被强制接管
case "uas-device-force-take-message":
this.$notify.warning({
title: "接管消息",
message: msg,
duration: 30000,
offset:40
});
break;
}
};
uavSocket.onopen = function () {
};
uavSocket.onmessage = (event) => {
let data = JSON.parse(event.data || "{}");
const type = data.type;
const content = JSON.parse(data.content || "{}");
const msg = content.message;
switch (type) {
case "uas-device-take-message":
console.log(msg,'msg');
break;
// 刷新无人机列表
case "uas-device-getTree-message":
this.bus.$emit("uas-device-getTree-message", {
type,
content,
msg,
});
break;
}
};
},
beforeDestroy() {
this.ws.close();
this.uavWs.close();
},
methods: {
reset() {
let cesiumEl = document.querySelector(".cesium-viewer");
// 判断cesium的父元素是否是layer-container来确定当前是否已经切换, 未切换就退出
if (cesiumEl.parentElement.id === 'layer-container') {
return;
}
let cesiumParentEl = document.querySelector("#layer-container");
let uavParentEl = document.querySelector("#playerUavParent");
let uavEl = document.querySelector("#playerUav");
let innerParentEl = document.querySelector("#playInnerParent");
let innerEl = document.querySelector("#playInner");
let outParentEl = document.querySelector("#playOutParent");
let outEl = document.querySelector("#playerOuter");
cesiumParentEl.innerHTML = "";
uavParentEl.innerHTML = "";
innerParentEl.innerHTML = "";
outParentEl.innerHTML = "";
cesiumParentEl.append(cesiumEl);
uavParentEl.append(uavEl);
innerParentEl.append(innerEl);
outParentEl.append(outEl);
},
},
methods: {},
};
</script>
......@@ -240,18 +431,30 @@ export default {
color: #fff !important;
}
.el-dialog__body {
button:nth-child(2) {
box-shadow: inset 0 0 5px #00ffff;
background: rgba(4, 227, 227, 0.1);
opacity: 0.8;
.el-dialog {
background: #222222;
border: none;
border-radius: 1px;
.el-dialog__header {
background: #3c3c3c;
.el-dialog__title {
color: #fff;
}
}
.el-dialog__body {
color: #fff;
}
}
* {
/* 滚动条整体样式 */
&::-webkit-scrollbar {
width: 4px; /* 滚动条宽度 */
width: 4px;
/* 滚动条宽度 */
}
//滚动条轨道
......@@ -269,6 +472,7 @@ export default {
background: #222222;
border-radius: 10px 10px 0px 0px;
border: 0;
.hd {
box-sizing: border-box;
padding-left: 0px;
......@@ -289,7 +493,8 @@ export default {
.dialog1027 {
z-index: 1;
background: #222222;
border-radius: 10px 10px 0px 0px;
border-radius: 10px 10px 10px 10px;
.dialog-header {
box-sizing: border-box;
padding-left: 32px;
......@@ -320,14 +525,12 @@ export default {
align-items: center;
font-size: 20px;
font-family: YouSheBiaoTiHei;
background-image: -webkit-linear-gradient(
right,
#e3aa77,
#f5cda9,
#f9ecd3,
#fcdbb1,
#edb07a
);
background-image: -webkit-linear-gradient(right,
#e3aa77,
#f5cda9,
#f9ecd3,
#fcdbb1,
#edb07a);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
letter-spacing: 0;
......@@ -427,6 +630,7 @@ export default {
}
.el-input-number {
.el-input-number__decrease,
.el-input-number__increase {
bottom: 1px;
......@@ -454,6 +658,7 @@ export default {
.popper__arrow::after {
border-bottom-color: #161d2d;
}
// 所有下拉选择框样式
&.el-select-dropdown {
border: none;
......@@ -466,18 +671,17 @@ export default {
.option.hover,
.option:hover {
background-image: linear-gradient(
90deg,
rgba(44, 135, 176, 0.7) 0%,
rgba(26, 100, 139, 0.37) 51%,
rgba(7, 61, 98, 0.7) 100%
);
background-image: linear-gradient(90deg,
rgba(44, 135, 176, 0.7) 0%,
rgba(26, 100, 139, 0.37) 51%,
rgba(7, 61, 98, 0.7) 100%);
font-family: MicrosoftYaHei;
font-size: 12px;
color: #00f5ff;
letter-spacing: 0;
font-weight: 400;
}
.el-select-dropdown__item {
color: #fff;
......@@ -510,7 +714,7 @@ export default {
.el-select-dropdown__empty {
background: #02173d;
border: 1px solid #315ec7;
border: 1px solid #4b4b4b;
}
}
......@@ -531,6 +735,7 @@ export default {
&:not(.is-disabled):hover {
background: #4b4b4b;
}
&:not(.is-disabled):focus {
background: #4b4b4b;
}
......@@ -552,6 +757,7 @@ export default {
.el-popper {
background: #222222;
}
// 日期选择器组件
&.el-time-range-picker,
&.el-date-range-picker,
......@@ -638,6 +844,7 @@ export default {
.el-pagination {
text-align: center;
.el-pager li {
background: transparent !important;
}
......
import * as mountList from "../../MMCMount/utils.js";
import { mapState } from "vuex";
export default {
data() {
return {
wsJoystick: null,
control_speed: 3, //控制速度
mountList,
lastDirection: "stop", //最后一次操控方向
str: null,
mountCtrlList: null,
};
},
mounted() {
this.mountCtrlList = {
...this.mountList,
};
},
computed: {
...mapState("MMCFlightControlCenter", ["mqttIP"]),
...mapState("MMCFlightControlCenter/uav", ["selectMount", "uav"]),
mountCtrl() {
return this.mountCtrlList[this.selectMount?.gimbalName];
},
},
watch: {
str: function (val) {
this.$store.dispatch("MMCMQTT/publish", {
topic: "PX4/OBTAIN/" + this.uav.deviceId,
data: {
type: 513,
data: val,
},
callback() { },
});
},
},
beforeDestroy() {
console.log("closeJoystick.........................");
this.closeJoystick();
},
methods: {
/**
* 初始化操纵杆连接
*/
initJoystick() {
this.wsJoystick && this.wsJoystick.close();
let uavCate = "PX4";
let topic = `${uavCate}/OBTAIN/${this.uav.deviceId}`;
this.wsJoystick = new WebSocket("ws://127.0.0.1:8802");
this.wsJoystick.onopen = () => {
console.log("joystick.js 连接上 ws://127.0.0.1:8802 1112222");
this.wsJoystick.send(
JSON.stringify({
type: 2003,
data: {
mqttAddr: this.mqttIP,
mqttIport: 1883,
mqttTopic: topic,
vehicleType: uavCate == "PX4" ? 1 : 0,
},
})
);
this.wsJoystick.send(JSON.stringify({ type: 2001, data: {} }));
};
let _this = this;
this.wsJoystick.onmessage = (e) => {
let reader = new FileReader();
reader.onload = (event) => {
let obj = JSON.parse(event.currentTarget.result);
if (obj.type == 518) {
}
let data = JSON.parse(event.currentTarget.result).data;
let y = data.channel03; //油门值 0-1000
this.manualControlStatus = true
// console.log(data.channel03,data,"yyyyyyyy");
if (y || y == 0) {
this.$store.commit("MMCFlightControlCenter/joystick/setState", {
key: "throttleValue",
value: y,
});
}
if (this.mountCtrl) {
//拍照
if (data.channel06) {
let buffer = this.mountCtrl.take_photo();
this.send_mqtt(buffer);
}
//录像
if (data.channel05) {
let buffer = null;
if (data.channel05 == 1) {
buffer = this.mountCtrl.record(true);
} else if (data.channel05 == 2) {
buffer = this.mountCtrl.record(false);
}
this.send_mqtt(buffer);
}
//云台模式
// if (data.channel07) {
// let buffer = null
// if (data.channel07 == 1) {
// buffer = this.mountCtrl.gimbal_mode_ctrl(0)
// } else if (data.channel07 == 2) {
// buffer = this.mountCtrl.gimbal_mode_ctrl(2)
// }
// this.send_mqtt(buffer)
// } else {
// let buffer = this.mountCtrl.gimbal_mode_ctrl(1)
// this.send_mqtt(buffer)
// }
//变焦
if (data.channel09) {
let buffer = null;
if (data.channel09 == 1) {
buffer = this.mountCtrl.zoom(2, 0);
} else if (data.channel09 == 2) {
buffer = this.mountCtrl.zoom(0, 0);
}
this.send_mqtt(buffer);
buffer = this.mountCtrl.zoom(1, 0);
this.send_mqtt(buffer);
}
}
//飞行模式
if (data.channel08) {
if (data.channel08 == 1) {
//定点
this.str = "POSITION";
} else if (data.channel08 == 2) {
//航线
this.str = "AUTO_MISSION";
} else if (data.channel08 == 3) {
//返航
this.str = "AUTO_RTL";
} else if (data.channel08 == 4) {
//保持
this.str = "HOLD";
}
}
//channel10 云台俯仰 0:没按 1:上 2:下
if (data.channel10) {
const direction = {
1: "up",
2: "down",
};
const ctr = direction[data.channel10];
// console.log('摇杆按下了channel10', ctr);
_this.cameraMountCtr(ctr);
}
//channel11 云台偏航 0:没按 1:左 2:右
if (data.channel11) {
const direction = {
1: "left",
2: "right",
};
const ctr = direction[data.channel11];
// console.log('摇杆按下了channel11', ctr);
_this.cameraMountCtr(ctr);
}
if (data.channel10 == 0 && data.channel11 == 0) {
_this.cameraMountCtr("stop");
}
};
reader.readAsText(e.data);
};
},
/**
* 关闭操纵杆
*/
closeJoystick() {
if (!this.wsJoystick) {
return;
}
this.cameraMountCtr("stop", this.lastMountCtrl);
this.manualControlStatus = false
setTimeout(() => {
this.wsJoystick.send(JSON.stringify({ type: 2010, data: {} }));
this.wsJoystick && this.wsJoystick.close();
this.wsJoystick = null;
}, 2000);
},
/**
* 相机挂载控制
* @param {String} type up: 上,left:打,right:右,down:下
*/
cameraMountCtr(type) {
/* if(type !== 'stop'){
console.log('cameraMountCtr', !this.wsJoystick, !this.mountCtrl || !type, this.lastDirection === type)
console.log('this.mountCtrl', this.mountCtrl, type)
} */
if (!this.wsJoystick) {
return;
}
if (!this.mountCtrl || !type) {
return;
}
if (this.lastDirection === type) {
return;
}
console.log("摇杆按下了", type);
let buffer = null;
switch (type) {
case "stop":
if (["up", "down"].includes(this.lastDirection)) {
buffer = this.mountCtrl.gimbal_pitch_ctrl(0, this.control_speed);
} else if (["left", "right"].includes(this.lastDirection)) {
buffer = this.mountCtrl.gimbal_yaw_ctrl(0, this.control_speed);
}
// buffer = this.mountCtrl.gimbal_pitch_ctrl(0, this.control_speed);
// buffer = this.mountCtrl.gimbal_yaw_ctrl(0, this.control_speed);
break;
case "up":
buffer = this.mountCtrl.gimbal_pitch_ctrl(1, this.control_speed);
break;
case "left":
buffer = this.mountCtrl.gimbal_yaw_ctrl(-1, this.control_speed);
break;
case "right":
buffer = this.mountCtrl.gimbal_yaw_ctrl(1, this.control_speed);
break;
case "down":
buffer = this.mountCtrl.gimbal_pitch_ctrl(-1, this.control_speed);
break;
}
this.lastDirection = type;
this.send_mqtt(buffer);
},
send_mqtt(buffer) {
this.$store.dispatch("MMCMQTT/publish", {
topic: "PX4/OBTAIN/" + this.uav.deviceId,
data: {
type: 514,
data: {
mountId: this.selectMount.mountId,
payload: buffer,
},
},
callback() { },
});
},
},
};
import moment from "moment";
import { Control_API, TaskInfo } from "../api";
function initHangarRealTimeData(){
function initHangarRealTimeData() {
return {
chargerPower: 0, //充电电源,0-未知,1-打开,2-关闭
cover: 0, //舱盖,0-未知,1-关闭,2-打开,3-正在关闭,4-正在打开
......@@ -101,6 +101,7 @@ const actions = {
});
}
}
// console.log(msgList, "机库返回数据");
commit("setState", {
key: "hangarRealTimeData",
......@@ -295,12 +296,13 @@ const actions = {
* @param {function} data.callback //完成回调
*/
async takeOff({ state }, data) {
console.log(state.airlineData, data);
console.log(state.airlineData, data, "1111");
try {
// 生成架次号
const flightSortieId = await TaskInfo.flightSortieId({
device_id: state.hangar.uav.deviceId,
reouteId: state.airlineData.id
reouteId: state.airlineData.id,
taskInfoId: data.taskInfoId,
});
/* const flightSortieId = {
data: `tmj-v4-${Date.now()}`
......@@ -335,8 +337,9 @@ const actions = {
* @param { Number } data.id 无人机id
*/
async isTakeOver({ state }, data) {
let device = data || state.hangar;
let res = await Control_API.getDeviceDetail({
id: data?.id || state.hangar.id,
id: device.id,
});
if (
res.data.currentOperator &&
......
import uav from "./uav";
import hangar from "./hangar";
import joystick from './joystick';
import { Control_API } from "../api";
import { Utils } from "../lib/cesium";
export default {
namespaced: true,
state: {
flyLogStatus: false, //飞行日志状态
devMode: false, //开发模式, 使用开发环境接口
token: "", //登录token
TenantId: "", //租户id
......@@ -40,11 +42,13 @@ export default {
airwayEntities: [], //航线实体集合, 元素为new Cesium.EntityCollection()创建
useSTLAirway: true, //是否使用标准航线库
useTimedTask: false, //是否使用定时任务
useAirway: true, //使用航线而不使用任务起飞
useTask: false, //使用任务进行航线选择
showVideoPanel: false, //显示视频面板
baseUrl: '', //api请求的base url
wsUrl: '', //websocket的url
mqttUrl: '', //无人机的mqtt地址
mqttUrlHangar: '', //机库的mqtt地址
mqttIP: '', //mqtt ip地址, 给于摇杆程序使用, 不支持域名
mqttToken: '', //mqtt token
showAirwayEdit: false, //展开航线编辑
},
......@@ -305,5 +309,6 @@ export default {
modules: {
uav,
hangar,
joystick
},
};
const state = {
throttleValue: 0, //油门值
manualControlStatus: false, //是否手动控制
onInfieldControlFn: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 = {};
const getters = {
/**
* //油门是否置中
* @param {*} state
* @returns
*/
isThrottleCenter(state) {
if (state.throttleValue >= 470 && state.throttleValue <= 530) {
return true;
} else {
return false;
}
}
};
export default {
namespaced: true,
name: "uav",
state,
mutations,
actions,
getters,
};
......@@ -355,16 +355,16 @@ const actions = {
type260.grade <= 2
? "[危险]"
: type260.grade == 3
? "[错误]"
: type260.grade == 4
? "[警告]"
: type260.grade == 5
? "[通知]"
: type260.grade == 6
? "[正常]"
: type260.grade == 7
? "[调试]"
: "AUTO",
? "[错误]"
: type260.grade == 4
? "[警告]"
: type260.grade == 5
? "[通知]"
: type260.grade == 6
? "[正常]"
: type260.grade == 7
? "[调试]"
: "AUTO",
text: type260.msg,
time: moment(type260.timestamp).format("YYYY-MM-DD HH:mm:ss"),
timestamp: type260.timestamp,
......@@ -499,15 +499,15 @@ const actions = {
if (state.uavRealTimeData.locationCoordinate3D.longitude) {
if (
state.uavRealTimeData.locationCoordinate3D.longitude ===
defaultPos.longitude &&
defaultPos.longitude &&
state.uavRealTimeData.locationCoordinate3D.latitude ===
defaultPos.latitude
defaultPos.latitude
) {
// 默认坐标不记录
} else {
// const posData = UAVDataParser(state.uavRealTimeData); // 这种写法在执行rollup混淆压缩后, posData对象会变成elementUI的对象,原因未知
// 更新轨迹
let flag = positions.some(val=> val.x == UAVDataParser(state.uavRealTimeData).position.x && val.y == UAVDataParser(state.uavRealTimeData).position.y)
let flag = positions.some(val => val.x == UAVDataParser(state.uavRealTimeData).position.x && val.y == UAVDataParser(state.uavRealTimeData).position.y)
if (!flag) {
positions.push(UAVDataParser(state.uavRealTimeData).position);
}
......@@ -516,7 +516,7 @@ const actions = {
if (
state.uavRealTimeData.locationCoordinate3D.longitude !==
defaultPos.longitude &&
defaultPos.longitude &&
!state.uavModelEntity
) {
dispatch("createUavModel");
......@@ -697,16 +697,27 @@ const actions = {
/**
* 一键起飞
* @param {function} data.callback //完成回调
* @param {object} data.taskInfoId //任务id
*/
async takeOff({ state, commit }, data) {
console.log(state.airlineData, data);
if (state.uav.network == 2) {
try {
// 生成架次号
const flightSortieId = await TaskInfo.flightSortieId({
device_id: state.uav.deviceId,
reouteId: state.airlineData.id,
});
let flightSortieId;
if (data.taskInfoId) {
flightSortieId = await TaskInfo.createTaskRecord({
taskInfoId: data.taskInfoId || undefined,
deviceId: state.uav.deviceId,
reouteId: state.airlineData.id,
})
} else {
// 生成架次号
flightSortieId = await TaskInfo.flightSortieId({
device_id: state.uav.deviceId,
reouteId: state.airlineData.id,
});
}
/* const flightSortieId = {
data: `tmj-v4-${Date.now()}`
} */
......@@ -727,7 +738,7 @@ const actions = {
maxFlightSpeed: 12,
},
},
callback() {},
callback() { },
});
// 告诉飞控开始任务,并且把架次号和 任务id传过去
......@@ -740,7 +751,7 @@ const actions = {
flightSortiesID: flightSortieId.data,
},
},
callback() {},
callback() { },
});
// 起飞指令
......@@ -1333,6 +1344,9 @@ const actions = {
});
}
},
async showUavRealTimeData({ state }, data) {
return state.isFlying;
},
/**
* 判断是否已接管
* @param { Number } data.id 无人机id
......@@ -1344,7 +1358,7 @@ const actions = {
if (
res.data.currentOperator &&
res.data.currentOperator ===
window.$mmc_stl.$store.state.MMCFlightControlCenter.userInfo.id
window.$mmc_stl.$store.state.MMCFlightControlCenter.userInfo.id
) {
return true;
}
......@@ -1362,7 +1376,7 @@ const actions = {
type: window.$mmc_stl.$store.state.MMCMQTT.orders.链路切换,
data,
},
callback() {},
callback() { },
});
},
// 键盘控制
......
......@@ -681,14 +681,14 @@ export default {
this.position = position;
// 添加目标点
if (!targetPoint && this.position) {
targetPoint = window.viewer.entities.add({
/* targetPoint = window.viewer.entities.add({
position: new Cesium.CallbackProperty(() => this.position, false),
billboard: {
image: svgMB,
width: 32,
height: 32,
},
});
}); */
}
}
} catch (error) {
......
......@@ -816,14 +816,14 @@ export default {
this.position = position;
// 添加目标点
if (!targetPoint && this.position) {
targetPoint = window.viewer.entities.add({
/* targetPoint = window.viewer.entities.add({
position: new Cesium.CallbackProperty(() => this.position, false),
billboard: {
image: require("./mb.svg"),
width: 32,
height: 32,
},
});
}); */
}
}
} catch (error) {
......
......@@ -413,12 +413,10 @@ div.dib {
button{
width: 100px;
height: 32px;
background: #3388FF;
border-radius: 2px;
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 14px;
color: #FFFFFF;
line-height: 16px;
font-style: normal;
}
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论