提交 bc5e5a8a 作者: 翁进城

AI未完成

上级 40c90ae4
流水线 #10847 已失败 于阶段
......@@ -2,26 +2,25 @@
<MMCFlightControlCenter
style="width: 100%; height: 100%;"
v-if="userInfo"
:url="url"
:userInfo="userInfo"
:devMode="devMode"
:uavTaskList="uavTaskList"
:hangarTaskList="hangarTaskList"
:scene="scene"
:useSTLAirway="useSTLAirway"
:useTimedTask="useTimedTask"
:useAirway="useAirway"
@tokenInvalid="dispatchEvent('tokenInvalid')"
@uavChange="dispatchEvent('uavChange', $event)"
@uavTaskStart="dispatchEvent('uavTaskStart', $event)"
@uavTaskAdd="dispatchEvent('uavTaskAdd', $event)"
@uavAirwayAdd="dispatchEvent('uavAirwayAdd', $event)"
@taskAdd="dispatchEvent('taskAdd', $event)"
@taskBatchAdd="dispatchEvent('taskBatchAdd', $event)"
@airwayAdd="dispatchEvent('airwayAdd', $event)"
@hangarChange="dispatchEvent('hangarChange', $event)"
@hangarTaskTabChange="dispatchEvent('hangarTaskTabChange', $event)"
@hangarTaskStart="dispatchEvent('hangarTaskStart', $event)"
@hangarTaskAdd="dispatchEvent('hangarTaskAdd', $event)"
@hangarTaskDel="dispatchEvent('hangarTaskDel', $event)"
@airwayPageChange="dispatchEvent('airwayPageChange', $event)"
@taskStart="dispatchEvent('taskStart', $event)"
@taskDel="dispatchEvent('taskDel', $event)"
@airwayListGet="dispatchEvent('airwayListGet', $event)"
@airwayGet="dispatchEvent('airwayGet', $event)"
@taskListGet="dispatchEvent('taskListGet', $event)"
></MMCFlightControlCenter>
</template>
......@@ -30,81 +29,30 @@ export default {
name: "App",
data() {
return {
baseUrl: "https://test.tmj.mmcuav.cn",
devMode: false,
url: {
baseUrl: "/",
wsUrl: "wss://tmj.mmcuav.cn/websocket",
mqttUrl: "wss://fkzx.mmcuav.cn:8884/mqtt",
},
scene: 0, // 场景类型 1: 无人机 2: 机库
account: "mmctest@admin",
password: "test@Admin001",
userInfo: null,
useSTLAirway: true, // 使用标准航线
useTimedTask: false, // 使用定时任务
uavTaskList: [
],
hangarTaskList: {
// 常态
normal: [
/*
{
name: "任务1",
id: 1,
airwayId: 105,
},
{
name: "任务2",
id: 2,
airwayId: 106,
}, */
],
// 定时
timed: [
/* {
name: "任务",
id: 1,
time: "2024-04-28 01:00:00", //定时与周期的时间
status: "未执行", //任务状态
airwayId: 105,
}, */
],
// 周期
period: [
/* {
name: '任务',
id: 1,
time: '', //定时与周期的时间
status: '', 任务状态
airway: {
name: '航线名称',
id: 1
}
} */
],
},
airwayList: [
],
uavTaskList: [],
airwayList: [],
hangarTaskAddCB: null, //机库创建任务回调
uavTaskAddCB: null, //机库创建任务回调
airwayPageChangeCB: null, //航线翻页时回调
airwayGetCB: null, //获取航线数据回调
useAirway: true, //使用航线而不使用任务起飞
taskListGetCB: null, //获取任务数据回调
useAirway: true, //使用航线而不使用任务起飞
callbackList: {},
};
},
computed: {},
watch: {
devMode: {
immediate: true,
handler() {
if (this.devMode) {
this.account = "mmctest@admin";
this.password = "test@Admin001";
this.baseUrl = "https://test.tmj.mmcuav.cn";
} else {
this.account = "mmcadmin@kbt001";
this.password = "TMJMMC@kbta0227&adm";
this.baseUrl = "https://tmj.mmcuav.cn";
}
},
},
},
watch: {},
created() {
this.postTop({
type: "ready",
......@@ -130,21 +78,17 @@ export default {
* 事件处理
*/
eventHandler() {
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);
}
},
false
);
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);
}
});
},
/**
* 参数处理
* 外部平台参数传入处理
*/
paramHandler({ type, param, data }) {
if (type === "param") {
......@@ -156,10 +100,10 @@ export default {
*/
callbackHandler({ type, event, data }) {
if (type === "callback") {
let cb = this[event + "CB"];
let cb = this.callbackList[event]; // this[event + "CB"];
if (cb) {
cb(data);
this[event + "CB"] = null;
this.callbackList[event] = null;
}
}
},
......@@ -198,7 +142,7 @@ export default {
*/
dispatchEvent(event, data) {
// 回调函数不能通过postMessage传递
switch (event) {
/* switch (event) {
case "hangarTaskAdd":
this.hangarTaskAddCB = data.callback;
delete data.callback;
......@@ -218,6 +162,15 @@ export default {
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.postTop({
type: "event",
......
export { default as Control_API } from './modules/uav_control';
export { default as flightTaskAPI } from './modules/flightTask';
export { default as AirLine } from './modules/air-line';
export { default as Map } from './modules/map';
\ No newline at end of file
export { default as Map } from './modules/map';
export { default as AI_API} from './modules/ai';
\ No newline at end of file
import axios from "axios";
class AI_API {
// 人脸
static face(data){
return axios.post("http://api.user.mmcuav.cn/aidemo/facedetect", data);
}
// 车牌
static car(data) {
return axios.post("http://183.62.225.251:9090/api/inflet/v1/tasks/e01d1d01-52e2-4883-a5de-0ae268764db0/predict", data);
}
// 人流
static person(data){
return axios.post("http://183.62.225.251:9090/api/inflet/v1/tasks/18493235-4dd0-4f54-ab55-c1856ca7e3a5/predict", data);
}
// 烟雾
static smoke(data){
return axios.post("http://183.62.225.251:9090/api/inflet/v1/tasks/fca2eb65-8b99-4109-9f9e-a9f7fd06ac1f/predict", data);
}
// 漏油识别
static oilLeak(data){
return axios.post("http://183.62.225.251:9002/detect/image", data);
}
// 裸土识别
static bareSoil(data){
return axios.post("http://183.62.225.251:9090/api/inflet/v1/tasks/05a9d657-8339-4575-bced-04b60b74c690/predict", data);
}
}
\ No newline at end of file
......@@ -77,6 +77,14 @@ class Control_API {
data,
});
}
static uploadFile(data){
return request({
url: `/admin-api/infra/file/upload`,
method: "post",
data,
});
}
// 保存AI图片
// static addAiPhoto(data) {
// return request({
......
......@@ -4,10 +4,6 @@ import { resetMessage } from "./message";
import router from "../router";
import store from "../store";
let prodUrl = "http://192.168.5.80:30080";
// let prodUrl = "http://192.168.3.12:48080"; // 戴嘉骏
let devUrl = "http://192.168.5.80:30080";
const $axios = axios.create({
// baseURL: process.env.VUE_APP_BASE_API_TG
// withCredentials: true
......@@ -21,11 +17,7 @@ const loading = null;
*/
$axios.interceptors.request.use(
(config) => {
if (store.state.devMode) {
config.baseURL = devUrl;
} else {
config.baseURL = prodUrl;
}
config.baseURL = store.state.baseUrl;
const token = store.state.token;
if (token) {
......
<template>
<div class="rm-actions dialog1027" v-interact>
<div class="dialog-header">
<img class="dialog-header__icon" src="../../../../../../../../assets/images/mount_head.png" />
<div class="dialog-header__title">航点动作</div>
<div class="dialog-header__close">
<el-dropdown trigger="click">
<span class="el-dropdown-link">
<div class="icon el-icon-plus" title="添加"></div>
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item
v-for="(item, index) in actions"
@click.native="selectActions1.push(item)"
>{{ item.label }}</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<div class @click="$emit('close')">关闭</div>
</div>
</div>
<div class="rm-as-list">
<div
class="rm-as-item"
v-for="(item, i) in selectActions1"
:key="i"
:class="{double: ['云台控制'].includes(item.label)}"
>
<div class="rm-as-item__title">{{item.label}}</div>
<div class="rm-as-item__input" v-if="['间隔拍照', '悬停', '变焦'].includes(item.label)">
<div>
<el-input-number
:min="item.min"
:max="item.max"
v-if="['间隔拍照', '悬停'].includes(item.label)"
v-model="item.param1"
></el-input-number>
<el-input-number
:min="item.min"
:max="item.max"
v-if="['变焦'].includes(item.label)"
v-model="item.param2"
></el-input-number>
{{item.unit}}
</div>
</div>
<div class="rm-as-item__input" v-if="['云台控制'].includes(item.label)">
<div>
(俯仰)
<el-input-number :min="-90" :max="30" v-model="item.param1"></el-input-number>(度)
</div>
<div>
(偏航)
<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>
</div>
</div>
<div class="rm-rp-btns">
<div class="rm-rp-btn" v-hover @click="$emit('close')">取消</div>
<div class="rm-rp-btn save" v-hover @click="$emit('save', selectActions1)">保存</div>
</div>
</div>
</template>
<script>
export default {
name: "Actions",
props: {
selectActions: {
type: Array,
default() {
return [];
},
},
},
data() {
return {
actions: [
{
label: "无动作",
actionType: "",
param1: 1,
},
{
label: "间隔拍照",
actionType: "TRIGGER",
param1: 1,
unit: "米",
},
{
label: "悬停",
min: 0,
// max: 32000,
actionType: "STAY",
param1: 10,
unit: "秒",
},
{
label: "云台控制",
actionType: "GIMBAL_PITCH",
param1: 0,
param2: 0,
param3: 0,
param4: 2,
},
{
label: "开始录像",
actionType: "START_RECORD",
param1: 1,
},
{
label: "停止录像",
actionType: "STOP_RECORD",
param1: 1,
},
{
label: "变焦",
min: 0,
// max: 32000,
actionType: "CAMERA_ZOOM",
param1: 2,
param2: 0,
unit: "倍",
},
{
label: "拍照",
actionType: "START_TAKE_PHOTO",
param3: 1,
},
], //全部动作
selectActions1: [], //选中的动作
};
},
created(){
this.selectActions1 = JSON.parse(JSON.stringify(this.selectActions));
}
};
</script>
<style lang="scss" scoped>
.rm-actions {
position: absolute;
left: 480px;
top: 0;
height: 100%;
width: 420px;
background: #222222;
display: flex;
flex-direction: column;
.dialog-header__close::v-deep {
display: flex;
gap: 20px;
.icon {
color: #fff;
}
}
.rm-as-list {
padding: 16px;
flex: auto;
overflow-y: auto;
display: flex;
flex-direction: column;
gap: 16px;
.rm-as-item::v-deep {
background: #3c3c3c;
border-radius: 1px;
display: flex;
align-items: center;
font-weight: 400;
font-size: 14px;
color: #dedede;
line-height: 20px;
padding: 16px 16px;
justify-content: space-between;
&.double {
.rm-as-item__title {
width: 60px;
}
}
.el-input__inner {
height: 32px;
background: #191919;
border-radius: 2px;
border: 1px solid #4b4b4b;
}
.rm-as-item__title {
width: 120px;
}
.rm-as-item__input {
width: 140px;
flex: auto;
display: flex;
flex-direction: column;
gap: 16px;
.el-input-number {
width: 140px;
line-height: 32px;
}
.el-input-number__decrease {
width: 32px;
height: 32px;
background: transparent;
border-right: 1px solid #4b4b4b;
}
.el-input-number__increase {
width: 32px;
height: 32px;
background: transparent;
border-left: 1px solid #4b4b4b;
}
}
.rm-as-item__del {
font-size: 24px;
}
}
}
}
.rm-rp-btns {
flex: 0;
padding: 32px 0;
display: flex;
justify-content: center;
gap: 32px;
}
.rm-rp-btn {
width: 100px;
height: 32px;
border-radius: 2px;
border: 1px solid #3388ff;
font-weight: 400;
font-size: 14px;
color: #ffffff;
line-height: 16px;
display: flex;
justify-content: center;
align-items: center;
box-sizing: border-box;
&.save {
background: #3388ff;
border: none;
}
&.del {
background: #f56c6c;
border: none;
}
}
</style>
\ No newline at end of file
<template>
<div class="airway-edit dialog1027" v-interact>
<div class="dialog-header">
<img class="dialog-header__icon" src="../../../../../../assets/images/mount_head.png" />
<div class="dialog-header__title">手动规划</div>
<div class="dialog-header__close" @click="$emit('close')">关闭</div>
</div>
<div class="dialog-content">
<div class="ae-page">
<div v-hover @click="onPrev">上一航点</div>
<div>{{ pageIndex }} / {{ pageCount }}</div>
<div v-hover @click="onNext">下一航点</div>
</div>
<el-form class="ae-form" :form="curForm" label-width="100px">
<el-form-item label="航线名称" required>
<el-input clearable v-model="name"></el-input>
</el-form-item>
<el-form-item label="航线速度" prop="speed">
<el-input clearable v-model="curForm.speed"></el-input>
</el-form-item>
<el-form-item label="目标位置" prop="address">
<el-autocomplete
:popper-append-to-body="false"
v-model="curForm.address"
:fetch-suggestions="onAddressInput"
placeholder="请输入目标位置"
:trigger-on-focus="false"
@select="
(item) => {
onAddressChange(item, 'end');
}
"
clearable
>
<template slot-scope="{ item }">
<div>
<span style="font-size: 14px; color: #9e9e9e">
{{
item.name
}}
</span>
<span style="font-size: 12px; color: #999; margin-left: 12px">{{ item.address }}</span>
</div>
</template>
<el-button slot="append" icon="el-icon-location" @click="onPickAddress"></el-button>
</el-autocomplete>
</el-form-item>
<el-form-item label="纬度" prop="latitude">
<el-input clearable v-model="curForm.latitude"></el-input>
</el-form-item>
<el-form-item label="经度" prop="longitude">
<el-input clearable v-model="curForm.longitude"></el-input>
</el-form-item>
<el-form-item label="高度" prop="altitude">
<el-input clearable v-model="curForm.altitude"></el-input>
</el-form-item>
<el-form-item label="航线标签" prop="label">
<el-input clearable v-model="curForm.label"></el-input>
</el-form-item>
<el-form-item label="航点动作">
<el-button type="text" @click="showActions = true">{{curForm.actions.length}}个动作</el-button>
</el-form-item>
<el-form-item label="航线总里程">{{distance}}m</el-form-item>
<el-form-item label="预计飞行时间">{{time}}s</el-form-item>
</el-form>
<div class="ae-btns">
<el-button type="primary" @click="onSave">保存</el-button>
<el-button type="danger" @click="onDel">删除航点</el-button>
</div>
</div>
<Actions
v-if="showActions"
@close="showActions = false"
@save="onActionsSave"
:selectActions="curForm.actions"
></Actions>
</div>
</template>
<script>
import { Map } from "../../../../../../../../../../../../api";
import { mapState } from "vuex";
import Utils from "../../../../../../../../../../../../components/cesiumLayer/lib/cesium/utils";
import { nanoid } from "nanoid";
import Actions from "./components/actions";
class Airway {
uuid = nanoid();
speed = "6";
address = "";
latitude = "";
longitude = "";
altitude = "100";
label = "";
actions = [];
position = null; // cesium卡迪尔积三维数据
distance = 0; // 与上一个航点的距离
}
export default {
name: "AirwayEdit",
components: {
Actions,
},
inject: ["rootNode"],
data() {
return {
name: "", //航线名
form: [], //表单集合
pageIndex: 0, //当前页码
locationIcon: null, //定位图标
handler: null, //地图内容抓取事件
dataSource: null, //航点数据集
positions: [], //航点坐标集合
isPickAddress: false, //是否通过目标位置对地理信息
showActions: false, // 打开航点动作
};
},
computed: {
...mapState("MMCFlightControlCenter", ["cesiumViewer"]),
...mapState("MMCFlightControlCenter/hangar", ["hangar"]),
// 当前的表单
curForm() {
return this.form[this.pageIndex - 1] || new Airway();
},
//总页数,
pageCount() {
return this.form.length;
},
//总里程
distance() {
let distance = 0;
this.form.forEach((item) => {
distance += item.distance;
});
return distance;
},
//预计总时间
time() {
let time = 0;
this.form.forEach((item) => {
let speed = item.speed || 1;
time += parseInt(item.distance / speed);
});
return time;
},
},
mounted() {
let viewer = this.cesiumViewer;
this.dataSource = new Cesium.CustomDataSource("airway_edit");
viewer.dataSources.add(this.dataSource);
this.handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas); //获取事件对象
// 绘制航线
let polyline = this.dataSource.entities.add({
polyline: {
material: Cesium.Color.RED,
width: 3,
positions: new Cesium.CallbackProperty(() => {
return this.positions.map((item) => {
let wgs84 = Utils.transformCartesian2WGS84(item);
return Utils.transformWGS842Cartesian({
lng: wgs84.lng,
lat: wgs84.lat,
alt: wgs84.alt + 10,
});
});
}, false),
},
});
// 监听取点事件
this.handler.setInputAction(
this.onPickPoint,
Cesium.ScreenSpaceEventType.LEFT_CLICK
);
this.pickerPointInit();
},
beforeDestroy() {
this.handler.removeInputAction(
this.onPickPoint,
Cesium.ScreenSpaceEventType.LEFT_DOWN
);
// 直接销毁会报错
this.$nextTick(() => {
this.cesiumViewer.dataSources.remove(this.dataSource);
})
},
methods: {
// 保存航线
onSave() {
if (!this.name) {
this.$message.warning("请输入航线名称");
return;
}
if (this.form.length === 0) {
this.$message.warning("请点击地图选择航点");
return;
}
let waypoints = this.form.map((val) => {
let actions = val.actions.map((item) => {
let ret = {
actionType: item.actionType,
};
if (item.param1) {
ret.param1 = item.param1;
}
if (item.param2) {
ret.param2 = item.param2;
}
if (item.param3) {
ret.param3 = item.param3;
}
if (item.param4) {
ret.param4 = item.param4;
}
return ret;
});
return {
altitude: val.altitude,
coordinate: {
latitude: val.latitude,
longitude: val.longitude,
},
frame: 3,
speed: val.speed,
stay: 0,
waypointActions: actions,
};
});
this.rootNode.$emit("airwayAdd", {
airway: {
content: waypoints,
distance: this.distance,
dutyOrganizationId: "",
name: this.name,
speed: this.form[0].speed,
},
hangar: this.hangar,
callback: (data) => {
this.$emit('addDone', data.id);
this.$emit('close');
}
});
},
/**
* 动作保存
*/
onActionsSave(actions) {
console.log("动作", actions);
this.curForm.actions = actions;
this.showActions = false;
},
/**
* 刷新所有点,线,标签
*/
refreshPointLineLabel() {
this.distance = 0;
this.dataSource.entities.removeAll();
this.form.forEach((item, i) => {
let position = item.position;
let uuid = item.uuid;
if (this.form.length > 1 && i > 0) {
let before = this.form[i - 1].position;
let after = position;
this.curForm.distance = this.createLabel(uuid, before, after);
}
this.createPoint(uuid, position);
});
// 航线
this.dataSource.entities.add({
polyline: {
material: Cesium.Color.RED,
width: 3,
positions: new Cesium.CallbackProperty(() => {
return this.positions.map((item) => {
let wgs84 = Utils.transformCartesian2WGS84(item);
return Utils.transformWGS842Cartesian({
lng: wgs84.lng,
lat: wgs84.lat,
alt: wgs84.alt + 10,
});
});
}, false),
},
});
},
/**
* 删除航点
*/
onDel() {
if (this.pageIndex > 0) {
this.positions.splice(this.pageIndex - 1, 1);
let delForm = this.form.splice(this.pageIndex - 1, 1)[0];
this.pageIndex = Math.max(
Math.min(this.pageCount, 1),
this.pageIndex - 1
);
let viewer = this.cesiumViewer;
this.refreshPointLineLabel();
}
},
/**
* 上一航点
*/
onPrev() {
if (this.pageIndex > 0) {
this.pageIndex = Math.max(1, this.pageIndex - 1);
let position = Utils.transformWGS842Cartesian({
lng: this.curForm.longitude,
lat: this.curForm.latitude,
alt: 10000,
});
this.cesiumViewer.camera.flyTo({
destination: position,
});
}
},
/**
* 下一航点
*/
onNext() {
if (this.pageIndex < this.pageCount) {
this.pageIndex = Math.min(this.pageCount, this.pageIndex + 1);
let position = Utils.transformWGS842Cartesian({
lng: this.curForm.longitude,
lat: this.curForm.latitude,
alt: 10000,
});
this.cesiumViewer.camera.flyTo({
destination: position,
});
}
},
/**
* 地图取点事件
*/
async onPickPoint(movement) {
let viewer = this.cesiumViewer;
let entities = this.dataSource.entities;
let windowPosition = movement.position;
let pickedObject = viewer.scene.pick(windowPosition);
if (pickedObject) {
console.log("pickedObject", JSON.stringify(pickedObject.id.id));
}
if (
Cesium.defined(pickedObject) &&
pickedObject.id?.name === "airline_point"
) {
} else {
// 航点添加
let position = Utils.getCartesian3FromPX(viewer, movement.position);
if (Cesium.defined(position)) {
let wgs84 = Utils.transformCartesian2WGS84(position);
let address = await Map.Regeo({
lon: wgs84.lng,
lat: wgs84.lat,
ver: 1,
});
// 是否取地址中
if (this.isPickAddress) {
if (address) {
this.isPickAddress = false;
this.curForm.address = address;
this.curForm.longitude = wgs84.lng;
this.curForm.latitude = wgs84.lat;
this.curForm.position = position;
this.positions[this.pageIndex - 1] = position;
this.refreshPointLineLabel();
}
} else {
let form = this.formAdd();
let uuid = form.uuid;
this.pageIndex++;
this.positions.push(position);
if (address) {
form.address = address;
}
form.longitude = wgs84.lng;
form.latitude = wgs84.lat;
form.position = position;
if (this.positions.length > 1) {
let before = this.positions[this.positions.length - 2];
let after = this.positions[this.positions.length - 1];
form.distance = this.createLabel(uuid, before, after);
}
this.createPoint(uuid, position);
}
}
}
},
/**
* 选取航线初始化
*/
async pickerPointInit() {
if (this.handler) {
this.handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_DOWN);
}
},
/**
* 创建航点
*/
createPoint(uuid, position) {
let wgs84 = Utils.transformCartesian2WGS84(position);
if (this.dataSource) {
let entities = this.dataSource.entities;
entities.add({
name: "airline_point",
id: uuid,
position: Utils.transformWGS842Cartesian({
lng: wgs84.lng,
lat: wgs84.lat,
alt: wgs84.alt + 10,
}),
point: {
pixelSize: 20,
color: Cesium.Color.RED,
fillColor: Cesium.Color.RED,
// heightReference: Cesium.HeightReference.RELATIVE_TO_GROUND, // supermap版本会导致拖动显示错误
},
label: {
text: new Cesium.CallbackProperty(() => {
let index = this.form.findIndex((item) => item.uuid === uuid);
return String(index + 1);
}, false),
scale: 0.5,
font: "bold 24px Microsoft YaHei",
fillColor: Cesium.Color.WHITE,
horizontalOrigin: Cesium.VerticalOrigin.CENTER,
verticalOrigin: Cesium.VerticalOrigin.CENTER,
disableDepthTestDistance: Number.POSITIVE_INFINITY,
showBackground: false,
outlineWidth: 0,
},
});
}
},
/**
* 创建航点标签
*/
createLabel(uuid, before, after, alt) {
if (this.dataSource) {
let entities = this.dataSource.entities;
let before_wgs84 = Utils.transformCartesian2WGS84(before);
let after_wgs84 = Utils.transformCartesian2WGS84(after);
let center_lng = (before_wgs84.lng + after_wgs84.lng) / 2;
let cetner_lat = (before_wgs84.lat + after_wgs84.lat) / 2;
let alt = (after_wgs84.alt + before_wgs84.alt) / 2;
let position = Utils.transformWGS842Cartesian({
lng: center_lng,
lat: cetner_lat,
alt: alt + 10,
});
let distance = Number(
Cesium.Cartesian3.distance(before, after).toFixed(2)
);
let text = `${distance} m`;
entities.add({
id: `label_${uuid}`,
position: position,
label: {
text: text,
scale: 0.5,
font: "bold 30px Microsoft YaHei",
fillColor: Cesium.Color.fromCssColorString("#fff"),
horizontalOrigin: Cesium.VerticalOrigin.CENTER,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
disableDepthTestDistance: Number.POSITIVE_INFINITY,
showBackground: true,
backgroundPadding: new Cesium.Cartesian2(10, 10),
},
});
return distance;
}
},
/**
* 地理查询
*/
onAddressInput(address, cb) {
Map.Geo({
keyWord: address,
level: 12,
// specify: "156320900",
mapBound: "-180,-90,180,90",
queryType: 1,
start: 0,
count: 10,
})
.then((res) => {
cb(res.data.data.rows);
})
.catch((e) => cb([]));
},
// 表单位置信息索引
onAddressChange(item, type) {
if (item) {
let location = item.lonlat.split(",");
this.curForm.address = item.name;
this.curForm.longitude = Number(location[0]);
this.curForm.latitude = Number(location[1]);
let viewer = this.cesiumViewer;
let position = Utils.transformWGS842Cartesian({
lng: this.curForm.longitude,
lat: this.curForm.latitude,
alt: Number(this.curForm.altitude),
});
this.curForm.position = position;
this.positions[this.pageIndex - 1] = position;
this.refreshPointLineLabel();
let position1 = Utils.transformWGS842Cartesian({
lng: this.curForm.longitude,
lat: this.curForm.latitude,
alt: 10000,
});
viewer.camera.flyTo({
destination: position1,
});
}
},
// 点击表单旁图标定位
async onPickAddress(type) {
this.isPickAddress = true;
},
formAdd() {
let altitude = this.curForm.altitude;
let form = new Airway();
//继承上一个点的高度
form.altitude = altitude;
this.form.push(form);
return form;
},
},
};
</script>
<style lang="scss" scoped>
.airway-edit {
position: absolute;
top: -50px;
width: 450px;
.dialog-content {
display: flex;
flex-direction: column;
.ae-page {
flex-shrink: 0;
display: flex;
justify-content: space-around;
margin-bottom: 16px;
margin-top: 16px;
}
.ae-form {
flex: auto;
}
.ae-btns {
text-align: right;
}
}
}
</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 class="status">{{item.status || "暂无"}}</div>
<!-- <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"
: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"]),
},
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,
});
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;
.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: 100%;
max-height: 280px;
overflow: hidden;
overflow-y: auto;
.tb-tr {
display: flex;
color: #fff;
align-items: center;
font-size: 14px;
width: 100%;
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%);
// }
// }
// 提示框样式
.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="taskListBox">
<el-form class="task-main" label-width="70px">
<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>
</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>
<AirwayEdit v-if="showAirwayEdit" @close="showAirwayEdit = false" @addDone="getAirwayList"></AirwayEdit>
</div>
</template>
<script>
import { Utils } from "../../../../../../../../../../lib/cesium";
import { mapState, mapActions } from "vuex";
import { Control_API } from "../../../../../../../../../../api";
import AirwayEdit from "./components/airwayEdit";
const airwayEntities = []; // 航线实体
let point_entity = null;
export default {
name: "taskList",
components: { AirwayEdit },
props: {},
inject: ["rootNode", "bus"],
data() {
return {
//航线列表
airwayList: [],
// 选择的航线
selectedAirwayId: "",
// 创建航线窗口
showAirwayEdit: false,
};
},
computed: {
...mapState("MMCFlightControlCenter", ["cesiumViewer", "useSTLAirway"]),
...mapState("MMCFlightControlCenter/uav", ["uav"]),
...mapState("MMCFlightControlCenter/hangar", ["hangar"]),
// 选择的航线
selectedAirway() {
let find = this.airwayList.find((item) => {
return item.id == this.selectedAirwayId;
});
if (find) {
return find;
} else {
return {
name: "",
id: -1,
};
}
},
},
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);
}
}
},
},
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 || [];
},
});
} */
this.getAirwayList();
},
beforeDestroy() {
this.clearAirwayEntities();
},
methods: {
...mapActions("MMCFlightControlCenter", [
"createAirwayEntities",
"clearAirwayEntities",
"apiPointsToFKZXPoints",
]),
...mapActions("MMCFlightControlCenter/uav", ["isTakeOver"]),
/**
* 更新任务列表
*/
getAirwayList(id) {
console.log("getAirwayList", this.taskListAll);
this.rootNode.$emit("airwayListGet", {
pageNo: 1,
pageSize: 100,
hangar: this.hangar,
callback: (res) => {
this.airwayList = res?.records || [];
this.$nextTick(() => {
if(id){
this.selectedAirwayId = id;
}
});
},
});
},
/**
* 一键任务事件
*/
async onStartTask() {
// 判断是否已接管
if (!(await this.isTakeOver())) {
this.$message.warning("请先接管无人机");
return;
}
// 判断是否选择了航线
if (this.selectedAirway.id === -1) {
this.$message.warning("请选择航线");
return;
}
try {
await this.$confirm("请确认是否进行一键任务操作?", "安全确认", {
cancelButtonText: "取消",
confirmButtonText: "确定",
customClass: "uav_controlPane",
showClose: false,
});
this.$store.commit("MMCFlightControlCenter/uav/setState", {
key: "airlineData",
value: this.selectedAirway,
});
this.$store.dispatch("MMCFlightControlCenter/uav/takeOff", {
callback: (status) => {
if (status) {
this.$message.success("一键任务指令发送成功");
} else {
this.$message.error("一键任务指令发送失败");
}
},
});
this.rootNode.$emit("taskStart", {
uav: this.uav,
task: this.selectedTask,
airway: this.selectedAirway,
});
} catch (e) {}
},
},
};
</script>
<style lang="scss" scoped>
.taskListBox {
height: 100%;
width: 416px;
background: #222222;
border-radius: 12px;
transition: 0.3s;
display: flex;
flex-direction: column;
.header {
flex-shrink: 0;
display: flex;
justify-content: space-between;
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
);
-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%
);
border: 1px solid #70daf9;
box-shadow: inset 0 0 10px 2px #3f9dff;
font-family: MicrosoftYaHei-Bold;
font-size: 14px;
color: #70daf9;
letter-spacing: 0;
font-weight: 700;
}
.default {
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;
color: rgba(112, 218, 249, 0.5);
letter-spacing: 0;
font-weight: 700;
}
}
.task-main::v-deep {
flex: auto;
padding: 38px 16px 16px;
position: relative;
display: flex;
flex-direction: column;
.el-form-item__label {
color: #fff;
}
.btn__add-line {
position: absolute;
bottom: 20px;
right: 20px;
font-size: 10px;
color: #43deff;
cursor: pointer;
}
.el-form-item {
flex-grow: 1;
}
}
.btn {
width: 122px;
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;
cursor: pointer;
}
}
.select-airway__btn {
width: 100%;
height: 30px;
padding: 0;
}
</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="$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.airwayId" size="mini" popper-class="mmc" style="width:100%">
<el-option :label="item.name" :value="item.id" v-for="(item, index) in airwayList"></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, Control_API } from "../../../../../../../../../../../../api";
export default {
name: "TaskAdd",
inject: ["rootNode"],
data() {
return {
form: {
date: [],
time: ["00:00:00", "23:59:59"],
airwayId: "",
},
rules: {
date: [{ required: true, message: "请选择日期", trigger: "blur" }],
time: [{ required: true, message: "请选择时间", trigger: "blur" }],
airwayId: [{ required: true, message: "请选择航线", trigger: "blur" }],
},
pickerOptions: {
disabledDate: (time) => {
// 日期选择限制
return time.getTime() < Date.now() - 8.64e7;
},
},
airwayList: [], //航线列表
};
},
computed: {
...mapState("MMCFlightControlCenter/hangar", ["hangar"]),
...mapState("MMCFlightControlCenter", ["airwayEntities", "useSTLAirway"]),
/**
* 选择的日常任务数据
*/
selectedAirway() {
let find = this.airwayList.find((item) => {
return item.id === this.form.airwayId;
});
return find;
},
},
watch: {
selectedAirway: {
async handler(newVal, oldVal) {
//清除旧的航线并渲染新航线
let find = this.airwayEntities.find(
(item1) => oldVal?.id === item1.airwayId
);
if (find) {
this.clearAirwayEntities({ id: this.selectedAirway.id });
}
//渲染新航线
if (newVal) {
this.createAirwayEntities({
polyline: this.selectedAirway.content,
id: this.selectedAirway.id,
});
}
},
},
},
async mounted() {
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: 1,
pageSize: 100,
hangar: this.hangar,
callback: (data) => {
this.airwayList = data?.records || [];
},
});
}
},
methods: {
...mapActions("MMCFlightControlCenter", [
"createAirwayEntities",
"clearAirwayEntities",
]),
/**
* 确认事件
*/
onConfirm() {
this.$refs["form"].validate((valid) => {
if (valid) {
this.rootNode.$emit("taskBatchAdd", {
type: 3, //1: 日常任务 2.定时任务 3.周期任务
taskList: [{ ...this.form, airway: this.selectedAirway }], //任务数据
hangar: this.hangar,
callback: () => {
this.$emit("addDone");
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.taskStartTime}至${item.taskEndTime}`"
placement="top-start"
>
<span>{{`${item.taskStartTime}至${item.taskEndTime}`}}</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="onTaskAddClose" @addDone="onAddDone"></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",
]),
},
created() {
this.rootNode.$emit("hangarTaskTabChange", {
type: 3,
});
this.getTaskList();
},
beforeDestroy() {
this.clearAirwayEntities();
},
methods: {
...mapActions("MMCFlightControlCenter", [
"createAirwayEntities",
"clearAirwayEntities",
]),
/**
* 更新任务列表
*/
getTaskList() {
console.log("getTaskList", this.taskListAll);
this.rootNode.$emit("taskListGet", {
pageNo: 1,
pageSize: 100,
type: 3, // 1: 日常任务 2: 定时任务 3:周期任务
hangar: this.hangar,
callback: (res) => {
this.taskListAll = res.records || [];
},
});
},
/**
* 显示或隐藏航线
*/
async onSwitchAirway(item) {
this.rootNode.$emit("airwayGet", {
airwayId: item.airwayId,
callback: (airway) => {
let find = this.airwayEntities.find(
(item1) => item1.airwayId === airway.id
);
if (find) {
this.clearAirwayEntities({ id: airway.id });
} else {
this.createAirwayEntities({
polyline: airway.content,
id: airway.id,
});
}
},
});
},
async onDelAirway(item) {
try {
await this.$confirm("请确认是否删除该任务?", "安全确认", {
cancelButtonText: "取消",
confirmButtonText: "确定",
customClass: "uav_controlPane",
showClose: false,
});
this.rootNode.$emit("taskDel", {
task: item,
type: 3, // 1: 日常任务 2: 定时任务 3:周期任务
callback: () => {
this.getTaskList();
}
});
} catch (e) {
console.log(e);
}
},
onTaskAddClose() {
this.showTaskAdd = false;
},
onAddDone(){
this.getTaskList();
}
},
};
</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.airwayId"
size="mini"
popper-class="mmc"
placeholder="请选择航线"
>
<el-option
:label="item1.name"
:value="item1.id"
v-for="(item1, index) in airwayList"
></el-option>
</el-select>
<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: '',
airwayId: ''
} */
],
showMore: false,
pickerOptions: {
disabledDate: (time) => {
// 日期选择限制
return time.getTime() < Date.now() - 8.64e7;
},
},
airwayList: [], //航线列表
};
},
computed: {
...mapState("MMCFlightControlCenter/hangar", ["hangar"]),
...mapState("MMCFlightControlCenter", ["airwayEntities"]),
},
mounted(){
this.rootNode.$emit('airwayListGet', {
pageNo: 1,
pageSize: 100,
hangar: this.hangar,
callback: (data) => {
this.airwayList = data?.records || [];
}
})
},
methods: {
...mapActions("MMCFlightControlCenter", [
"createAirwayEntities",
"clearAirwayEntities",
]),
/**
* 显示或隐藏航线
*/
async onSwitchAirway(item) {
this.rootNode.$emit("airwayGet", {
airwayId: item.airwayId,
callback: (airway) => {
let find = this.airwayEntities.find(
(item1) => item1.airwayId === airway.id
);
if (find) {
this.clearAirwayEntities({ id: airway.id });
} else {
this.createAirwayEntities({
polyline: airway.content,
id: airway.id,
});
}
},
});
},
/**
* 添加新任务
*/
onTaskAdd(item) {
this.list.push({
time: "",
airwayId: "",
});
},
/**
* 删除的任务
*/
onDelTask(index) {
this.list = this.list.filter((item, i) => i !== index);
},
/**
* 确认事件
*/
onConfirm() {
let isOk = true;
this.list.some((item) => {
if (!item.time) {
this.$message.warning("请选择时间");
isOk = false;
return true;
}
if (!item.airwayId) {
this.$message.warning("请选择航线");
isOk = false;
return true;
}
});
if (isOk) {
let list = this.list.map(item => {
let find = this.airwayList.find(airway => airway.id === item.airwayId);
return {
...item,
airway: find
}
})
this.rootNode.$emit("taskBatchAdd", {
type: 2, //1: 日常任务 2.定时任务 3.周期任务
taskList: list, //任务数据
hangar: this.hangar,
callback: () => {
this.$emit("addDone");
this.$emit("close");
},
}); // 根节点发送机库任务新增事件
}
},
},
};
</script>
<style lang="scss" scoped>
.task-add {
height: 250px;
position: absolute;
top: -5px;
left: 550px;
width: 520px;
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.taskStartTime" placement="top-start">
<span>{{item.taskStartTime}}</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="onTaskAddClose" @addDone="onAddDone"></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.getTaskList();
},
beforeDestroy() {
this.clearAirwayEntities();
},
methods: {
...mapActions("MMCFlightControlCenter", [
"createAirwayEntities",
"clearAirwayEntities",
]),
/**
* 更新任务列表
*/
getTaskList() {
console.log("getTaskList", this.taskListAll);
this.rootNode.$emit("taskListGet", {
pageNo: 1,
pageSize: 100,
type: 2, // 1: 日常任务 2: 定时任务 3:周期任务
hangar: this.hangar,
callback: (res) => {
this.taskListAll = res.records || [];
},
});
},
/**
* 显示或隐藏航线
*/
async onSwitchAirway(item) {
this.rootNode.$emit("airwayGet", {
airwayId: item.airwayId,
callback: (airway) => {
let find = this.airwayEntities.find(
(item1) => item1.airwayId === airway.id
);
if (find) {
this.clearAirwayEntities({ id: airway.id });
} else {
this.createAirwayEntities({
polyline: airway.content,
id: airway.id,
});
}
},
});
},
async onDelAirway(item) {
try {
await this.$confirm("请确认是否删除该任务?", "安全确认", {
cancelButtonText: "取消",
confirmButtonText: "确定",
customClass: "uav_controlPane",
showClose: false,
});
this.rootNode.$emit("taskDel", {
task: item,
type: 2, // 1: 日常任务 2: 定时任务 3:周期任务
callback: () => {
this.getTaskList();
}
});
} catch (e) {
console.log(e);
}
},
onTaskAddClose() {
this.showTaskAdd = false;
},
onAddDone(){
this.getTaskList();
}
},
};
</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: "正在执行飞行任务",
},
];
<template>
<div class="task-list">
<div class="task-list-header">
<div class="task-list-header__item" :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">
<label>定时飞行</label>
</div>
<div class="task-list-header__item" :class="{active: tabIndex === 2}" @click="tabIndex = 2">
<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>
</div>
</div>
</template>
<script>
import NormalTask from "./components/normalTask";
import TimedTask from "./components/timedTask";
import PeriodTask from "./components/periodTask";
import { mapState } from "vuex";
export default {
name: "hangarTaskList",
components: {
NormalTask,
TimedTask,
PeriodTask,
},
data() {
return {
tabIndex: 0,
};
},
computed: {
...mapState("MMCFlightControlCenter", ["useTimedTask"]),
},
watch: {
useTimedTask() {
if (!this.useTimedTask) {
this.tabIndex = 0;
}
},
},
mounted() {},
methods: {},
};
</script>
<style lang="scss" scoped>
.task-list {
width: 416px;
height: 254px;
background: #222222;
border-radius: 10px 10px 0 0;
display: flex;
flex-direction: column;
.task-list-header {
background: #3c3c3c;
border-radius: 10px 10px 0px 0px;
height: 32px;
flex-shrink: 0;
display: flex;
.task-list-header__item {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
font-family: YouSheBiaoTiHei;
font-size: 16px;
color: #fff;
cursor: pointer;
* {
cursor: pointer;
}
&.active {
background: #3388ff;
label {
font-family: YouSheBiaoTiHei;
font-size: 20px;
color: #14faff;
line-height: 26px;
text-shadow: 0px 1px 1px rgba(2, 32, 56, 0.2);
text-align: left;
font-style: normal;
background: linear-gradient(
right,
#e3aa77,
#f5cda9,
#f9ecd3,
#fcdbb1,
#edb07a
);
line-height: 32px;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
}
}
}
.task-list-main {
flex: 1;
overflow: hidden;
}
}
</style>
\ No newline at end of file
......@@ -58,8 +58,8 @@
<el-pagination
layout="prev, pager, next"
:total="airwayData.total"
:pageSize="airwayData.size"
:currentPage.sync="airwayData.current"
:pageSize="airwayData.pageSize"
:currentPage.sync="airwayData.pageNo"
@current-change="getAirway"
></el-pagination>
</div>
......@@ -75,9 +75,9 @@ export default {
return {
keyword: null,
airwayData: {
current: 1,
pageNo: 1,
records: [],
size: 10,
pageSize: 10,
total: 0,
},
};
......@@ -109,8 +109,8 @@ export default {
async getAirway() {
if (this.useSTLAirway) {
let res = await Control_API.getUavRouteList({
pageNo: this.airwayData.current,
pageSize: this.airwayData.size,
pageNo: this.airwayData.pageNo,
pageSize: this.airwayData.pageSize,
// nestId: this.hangar.id, // TODO 目前还没有新增航线操作
});
if (res?.code === 0) {
......@@ -122,14 +122,14 @@ export default {
5: "驳回",
};
this.airwayData = (res.data.list && {
current: this.airwayData.current,
pageNo: this.airwayData.pageNo,
records: res.data.list,
size: this.airwayData.size,
pageSize: this.airwayData.pageSize,
total: res.data.total,
}) || {
current: this.airwayData.current,
pageNo: this.airwayData.pageNo,
records: [],
size: this.airwayData.size,
pageSize: this.airwayData.pageSize,
total: this.airwayData.total,
};
......@@ -148,14 +148,14 @@ export default {
});
}
} else {
this.rootNode.$emit("airwayPageChange", {
page: this.airwayData.current,
pageSize: this.airwayData.size,
this.rootNode.$emit("airwayListGet", {
pageNo: this.airwayData.pageNo,
pageSize: this.airwayData.pageSize,
callback: (data) => {
this.airwayData = data || {
current: 1,
pageNo: 1,
records: [],
size: 10,
pageSize: 10,
total: 0,
};
},
......
......@@ -203,7 +203,7 @@ export default {
}
},
});
this.rootNode.$emit("hangarTaskStart", {
this.rootNode.$emit("taskStart", {
type: 1, //1: 日常任务 2:定时任务 3:周期任务
hangar: this.hangar,
task: this.selectedTask,
......
......@@ -4,7 +4,7 @@
<img class="left-bar-item__icon" src="./assets/images/task.svg" />
<div class="left-bar-item__text">任务</div>
</div>
<TaskList class="task-list" v-if="openTask"></TaskList>
<AirwayList class="task-list" v-if="openTask"></AirwayList>
<div class="left-bar-item item" @click="onClickAI">
<img class="left-bar-item__icon" src="./assets/images/ai.svg" />
<div class="left-bar-item__text">智能识别</div>
......@@ -62,7 +62,7 @@ import { mapState } from "vuex";
import Car from "./components/car";
import Face from "./components/face";
import Jm from "./components/Jm";
import TaskList from "./components/taskList";
import AirwayList from "./components/airwayList";
import Traffic from "./components/traffic";
import PlayerInner from "./components/player/inner";
import PlayerOuter from "./components/player/outer";
......@@ -73,7 +73,7 @@ export default {
components: {
Car,
Jm,
TaskList,
AirwayList,
Traffic,
Face,
PlayerInner,
......
......@@ -13,7 +13,7 @@ export default {
return this.$store.state.MMCMQTT?.dataSet?.[this.uav?.deviceId];
},
mqttUrl() {
return this.$store.getters["MMCFlightControlCenter/mqttUrl"];
return this.$store.state.MMCFlightControlCenter.mqttUrl;
},
},
watch: {
......
......@@ -510,8 +510,8 @@ export default {
};
},
computed: {
stream() {
return this.$store.state.fckernel.stream;
isQingLiu() {
return this.$store.state.MMCFlightControlCenter.uav.isQingLiu;
}
},
watch: {
......@@ -691,7 +691,7 @@ export default {
},
type: 528
};
if (this.stream == 'QingLiu') {
if (this.isQingLiu) {
streamData.data.messageID = 1016;
} else {
streamData.data.messageID = 1007;
......@@ -711,7 +711,7 @@ export default {
},
type: 528
};
if (this.stream == 'QingLiu') {
if (this.isQingLiu) {
streamData.data.messageID = 1017;
streamData.data.data.status = this.record;
} else {
......
......@@ -595,8 +595,8 @@ export default {
};
},
computed: {
stream() {
return this.$store.state.fckernel.stream;
isQingLiu() {
return this.$store.state.MMCFlightControlCenter.uav.isQingLiu;
}
},
watch: {
......@@ -972,7 +972,7 @@ export default {
},
type: 528
};
if (this.stream == 'QingLiu') {
if (this.isQingLiu) {
streamData.data.messageID = 1016;
} else {
streamData.data.messageID = 1007;
......@@ -990,7 +990,7 @@ export default {
},
type: 528
};
if (this.stream == 'QingLiu') {
if (this.isQingLiu) {
streamData.data.messageID = 1017;
streamData.data.data.status = this.record;
} else {
......
......@@ -177,7 +177,10 @@ export default {
this.onPickPoint,
Cesium.ScreenSpaceEventType.LEFT_DOWN
);
this.cesiumViewer.dataSources.remove(this.dataSource);
// 直接销毁会报错
this.$nextTick(() => {
this.cesiumViewer.dataSources.remove(this.dataSource);
})
},
methods: {
// 保存航线
......@@ -222,7 +225,7 @@ export default {
waypointActions: actions,
};
});
this.rootNode.$emit("uavAirwayAdd", {
this.rootNode.$emit("airwayAdd", {
airway: {
content: waypoints,
distance: this.distance,
......@@ -230,10 +233,11 @@ export default {
name: this.name,
speed: this.form[0].speed,
},
callback: (data) => {
this.$emit('addDone', data.id);
this.$emit('close');
}
});
this.$nextTick(() => {
this.$emit('close');
})
},
/**
* 动作保存
......
......@@ -57,8 +57,8 @@
<el-pagination
layout="prev, pager, next"
:total="airwayData.total"
:pageSize="airwayData.size"
:currentPage.sync="airwayData.current"
:pageSize="airwayData.pageSize"
:currentPage.sync="airwayData.pageNo"
@current-change="getAirway"
></el-pagination>
</div>
......@@ -74,9 +74,9 @@ export default {
return {
keyword: null,
airwayData: {
current: 1,
pageNo: 1,
records: [],
size: 10,
pageSize: 10,
total: 0,
},
};
......@@ -107,8 +107,8 @@ export default {
async getAirway() {
if (this.useSTLAirway) {
let res = await Control_API.getUavRouteList({
pageNo: this.airwayData.current,
pageSize: this.airwayData.size,
pageNo: this.airwayData.pageNo,
pageSize: this.airwayData.pageSize,
});
if (res?.code === 0) {
let statusMap = {
......@@ -119,14 +119,14 @@ export default {
5: "驳回",
};
this.airwayData = (res.data.list && {
current: this.airwayData.current,
pageNo: this.airwayData.pageNo,
records: res.data.list,
size: this.airwayData.size,
pageSize: this.airwayData.pageSize,
total: res.data.total,
}) || {
current: this.airwayData.current,
pageNo: this.airwayData.pageNo,
records: [],
size: this.airwayData.size,
pageSize: this.airwayData.pageSize,
total: this.airwayData.total,
};
......@@ -145,14 +145,14 @@ export default {
});
}
} else {
this.rootNode.$emit("airwayPageChange", {
page: this.airwayData.current,
pageSize: this.airwayData.size,
this.rootNode.$emit("airwayListGet", {
pageNo: this.airwayData.pageNo,
pageSize: this.airwayData.pageSize,
callback: (data) => {
this.airwayData = data || {
current: 1,
pageNo: 1,
records: [],
size: 10,
pageSize: 10,
total: 0,
};
},
......
......@@ -19,7 +19,7 @@
</span>
</div>
</el-form>
<AirwayEdit v-if="showAirwayEdit" @close="showAirwayEdit = false"></AirwayEdit>
<AirwayEdit v-if="showAirwayEdit" @close="showAirwayEdit = false" @addDone="getAirwayList"></AirwayEdit>
</div>
</template>
<script>
......@@ -82,7 +82,7 @@ export default {
},
async created() {
this.bus.$on("startTask", this.onStartTask);
let res = await Control_API.getUavRouteList({
/* let res = await Control_API.getUavRouteList({
pageNo: 1,
pageSize: 100,
});
......@@ -113,7 +113,8 @@ export default {
});
}
this.airwayList = airwayList;
}
} */
this.getAirwayList();
},
beforeDestroy() {
this.clearAirwayEntities();
......@@ -126,6 +127,24 @@ export default {
]),
...mapActions("MMCFlightControlCenter/uav", ["isTakeOver"]),
/**
* 更新任务列表
*/
getAirwayList(id) {
console.log("getAirwayList", this.taskListAll);
this.rootNode.$emit("airwayListGet", {
pageNo: 1,
pageSize: 100,
callback: (res) => {
this.airwayList = res?.records || [];
this.$nextTick(() => {
if(id){
this.selectedAirwayId = id;
}
});
},
});
},
/**
* 一键任务事件
*/
async onStartTask() {
......@@ -160,10 +179,10 @@ export default {
}
},
});
this.rootNode.$emit("uavTaskStart", {
this.rootNode.$emit("taskStart", {
uav: this.uav,
selectedTask: this.selectedTask,
selectedAirway: this.selectedAirway,
task: this.selectedTask,
airway: this.selectedAirway,
});
} catch (e) {}
},
......
......@@ -222,7 +222,7 @@ export default {
waypointActions: actions,
};
});
this.rootNode.$emit("uavAirwayAdd", {
this.rootNode.$emit("airwayAdd", {
airway: {
content: waypoints,
distance: this.distance,
......
......@@ -57,8 +57,8 @@
<el-pagination
layout="prev, pager, next"
:total="airwayData.total"
:pageSize="airwayData.size"
:currentPage.sync="airwayData.current"
:pageSize="airwayData.pageSize"
:currentPage.sync="airwayData.pageNo"
@current-change="getAirway"
></el-pagination>
</div>
......@@ -74,9 +74,9 @@ export default {
return {
keyword: null,
airwayData: {
current: 1,
pageNo: 1,
records: [],
size: 10,
pageSize: 10,
total: 0,
},
};
......@@ -107,8 +107,8 @@ export default {
async getAirway() {
if (this.useSTLAirway) {
let res = await Control_API.getUavRouteList({
pageNo: this.airwayData.current,
pageSize: this.airwayData.size,
pageNo: this.airwayData.pageNo,
pageSize: this.airwayData.pageSize,
});
if (res?.code === 0) {
let statusMap = {
......@@ -119,14 +119,14 @@ export default {
5: "驳回",
};
this.airwayData = (res.data.list && {
current: this.airwayData.current,
pageNo: this.airwayData.pageNo,
records: res.data.list,
size: this.airwayData.size,
pageSize: this.airwayData.pageSize,
total: res.data.total,
}) || {
current: this.airwayData.current,
pageNo: this.airwayData.pageNo,
records: [],
size: this.airwayData.size,
pageSize: this.airwayData.pageSize,
total: this.airwayData.total,
};
......@@ -145,14 +145,14 @@ export default {
});
}
} else {
this.rootNode.$emit("airwayPageChange", {
page: this.airwayData.current,
pageSize: this.airwayData.size,
this.rootNode.$emit("airwayListGet", {
pageNo: this.airwayData.pageNo,
pageSize: this.airwayData.pageSize,
callback: (data) => {
this.airwayData = data || {
current: 1,
pageNo: 1,
records: [],
size: 10,
pageSize: 10,
total: 0,
};
},
......
......@@ -144,7 +144,7 @@ export default {
*/
onChangeLine(data) {
this.selectedAirway = data;
this.rootNode.$emit("uavTaskAdd", {
this.rootNode.$emit("taskAdd", {
airway: data,
callback: ({ id }) => {
// 返回新增任务后的任务id
......@@ -187,10 +187,10 @@ export default {
}
},
});
this.rootNode.$emit("uavTaskStart", {
this.rootNode.$emit("taskStart", {
uav: this.uav,
selectedTask: this.selectedTask,
selectedAirway: this.selectedAirway,
task: this.selectedTask,
airway: this.selectedAirway,
});
} catch (e) {}
},
......
......@@ -20,6 +20,7 @@
:is="selectMount.gimbalName"
v-if="selectMount"
class="mount-panel"
:keyFlag="nxNormal"
@directive="mountDirective"
@take_photo="mountTakePhoto"
@close="mountClose"
......@@ -61,7 +62,11 @@ export default {
"mountList",
"airlineId",
"selectMount",
"uavRealTimeData"
]),
nxNormal(){
return this.uavRealTimeData?.healthData?.NX?.warningLevel === 'NORMAL';
}
},
created() {},
mounted() {},
......
......@@ -487,9 +487,14 @@ export default {
align-items: center;
position: relative;
img {
width: 24px;
.item {
height: 24px;
width: 24px;
}
img {
width: 100%;
height: 100%;
}
.s-count {
......
<template>
<div>
<el-tooltip content="AI识别" placement="bottom">
<div class="menu-item">
<img src="../../assets/images/car1.png" @click="aiVisible = !aiVisible" />
<div class="ai-list" v-if="aiVisible">
<el-tooltip
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" />
</div>
</el-tooltip>
</div>
</div>
</el-tooltip>
<el-dialog :title="`${aiTitle}结果`" :visible.sync="aiResultShow">
<el-image style="width: 100px; height: 100px" :src="aiResultImg" fit="contain"></el-image>
</el-dialog>
</div>
</template>
<script>
import { mapState } from "vuex";
import axios from "axios";
import { Control_API } from "../../../../../../api";
import { AI_API } from "../../../../../../api";
import testImg from './img';
function blobToBase64(blob) {
return new Promise((resolve, reject) => {
let reader = new FileReader();
reader.onload = () => {
resolve(reader.result);
};
reader.readAsDataURL(blob);
});
}
export default {
name: "AIList",
data() {
return {
aiVisible: false,
aiIdentifyList: [
{
title: "人脸识别",
type: "face",
Img: require("../../assets/images/人脸识别.png"),
},
{
title: "车牌识别",
type: "car",
Img: require("../../assets/images/车牌检测.png"),
},
{
title: "人流识别",
type: "person",
Img: require("../../assets/images/人流识别.png"),
},
{
title: "火焰烟雾",
type: "smoke",
Img: require("../../assets/images/火焰烟雾.png"),
},
{
title: "漏油识别",
type: "oilLeak",
Img: require("../../assets/images/车辆识别.png"),
},
{
title: "裸土识别",
type: "bareSoil",
Img: require("../../assets/images/异物检测.svg"),
},
],
aiResultShow: false, //ai识别结果展示
aiTitle: "",
aiResultImg: "", //ai结果图
};
},
computed: {
...mapState("MMCFlightControlCenter", ["cesiumViewer"]),
...mapState("MMCFlightControlCenter/uav", ["uav"]),
},
methods: {
/**
* ai识别事件
*/
onAiIdentify(type) {
let find = this.aiIdentifyList.find((item) => item.type === type);
this.aiTitle = find.title;
// 截图做ai识别
this.$emit("screenShot", {
callback: async (blob) => {
let base64 = await blobToBase64(blob);
let results = [
/* {
x: 0,
y: 0,
width: 0,
height: 0,
label: "",
prob: 1,
}, */
];
switch (type) {
// 用的百度
case "face":
break;
// 另一种识别结果
case "bareSoil":
break;
// 共达地通用数据结构
default:
let res = await AI_API[type]({
image: base64,
});
results = res.data.targets.map((item) => {
return {
x: item.bbox.box.left_top_x,
y: item.bbox.box.left_top_y,
width:
item.bbox.box.right_bottom_x - item.bbox.box.left_top_x,
height:
item.bbox.box.right_bottom_y - item.bbox.box.left_top_x,
label: item.bbox.label,
prob: item.bbox.prob,
};
});
break;
}
// 将识别结果绘制到图片上
let img = new Image();
img.onload = function () {
let width = img.width;
let height = img.height;
console.log("图片宽度:", width, "高度:", height);
// 现在可以在Canvas上绘制图片和矩形框
let canvas = drawOnCanvas(img, width, height, results);
// 展示识别结果
this.aiResultImg = canvas.toDataURL("image/png");
this.aiResultShow = true;
// 识别结果上传到视图库
};
// img.src = base64;
img.src = testImg;
},
});
},
},
drawOnCanvas(img, width, height, aiResults) {
let canvas = document.createElement("canvas");
let ctx = canvas.getContext("2d");
// 设置Canvas大小与图片相同
canvas.width = width;
canvas.height = height;
// 绘制图片
ctx.drawImage(img, 0, 0, width, height);
// 绘制矩形框
aiResults.forEach((item) => {
ctx.beginPath();
ctx.rect(item.x, item.y, item.width, item.height); // 你可以调整这些值来改变矩形框的位置和大小
ctx.strokeStyle = "red"; // 矩形框的颜色
ctx.lineWidth = 1; // 矩形框的边框宽度
ctx.stroke();
ctx.fillStyle = "white"; // 文字颜色
ctx.textAlign = "left";
// 绘制文字背景
ctx.fillStyle = "rgba(255, 0, 0, 0.5)"; // 背景颜色
ctx.fillRect(item.x, item.y - 50, item.width, item.height); // 背景的位置和大小
// 绘制文字
ctx.fillText(`${item.label}: ${prob}`, item.x, item.y); // 文字内容和位置
});
return canvas;
},
};
</script>
<style>
</style>
\ No newline at end of file
......@@ -458,7 +458,7 @@ export default {
speed: this.speed,
};
this.rootNode.$emit('uavAirwayAdd', {
this.rootNode.$emit('airwayAdd', {
airway: data
});
this.$emit("close");
......
<template>
<!-- 清流融合 -->
<div class="player" v-interact>
<div ref="video" class="video-wrap" :class="big" @dblclick="screen">
<div class="player" :class="big" v-interact>
<div ref="video" class="video-wrap" @dblclick="screen">
<div class="cpt_video" @click="lensControl" v-if="showPlayer">
<Obstacle v-if="!isStatus"></Obstacle>
<div class="video">
......@@ -112,7 +112,11 @@
<div class="detail">{{ infoData ? infoData.vbuffer / 1000 : "0" }}ms</div>
</div>
</div>
<div class="info_isStatus" v-if="showInfo && streamSelect == 'QINGLIU'&&isStatus" v-interact>
<div
class="info_isStatus"
v-if="showInfo && streamSelect == 'QINGLIU'&&isStatus"
v-interact
>
<div class="title_box">
<div class="title pl20">
<img src="./assets/images/mount_head.png" />
......@@ -332,7 +336,7 @@
<img src="./assets/images/photojz.svg" />
</div>
</el-tooltip>
<el-tooltip content="AI识别" placement="bottom">
<!-- <el-tooltip content="AI识别" placement="bottom">
<div class="menu-item">
<img src="./assets/images/car1.png" @click="aiVisible = !aiVisible" />
<div class="ai-list" v-if="aiVisible">
......@@ -346,29 +350,10 @@
<img class="img_src" :src="item.Img" />
</div>
</el-tooltip>
<el-tooltip content="人脸识别" placement="bottom">
<div class="ai-item" @click="handle('a')">
<img src="~./assets/images/faceAI2.png" />
</div>
</el-tooltip>
<el-tooltip content="车牌识别" placement="bottom">
<div class="ai-item" @click="handle('b')">
<img src="~./assets/images/carAI.png" />
</div>
</el-tooltip>
<el-tooltip content="人流识别" placement="bottom">
<div class="ai-item" @click="frame()">
<img src="~./assets/images/trafficAI.png" />
</div>
</el-tooltip>
<el-tooltip content="车流识别" placement="bottom">
<div class="ai-item" @click="carFrame()">
<img src="~./assets/images/carAI2.png" />
</div>
</el-tooltip>
</div>
</div>
</el-tooltip>
</el-tooltip> -->
<AiList @screenShot="screenShot"></AiList>
<div class="menu-item" @click="startLinePoint" content="航点动作">
<img src="./assets/images/point_small.svg" />
</div>
......@@ -379,6 +364,7 @@
:mountData="mountDatas"
v-if="showFlywayAction"
@close="showFlywayAction = false"
@dblclick.native.stop
></PointList>
</div>
<FaceAI v-if="faceAiShow" :uavId="pid" @closeface="faceAiShow = false" />
......@@ -389,6 +375,7 @@
:trafficData="cartrafficData"
@close="cartrafficShow = false"
/>
</div>
</template>
......@@ -409,11 +396,8 @@ import Obstacle from "./components/obstacle";
import PointList from "./components/pointList";
import videoModelChange from "./components/videoModelChange";
import fkutils from "./methods/utils";
import svg1 from "./assets/images/车牌检测.svg";
import svg2 from "./assets/images/火焰烟雾.svg";
import svg3 from "./assets/images/异物检测.svg";
import svg4 from "./assets/images/跌倒检测.svg";
import svg5 from "./assets/images/游泳检测.svg";
import { mapState } from "vuex";
import AiList from './components/aiList';
export default {
name: "Player",
......@@ -428,6 +412,7 @@ export default {
Obstacle,
SRSPlayer,
videoModelChange,
AiList
},
inject: ["bus"],
props: {
......@@ -451,41 +436,55 @@ export default {
},
aiIdentifyList: [
{
title: "车牌识别",
aiType: 12,
class: "right28 top40",
Img: svg1,
title: "人脸识别",
aiType: 10,
// aiType: 1,
class: "right30",
Img: require("./assets/images/人脸识别.png"),
},
{
title: "车辆类型检测",
aiType: 9,
class: "right66 top40",
Img: svg1,
title: "车牌识别",
aiType: 8,
// aiType: 2,
class: "right-90",
Img: require("./assets/images/车牌检测.png"),
},
{
title: "火焰烟雾",
aiType: 7,
class: "right-88 top40",
Img: svg2,
title: "人流识别",
aiType: 3,
class: "right-10",
Img: require("./assets/images/人流识别.png"),
},
{
title: "异物检测",
aiType: 6,
class: "right-11 top40",
Img: svg3,
title: "火焰烟雾",
aiType: 4,
class: "right-50",
Img: require("./assets/images/火焰烟雾.png"),
},
{
title: "跌倒检测",
title: "漏油识别",
aiType: 5,
class: "right-50 top40",
Img: svg4,
class: "right70",
Img: require("./assets/images/车辆识别.png"),
},
{
title: "游泳检测",
aiType: 4,
class: " right66",
Img: svg5,
title: "裸土识别",
aiType: 6,
class: "right-90 top40",
Img: require("./assets/images/异物检测.svg"),
},
// {
// title: "跌倒检测",
// aiType: 5,
// class: "right-50 top40",
// Img: require("@/assets/newImage/跌倒检测.svg")
// },
// {
// title: "游泳检测",
// aiType: 4,
// class: " right66",
// Img: require("@/assets/newImage/游泳检测.svg")
// }
],
ygisCenterFlag: false,
ygValue: null,
......@@ -540,9 +539,12 @@ export default {
isInfoShow: false,
openOSD: true, // 是否开启OSD
showFlywayAction: false, //显示航点动作
showContinueFly: false, //显示继续飞行对话框
continueFlyContent: '', //继续飞行对话框内容
};
},
computed: {
...mapState("MMCFlightControlCenter/uav", ["uav"]),
/**
* 播放器组件名
*/
......@@ -647,6 +649,22 @@ export default {
},
watch: {
playerCom: {
immediate: true,
handler(newVal) {
if (newVal === "QingLiuPlayer") {
this.$store.commit("MMCFlightControlCenter/uav", {
key: "isQingLiu",
value: true,
});
} else {
this.$store.commit("MMCFlightControlCenter/uav", {
key: "isQingLiu",
value: false,
});
}
},
},
uavRealTimeData: function (newval) {
let gps = null;
if (
......@@ -863,7 +881,7 @@ export default {
},
});
},
//游泳识别
//AI识别
async aiIdentifyType(aiType) {
const data = {
deviceId: this.device.deviceId,
......@@ -902,7 +920,7 @@ export default {
});
}
} else {
this.$message.success("截屏失败");
this.$message.warning("截屏失败");
}
},
// 人脸车牌识别
......
......@@ -6,17 +6,14 @@ import pngAisu from '../assets/images/aisu.png';
import pngAier from '../assets/images/aier.png';
import pngAiing from '../assets/images/aiing.png';
// 识别类型 4 代表游泳 5:跌倒检测 6:异物检测7:火焰烟雾8:车辆朝向9:车辆类型检测 10:车道分割线 11:绿化带分割12:车牌识别
// 识别类型 2 车牌(公安) 3:人流 4:火焰烟雾 5:漏油识别6.裸土识别8.车牌(共达地)
let urlList = {
4: "http://32.128.6.151:9090/api/inflet/v1/tasks/3b2c435f-0652-418c-82d0-37efed27e9c1/predict",
5: "http://32.128.6.151:9090/api/inflet/v1/tasks/f1017eee-bbe2-4b24-bc16-a61c49c52451/predict",
6: "http://32.128.6.151:9090/api/inflet/v1/tasks/8811f0de-8cda-48f1-9e0c-b556ae1b22ee/predict",
7: "http://32.128.6.151:9090/api/inflet/v1/tasks/296c2a65-ed65-428f-a3f8-680747c3e1ef/predict",
8: "http://32.128.6.151:9090/api/inflet/v1/tasks/9d2f312d-c8d1-4e17-bb6c-0149ed77cee4/predict",
9: "http://32.128.6.151:9090/api/inflet/v1/tasks/f971b94f-a63e-4094-aa16-2a5b4ce4e468/predict",
10: "http://32.128.6.151:9090/api/inflet/v1/tasks/aad14687-7a17-46df-b0e4-9664e4e529d9/predict",
11: "http://32.128.6.151:9090/api/inflet/v1/tasks/b27e6ebd-feed-4011-a794-9d8a69b20084/predict",
12: "http://32.128.6.151:9090/api/inflet/v1/tasks/3b96b26d-dfd0-4362-8031-d77c7bfed369/predict"
2: "http://183.62.225.251:9090/api/inflet/v1/tasks/e01d1d01-52e2-4883-a5de-0ae268764db0/predict",
3: "http://183.62.225.251:9090/api/inflet/v1/tasks/18493235-4dd0-4f54-ab55-c1856ca7e3a5/predict",
4: "http://183.62.225.251:9090/api/inflet/v1/tasks/fca2eb65-8b99-4109-9f9e-a9f7fd06ac1f/predict",
5: "http://183.62.225.251:9002/detect/image",
6: "http://183.62.225.251:9090/api/inflet/v1/tasks/05a9d657-8339-4575-bced-04b60b74c690/predict",
8: "http://183.62.225.251:9090/api/inflet/v1/tasks/e01d1d01-52e2-4883-a5de-0ae268764db0/predict",
}
export default {
// 人脸车牌识别
......@@ -189,81 +186,93 @@ export default {
},
//ai识别
async aiIdentify(aiData, flag, single) {
console.log(aiData,"aiData");
let {
mqttType, //发送数据类型 true 代表无人机 false 代表鹰巢
mqttType, //发送数据类型 true 代表无人机 false 代表机库
deviceHardId,
id,
aiType, // 识别类型 4 代表游泳 5:跌倒检测 6:异物检测7:火焰烟雾8:车辆朝向9:车辆类型检测 10:车道分割线
aiType, // 识别类型 2 车牌(公安) 3:人流 4:火焰烟雾 5:漏油识别6.裸土识别8.车牌(共达地)
} = aiData
let blob = this.screenShot();
let data = {
image: null,
};
if (aiType > 3) {
if (aiType > 1 && aiType != 5 && aiType != 2 && aiType != 10) {
blobToBase64(blob, async (base64DataUrl) => {
data.image = base64DataUrl;
// console.log(aiData.aiType,"aiTypeaiTypev");
let res = await axios.post(
urlList[aiType],
data
);
// if(this.indexswim == 10){
if (res.data.data.targets && res.data.data.targets.length > 0) {
// clearInterval(this.AISetInterval);
// this.AISetInterval = null;
this.timerList.forEach(v => {
clearInterval(v)
})
this.timerList = []
// if (aiType == 4) {
if (flag) {
if (aiType != 12) {
if (aiType != 10) {
this.$message.success("识别成功!")
}
} else {
if (mqttType) {
this.$emit("fn", {
data: "HOLD",
type: 513
}, "wrj");
} else if(!mqttType && aiType != 6) {
// } else {
this.$emit("fn", {
data: "POSITION",
type: 513
if (this.uav.network == 2) {
this.$store.dispatch("MMCMQTT/publish", {
topic: "PX4/OBTAIN/" + this.uav.deviceId,
data: {
type: window.$mmc.$store.state.MMCMQTT.orders.无人机模式切换,
data: "HOLD",
},
callback() {
},
});
} else {
}
if (aiType == 4) {
this.$emit("AIDialog", true, "当前识别到有人游泳");
await this.$confirm("当前区域识别到烟雾", "提示", {
cancelButtonText: "取消",
confirmButtonText: "继续飞行",
customClass: "uav_controlPane",
showClose: false,
})
this.$store.dispatch("MMCMQTT/publish", {
topic: "PX4/OBTAIN/" + this.uav.deviceId,
data: {
type: window.$mmc.$store.state.MMCMQTT.orders.无人机模式切换,
data: "AUTO_MISSION",
},
callback() {
},
});
} else if (aiType == 5) {
this.$emit("AIDialog", true, "当前识别到有人员跌倒");
} else if (aiType == 6) { //
this.$emit("AIDialog", true, "当前区域识别到异物");
// let deviceTyoe = null
// if (mqttType) {
// deviceTyoe = 0
// } else {
// deviceTyoe = 1
// }
// 识别到异物后机载拍照三张
// stream 视频播放类型 deviceTyoe 代表无人机类型
// let stream = this.$store.state.fckernel.stream
// this.photoNX(id, stream, deviceTyoe, true)
// this.photoNX(id, stream, deviceTyoe, true)
// this.photoNX(id, stream, deviceTyoe, true)
} else if (aiType == 7) {
this.$emit("AIDialog", true, "当前区域识别到烟雾");
await this.$confirm("当前识别到有漏油", "提示", {
cancelButtonText: "取消",
confirmButtonText: "继续飞行",
customClass: "uav_controlPane",
showClose: false,
})
this.$store.dispatch("MMCMQTT/publish", {
topic: "PX4/OBTAIN/" + this.uav.deviceId,
data: {
type: window.$mmc.$store.state.MMCMQTT.orders.无人机模式切换,
data: "AUTO_MISSION",
},
callback() {
},
});
}
// else if (aiType == 6) { //
// this.$emit("AIDialog", true, "当前区域识别到异物");
// }
else if (aiType == 7) { }
this.getPopup(true)
}
// }
let fd = new FormData();
fd.append("uploadFiles", blob, `下载.jpeg`);
let res2 = await API.MAPMANAGE.fileUpload(fd);
let carJson = res.data.data//出鬼了,无人机识别车辆没用,鹰巢有用,才写的
if (aiType != 12) {
let carJson = res.data.data //出鬼了,无人机识别车辆没用,机库有用,才写的
if (aiType != 2) {
let data2 = {
aiType: aiType,
imageUrl: res2[0].storage,
......@@ -313,26 +322,118 @@ export default {
}
}
});
} else if (aiType <= 3) {
let fd = new FormData();
fd.append("uploadFiles", blob, `下载.jpeg`);
let res = await API.MAPMANAGE.fileUpload(fd);
if (aiData.spaceFlag) {
if (aiType == 1) {
this.aiuseV2(res[0].storage, deviceHardId, single, aiData.spaceFlag)
} else if (aiType == 2) {
this.plateV2(res[0].storage, deviceHardId, single, aiData.spaceFlag)
} else if (aiType == 3) {
this.flowV2(res[0].storage, deviceHardId, single, aiData.spaceFlag);
} else {
if (aiType == 5) {
let fds = new FormData();
fds.append("image", blob, `下载.jpeg`);
fds.append("iscount", 1);
let res = await axios.post(
urlList[aiType],
fds
);
if (res && res.data && res.data.data && res.data.data.data.length > 0) {
this.timerList.forEach(v => {
clearInterval(v)
})
this.timerList = []
if (flag) {
if (aiType != 10) {
this.$message.success("识别成功!")
}
} else {
if (mqttType) {
this.$emit("fn", {
data: "HOLD",
type: 513
}, "wrj");
} else if (!mqttType) {
// } else {
this.$emit("fn", {
data: "POSITION",
type: 513
});
}
this.getPopup(true)
}
// }
let fd = new FormData();
fd.append("uploadFiles", blob, `下载.jpeg`);
let res2 = await API.MAPMANAGE.fileUpload(fd);
if (aiType != 2) {
let data2 = {
aiType: aiType,
imageUrl: res2[0].storage,
deviceHardId: deviceHardId,
jsonData: JSON.stringify(res.data.data),
};
let swimres = await API.FCKERNEL.insertSwimmingMonitor(data2);
}
// process.env.VUE_APP_IMG_URL +
let imgshowurl = process.env.VUE_APP_IMG_URL + res2[0].url;
let jsondata = {
jsonData: JSON.stringify(res.data.data)
}
this.$emit("imgUrl", imgshowurl, aiType, jsondata);
} else {
if (single) {
this.getPopup(false)
}
// this.$message.error("无识别结果!")
if (flag) {
this.photoSelf(deviceHardId, true)
}
}
} else {
if (aiType == 1) {
this.aiuseV2(res[0].storage, deviceHardId, single)
} else if (aiType == 2) {
this.plateV2(res[0].storage, deviceHardId, single)
} else if (aiType == 3) {
this.flowV2(res[0].storage, deviceHardId, single);
} else if(aiType == 10){
// let token = await API.MAPMANAGE.getToken();
// console.log(token,"token");
// let data = {
// image_type: "BASE64",
// }
let fd = new FormData();
fd.append("image", blob, `下载.jpeg`);
let res = await API.MAPMANAGE.detect(fd);
if (res.code == 0) {
let fd2 = new FormData();
fd2.append("uploadFiles", blob, `下载.jpeg`);
let res2 = await API.MAPMANAGE.fileUpload(fd2);
let data2 = {
aiType: aiType,
imageUrl: res2[0].storage,
deviceHardId: deviceHardId,
jsonData: JSON.stringify(res.data),
};
let swimres = await API.FCKERNEL.insertSwimmingMonitor(data2);
let imgshowurl = process.env.VUE_APP_IMG_URL + res2[0].url;
let jsondata = {
jsonData: JSON.stringify(res.data)
}
this.$emit("imgUrl", imgshowurl, aiType, jsondata);
} else {
if (flag) {
this.photoSelf(deviceHardId, true)
}
}
console.log(res,"baidures");
// blobToBase64(blob, async (base64DataUrl) => {
// data.image = base64DataUrl;
// })
} else {
if (aiType != 0) {
let fd = new FormData();
fd.append("uploadFiles", blob, `下载.jpeg`);
let res = await API.MAPMANAGE.fileUpload(fd);
if (aiData.spaceFlag) {
if (aiType == 1) {
this.aiuseV2(res[0].storage, deviceHardId, single, aiData.spaceFlag)
}
} else {
if (aiType == 1) {
this.aiuse()
} else if (aiType == 2) {
this.plate()
}
}
}
}
}
......
......@@ -10,7 +10,7 @@ export default {
return this.$store.state.MMCGroundStation?.dataSet?.[this.uav?.deviceId];
},
mqttUrl() {
return this.$store.getters["MMCFlightControlCenter/mqttUrl"];
return this.$store.state.MMCFlightControlCenter.mqttUrl;
},
},
watch: {
......
......@@ -31,80 +31,22 @@ export default {
MapSearch,
},
props: {
devMode: {
// 开发环境
type: Boolean,
default: false,
url: {
// api地址前缀
type: Object,
default: () => {
return {
baseUrl: "/",
wsUrl: "wss://tmj.mmcuav.cn/websocket",
mqttUrl: "wss://fkzx.mmcuav.cn:8884/mqtt",
};
},
},
// 天目将登录用户信息
userInfo: {
type: Object,
default: null,
},
// 无人机任务列表
uavTaskList: {
type: Array,
default() {
return [
/* {
name: '任务',
id: 1,
children: [],
airway: {
name: '航线名称',
id: 1
}
} */
];
},
},
// 机库任务列表
hangarTaskList: {
type: Object,
default() {
return {
// 常态
normal: [
/* {
name: '任务',
id: 1,
status: '', 任务状态
children: [],
airway: {
name: '航线名称',
id: 1
}
} */
],
// 定时
Timed: [
/* {
name: '任务',
id: 1,
time: '', //定时与周期的时间
status: '', 任务状态
airway: {
name: '航线名称',
id: 1
}
} */
],
// 周期
period: [
/* {
name: '任务',
id: 1,
time: '', //定时与周期的时间
status: '', 任务状态
airway: {
name: '航线名称',
id: 1
}
} */
],
};
},
},
// 场景 1: 无人机 2: 机库
scene: {
type: Number,
......@@ -128,8 +70,8 @@ export default {
// 使用航线而不使用任务起飞
useAirway: {
type: Boolean,
default: true
}
default: true,
},
},
data() {
return {
......@@ -143,23 +85,21 @@ export default {
};
},
watch: {
uavTaskList: {
url: {
immediate: true,
handler(newVal) {
this.$store.commit("MMCFlightControlCenter/uav/setState", {
key: "taskList",
value: newVal,
this.$store.commit("MMCFlightControlCenter/setState", {
key: "baseUrl",
value: newVal.baseUrl,
});
},
},
hangarTaskList: {
immediate: true,
handler(newVal) {
this.$store.commit("MMCFlightControlCenter/hangar/setState", {
key: "taskList",
value: newVal,
this.$store.commit("MMCFlightControlCenter/setState", {
key: "wsUrl",
value: newVal.wsUrl,
});
this.$store.commit("MMCFlightControlCenter/setState", {
key: "mqttUrl",
value: newVal.mqttUrl,
});
this.bus.$emit("updateHangarTaskList");
},
},
useSTLAirway: {
......@@ -203,10 +143,6 @@ export default {
},
created() {
this.$store.commit("MMCFlightControlCenter/setState", {
key: "devMode",
value: this.devMode,
});
this.$store.commit("MMCFlightControlCenter/setState", {
key: "token",
value: this.userInfo.accessToken,
});
......@@ -289,6 +225,27 @@ export default {
}
}
div[class*="cpt-MMC_Gimbal"] {
background: #222222;
border-radius: 10px 10px 0px 0px;
border: 0;
.hd {
box-sizing: border-box;
padding-left: 32px;
padding-right: 16px;
background-position: 12px 4px;
height: 32px;
width: 100%;
background: #3c3c3c;
border-radius: 10px 10px 0px 0px;
display: flex;
justify-content: space-between;
align-items: center;
position: relative;
box-shadow: none;
}
}
.dialog1027 {
z-index: 1;
background: #222222;
......@@ -340,7 +297,7 @@ export default {
.dialog-header__close {
font-size: 14px;
font-family: MicrosoftYaHei;
color: #ACACAC;
color: #acacac;
line-height: 19px;
cursor: pointer;
}
......@@ -502,7 +459,7 @@ export default {
position: relative;
background: #191919;
border: 1px solid #4B4B4B;
border: 1px solid #4b4b4b;
}
&.is-multiple {
......
......@@ -35,6 +35,9 @@ export default {
useSTLAirway: true, //是否使用标准航线库
useTimedTask: false, //是否使用定时任务
useAirway: true, //使用航线而不使用任务起飞
baseUrl: '', //api请求的base url
wsUrl: '', //websocket的url
mqttUrl: '' //mqtt的url
},
mutations: {
/**
......@@ -271,6 +274,7 @@ export default {
},
},
getters: {
/*
//地面站websocket url
wsUrl(state) {
if (!state.devMode) {
......@@ -287,7 +291,7 @@ export default {
return "wss://test.fkzx.mmcuav.cn:8884/mqtt";
// return "wss://fkzx.mmcuav.cn:8884/mqtt";
}
},
}, */
},
modules: {
uav,
......
......@@ -194,20 +194,7 @@ const state = {
selectMount: null, // 选中的挂载
showPlayer: false, //显示播放器
showPanel: false, //显示数据面板
// 任务列表
taskList: [
/* {
name: "任务",
id: 1,
children: [],
airway: {
name: "航线名称1",
id: 1,
content:
'{"filename":"肇庆航线20240318","line":{"baseSpeed":3},"content":[{"uuid":"1nmI-Fo18IagbcVJsia7Q","latitude":23.178153411812204,"longitude":112.57807281336807,"alt":100,"yawAngle":0,"pitchAngle":0,"speed":3,"actions":[]},{"uuid":"9pTbBPlF8iIwbUNqusyHK","latitude":23.17783116525969,"longitude":112.57797543441967,"alt":100,"yawAngle":0,"pitchAngle":0,"speed":3,"actions":[]},{"uuid":"s91IhN22wuaeyG-UQs0XR","latitude":23.17786413506686,"longitude":112.57824336604547,"alt":100,"yawAngle":0,"pitchAngle":0,"speed":3,"actions":[]},{"uuid":"xS_JIl3wxQrhMPdpcjcSn","latitude":23.17820934975604,"longitude":112.5781357731637,"alt":100,"yawAngle":0,"pitchAngle":0,"speed":3,"actions":[]}],"baseSpeed":3,"gimbalYaw":0,"gimbalPitch":0,"alt":100}',
},
}, */
],
isQingLiu: null, // 当前视频播放的是否为清流
};
const mutations = {
......@@ -481,7 +468,7 @@ const actions = {
const token = window.$mmc.$store.state.MMCFlightControlCenter.token;
window.$mmc.$store
.dispatch("MMCGroundStation/init", {
url: window.$mmc.$store.getters["MMCFlightControlCenter/wsUrl"],
url: window.$mmc.$store.state.MMCFlightControlCenter.wsUrl,
userInfo: {
type: 100,
systemCode: "mmc",
......
......@@ -22,6 +22,8 @@ export default {
} */
},
orders, //所有指令
username: 'tmj',
password: 'Tmj@192D9'
},
mutations: {
/**
......@@ -57,6 +59,8 @@ export default {
init({ commit, state }, data) {
let clientId = Date.now();
let client = mqtt.connect(data.url, {
username: state.username,
password: state.password,
clientId,
});
......
......@@ -87,8 +87,12 @@ export default {
data() {
return {
isIframeReady: false, //是否接收到iframe里的ready事件
baseUrl: "http://192.168.5.80:30080",
devMode: false,
url: {
baseUrl: "/",
wsUrl: "wss://tmj.mmcuav.cn/websocket",
mqttUrl: "wss://fkzx.mmcuav.cn:8884/mqtt",
},
scene1: false, // 场景类型 true: 无人机 false: 机库
useSTLAirway: false, // 使用标准航线库
useTimedTask: false, // 使用定时任务
......@@ -167,6 +171,7 @@ export default {
} */
],
},
postIframeList: [], //给iframe传递参数的队列
};
},
computed: {
......@@ -175,28 +180,37 @@ export default {
},
},
watch: {
/* isIframeReady(){
if(this.isIframeReady){
this.login();
isIframeReady() {
if (this.isIframeReady) {
this.postIframeList.forEach((item) => {
this.postIframe(item);
});
}
}, */
},
devMode: {
immediate: true,
handler() {
if (this.devMode) {
this.account = "admin";
this.password = "mmc@123456";
this.baseUrl = "http://192.168.5.80:30080";
this.url = {
baseUrl: "http://192.168.5.80:30080",
wsUrl: "wss://tmj.mmcuav.cn/websocket",
mqttUrl: "wss://fkzx.mmcuav.cn:8884/mqtt",
};
} else {
this.account = "admin";
this.password = "mmc@123456";
this.baseUrl = "http://192.168.5.80:30080";
// this.baseUrl = "http://192.168.3.12:48080"; // 戴嘉骏
this.url = {
baseUrl: "http://192.168.5.80:30132",
wsUrl: "wss://tmj.mmcuav.cn/websocket",
mqttUrl: "wss://fkzx.mmcuav.cn:8884/mqtt",
};
}
this.postIframe({
type: "param",
param: "devMode",
data: this.devMode,
param: "url",
data: this.url,
});
},
},
......@@ -278,6 +292,7 @@ export default {
*/
postIframe(data) {
if (!this.isIframeReady) {
this.postIframeList.push(data);
throw Error("iframe未准备好");
}
let iframeWindow = this.$refs.iframe.contentWindow;
......@@ -636,12 +651,12 @@ export default {
let formData = new FormData();
formData.append("userAccount", this.account);
formData.append("password", Base64.encode(this.password));
let res = await fetch(this.baseUrl + "/admin-api/system/auth/login", {
let res = await fetch(this.url.baseUrl + "/admin-api/system/auth/login", {
method: "post",
headers: {
"Content-Type": "application/json",
"Tenant-Id": 1,
"terminal": 2
terminal: 2,
},
body: JSON.stringify({
username: this.account,
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论