提交 adbc5926 作者: 梁启东

Merge branch 'v4' of http://git.mmcuav.cn/root/mmc-stl-vue2 into v4

# Conflicts:
#	src/components/MMCFlightControlCenter/components/hangar/components/list/components/item/index.vue
...@@ -24,6 +24,8 @@ ...@@ -24,6 +24,8 @@
@airwayListGet="dispatchEvent('airwayListGet', $event)" @airwayListGet="dispatchEvent('airwayListGet', $event)"
@airwayGet="dispatchEvent('airwayGet', $event)" @airwayGet="dispatchEvent('airwayGet', $event)"
@taskListGet="dispatchEvent('taskListGet', $event)" @taskListGet="dispatchEvent('taskListGet', $event)"
@leapFrogFlighGet="dispatchEvent('leapFrogFlighGet', $event)"
@apronUavSkipEvent="dispatchEvent('apronUavSkipEvent', $event)"
@taskRecordPageGet="dispatchEvent('taskRecordPageGet', $event)" @taskRecordPageGet="dispatchEvent('taskRecordPageGet', $event)"
@taskInfoUpdateTime="dispatchEvent('taskInfoUpdateTime', $event)" @taskInfoUpdateTime="dispatchEvent('taskInfoUpdateTime', $event)"
@taskInfoRecordDel="dispatchEvent('taskInfoRecordDel', $event)" @taskInfoRecordDel="dispatchEvent('taskInfoRecordDel', $event)"
......
import axios from "axios"; import axios from "axios";
import request from "../request";
// const gddaiapi = 'https://hawk.mmcuav.cn/gddaiapi';
export default class AI_API { export default class AI_API {
// 获取当前的ai配置
static getAiconfig(data) {
return request({
url: `/admin-api/system/ai-config/getconfig`,
method: "post",
data,
});
}
// 人脸 // 人脸
static face(data){ static face(data) {
// return axios.post("http://api.user.mmcuav.cn/aidemo/facedetect", data); // 百度的ai return axios.post(
return axios.post("https://hawk.mmcuav.cn/faceaiapi/detect/imageface", data); "https://hawk.mmcuav.cn/faceaiapi/detect/imageface",
data
);
} }
// 车牌 // 车牌
static plate(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(
// return axios.post("https://hawk.mmcuav.cn/plateaiapi/detect/image", data); // 自研 "/gddaiapi/api/inflet/v1/tasks/e01d1d01-52e2-4883-a5de-0ae268764db0/predict",
data
); // 共达地
} }
// 人流 // 人流
static crowd(data){ static crowd(data) {
return axios.post("https://hawk.mmcuav.cn/gddaiapi/api/inflet/v1/tasks/18493235-4dd0-4f54-ab55-c1856ca7e3a5/predict", data); return axios.post(
"/gddaiapi/api/inflet/v1/tasks/18493235-4dd0-4f54-ab55-c1856ca7e3a5/predict",
data
);
} }
// 烟雾 // 烟雾
static smoke(data){ static smoke(data) {
return axios.post("https://hawk.mmcuav.cn/gddaiapi/api/inflet/v1/tasks/fca2eb65-8b99-4109-9f9e-a9f7fd06ac1f/predict", 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); return axios.post("https://hawk.mmcuav.cn/oilaiapi/detect/image", data);
} }
// 裸土识别 // 裸土识别
static bareSoil(data){ static bareSoil(data) {
return axios.post("https://hawk.mmcuav.cn/gddaiapi/api/inflet/v1/tasks/05a9d657-8339-4575-bced-04b60b74c690/predict", 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);
} }
} }
...@@ -29,6 +29,7 @@ $axios.interceptors.request.use( ...@@ -29,6 +29,7 @@ $axios.interceptors.request.use(
config.headers["Tenant-Id"] = TenantId; config.headers["Tenant-Id"] = TenantId;
config.headers["terminal"] = 2; // 1 为管理后台 2 为前端项目 config.headers["terminal"] = 2; // 1 为管理后台 2 为前端项目
config.headers["p-id"] = projectId; config.headers["p-id"] = projectId;
console.log(config, store.state, "token信息验证");
return config; return config;
}, },
(error) => { (error) => {
...@@ -73,11 +74,14 @@ $axios.interceptors.response.use( ...@@ -73,11 +74,14 @@ $axios.interceptors.response.use(
isRefreshToken = false; isRefreshToken = false;
if (data.code === 0) { if (data.code === 0) {
const token = data.token; const token = data.token;
console.log('store', store);
window.$mmc_stl.app.$store.commit('MMCFlightControlCenter/setState', { window.$mmc_stl.app.$store.commit(
key: 'token', "MMCFlightControlCenter/setState",
value: token {
}) key: "token",
value: token,
}
);
config.headers.Authorization = "Bearer " + token; config.headers.Authorization = "Bearer " + token;
requestList.forEach((cb) => { requestList.forEach((cb) => {
cb(); cb();
......
<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>
...@@ -172,7 +172,6 @@ export default { ...@@ -172,7 +172,6 @@ export default {
*/ */
getTaskList(id) { getTaskList(id) {
return new Promise((resolve) => { return new Promise((resolve) => {
console.log("getTaskList", this.taskListAll);
this.rootNode.$emit("taskListGet", { this.rootNode.$emit("taskListGet", {
pageNo: 1, pageNo: 1,
pageSize: 100, pageSize: 100,
......
...@@ -3,25 +3,46 @@ ...@@ -3,25 +3,46 @@
<div class="task-list-header"> <div class="task-list-header">
<div <div
class="task-list-header__item" class="task-list-header__item"
:class="{active: tabIndex === 0 && useTimedTask}" :class="{ active: tabIndex === 0 && useTimedTask }"
@click="tabIndex = 0" @click="tabIndex = 0"
> >
<label>常态飞行</label> <label>常态飞行</label>
</div> </div>
<template v-if="useTimedTask"> <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> <label>定时飞行</label>
</div> </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> <label>周期飞行</label>
</div> </div>
<div
v-if="isLeapFrogFligh"
class="task-list-header__item"
:class="{ active: tabIndex === 3 }"
@click="tabIndex = 3"
>
<label>蛙跳飞行</label>
</div>
</template> </template>
</div> </div>
<div class="task-list-main"> <div class="task-list-main">
<!-- 常态任务 --> <!-- 常态任务 -->
<NormalTask v-if="tabIndex === 0"></NormalTask> <NormalTask v-if="tabIndex === 0"></NormalTask>
<!-- 定时任务 --><!-- 周期任务 --> <!-- 定时任务 --><!-- 周期任务 -->
<TimedTask v-else :type="tabIndex"></TimedTask> <TimedTask
v-else-if="tabIndex === 1 || tabIndex === 2"
:type="tabIndex"
></TimedTask>
<!-- 蛙跳飞行 -->
<leapFrogFligh v-else></leapFrogFligh>
</div> </div>
</div> </div>
</template> </template>
...@@ -29,6 +50,8 @@ ...@@ -29,6 +50,8 @@
<script> <script>
import NormalTask from "./components/normalTask"; import NormalTask from "./components/normalTask";
import TimedTask from "./components/timedTask"; import TimedTask from "./components/timedTask";
import leapFrogFligh from "./components/leapFrogFligh";
import { mapState } from "vuex"; import { mapState } from "vuex";
export default { export default {
...@@ -36,10 +59,12 @@ export default { ...@@ -36,10 +59,12 @@ export default {
components: { components: {
NormalTask, NormalTask,
TimedTask, TimedTask,
leapFrogFligh,
}, },
data() { data() {
return { return {
tabIndex: 0, tabIndex: 0,
isLeapFrogFligh: false,
}; };
}, },
computed: { computed: {
...@@ -52,8 +77,36 @@ export default { ...@@ -52,8 +77,36 @@ 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() {}, 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> </script>
......
...@@ -8,11 +8,12 @@ ...@@ -8,11 +8,12 @@
<!-- 展示视频 --> <!-- 展示视频 -->
<div class="left-video" :class="{collapse: playerCollapse}" v-if="hangar && showPanel && listCollapse"> <div class="left-video" :class="{collapse: playerCollapse}" v-if="hangar && showPanel && listCollapse">
<div class="collapse-btn" @click="playerCollapse = !playerCollapse"> <div class="collapse-btn" @click="playerCollapse = !playerCollapse">
<img src="./assets/images/collapse.svg" /> <img style="width:23px" src="./assets/images/collapse.svg" />
</div> </div>
<div class="left-video-header"> <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"> <div class="nest-name">
<span class="nest-name__text">{{ hangar.name }}</span> <span class="nest-name__text">{{ hangar.name }}</span>
<span class="nest-name__text">{{ hangar.name }}</span> <span class="nest-name__text">{{ hangar.name }}</span>
...@@ -189,7 +190,7 @@ export default { ...@@ -189,7 +190,7 @@ export default {
.collapse-btn { .collapse-btn {
position: absolute; position: absolute;
cursor: pointer; cursor: pointer;
right: -35px; right: -22px;
top: 50%; top: 50%;
transform: translate(0, -50%); transform: translate(0, -50%);
z-index: 99; z-index: 99;
......
...@@ -7,10 +7,16 @@ ...@@ -7,10 +7,16 @@
</div> </div>
<div class="line-box w210"> <div class="line-box w210">
( (
<span class="cf">{{ data.onLineCount + data.offLineCount }}</span> <span class="cf"
<span class="healthy--un ml5" style="color: #31db24">{{ data.onLineCount }} 架在线</span> >{{ data.onLineCount + data.offLineCount }}</span
>
<span class="healthy--un ml5" style="color: #31db24"
>{{ data.onLineCount }} 架在线</span
>
<span>/</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> </div>
</div> </div>
...@@ -18,31 +24,69 @@ ...@@ -18,31 +24,69 @@
<div class="nest-children" :class="{ collapse: listCollapse }"> <div class="nest-children" :class="{ collapse: listCollapse }">
<template v-if="data && data.deviceDOList && data.deviceDOList.length"> <template v-if="data && data.deviceDOList && data.deviceDOList.length">
<div class="nest-device-list"> <div class="nest-device-list">
<div v-for="device in data.deviceDOList" :key="`device_${device.id}`" class="nest-device-item" <div
:class="{ online: device.isOnline }"> v-for="device in data.deviceDOList"
:key="`device_${device.id}`"
class="nest-device-item"
:class="{ online: device.isOnline }"
>
<!-- 最前面的选项框 --> <!-- 最前面的选项框 -->
<div class="title-box"> <div class="title-box">
<el-tooltip :content="device.isOnline ? '在线' : '离线'" placement="top" :enterable="false"> <el-tooltip
<el-checkbox :value="hangar && device.deviceId === hangar.deviceId && device.isCheck" :content="device.isOnline ? '在线' : '离线'"
@change="(e) => handClick(e, device)"></el-checkbox> placement="top"
:enterable="false"
>
<el-checkbox
:value="
hangar &&
device.deviceId === hangar.deviceId &&
device.isCheck
"
@change="(e) => handClick(e, device)"
></el-checkbox>
</el-tooltip> </el-tooltip>
<span :title="device.name" class="title">{{ device.name }}</span> <span :title="device.name" class="title">{{ device.name }}</span>
<span class="li" v-if="!device.isOnline">(离线)</span> <span class="li" v-if="!device.isOnline">(离线)</span>
<span class="zai" v-else>(在线)</span> <span class="zai" v-else>(在线)</span>
<span :title="device.comment || '异常'" v-if="device.state == 2" style="color: red" <span
class="status-icon iconfont icon-yichang1"></span> :title="device.comment || '异常'"
<span :title="device.comment || '维修'" v-if="device.state == 3" v-if="device.state == 2"
class="status-icon iconfont icon-weixiu"></span> style="color: red"
<span :title="device.comment || '保养'" v-if="device.state == 4" class="status-icon iconfont icon-yichang1"
class="status-icon iconfont icon-baoyang"></span> ></span>
<span
:title="device.comment || '维修'"
v-if="device.state == 3"
class="status-icon iconfont icon-weixiu"
></span>
<span
:title="device.comment || '保养'"
v-if="device.state == 4"
class="status-icon iconfont icon-baoyang"
></span>
</div> </div>
<div class="icon-box"> <div class="icon-box">
<span class="type fr" v-if="device.status">{{ typeName(device.status) }}</span> <span class="type fr" v-if="device.status">{{
<span @click="onLocation(device)" class="iconfont fr icon-dingwei1" v-hover></span> 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> <span
<img src="./assets/images/jieguan_active.svg" v-if="device.currentOperator === userInfo.id" /> 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 /> <img src="./assets/images/jieguan.svg" v-else />
</span> </span>
</div> </div>
...@@ -50,16 +94,37 @@ ...@@ -50,16 +94,37 @@
</div> </div>
</template> </template>
<div class="nest-child_group_box" v-if="data.child && data.child.length"> <div class="nest-child_group_box" v-if="data.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>
</div> </div>
<el-dialog title="接管确认" :visible.sync="takeOverVisible" width="20%" :modal-append-to-body="false" <el-dialog
:append-to-body="false" :close-on-click-modal="false" @close="takeLoading = false"> 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>是否请求接管 {{ departmentName }} 下的 {{ takeDevice.name }}</span>
<span slot="footer" class="dialog-footer"> <span slot="footer" class="dialog-footer">
<el-button @click="takeOverVisible = false">取 消</el-button> <el-button @click="takeOverVisible = false">取 消</el-button>
<el-button @click="onForceTakeOver" type="danger" :loading="forceTakeLoading">强制接管</el-button> <el-button
<el-button type="primary" @click="onApplyTakeOver" :loading="takeLoading">确 认</el-button> @click="onForceTakeOver"
type="danger"
:loading="forceTakeLoading"
>强制接管</el-button
>
<el-button
type="primary"
@click="onApplyTakeOver"
:loading="takeLoading"
>确 认</el-button
>
</span> </span>
</el-dialog> </el-dialog>
</div> </div>
...@@ -122,7 +187,7 @@ export default { ...@@ -122,7 +187,7 @@ export default {
title: "接管消息", title: "接管消息",
message: msg, message: msg,
duration: 30000, duration: 30000,
offset:40 offset: 40,
}); });
this.$emit("refresh"); this.$emit("refresh");
this.takeOverVisible = false; this.takeOverVisible = false;
...@@ -131,7 +196,7 @@ export default { ...@@ -131,7 +196,7 @@ export default {
title: "接管消息", title: "接管消息",
message: msg, message: msg,
duration: 30000, duration: 30000,
offset:40 offset: 40,
}); });
this.$message.warning("申请接管拒绝"); this.$message.warning("申请接管拒绝");
} }
...@@ -150,7 +215,7 @@ export default { ...@@ -150,7 +215,7 @@ export default {
setTimeout(() => { setTimeout(() => {
if (this.takeLoading) { if (this.takeLoading) {
this.$message.error(`接管失败,申请单位未同意`); this.$message.error(`接管失败,申请单位未同意`);
this.takeLoading = false this.takeLoading = false;
} }
}, 5500); }, 5500);
if (res.code === 0) { if (res.code === 0) {
...@@ -163,7 +228,7 @@ export default { ...@@ -163,7 +228,7 @@ export default {
setTimeout(() => { setTimeout(() => {
if (this.takeLoading) { if (this.takeLoading) {
this.$message.error(`接管失败,申请单位未同意`); this.$message.error(`接管失败,申请单位未同意`);
this.takeLoading = false this.takeLoading = false;
} }
}, 5500); }, 5500);
}, },
...@@ -181,7 +246,7 @@ export default { ...@@ -181,7 +246,7 @@ export default {
this.takeOverVisible = false; this.takeOverVisible = false;
this.$emit("refresh"); this.$emit("refresh");
} }
} catch (e) { } } catch (e) {}
this.forceTakeLoading = false; this.forceTakeLoading = false;
}, },
typeName(val) { typeName(val) {
...@@ -256,7 +321,8 @@ export default { ...@@ -256,7 +321,8 @@ export default {
}); });
} }
} else { } else {
this.$message.error("该机库中没有无人机!"); // this.$message.error("该机库中没有无人机!");
console.log(device, "该机库中没有无人机!");
} }
//获取机库中视频 //获取机库中视频
...@@ -331,22 +397,30 @@ export default { ...@@ -331,22 +397,30 @@ export default {
* 接管无人机 * 接管无人机
*/ */
async onTakeOver(hangar, departmentName) { async onTakeOver(hangar, departmentName) {
<<<<<<< HEAD
// console.log('onTakeOver:',hangar); // console.log('onTakeOver:',hangar);
=======
console.log("onTakeOver:", hangar);
>>>>>>> 27917c45f08d5b25c7e99d25f541733177cce61c
//upkeepStatus保养状态, upkeepErrorCode异常信息代码,upkeepTime保养时间 //upkeepStatus保养状态, upkeepErrorCode异常信息代码,upkeepTime保养时间
const {upkeepStatus,upkeepErrorCode,upkeepTime,countdown} = hangar; const { upkeepStatus, upkeepErrorCode, upkeepTime, countdown } = hangar;
//设备超过保养时间,不能起飞 //设备超过保养时间,不能起飞
if(!upkeepStatus){ if (!upkeepStatus) {
await this.$confirm(`设备超三个月未进行保养,存在安全隐患,无法进行正常飞行!`, "温馨提示", { await this.$confirm(
`设备超三个月未进行保养,存在安全隐患,无法进行正常飞行!`,
"温馨提示",
{
cancelButtonText: "取消", cancelButtonText: "取消",
confirmButtonText: "确定", confirmButtonText: "确定",
showClose: false, showClose: false,
}); }
);
return; return;
} }
//保养周期小于20天时,提示保养 //保养周期小于20天时,提示保养
if(countdown==0 || (countdown && countdown<=20)){ if (countdown == 0 || (countdown && countdown <= 20)) {
this.$message({ this.$message({
type: "warning", type: "warning",
message: `需安排时间进行保养,上次保养时间为${upkeepTime},距离下次保养时间还有${countdown}日!超出时间将无法正常飞行!!!`, message: `需安排时间进行保养,上次保养时间为${upkeepTime},距离下次保养时间还有${countdown}日!超出时间将无法正常飞行!!!`,
...@@ -372,7 +446,7 @@ export default { ...@@ -372,7 +446,7 @@ export default {
setTimeout(() => { setTimeout(() => {
if (this.takeLoading) { if (this.takeLoading) {
this.$message.error(`接管失败,申请单位未同意`); this.$message.error(`接管失败,申请单位未同意`);
this.takeLoading = false this.takeLoading = false;
} }
}, 5500); }, 5500);
} }
...@@ -394,7 +468,7 @@ export default { ...@@ -394,7 +468,7 @@ export default {
this.$message.success(`已退出接管${hangar.name}`); this.$message.success(`已退出接管${hangar.name}`);
this.$emit("refresh"); this.$emit("refresh");
} }
} catch (e) { } } catch (e) {}
} else { } else {
// 已被接管且接管人不是自已的情况下, 需要申请接管 // 已被接管且接管人不是自已的情况下, 需要申请接管
this.takeDevice = hangar; this.takeDevice = hangar;
...@@ -403,7 +477,7 @@ export default { ...@@ -403,7 +477,7 @@ export default {
setTimeout(() => { setTimeout(() => {
if (this.takeLoading) { if (this.takeLoading) {
this.$message.error(`接管失败,申请单位未同意`); this.$message.error(`接管失败,申请单位未同意`);
this.takeLoading = false this.takeLoading = false;
} }
}, 5500); }, 5500);
} }
......
...@@ -35,8 +35,8 @@ ...@@ -35,8 +35,8 @@
<div <div
class="hangar-list_btn" class="hangar-list_btn"
@click="listCollapse = !listCollapse;" @click="listCollapse = !listCollapse;"
v-if="!hangar || (hangar && !listCollapse)"
> >
<!-- v-if="!hangar || (hangar && !listCollapse)" -->
<img style src="./assets/images/collapse.svg" /> <img style src="./assets/images/collapse.svg" />
</div> </div>
</div> </div>
...@@ -156,7 +156,7 @@ export default { ...@@ -156,7 +156,7 @@ export default {
position: absolute; position: absolute;
cursor: pointer; cursor: pointer;
right: -35px; right: -35px;
top: 50%; top: 23%;
transform: translate(0, -50%); transform: translate(0, -50%);
z-index: 99; z-index: 99;
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<div class="control-bottom"> <div class="control-bottom">
<div class="control-bottom-item" @click="onStartTask"> <div class="control-bottom-item" @click="onStartTask">
<img src="./assets/images/start.svg" /> <img src="./assets/images/start.svg" />
<span class="dib">一键任务</span> <span class="dib">一键任务 </span>
</div> </div>
<div class="control-bottom-item" @click="onReturnFlight"> <div class="control-bottom-item" @click="onReturnFlight">
<img src="./assets/images/return.svg" /> <img src="./assets/images/return.svg" />
......
...@@ -25,6 +25,12 @@ ...@@ -25,6 +25,12 @@
emitPath: false, emitPath: false,
}" @change="changeNode"></el-cascader> }" @change="changeNode"></el-cascader>
</el-form-item> </el-form-item>
<el-form-item label="终点降落:" required>
<el-radio-group v-model="finishedAction">
<el-radio label="USING_INITIAL_DIRECTION"></el-radio>
<el-radio label="GO_HOME"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="航线速度" prop="speed"> <el-form-item label="航线速度" prop="speed">
<el-input clearable v-model="curForm.speed"></el-input> <el-input clearable v-model="curForm.speed"></el-input>
</el-form-item> </el-form-item>
...@@ -135,6 +141,7 @@ export default { ...@@ -135,6 +141,7 @@ export default {
return { return {
orgList: [], orgList: [],
name: "", //航线名 name: "", //航线名
finishedAction: 'GO_HOME',//终点降落
departmentId:'',//部门id departmentId:'',//部门id
flightLabel:"",//航线标签 flightLabel:"",//航线标签
form: [], //表单集合 form: [], //表单集合
...@@ -360,7 +367,8 @@ export default { ...@@ -360,7 +367,8 @@ export default {
departmentId: this.departmentId, //部门id departmentId: this.departmentId, //部门id
name: this.name, name: this.name,
speed: this.form[0].speed, speed: this.form[0].speed,
flyTime: this.convertToSeconds(this.time) flyTime: this.convertToSeconds(this.time),
finishedAction: this.finishedAction,
}; };
try { try {
let res = await AirLine.add({ let res = await AirLine.add({
...@@ -370,6 +378,7 @@ export default { ...@@ -370,6 +378,7 @@ export default {
departmentId: airway.departmentId, departmentId: airway.departmentId,
sourceType: 1, sourceType: 1,
flyTime:airway.flyTime, flyTime:airway.flyTime,
finishedAction: airway.finishedAction,
linePointSaveReqVOS: airway.content.map((point) => ({ linePointSaveReqVOS: airway.content.map((point) => ({
latitude: point.coordinate.latitude, latitude: point.coordinate.latitude,
longitude: point.coordinate.longitude, longitude: point.coordinate.longitude,
......
...@@ -72,7 +72,7 @@ export default { ...@@ -72,7 +72,7 @@ export default {
"useSTLAirway", "useSTLAirway",
"useTask", "useTask",
]), ]),
...mapState("MMCFlightControlCenter/uav", ["uav","uavRealTimeData"]), ...mapState("MMCFlightControlCenter/uav", ["uav", "uavRealTimeData"]),
// 选择的任务 // 选择的任务
selectedTask() { selectedTask() {
let find = this.taskList.find((item) => { let find = this.taskList.find((item) => {
...@@ -176,7 +176,7 @@ export default { ...@@ -176,7 +176,7 @@ export default {
this.bus.$on("refreshAirway", this.getAirwayList); this.bus.$on("refreshAirway", this.getAirwayList);
await this.getTaskList(); await this.getTaskList();
await this.getAirwayList(); await this.getAirwayList();
console.log(this.uavRealTimeData,'this.uavRealTimeData'); console.log(this.uavRealTimeData, "this.uavRealTimeData");
// 获取正在飞行的航线 // 获取正在飞行的航线
if (this.uavRealTimeData.isFlying) { if (this.uavRealTimeData.isFlying) {
this.getTaskInfoRecord(); this.getTaskInfoRecord();
...@@ -240,7 +240,19 @@ export default { ...@@ -240,7 +240,19 @@ export default {
pageNo: 1, pageNo: 1,
pageSize: 100, pageSize: 100,
callback: (res) => { callback: (res) => {
this.airwayList = res?.records || []; this.airwayList = res?.records || [
/* {
id: item.id,
name: item.flightName,
organizationName: "无",
status: "可用", //空域状态
safe: item.safe ? 1 : 0, // 安全状态1: 安全 , 0: 待确定,
labelName: "无",
//航线数据
content,
finishedAction: "GO_HOME"
} */
];
this.$nextTick(() => { this.$nextTick(() => {
if (id) { if (id) {
this.selectedAirwayId = id; this.selectedAirwayId = id;
...@@ -266,10 +278,15 @@ export default { ...@@ -266,10 +278,15 @@ export default {
this.$message.warning("请选择航线"); this.$message.warning("请选择航线");
return; return;
} }
let diversionPoint = this.uav.diversionPoint;
if (!diversionPoint) {
return this.$message.warning("设备暂无备降点无法进行一键任务,请前往后台管理设置备降点!");
}
let data = this.taskList.filter((item) => item.id == this.selectedTaskId); let data = this.taskList.filter((item) => item.id == this.selectedTaskId);
if (data && data[0].status == "执行中") { if (data && data[0].status == "执行中") {
return this.$message.warning("当前任务执行中"); return this.$message.warning("当前任务执行中");
} }
try { try {
await this.$confirm("请确认是否进行一键任务操作?", "安全确认", { await this.$confirm("请确认是否进行一键任务操作?", "安全确认", {
cancelButtonText: "取消", cancelButtonText: "取消",
...@@ -277,6 +294,7 @@ export default { ...@@ -277,6 +294,7 @@ export default {
customClass: "uav_controlPane", customClass: "uav_controlPane",
showClose: false, showClose: false,
}); });
//
this.$store.commit("MMCFlightControlCenter/uav/setState", { this.$store.commit("MMCFlightControlCenter/uav/setState", {
key: "airlineData", key: "airlineData",
value: this.selectedAirway, value: this.selectedAirway,
......
...@@ -17,9 +17,9 @@ ...@@ -17,9 +17,9 @@
> >
<el-option <el-option
v-for="item in aiTypeList" v-for="item in aiTypeList"
:key="item.id" :key="item.typeId"
:label="item.value" :label="item.title"
:value="item.id" :value="item.typeId"
></el-option> ></el-option>
</el-select> </el-select>
<el-checkbox <el-checkbox
...@@ -262,39 +262,118 @@ export default { ...@@ -262,39 +262,118 @@ export default {
isIndeterminate: false, isIndeterminate: false,
selectAll: false, //全选 selectAll: false, //全选
viewLibTab: 0, // 视图库tab索引, 0: 视图, 1: 机载 viewLibTab: 0, // 视图库tab索引, 0: 视图, 1: 机载
aiType: 0, // 图片类型 aiType: 1, // 图片类型
aiTypeList: [ aiTypeList: [
// 普通图片或ai图片选项
{ {
id: 0, typeId: 1,
value: "全部", title: "人车识别",
}, },
{ {
id: 1, typeId: 2,
value: "人脸识别", title: "烟火识别",
}, },
{ {
id: 8, typeId: 4,
// id: 2, title: "行人识别",
value: "车牌识别",
}, },
{ {
id: 3, typeId: 5,
value: "人流识别", title: "机动车识别",
}, },
{ {
id: 4, typeId: 6,
value: "烟雾识别", title: "两轮车识别",
}, },
{ {
id: 5, typeId: 7,
value: "漏油识别", title: "三轮车识别",
}, },
{ {
id: 6, typeId: 8,
value: "裸土识别", 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:视频 fileType: "图片", //视图文件类型 0:图片;1:视频
photoList: [], //资源列表对应的对象 photoList: [], //资源列表对应的对象
photoListDate: null, //某日期的所有资源 photoListDate: null, //某日期的所有资源
......
...@@ -5,21 +5,26 @@ ...@@ -5,21 +5,26 @@
<img src="./assets/images/car1.png" @click="aiVisible = !aiVisible" /> <img src="./assets/images/car1.png" @click="aiVisible = !aiVisible" />
<div class="ai-list" v-show="aiVisible"> <div class="ai-list" v-show="aiVisible">
<el-tooltip <el-tooltip
v-for="(item,index) in aiIdentifyList" v-for="(item, index) in aiIdentifyList"
:key="index" :key="index"
:content="item.title" :content="item.title"
placement="bottom" placement="bottom"
> >
<div class="ai-item" @click="onAiIdentify(item.type)"> <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> </div>
</el-tooltip> </el-tooltip>
</div> </div>
</div> </div>
</el-tooltip> </el-tooltip>
<el-dialog :title="`${aiTitle}结果`" :visible.sync="aiResultShow" append-to-body width="700px"> <el-dialog
<div style="text-align: center;"> :title="`${aiTitle}结果`"
<img style="width: 100%;" :src="aiResultImg" /> :visible.sync="aiResultShow"
append-to-body
width="700px"
>
<div style="text-align: center">
<img style="width: 100%" crossorigin="anonymous" :src="aiResultImg" />
</div> </div>
</el-dialog> </el-dialog>
</div> </div>
...@@ -46,44 +51,234 @@ export default { ...@@ -46,44 +51,234 @@ export default {
data() { data() {
return { return {
aiVisible: false, aiVisible: false,
aiIdentifyList: [ aiIdentifyList: [],
deAiIdentifyList: [
{ {
title: "人脸识别",
type: "face",
typeId: 1, 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: "车牌识别", title: "车牌识别",
type: "plate", type: "plate",
typeId: 8,
img: require("./assets/images/车牌识别.svg"),
}, },
{ {
title: "人流识别", typeId: 10,
type: "crowd",
typeId: 3, type: "face",
img: require("./assets/images/人流识别.svg"), 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", type: "smoke",
typeId: 7, img: "https://mmc-crm.oss-cn-shenzhen.aliyuncs.com/prod/tmj-icon/ai/smoke.png",
img: require("./assets/images/烟雾识别.svg"), 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", type: "oilLeak",
typeId: 5, img: "https://mmc-crm.oss-cn-shenzhen.aliyuncs.com/prod/tmj-icon/ai/oilspill.png",
img: require("./assets/images/漏油识别.svg"), 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: "裸土识别", title: "裸土识别",
type: "bareSoil", type: "bareSoil",
typeId: 6, typeId: 35,
img: require("./assets/images/裸土识别.svg"), 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识别结果展示 aiResultShow: false, //ai识别结果展示
aiTitle: "", aiTitle: "",
aiResultImg: "", //ai结果图 aiResultImg: "", //ai结果图
...@@ -91,9 +286,43 @@ export default { ...@@ -91,9 +286,43 @@ export default {
}, },
computed: { computed: {
...mapState("MMCFlightControlCenter", ["cesiumViewer", "baseUrl"]), ...mapState("MMCFlightControlCenter", ["cesiumViewer", "baseUrl"]),
...mapState("MMCFlightControlCenter/uav", ["uav"]), ...mapState("MMCFlightControlCenter/uav", ["uav", "userInfo"]),
},
mounted() {
this.getAiconfig();
}, },
methods: { 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识别事件 * ai识别事件
*/ */
...@@ -200,7 +429,28 @@ export default { ...@@ -200,7 +429,28 @@ export default {
} }
} }
break; 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: default:
{ {
...@@ -371,11 +621,13 @@ export default { ...@@ -371,11 +621,13 @@ export default {
position: absolute; position: absolute;
left: -124px; left: -124px;
top: 0; top: 0;
width: 111px; width: 123px;
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
justify-content: space-between; justify-content: space-between;
overflow-y: auto;
max-height: 142px;
gap: 4px;
.ai-item { .ai-item {
cursor: pointer; cursor: pointer;
width: 35px; width: 35px;
......
<template> <template>
<div class="cpt-app-uav-list"> <div class="cpt-app-uav-list">
<div class="uav-item-box"> <div class="uav-item-box">
<div class="uav-item-inner" @click="$set(data, 'collapse', !data.collapse)"> <div
class="uav-item-inner"
@click="$set(data, 'collapse', !data.collapse)"
>
<div class="title-box"> <div class="title-box">
<span class="el-icon-caret-right" :class="{ collapse: data.collapse }"></span> <span
<img class="level-icon" src="./assets/images/uav_item1_1.png" v-if="level === 1" /> class="el-icon-caret-right"
<img class="level-icon" src="./assets/images/uav_item2.svg" v-if="level === 2" /> :class="{ collapse: data.collapse }"
<img class="level-icon" src="./assets/images/uav_item3.svg" v-if="level === 3" /> ></span>
<img
class="level-icon"
src="./assets/images/uav_item1_1.png"
v-if="level === 1"
/>
<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> <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>
<div class="online-info"> <div class="online-info">
(共 {{ data.onLineCount + data.offLineCount }} (共 {{ data.onLineCount + data.offLineCount }}
<span class="ml10" :class="{ online: data.onLineCount }">{{ data.onLineCount }} 在线</span> <span class="ml10" :class="{ online: data.onLineCount }"
>{{ data.onLineCount }} 在线</span
>
/ /
{{ data.offLineCount }} 离线) {{ data.offLineCount }} 离线)
</div> </div>
</div> </div>
<div class="uav-item-child-box" :class="{ collapse: data.collapse }"> <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" <Item
@refresh="$emit('refresh')" /> v-for="child in data.child"
<div class="device-item-box" :class="{ online: device.isOnline }" v-for="device in data.deviceDOList" :key="child.deptId"
:key="`device_${device.deviceId}`"> :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"> <div class="device-name">
<!-- <span <!-- <span
style="margin-right:10px" style="margin-right:10px"
:class="device.status==1&&device.currentOperator==1? 'blue' : device.status==1&&device.currentOperator!=1 ?'yellow':'' " :class="device.status==1&&device.currentOperator==1? 'blue' : device.status==1&&device.currentOperator!=1 ?'yellow':'' "
:title="device.name" :title="device.name"
>{{device.name}}</span>--> >{{device.name}}</span>-->
<span class="device-name-text" style="margin-right:10px" :class="'blue'" :title="device.name">{{ device.name }}</span> <span
<span style="color:#31DB24 " class="dib" v-if="device.isOnline">(在线)</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> <span v-else class="dib">(离线)</span>
<div class="symbol-icon-box"> <div class="symbol-icon-box">
<!-- <template v-if="device.modelName && device.modelName.includes('入云龙1')"> <!-- <template v-if="device.modelName && device.modelName.includes('入云龙1')">
...@@ -58,27 +99,67 @@ ...@@ -58,27 +99,67 @@
</div> </div>
</div> </div>
<div class="device-fns"> <div class="device-fns">
<div v-if="showVideoPanel" class="iconfont icon-luxiang_xianxing" <div
:class="{ active: uav && device.deviceId === uav.deviceId && uav.showPlayer }" title="视频" v-if="showVideoPanel"
@click="onShowPlayer(device)" v-hover></div> class="iconfont icon-luxiang_xianxing"
<div class="iconfont icon-kongzhi_xianxing" :class="{
:class="{ active: uav && device.deviceId === uav.deviceId && uav.showPanel }" title="控制面板" active:
@click="onShowPanel(device)" v-hover></div> uav && device.deviceId === uav.deviceId && uav.showPlayer,
<div class="takeover" title="接管" @click="onTakeOver(device, data.name)" v-hover> }"
<img src="./assets/images/jieguan_active.svg" v-if="device.currentOperator === userInfo.id" /> 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 /> <img src="./assets/images/jieguan.svg" v-else />
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<el-dialog title="接管确认" :visible.sync="takeOverVisible" width="20%" :modal-append-to-body="false" <el-dialog
:append-to-body="false" :close-on-click-modal="false" @close="takeLoading = false"> 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>是否请求接管 {{ departmentName }} 下的 {{ takeDevice.name }}</span>
<span slot="footer" class="dialog-footer"> <span slot="footer" class="dialog-footer">
<el-button @click="takeOverVisible = false">取 消</el-button> <el-button @click="takeOverVisible = false">取 消</el-button>
<el-button @click="onForceTakeOver" type="danger" :loading="forceTakeLoading">强制接管</el-button> <el-button
<el-button type="primary" @click="onApplyTakeOver" :loading="takeLoading">确 认</el-button> @click="onForceTakeOver"
type="danger"
:loading="forceTakeLoading"
>强制接管</el-button
>
<el-button
type="primary"
@click="onApplyTakeOver"
:loading="takeLoading"
>确 认</el-button
>
</span> </span>
</el-dialog> </el-dialog>
</div> </div>
...@@ -124,8 +205,14 @@ export default { ...@@ -124,8 +205,14 @@ export default {
"userInfo", "userInfo",
"showAirwayEdit", "showAirwayEdit",
"deptId", "deptId",
'showVideoPanel', "showVideoPanel",
]), ]),
mqttUrl() {
return this.$store.state.MMCFlightControlCenter.mqttUrl;
},
mqttToken() {
return this.$store.state.MMCFlightControlCenter.mqttToken;
},
}, },
watch: { watch: {
showAirwayEdit(newVal) { showAirwayEdit(newVal) {
...@@ -160,7 +247,7 @@ export default { ...@@ -160,7 +247,7 @@ export default {
title: "接管消息", title: "接管消息",
message: msg, message: msg,
duration: 30000, duration: 30000,
offset:40 offset: 40,
}); });
this.$emit("refresh"); this.$emit("refresh");
this.takeOverVisible = false; this.takeOverVisible = false;
...@@ -169,7 +256,7 @@ export default { ...@@ -169,7 +256,7 @@ export default {
title: "接管消息", title: "接管消息",
message: msg, message: msg,
duration: 30000, duration: 30000,
offset:40 offset: 40,
}); });
this.$message.warning("申请接管拒绝"); this.$message.warning("申请接管拒绝");
} }
...@@ -196,7 +283,7 @@ export default { ...@@ -196,7 +283,7 @@ export default {
setTimeout(() => { setTimeout(() => {
if (this.takeLoading) { if (this.takeLoading) {
this.$message.error(`接管失败,申请单位未同意`); this.$message.error(`接管失败,申请单位未同意`);
this.takeLoading = false this.takeLoading = false;
} }
}, 5500); }, 5500);
}, },
...@@ -214,7 +301,7 @@ export default { ...@@ -214,7 +301,7 @@ export default {
this.takeOverVisible = false; this.takeOverVisible = false;
this.$emit("refresh"); this.$emit("refresh");
} }
} catch (e) { } } catch (e) {}
this.forceTakeLoading = false; this.forceTakeLoading = false;
}, },
...@@ -256,7 +343,7 @@ export default { ...@@ -256,7 +343,7 @@ export default {
this.$message.success(`已退出接管${uav.name}`); this.$message.success(`已退出接管${uav.name}`);
this.$emit("refresh"); this.$emit("refresh");
} }
} catch (e) { } } catch (e) {}
} else { } else {
// 已被接管且接管人不是自已的情况下, 需要申请接管 // 已被接管且接管人不是自已的情况下, 需要申请接管
this.takeDevice = uav; this.takeDevice = uav;
...@@ -264,9 +351,30 @@ export default { ...@@ -264,9 +351,30 @@ export default {
} }
}, },
/** /**
* 显示面板 * 显示面板 点击面板时判断mqtt是否连接
*/ */
async onShowPanel(item) { async onShowPanel(item) {
let client = this.$store.state.MMCMQTT.client;
console.log("client", client);
if (!client || !client.connected) {
try {
this.$store
.dispatch("MMCMQTT/init", {
url: this.mqttUrl,
password: this.mqttToken,
})
.then(() => {
console.log("mqtt连接成功");
});
} catch (e) {
console.log("mqtt失败", e);
}
// setTimeout(() => {
// this.onShowPanel(item);
// }, 200);
// return;
}
// 选中与取消选中 // 选中与取消选中
if (this.uav?.deviceId === item.deviceId) { if (this.uav?.deviceId === item.deviceId) {
// 已打开播放器的情况下只需要展示数据面板 // 已打开播放器的情况下只需要展示数据面板
...@@ -523,12 +631,12 @@ export default { ...@@ -523,12 +631,12 @@ export default {
width: calc(100% - 90px); width: calc(100% - 90px);
white-space: nowrap; white-space: nowrap;
font-size: 13px; font-size: 13px;
.device-name-text{ .device-name-text {
display: inline-block; display: inline-block;
max-width: 100%; max-width: 100%;
white-space: nowrap; white-space: nowrap;
text-overflow: ellipsis; text-overflow: ellipsis;
overflow: hidden overflow: hidden;
} }
} }
......
...@@ -20,7 +20,9 @@ ...@@ -20,7 +20,9 @@
style="color: rgba(123, 181, 213, 1)" style="color: rgba(123, 181, 213, 1)"
></i> ></i>
</el-input> </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> </div>
<List <List
class="uav-list-main" class="uav-list-main"
...@@ -135,7 +137,7 @@ export default { ...@@ -135,7 +137,7 @@ export default {
position: absolute; position: absolute;
cursor: pointer; cursor: pointer;
right: -35px; right: -35px;
top: 50%; top: 23%;
transform: translate(0, -50%); transform: translate(0, -50%);
z-index: 99; z-index: 99;
......
...@@ -257,6 +257,7 @@ export default { ...@@ -257,6 +257,7 @@ export default {
const content = JSON.parse(data.content || "{}"); const content = JSON.parse(data.content || "{}");
const msg = content.message; const msg = content.message;
switch (type) { switch (type) {
// 接管申请 // 接管申请
case "uas-device-take-message": case "uas-device-take-message":
//接管消息 //接管消息
...@@ -344,6 +345,9 @@ export default { ...@@ -344,6 +345,9 @@ export default {
const content = JSON.parse(data.content || "{}"); const content = JSON.parse(data.content || "{}");
const msg = content.message; const msg = content.message;
switch (type) { switch (type) {
case "uas-device-take-message":
console.log(msg,'msg');
break;
// 刷新无人机列表 // 刷新无人机列表
case "uas-device-getTree-message": case "uas-device-getTree-message":
this.bus.$emit("uas-device-getTree-message", { this.bus.$emit("uas-device-getTree-message", {
......
...@@ -101,6 +101,7 @@ const actions = { ...@@ -101,6 +101,7 @@ const actions = {
}); });
} }
} }
// console.log(msgList, "机库返回数据");
commit("setState", { commit("setState", {
key: "hangarRealTimeData", key: "hangarRealTimeData",
...@@ -295,7 +296,7 @@ const actions = { ...@@ -295,7 +296,7 @@ const actions = {
* @param {function} data.callback //完成回调 * @param {function} data.callback //完成回调
*/ */
async takeOff({ state }, data) { async takeOff({ state }, data) {
console.log(state.airlineData, data, '1111'); console.log(state.airlineData, data, "1111");
try { try {
// 生成架次号 // 生成架次号
const flightSortieId = await TaskInfo.flightSortieId({ const flightSortieId = await TaskInfo.flightSortieId({
...@@ -324,7 +325,7 @@ const actions = { ...@@ -324,7 +325,7 @@ const actions = {
maxFlightSpeed: 12, maxFlightSpeed: 12,
}, },
}, },
callback() { }, callback() {},
}); });
} catch (e) { } catch (e) {
console.log("一键起飞失败", e); console.log("一键起飞失败", e);
......
...@@ -6,7 +6,7 @@ let positions = []; // 飞机走过的点, 会一直累计, 每n秒减半一次, ...@@ -6,7 +6,7 @@ let positions = []; // 飞机走过的点, 会一直累计, 每n秒减半一次,
setInterval(() => { setInterval(() => {
if (positions.length > 1000) { if (positions.length > 1000) {
positions = positions.filter((x, index) => index % 2 === 0); positions = positions.filter((x, index) => index % 2 === 0);
console.log('飞行轨迹', positions); console.log("飞行轨迹", positions);
} }
}, 60000); }, 60000);
if (!window.$mmc_stl) { if (!window.$mmc_stl) {
...@@ -14,7 +14,7 @@ if (!window.$mmc_stl) { ...@@ -14,7 +14,7 @@ if (!window.$mmc_stl) {
} }
window.$mmc_stl.positions = () => { window.$mmc_stl.positions = () => {
console.log(positions); console.log(positions);
} };
const defaultPos = { const defaultPos = {
latitude: 0, // 纬度 latitude: 0, // 纬度
longitude: 0, // 经度 longitude: 0, // 经度
...@@ -432,7 +432,7 @@ const actions = { ...@@ -432,7 +432,7 @@ const actions = {
if (item.mountId === type259.mountId) { if (item.mountId === type259.mountId) {
return { return {
...item, ...item,
...type259 ...type259,
}; };
} }
return item; return item;
...@@ -507,7 +507,11 @@ const actions = { ...@@ -507,7 +507,11 @@ const actions = {
} else { } else {
// const posData = UAVDataParser(state.uavRealTimeData); // 这种写法在执行rollup混淆压缩后, posData对象会变成elementUI的对象,原因未知 // 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) { if (!flag) {
positions.push(UAVDataParser(state.uavRealTimeData).position); positions.push(UAVDataParser(state.uavRealTimeData).position);
} }
...@@ -700,7 +704,11 @@ const actions = { ...@@ -700,7 +704,11 @@ const actions = {
* @param {object} data.taskInfoId //任务id * @param {object} data.taskInfoId //任务id
*/ */
async takeOff({ state, commit }, data) { async takeOff({ state, commit }, data) {
console.log(state.airlineData, data); let diversionPoint = state.uav.diversionPoint;
let diversionPointArr = diversionPoint.split(",");
if (diversionPointArr.length < 2) {
return console.log("备降点错误");
}
if (state.uav.network == 2) { if (state.uav.network == 2) {
try { try {
let flightSortieId; let flightSortieId;
...@@ -709,7 +717,7 @@ const actions = { ...@@ -709,7 +717,7 @@ const actions = {
taskInfoId: data.taskInfoId || undefined, taskInfoId: data.taskInfoId || undefined,
deviceId: state.uav.deviceId, deviceId: state.uav.deviceId,
reouteId: state.airlineData.id, reouteId: state.airlineData.id,
}) });
} else { } else {
// 生成架次号 // 生成架次号
flightSortieId = await TaskInfo.flightSortieId({ flightSortieId = await TaskInfo.flightSortieId({
...@@ -721,82 +729,89 @@ const actions = { ...@@ -721,82 +729,89 @@ const actions = {
/* const flightSortieId = { /* const flightSortieId = {
data: `tmj-v4-${Date.now()}` data: `tmj-v4-${Date.now()}`
} */ } */
// 上传航线指令 // 一键任务
const waypointList = state.airlineData?.content; const waypointList = state.airlineData?.content;
window.$mmc_stl.$store.dispatch("MMCMQTT/publish", { window.$mmc_stl.$store.dispatch("MMCMQTT/publish", {
topic: "PX4/OBTAIN/" + state.uav.deviceId, topic: "PX4/OBTAIN/" + state.uav.deviceId,
data: { data: {
type: window.$mmc_stl.$store.state.MMCMQTT.orders.航线上传, type: window.$mmc_stl.$store.state.MMCMQTT.orders.一键任务,
data: { data: {
taskId: state.airlineData.id, taskId: state.airlineData.id,
flightSortiesID: flightSortieId.data, flightSortiesID: flightSortieId.data,
waypointList: waypointList, waypointList: waypointList,
autoFlightSpeed: state.airlineData.baseSpeed || 6, autoFlightSpeed: state.airlineData.baseSpeed || 6,
finishedAction: "GO_HOME", finishedAction: state.airlineData.finishedAction || "GO_HOME",
headingMode: "AUTO", headingMode: "AUTO",
isExitMissionOnRCSignalLostEnabled: true, isExitMissionOnRCSignalLostEnabled: true,
maxFlightSpeed: 12, maxFlightSpeed: 12,
rallyList: [
{
longitude: diversionPointArr[0],
altitude: diversionPointArr[2],
latitude: diversionPointArr[1],
}, },
}, ],
callback() { },
});
// 告诉飞控开始任务,并且把架次号和 任务id传过去
window.$mmc_stl.$store.dispatch("MMCMQTT/publish", {
topic: "PX4/OBTAIN/" + state.uav.deviceId,
data: {
type: window.$mmc_stl.$store.state.MMCMQTT.orders.绑定任务id,
data: {
taskId: state.airlineData.id,
flightSortiesID: flightSortieId.data,
}, },
}, },
callback() { }, callback() {},
}); });
// // 告诉飞控开始任务,并且把架次号和 任务id传过去
// window.$mmc_stl.$store.dispatch("MMCMQTT/publish", {
// topic: "PX4/OBTAIN/" + state.uav.deviceId,
// data: {
// type: window.$mmc_stl.$store.state.MMCMQTT.orders.绑定任务id,
// data: {
// taskId: state.airlineData.id,
// flightSortiesID: flightSortieId.data,
// },
// },
// callback() {},
// });
// 起飞指令 // 起飞指令
commit("setState", { // commit("setState", {
key: "waitAirlineUpload", // key: "waitAirlineUpload",
value: true, // value: true,
}); // });
let time = setInterval(() => { // let time = setInterval(() => {
if (state.uavRealTimeData.uploadAirline) { // if (state.uavRealTimeData.uploadAirline) {
clearInterval(time); // clearInterval(time);
window.$mmc_stl.$store.dispatch("MMCMQTT/publish", { // window.$mmc_stl.$store.dispatch("MMCMQTT/publish", {
topic: "PX4/OBTAIN/" + state.uav.deviceId, // topic: "PX4/OBTAIN/" + state.uav.deviceId,
data: { // data: {
type: window.$mmc_stl.$store.state.MMCMQTT.orders.航线一键起飞, // type: window.$mmc_stl.$store.state.MMCMQTT.orders.航线一键起飞,
data: { // data: {
taskId: state.airlineData.id, // taskId: state.airlineData.id,
seq: 0, // seq: 0,
}, // },
}, // },
callback() { // callback() {
data?.callback && data.callback(true, flightSortieId.data); // data?.callback && data.callback(true, flightSortieId.data);
}, // },
}); // });
// 清空261数据 // // 清空261数据
let dataSet = window.$mmc_stl.$store.state.MMCMQTT.dataSet; // let dataSet = window.$mmc_stl.$store.state.MMCMQTT.dataSet;
dataSet[state.uav.deviceId][261] = null; // dataSet[state.uav.deviceId][261] = null;
window.$mmc_stl.$store.commit("MMCMQTT/setSate", { // window.$mmc_stl.$store.commit("MMCMQTT/setSate", {
key: "dataSet", // key: "dataSet",
value: dataSet, // value: dataSet,
}); // });
commit("setState", { // commit("setState", {
key: "uavRealTimeData", // key: "uavRealTimeData",
value: { // value: {
...state.uavRealTimeData, // ...state.uavRealTimeData,
uploadAirline: null, // uploadAirline: null,
}, // },
}); // });
} // }
}, 1000); // }, 1000);
// 做个保险, 要是因为各种原因导致没飞起, 超过一分钟删除循环定时器 // // 做个保险, 要是因为各种原因导致没飞起, 超过一分钟删除循环定时器
setTimeout(() => { // setTimeout(() => {
clearInterval(time); // clearInterval(time);
}, 60000); // }, 60000);
} catch (e) { } catch (e) {
console.log("一键起飞失败", e); console.log("一键起飞失败", e);
data?.callback && data.callback(false); data?.callback && data.callback(false);
...@@ -1317,7 +1332,8 @@ const actions = { ...@@ -1317,7 +1332,8 @@ const actions = {
window.$mmc_stl.$store.dispatch("MMCMQTT/publish", { window.$mmc_stl.$store.dispatch("MMCMQTT/publish", {
topic: "PX4/OBTAIN/" + state.uav.deviceId, topic: "PX4/OBTAIN/" + state.uav.deviceId,
data: { data: {
type: window.$mmc_stl.$store.state.MMCMQTT.orders.云台控制指令can包透传, type: window.$mmc_stl.$store.state.MMCMQTT.orders
.云台控制指令can包透传,
data: { data: {
mountId: data.mountId, mountId: data.mountId,
payload: data.buffer, payload: data.buffer,
...@@ -1376,7 +1392,7 @@ const actions = { ...@@ -1376,7 +1392,7 @@ const actions = {
type: window.$mmc_stl.$store.state.MMCMQTT.orders.链路切换, type: window.$mmc_stl.$store.state.MMCMQTT.orders.链路切换,
data, data,
}, },
callback() { }, callback() {},
}); });
}, },
// 键盘控制 // 键盘控制
......
...@@ -8,6 +8,7 @@ export default { ...@@ -8,6 +8,7 @@ export default {
摇杆控制: 519, 摇杆控制: 519,
航线下载: 520, 航线下载: 520,
航线上传: 521, 航线上传: 521,
一键任务: 529,
航线一键起飞: 522, 航线一键起飞: 522,
暂停航线任务: 523, 暂停航线任务: 523,
继续航线任务: 524, 继续航线任务: 524,
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论