提交 a0346bba 作者: 翁进城

feat: 飞控中心,右侧 健康管理, 挂载, 无人机(轨迹, 继续飞行, 暂停飞行, 紧急迫降, 运行日志)

上级 494889e0
......@@ -10,6 +10,7 @@ import MMCUavList from "./src/components/MMCUavList";
import MMCMQTT from './src/plugins/MMCMQTT';
import MMCGroundStation from "./src/plugins/MMCGroundStation";
import MMCFlightControlCenter from './src/components/MMCFlightControlCenter';
import SymbolIcon from './src/components/symbol-icon';
const components = [
......@@ -17,7 +18,8 @@ const components = [
MMCDataTransferPanel,
MMCPlayer,
MMCUavList,
MMCFlightControlCenter
MMCFlightControlCenter,
SymbolIcon
];
const plugins = [MMCMQTT, MMCGroundStation];
......
......@@ -26,7 +26,7 @@
"global": "^4.4.0",
"interactjs": "^1.10.17",
"jspack": "^0.0.4",
"moment": "^2.29.4",
"moment": "^2.30.1",
"mqtt": "^4.3.6",
"prismjs": "^1.29.0",
"recorder-core": "^1.2.23020100",
......
<template lang="">
<div class="nest_info_maxBox">
<div class="infoBox cf" v-if="!wsShow">
<div class="dib title">
{{ props_obj.relativeAlt ? props_obj.relativeAlt.toFixed(2) : 0 }}
</div>
m
<div class="cf infor">飞行高度</div>
</div>
<div class="infoBox cf" v-else>
<div class="infoBox cf">
<div class="dib title">
{{ (uavData && uavData.height) ? uavData.height.toFixed(2) : 0 }}
{{ uavData.relativeAlt }}
</div>
m
<div class="cf infor">飞行高度</div>
</div>
<div class="infoBox cf" v-if="!wsShow">
<div class="infoBox cf">
<div class="dib title">
{{ props_obj.absoluteAlt ? props_obj.absoluteAlt.toFixed(2) : 0 }}
{{ uavData.absoluteAlt }}
</div>
m
<div class="cf">海拔高度</div>
</div>
<div class="infoBox cf" v-else>
<div class="dib title">
{{ (uavData && uavData.altitude) ? uavData.altitude.toFixed(2) : 0 }}
</div>
m
<div class="cf">海拔高度</div>
</div>
<div class="infoBox cf" v-if="!isM300 && !wsShow">
<div class="dib title">
{{ props_obj.flyDistance ? props_obj.flyDistance.toFixed(2) : 0 }}
</div>
m
<div class="cf">飞行里程</div>
</div>
<div class="infoBox cf" v-else>
<div class="infoBox cf">
<div class="dib title">
{{ (uavData && uavData.flightDistance) ? uavData.flightDistance.toFixed(2) : 0 }}
{{ uavData.flyDistance }}
</div>
m
<div class="cf">飞行里程</div>
......@@ -46,55 +24,28 @@
<div class="infoBox cf">
<div class="dib title">
{{
uavData && uavData.distanceToHome
? uavData.distanceToHome.toFixed(2)
: 0
}}
{{ uavData.distanceToHome }}
</div>
m
<div class="cf">起点距离</div>
</div>
<div class="infoBox cf" v-if="!wsShow">
<div class="dib title">
{{ props_obj.flyTime ? (props_obj.flyTime / 60).toFixed(2) : 0 }}
</div>
min
<div class="cf">飞行时间</div>
</div>
<div class="infoBox cf" v-else>
<div class="infoBox cf">
<div class="dib title">
{{ (uavData && uavData.flightTime) ? (uavData.flightTime / 60).toFixed(2) : 0 }}
{{ uavData.flyTime }}
</div>
min
<div class="cf">飞行时间</div>
</div>
<div class="infoBox cf" v-if="!wsShow">
<div class="dib title">
{{ props_obj.groundSpeed ? props_obj.groundSpeed.toFixed(2) : 0 }}
</div>
m/s
<div class="cf">飞行速度</div>
</div>
<div class="infoBox cf" v-else>
<div class="infoBox cf">
<div class="dib title">
{{
(uavData && uavData.groundSpeed.toFixed(2)) ? uavData.groundSpeed.toFixed(2) : 0
}}
{{uavData.groundSpeed }}
</div>
m/s
<div class="cf">飞行速度</div>
</div>
<div class="infoBox cf" v-if="!isM300 && !wsShow">
<div class="dib title" :style="up ? 'color: #ff2626':'color: #00f5ff'">
{{ (props_obj && props_obj.velocityZ) ? props_obj.velocityZ.toFixed(2) : 0 }}
</div>
m/s
<div class="cf">爬升率</div>
</div>
<div class="infoBox cf" v-else>
<div class="infoBox cf">
<div class="dib title" :style="up ? 'color: #ff2626':'color: #00f5ff'">
{{ (uavData && uavData.climbRate.toFixed(2)) ? uavData.climbRate.toFixed(2) : 0 }}
{{ uavData.velocityZ }}
</div>
m/s
<div class="cf">爬升率</div>
......@@ -104,39 +55,29 @@
<script>
export default {
props: {
isM300: {
type: Boolean,
default: false
},
uavData: {
type: Object,
default: () => ({})
default: () => ({}),
},
wsShow: {
type: Boolean,
default: () => {
false;
}
}
},
data() {
return {
// stationType:0
up: false
up: false,
};
},
watch: {
uavData: function(val, old) {
if(!val){
uavData: function (val, old) {
if (!val) {
return;
}
// console.log(vla,'uavDatauavDatauavDatauavData');
if (val.velocityZ > 0 || val.climbRate > 0) {
this.up = true;
} else {
this.up = false;
}
}
this.up = true;
} else {
this.up = false;
}
},
// device: function(val){
// this.stationType = val.stationType
// }
......@@ -144,43 +85,10 @@ export default {
mounted() {
// this.stationType = this.device.stationType
},
computed: {
props_obj() {
let { uavData } = this;
//
// console.log(uavData,'uavDatauavDatauavData');
if (
uavData &&
uavData.attitude &&
uavData.locationCoordinate3D &&
uavData.gps
) {
let sleep = 0;
let x = uavData.velocityX * uavData.velocityX;
let y = uavData.velocityY * uavData.velocityY;
let z = uavData.velocityZ * uavData.velocityZ;
sleep = Math.sqrt(x + y + z);
return {
...uavData.attitude,
...uavData.gps,
sleep,
groundSpeed: uavData.groundSpeed,
...uavData.locationCoordinate3D,
flyDistance: uavData.flyDistance,
flyTime: uavData.flyTime / 1000,
velocityX: uavData.velocityX,
velocityY: uavData.velocityY,
velocityZ: uavData.velocityZ
};
}
return false;
}
}
};
</script>
<style lang="scss" scoped>
.dib{
.dib {
display: inline-block;
}
.nest_info_maxBox {
......
......@@ -3,8 +3,8 @@
<div class="nest_controlBox">
<throttleGauge :uavData="uavData" :throttleValue="throttleValue" style="transform: translateX(35px);"></throttleGauge>
<div class="nest_control">
<Info class="" :uav-data="uavData" :wsShow="wsShow" :isM300="device.goodsName == 'M300'"></Info>
<div class="xian" v-if="!device.goodsName == 'M300'"></div>
<Info class="" :uav-data="uavData"></Info>
<div class="xian"></div>
<battery v-if="uavBattery" :uav-battery="uavBattery" :device="device"></battery>
</div>
<obstacle :uav-data="uavData" style="transform: translateX(-35px);"></obstacle>
......@@ -68,7 +68,7 @@ export default {
display: flex;
align-items: center;
background: rgba(9, 32, 87, 0.7);
padding: 0 50px;
padding: 0 60px 0 40px;
}
}
......
export { default as Control_API } from './modules/uav_control';
\ No newline at end of file
export { default as Control_API } from './modules/uav_control';
export { default as flightTaskAPI } from './modules/flightTask';
\ No newline at end of file
import request from '../request';
class flightTaskAPI {
/**
* 飞行任务列表 1
* @param {*} data
* @returns
*/
static getFlightList(data) {
return request({
url: `/tmj/task/getTaskList`,
method: 'post',
data
});
}
/**
* 飞行任务列表 3 期
* @param {*} data
* @returns
*/
static tssTaskPage(data) {
return request({
url: `/tss/task/web/page`,
method: 'post',
data
});
}
/**
* 流程选择 3 期
* @param {*} projectId
* @returns
*/
static processProcessBoxProjectId(projectId) {
return request({
url: `/tss/process/processBox/${projectId}`,
method: 'get'
});
}
/**
* 创建飞行任务 3 期
* @param {*} data
* @returns
*/
static tssTask(data) {
return request({
url: `/tss/task`,
method: 'POST',
data
});
}
// 编辑航线 3 期修改航线
static editFlight(data) {
return request({
url: `/tss/task`,
method: 'put',
data
});
}
static reCreateTask(data) {
return request({
url: `/tss/task/reCreate`,
method: 'post',
data
});
}
// 获取无人机列表
static getUav(params) {
return request({
url: `/tmj/device/getDeviceSelect`,
method: 'get',
params
});
}
// 获取无任务无人机列表
static getUnbindUav(params) {
return request({
url: `/tmj/device/getDeviceSelect`,
method: 'get',
params
});
}
// 飞行任务创建任务获取无人机列表
static getUavflyList(params) {
return request({
url: `/dms/uav/page`,
method: 'get',
params
});
}
// 获取组织列表
static getCompany(data) {
return request({
url: `/crm/organization/getOrganizationSelect`,
method: 'get',
data
});
}
// 获取航线
static getflight(data) {
return request({
url: `/tmj/route/getRouteSelect`,
method: 'get',
data
});
}
// 新增航线
static addFlight(data) {
return request({
url: `/tmj/task/createTask`,
method: 'post',
data
});
}
// 编辑航线
static changeFlight(data) {
return request({
url: `/dms/route/update`,
method: 'put',
data
});
}
// 设备在线状态
static getDeviceOnlineState(data) {
return request({
url: `/tmj/device/deviceIsOnline`,
method: 'post',
data
});
}
// 设备任务状态
static isDeviceHaveTask(data) {
return request({
url: `/tmj/device/deviceHaveTask`,
method: 'post',
data
});
}
// 获取单个无人机数据最后一次上传
static deviceData(data) {
const formData = new FormData();
Object.keys(data).forEach((key) => {
formData.append(key, data[key]);
});
return request({
url: `/tmj/device/deviceData`,
method: 'post',
data: formData
});
}
// 任务列表
static getTaskSelect(data) {
return request({
url: `/tmj/task/getTaskSelect`,
method: 'get',
data
});
}
// 任务开始
static taskStart(params) {
return request({
url: `/tmj/task/startTask`,
method: 'get',
params
});
}
// 任务完成
static taskEnd(params) {
return request({
url: `/tmj/task/endTask`,
method: 'get',
params
});
}
// 图片查询
static getTaskImages(params) {
return request({
url: `/tmj/task/getPhotograph`,
method: 'get',
params
});
}
// 保存图片
static savaTaskImages(data) {
return request({
// headers: {
// "Content-Type": "multipart/form-data",
// },
url: `/tmj/task/photograph`,
method: 'post',
data
});
}
// 导出报告
static getExportToWord(params) {
return request({
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
responseType: 'blob',
url: `/tmj/taskPointExportToWordV1`,
method: 'GET',
params
});
}
// 开始任务
static startTask(params) {
return request({
url: '/tmj/task/startTask',
method: 'GET',
params
});
}
// 删除任务
static deleteTask(data) {
return request({
url: `/tss/task/${data}`,
method: 'DELETE'
});
}
// 审批任务
static approveTask(data) {
return request({
url: `/tss/task/approve`,
method: 'post',
data
});
}
}
export default flightTaskAPI;
import request from '../request_tg';
import request from '../request';
import request_uav from '../request_uav';
class Control_API {
......
......@@ -10,6 +10,7 @@ import _3dList from "./lib/3d";
import _2dList from './lib/2d';
export default {
name: 'CesiumLayer',
data() {
return {
viewer: null,
......@@ -91,6 +92,11 @@ export default {
`layer-container`,
viewerOptions
);
this.$store.commit('MMCFlightControlCenter/uavApplications/setState', {
key: 'cesiumViewer',
value: this.viewer
})
// 卫星图
this.imageryLayers.satellite = this.viewer.imageryLayers.addImageryProvider(
new Cesium.UrlTemplateImageryProvider({
......@@ -219,18 +225,22 @@ export default {
.cesium_layerBox {
}
.cpt-cesium_layer {
.cpt-cesium_layer::v-deep {
width: 100%;
height: 100%;
#layer-container {
}
::v-deep .cesium-viewer-bottom {
.cesium-viewer-bottom {
display: none;
}
::v-deep .cesium-viewer-zoomIndicatorContainer {
.cesium-viewer-zoomIndicatorContainer {
display: none;
}
.cesium-viewer-navigationContainer {
display: none;
}
}
......
<template>
<div class="angleControlBox mt24">
<div class="angleControlBg w100 h100 dib">
<div class="dib wih100 ht100 pr">
<div
:style="`transform: rotate(${90-rotate}deg);`"
class="angleControlLB tc w40 ml33 mt30 h40"
/>
<img
class="pa top0 left27 w50 h50"
src="../assets/images/LBT.png"
alt=""
/>
<div class="iconfont icon-zuo1 pa top40 left10 c08c"></div>
<div class="rolate iconfont icon-zuo1 pa top40 right10 c08c"></div>
</div>
</div>
<div class="mt26 cf f16">
<img
class="dib w24 h24 mr10"
src="../assets/images/jd.png"
alt=""
/><span class="dib vas">角度调节</span>
</div>
<div class="h80 wih100 mt16 bg tc">
<div class="AngleControl dib w120 h80 tc pr">
<div
class="left12 top23 pa w30 lh30 h30 left cp"
@mousedown="rotateFn(1)"
@mouseup="stopFn()"
>
<div class="iconfont icon-zuo1"></div>
</div>
<div
class="pa right-10 top23 w30 lh30 h30 right cp"
@mousedown="rotateFn(-1)"
@mouseup="stopFn()"
>
<div class="rolate iconfont icon-zuo1"></div>
</div>
</div>
</div>
<div class="mt26 cf f16">
<img
class="dib w24 h24 mr10"
src="../assets/images/Voice.png"
alt=""
/>
<div class="dib vas">音量调节</div>
<div class="jcsb pl20 mr10">
<div
class="dib rightBtn"
@mousedown="handleChangeVolume(-1)"
@mouseup="stophandleChangeVolume()"
>
-
</div>
<el-progress
class="w120 lh1.3"
:text-inside="true"
:percentage="volume || 0"
:stroke-width="17"
></el-progress>
<div
class="dib rightBtn"
@mousedown="handleChangeVolume(1)"
@mouseup="stophandleChangeVolume()"
>
+
</div>
</div>
</div>
</div>
</template>
<script>
import CmdSetSystemVolume from "../utils/cmd_set_system_volume"; //设置系统音量
import CmdServoAngle from "../utils/cmd_servo_angle"; //设置偏转角
export default {
data() {
return {
volume: 0,
rotate: 0,
time: "",
handleChangeVolumeTime: "",
};
},
mounted() {
setTimeout(() => {
this.volume = this.PagerP1.volume
this.rotate = this.PagerP1.angle
}, 1000);
},
inject: ["PagerP1", "PoliceKey"],
methods: {
stopFn() {
clearInterval(this.time);
},
rotateFn(type) {
if (type == 1) {
let message = {
data: this.rotate ,
type: 2314,
};
this.mqtt_publish(message);
this.time = setInterval(() => {
if (this.rotate < 60) {
this.rotate++;
}
}, 100);
} else {
let message = {
data: this.rotate,
type: 2314,
};
this.mqtt_publish(message);
this.time = setInterval(() => {
if (this.rotate > 0) {
this.rotate--;
}
}, 100);
}
},
// 控制音量 start
handleChangeVolume(cate) {
this.stophandleChangeVolume();
this.handleChangeVolumeTime = setInterval(() => {
if (
(this.volume == 0 && cate == -1) ||
(this.volume == 100 && cate == 1)
) {
return;
}
this.volume += cate;
let message = {
data: this.volume,
type: 2315,
};
this.mqtt_publish(message);
}, 100);
},
stophandleChangeVolume() {
clearInterval(this.handleChangeVolumeTime);
},
async mqtt_publish(message) {
if (this.PoliceKey()) {
let key = await this.PoliceKey();
this.PagerP1.mqtt.client.publish(
`SPEAK/OBTAIN/${key}-01`,
new TextEncoder().encode(JSON.stringify(message)),
{
qos: 0,
},
(e) => {
console.log("发送指令成功:", message);
}
);
}
},
mqtt_json2uint8array(data) {
if (!data) {
return data;
}
let { encoder } = this.PagerP1.mqtt;
if (!encoder) {
encoder = new TextEncoder();
}
let uint8array = encoder.encode(JSON.stringify(data));
return uint8array;
},
// 控制音量 end
},
};
</script>
<style lang="scss" scoped>
.angleControlBox {
margin: 0 auto;
text-align: center;
.angleControlBg {
background-image: url("../assets/images/bg.png");
background-repeat: no-repeat;
background-size: 100%;
.angleControlLB {
// transform-origin: 21px 46px;
background-image: url("../assets/images/LB.png");
background-repeat: no-repeat;
background-size: 100% 100%;
}
}
.rightBtn {
box-sizing: border-box;
border-radius: 50%;
border: 1px solid #08c2d1;
width: 24px;
height: 24px;
line-height: 20px;
text-align: center;
cursor: pointer;
font-size: 20px;
padding-left: 1px;
&:hover {
opacity: 0.7;
}
}
.AngleControl {
background-image: url("../assets/images/jdbj.png");
background-repeat: no-repeat;
background-size: 100%;
.left {
border-radius: 50%;
color: #3d4654;
background: #9aabbd;
}
.left:hover {
color: #08c2d1;
}
.right {
border-radius: 50%;
color: #3d4654;
background: #9aabbd;
}
.right:hover {
color: #08c2d1;
}
}
}
.rolate{
transform: rotateY(180deg);
}
.c08c {
color: #08c2d1;
}
.el-progress-bar__innerText::v-deep{
color: #000 ;
}
</style>
<template>
<div class="itemAMaxBox">
<!-- <textarea
class="dib mt24 w432 h175"
placeholder="请输入想要发送的文字"
:disabled="write"
v-model="text"
></textarea> -->
<el-input
type="textarea"
placeholder="请输入想要发送的文字"
:disabled="write"
v-model="text"
maxlength="70"
show-word-limit
>
</el-input>
<div class="jcsb selectBox pl24 pr24 mt70">
<div>
<span> 语音:</span>
<el-select
size="mini"
class="dib w100"
v-model="value"
placeholder="请选择"
:disabled="write"
>
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value"
>
</el-option>
</el-select>
</div>
<div>
<span> 速度:</span>
<el-select
size="mini"
class="dib w100"
v-model="value2"
placeholder="请选择"
popper-append-to-body
:disabled="write"
>
<el-option
v-for="item in options2"
:key="item.value2"
:label="item.label2"
:value="item.value2"
>
</el-option>
</el-select>
</div>
<!-- <div>
<span> 重复:</span>
<el-select
size="mini"
class="dib w100"
v-model="ttsCycle"
placeholder="请选择"
@change="changeType"
@change="changeType"
>
<el-option
v-for="item in options3"
:key="item.ttsCycle"
:label="item.label3"
:value="item.ttsCycle"
>
</el-option>
</el-select>
</div> -->
</div>
<div class="bottomBtnBox jcsb mt10 pl24 pr24">
<!-- <div class="cf f14">
<div class="w35 h35 btnStyle lh35 tc">
<div class="w15 h15 ml5 iconfont icon-jilu"></div>
</div>
<div>记录</div>
</div> -->
<div class="cf f14" style="transform: scale(0.7)">
<div class="w45 h45 btnStyle tc" @click="handleSendTTSText">
<!-- <div class="w5 h5 mt13 ml26 iconfont icon-shang2 bf"></div> -->
<div
class="w5 h5 mt13 ml15 iconfont icon-a-bofang2px"
v-if="flag"
></div>
<div
class="w20 h20 mt13 ml14 iconfont icon-a-zanting2px"
v-else
></div>
</div>
<div>播放</div>
</div>
<!-- <div class="cf f14">
<div class="w45 h45 btnStyle tc">
<div class="w5 h5 mt13 ml26 iconfont icon-shang2 bf"></div>
</div>
<div>暂停</div>
</div> -->
<!-- <div class="cf f14">
<div class="w35 h35 btnStyle" @click="handleSendsupse">
<div class="w5 h5 mt10 ml9 iconfont icon-baocun1"></div>
</div>
<div>暂停</div>
</div> -->
</div>
</div>
</template>
<script>
import CmdTtsText from "../utils/cmd_tts_text";
import CMD_TTS_STATE from "../utils/cmd_record_state";
import MavLink20Processor from "../utils/mavlink20_processor";
import CmdReadFileList from "../utils/cmd_read_file_list";
import CmdRecordName from "../utils/cmd_record_name";
import CmdSetSystemVolume from "../utils/cmd_set_system_volume";
import CmdStreamFunction from "../utils/cmd_stream_function";
import CmdStreamUpData from "../utils/cmd_stream_up_data";
import CmdSaveFile from "../utils/cmd_save_file";
export default {
data() {
return {
text: "",
write: false,
ttsState: 10,
options: [
{
value: "1",
label: "普通话女",
},
{
value: "0",
label: "普通话男",
},
// {
// value: "xiaomei",
// label: "广东话",
// },
// {
// value: "xiaoqiang",
// label: "湖南话",
// },
// {
// value: "xiaorong",
// label: "四川话",
// },
// {
// value: "xiaoqian",
// label: "东北话",
// },
// {
// value: "xiaokun",
// label: "河南话",
// },
// {
// value: "xiaoying",
// label: "陕西话",
// },
],
value: "1",
options2: [
{
value2: "50",
label2: "正常",
},
{
value2: "100",
label2: "最快",
},
{
value2: "75",
label2: "较快",
},
{
value2: "25",
label2: "较慢",
},
{
value2: "0",
label2: "最慢",
},
],
value2: "50",
options3: [
{
ttsCycle: 10,
label3: "单次",
},
{
ttsCycle: 11,
label3: "循环",
},
// {
// ttsCycle: -1,
// label3: "未初始化",
// },
],
ttsCycle: 10,
flag: true,
};
},
mounted(){
// setInterval(() => {
// this.ttsCycle = this.PagerP1.ttsCycle
// }, 100);
},
watch:{
ttsState: {
handler(val){
if(val == 10){
this.flag = true
this.write = false
}else{
this.flag = false
this.write = true
}
}
}
},
inject: ["PagerP1", "PoliceKey"],
beforeDestroy() {
// this.handleSendsupse();
},
methods: {
changeType(e){
let data = {
data: e,
type: 2307
}
this.mqtt_publish(data);
},
handleSendTTSText() {
if(this.text == "") return this.$message.info("文字不能为空!")
this.flag = false;
if(this.ttsState == 11) return
if (!this.flag) {
// this.write = true;
let message = null;
let start = {
data: 11,
type: 2306
}
this.mqtt_publish(start);
message = {
data: {
text: this.text,
speed: this.value2,
voice: this.value,
},
type: 2305,
};
this.mqtt_publish(message);
} else {
// this.handleSendsupse();
}
},
handleSendsupse() {
// this.flag = true
// this.write = false;
let message = {
data: 10,
type: 2306,
};
this.mqtt_publish(message);
},
async mqtt_publish(message) {
let key = await this.PoliceKey();
// console.log(`SPEAK/OBTAIN/${key}-01`, "发送主题");
this.PagerP1.mqtt.client.publish(
`SPEAK/OBTAIN/${key}-01`,
new TextEncoder().encode(JSON.stringify(message)),
{
qos: 0,
},
(e) => {
console.log("发送指令成功:", message);
}
);
this.PagerP1.mqtt.client.on("message", (topic, payload, packet) => {
const data = JSON.parse(packet.payload.toString());
this.ttsState = data.ttsState;
});
},
},
};
</script>
<style lang="scss" scoped>
.itemAMaxBox {
width: 100%;
min-height: 393px;
text-align: center;
.selectBox::v-deep {
color: #b0b3be;
el-select {
.el-input--mini {
background: #3768b3;
}
}
}
.bottomBtnBox {
.btnStyle {
cursor: pointer;
border-radius: 50%;
background: #9bacbe;
color: #3e495b;
border: 10px solid #000;
.bf {
transform: rotate(90deg);
}
}
.btnStyle:hover {
color: #43deff;
}
}
}
.el-textarea::v-deep {
margin-top: 30px;
width: 90%;
height: 120px;
resize: none;
outline: none;
background: rgba(24, 39, 76, 0.7);
border: 1px solid #43deff;
border-radius: 10px;
color: #d6d9df;
text-indent: 1em;
.el-textarea__inner{
border: 1px solid #43deff;
background: rgba(24, 39, 76, 0.7) !important;
}
textarea{
height: 120px;
}
.el-input__count{
background: transparent;
color: #fff;
}
// padding-top: 10px;
}
textarea::-webkit-input-placeholder {
/* WebKit browsers */
color: #d6d9df;
}
textarea:-moz-placeholder {
/* Mozilla Firefox 4 to 18 */
color: #d6d9df;
}
textarea::-moz-placeholder {
/* Mozilla Firefox 19+ */
color: #d6d9df;
}
textarea::-ms-input-placeholder {
/* Internet Explorer 10+ */
color: #d6d9df;
}
</style>
<style lang="scss">
.itemAMaxBox {
.selectBox {
color: #b0b3be;
.el-select {
.el-input__inner {
border: 1px solid #3768b3;
background: #132550;
border-radius: 4px 4px 0 0;
color: #fff;
}
}
}
}
</style>
<template>
<div class="PagerP1Box" style="pointer-events: auto">
<div class="PagerP1TitleBox jcsb" v-interact>
<span class="cp">{{ title }}</span>
<span class="cp" @click="close">{{ exit }}</span>
</div>
<div class="PagerP1AreaBox jcsb">
<div class="leftArea">
<AngleControl />
</div>
<div class="rightArea">
<div class="w340 h409 mt24 rightAreaBox">
<div class="jcsb h40 tc lh40">
<div
v-for="item in ItemList"
:key="item.id"
class="w160 f12"
:class="type == item.name ? 'active' : 'rightAreaNav'"
@click="type = item.name"
>{{ item.title }}</div>
</div>
<div>
<component :is="type"></component>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import MavLink20Processor from "./utils/mavlink20_processor";
import AngleControl from "./components/angleControl"; //p1喊话器
import ItemA from "./components/itemA"; //文字转语音
import ItemB from "./components/itemB"; //语音广播
import ItemC from "./components/itemC"; //音频文件
//必须引入的核心,换成require也是一样的。注意:recorder-core会自动往window下挂载名称为Recorder对象,全局可调用window.Recorder,也许可自行调整相关源码清除全局污染
import Recorder from "recorder-core";
import { mapGetters } from "vuex";
const { VUE_APP_FCMQTT_URL } = process.env;
//需要使用到的音频格式编码引擎的js文件统统加载进来
import "recorder-core/src/engine/mp3";
import "recorder-core/src/engine/mp3-engine";
import "recorder-core/src/engine/pcm";
import mqtt from 'mqtt/dist/mqtt';
export default {
props: {
title: {
default: "喊话器",
type: String
},
exit: {
default: "关闭",
type: String
},
PoliceKeyCode: {
default: "MMC301R22205057",
type: String
}
},
data() {
return {
type: "ItemA",
music: {
list: []
},
// ttsState: null,
key: "PoliceF737",
ItemList: [
{
id: 1,
name: "ItemA",
title: "文字转语音"
},
{
id: 2,
name: "ItemB",
title: "语音广播"
},
{
id: 3,
name: "ItemC",
title: "音频文件"
}
],
mqtt: {
client: null,
decoder: null,
encoder: new TextEncoder()
},
ttsState: null,
recodeState: null,
volume: null,
angle: null,
ttsCycle: null,
recodeCycle: null
};
},
provide() {
return {
PagerP1: this,
PoliceKey: () => this.PoliceKeyCode,
};
},
// watch: {
// 'PoliceKeyCode': {
// handler(value) {
// if(value){
// this.key = value;
// }
// this.init();
// },
// deep: true,
// immediate:true
// },
// },
components: {
AngleControl,
ItemA,
ItemB,
ItemC
},
computed: {
...mapGetters(["user_info"])
},
mounted() {
this.init();
},
methods: {
init() {
let url = VUE_APP_FCMQTT_URL;
// let url = 'ws://200.10.1.245:8883/mqtt'
console.log("测试开始连接");
this.mqtt.client = mqtt.connect(url, {
protocol: "mqtt",
clientId: Date.now()
});
let key = this.PoliceKeyCode;
console.log(`SPEAK/RECEIVE/${key}-01`, "链接主题");
this.mqtt.client.subscribe(`SPEAK/RECEIVE/${key}-01`, e => {
console.log("init初始化完成", "subscribe on_and_off_broker");
console.log(this.mqtt.client);
});
let music_list = [];
this.mqtt.client.on("message", (topic, payload, packet) => {
const data = JSON.parse(packet.payload.toString());
// console.log(data,"datadata");
this.music.list = data.musicList;
this.ttsState = data.ttsState;
this.recodeState = data.recodeState;
this.volume = data.status_info.volume
this.angle = data.angle
this.ttsCycle = data.ttsCycle
this.recodeCycle = data.recodeCycle
});
},
close() {
this.$emit("close");
this.mqtt.client.end();
this.mqtt.client = null;
},
mqtt_subscribe(topic, callback) {
if (!topic) {
return topic;
}
let { client } = this.mqtt;
if (client) {
client.subscribe(topic, callback);
}
}
}
};
</script>
<style lang="scss" scoped>
.PagerP1Box {
position: fixed;
top: 70px;
right: 60px;
/* background: center url("~@/assets/images/observe/fckernel/mount/01_bg.png")
no-repeat; */
// background: rgba(0, 23, 79, 0.7);
// box-shadow: 0 2px 4px 0 rgba(1, 162, 255, 0.35),
// inset 0 0 40px 0 rgba(0, 184, 255, 0.5);
// border-radius: 10px;
// background-size: 100% 100%;
// width: 700px;
// height: 400px;
box-sizing: border-box;
padding: 10px 20px;
// position: relative;
// z-index: 10;
width: 546px;
// border: 1px solid #43deff;
// box-shadow: 0 2px 8px 0 rgba(1, 162, 255, 0.7), inset 0 0 8px 0 #019aff,
// inset 0 0 64px 0 rgba(26, 138, 227, 0.35);
// border-radius: 10px;
min-height: 501px;
.PagerP1TitleBox {
height: 44px;
line-height: 44px;
padding: 0 24px;
color: #41d8fa;
background: rgba(25, 66, 156, 0.5);
background-image: radial-gradient(
50% 100%,
rgba(107, 217, 255, 0.15) 0%,
rgba(35, 68, 184, 0) 100%
);
box-shadow: 0 2px 8px 0 rgba(2, 4, 10, 0.15);
border-radius: 10px 10px 0 0;
}
.PagerP1AreaBox {
height: 457px;
background: rgba(24, 39, 76, 0.7);
.leftArea {
width: 150px;
}
.rightArea {
width: calc(100% - 150px);
// background-color:aquamarine
.rightAreaBox {
border: 1px solid #3768b3;
border-radius: 4px 4px 0 0;
.rightAreaNav {
background: rgba(23, 70, 216, 0.2);
box-shadow: 0 2px 4px 0 rgba(23, 33, 60, 0.5), inset 0 0 4px 0 #00a7ff,
inset 0 0 16px 0 rgba(33, 137, 255, 0.4);
cursor: pointer;
color: #3ca8e0;
}
.active {
background: #304bc2;
box-shadow: 0 2px 4px 0 rgba(23, 33, 60, 0.5), inset 0 0 4px 0 #00a7ff,
inset 0 0 16px 0 rgba(33, 137, 255, 0.4);
cursor: pointer;
color: #fff;
}
}
}
}
}
</style>
const jspack = require("jspack").jspack
const Mavlink20 = require("./mavlink20");
class CmdReadFileList extends Mavlink20 {
format = '<BBB100s';
msg_id = 100100;
order_map = [0, 1, 2, 3];
crc_extra = 250;
name = 'CMD_READ_FILE_LIST';
sum = 0;
id = 0;
// 0 背景音, 1 录音, 2 实时语音, 3 TTS, 4 缓存文件, 5
channel = 0;
constructor(channel = 1, id = 0, sum = 0, name = 'CMD_READ_FILE_LIST') {
super()
this.channel = channel
this.id = id
this.sum = sum
this.name = name
}
pack() {
return super.pack(this, this.crc_extra, jspack.Pack(this.format, [this.channel, this.id, this.sum, this.name]))
}
}
module.exports = CmdReadFileList
\ No newline at end of file
const jspack = require("jspack").jspack
const Mavlink20 = require("./mavlink20");
class CmdRecordName extends Mavlink20 {
format = '<B100A';
msg_id = 100094;
order_map = [0, 1];
crc_extra = 224;
srcSystem = 255;
srcComponent = 190;
name = 'CMD_RECORD_NAME';
result = null;
constructor(text, format) {
super()
this.text = text
this.format = format
}
pack() {
return super.pack(this, this.crc_extra, jspack.Pack(this.format, [this.result, this.text]))
}
}
module.exports = CmdRecordName
\ No newline at end of file
const jspack = require("jspack").jspack
const Mavlink20 = require("./mavlink20");
class CmdRecordState extends Mavlink20 {
format = '<BB';
msg_id = 100095;
order_map = [0, 1];
crc_extra = 132;
// srcSystem = 255;
// srcComponent = 190;
state = 11
name = 'CMD_RECORD_STATE';
result = null;
constructor(state) {
super()
this.state = state
}
pack() {
return super.pack(this, this.crc_extra, jspack.Pack(this.format, [this.state, this.result]))
}
}
module.exports = CmdRecordState
\ No newline at end of file
const jspack = require("jspack").jspack
const Mavlink20 = require("./mavlink20");
class CmdSaveFile extends Mavlink20 {
format = '<BB100A';
msg_id = 100103;
order_map = [0, 1, 2];
crc_extra = 49;
name = 'CMD_SAVE_FILE';
channel = null;
result = null;
filename = "";
constructor(channel, filename, result) {
super()
this.channel = channel
this.filename = filename
}
pack() {
return super.pack(this, this.crc_extra, jspack.Pack(this.format, [this.channel, this.result, this.filename]))
}
}
export default CmdSaveFile
\ No newline at end of file
const jspack = require("jspack").jspack
const Mavlink20 = require("./mavlink20");
class CmdServoAngle extends Mavlink20 {
format = "<BB";
msg_id = 100112;
order_map = [0, 1];
crc_extra = 33;
name = "CMD_SERVO_ANGLE"
// 0 ~ 60
angle = 0;
result = null;
constructor(angle) {
super()
this.angle = angle
}
pack() {
return super.pack(this, this.crc_extra, jspack.Pack(this.format, [this.angle, this.result]))
}
}
module.exports = CmdServoAngle
\ No newline at end of file
const jspack = require("jspack").jspack
const Mavlink20 = require("./mavlink20");
class CmdSetSystemVolume extends Mavlink20 {
format = '<BB';
msg_id = 100113;
order_map = [0, 1];
crc_extra = 144;
name = 'CMD_SET_SYSTEM_VOLUME';
result = null;
constructor(volume = 100) {
super()
this.volume = volume
}
pack() {
return super.pack(this, this.crc_extra, jspack.Pack(this.format, [this.volume, this.result]))
}
}
module.exports = CmdSetSystemVolume
\ No newline at end of file
const jspack = require("jspack").jspack
import Mavlink20 from "./mavlink20"
// mavlink20.GPI_MEDIA_STREAM_UPLOAD_START = 10 // 流上传开始
// mavlink20.GPI_MEDIA_STREAM_UPLOAD_STOP = 11 // 流上传停止
class CmdStreamFunction extends Mavlink20 {
format = '<BBB';
msg_id = 100097;
order_map = [0, 1, 2];
crc_extra = 109;
name = 'CMD_STREAM_FUNCTION';
func = 0;
type = 0;
result = null;
constructor(func, type, result) {
super()
this.func = func
this.type = type
}
pack() {
return super.pack(this, this.crc_extra, jspack.Pack(this.format, [this.func, this.type, this.result]))
}
}
export default CmdStreamFunction
\ No newline at end of file
const jspack = require("jspack").jspack
const Mavlink20 = require("./mavlink20");
class CmdStreamUpData extends Mavlink20 {
format = '<B250A';
msg_id = 100098;
order_map = [0, 1];
crc_extra = 14;
name = 'CMD_STREAM_UP_DATA';
constructor(len, data) {
super()
this.len = len
this.data = data
}
pack() {
return super.pack(this, this.crc_extra, jspack.Pack(this.format, [this.len, this.data]))
}
}
module.exports = CmdStreamUpData
\ No newline at end of file
const jspack = require("jspack").jspack
const Mavlink20 = require("./mavlink20")
class CmdTts extends Mavlink20 {
msg_id = 100085;
order_map = [0, 1];
crc_extra = 253;
name = 'CMD_TTS_TEXT';
result = null;
text;
constructor(text, format = '<B250s') {
super()
this.text = text
this.format = format
}
pack() {
return super.pack(this, this.crc_extra, jspack.Pack(this.format, [this.result, this.text]))
}
}
module.exports = CmdTts
// let tts = new CmdTts("hello world")
// // console.log("tts:", tts);
// console.log("tts:", tts.pack());
\ No newline at end of file
const jspack = require("jspack").jspack
const Mavlink20Header = require("./mavlink20_header")
class Mavlink20 {
header;
payload;
static HEADER_LEN = 10;
static x25Crc(buffer, crcIN) {
let bytes = buffer;
let crcOUT = crcIN || 0xffff;
bytes.forEach(e => {
let tmp = e ^ (crcOUT & 0xff);
tmp = (tmp ^ (tmp << 4)) & 0xff;
crcOUT = (crcOUT >> 8) ^ (tmp << 8) ^ (tmp << 3) ^ (tmp >> 4);
crcOUT = crcOUT & 0xffff;
})
return crcOUT
}
pack(mav, crc_extra, payload) {
this.payload = payload;
let plen = this.payload.length;
//in MAVLink2 we can strip trailing zeros off payloads. This allows for simple
// variable length arrays and smaller packets
while (plen > 1 && this.payload[plen - 1] == 0) {
plen = plen - 1;
}
this.payload = this.payload.slice(0, plen);
let incompat_flags = 0;
this.header = new Mavlink20Header(this.msg_id, this.payload.length, mav.seq, mav.srcSystem, mav.srcComponent, incompat_flags, 0);
this.msgbuf = this.header.pack().concat(this.payload);
let crc = Mavlink20.x25Crc(this.msgbuf.slice(1));
// For now, assume always using crc_extra = True. TODO: check/fix this.
crc = Mavlink20.x25Crc([crc_extra], crc);
this.msgbuf = this.msgbuf.concat(jspack.Pack('<H', [crc]));
return this.msgbuf;
}
}
module.exports = Mavlink20
\ No newline at end of file
class Mavlink20BadData {
id = -1;
constructor(data, reason) {
this.data = data;
this.reason = reason;
this.msgbuf = data;
}
}
module.exports = Mavlink20BadData
\ No newline at end of file
const jspack = require("jspack").jspack
class Mavlink20Header {
msgId;
mlen = 0;
incompat_flags = 0;
compat_flags = 0;
seq = 0;
srcSystem = 0;
srcComponent = 0;
constructor(msgId, mlen = 0, seq = 0, srcSystem = 0, srcComponent = 0) {
this.msgId = msgId
this.mlen = mlen
this.seq = seq
this.srcSystem = srcSystem
this.srcComponent = srcComponent
}
pack() {
return jspack.Pack('BBBBBBBHB', [253, this.mlen, this.incompat_flags, this.compat_flags, this.seq, this.srcSystem, this.srcComponent, ((this.msgId & 0xFF) << 8) | ((this.msgId >> 8) & 0xFF), this.msgId >> 16]);
}
}
module.exports = Mavlink20Header
\ No newline at end of file
const CmdReadFileList = require("./cmd_read_file_list")
module.exports = {
100100: { format: '<BBB100A', type: CmdReadFileList, order_map: [0, 1, 2, 3], crc_extra: 250 },
}
/*
* @Author: xiuquanxu
* @Company: kaochong
* @Date: 2020-03-30 22:47:07
* @LastEditors: xiuquanxu
* @LastEditTime: 2021-05-20 16:25:18
*
*
* from: https://github.com/this-spring/pcm-recorder-player
*/
function PcmRecorder(config, cb) {
if (!config) {
config = {
sampleBites: 16,
sampleRate: (new (window.AudioContext
|| window.webkitAudioContext)()).sampleRate,
numberChannels: 1,
fftSize: 512,
down: true,
debug: true,
}
}
this.config = config;
this.recorder = null;
this.analyser = null;
this.audioInput = null; //
this.context = null; // AudioContext对象
this.recorder = null; // 音频输入对象
this.pcmBuffer = [];
this.pcmBufferSize = 0;
this.visualVolume = 0;
this.cb = cb;
this.init();
}
PcmRecorder.prototype.getVolume = function () {
return this.visualVolume;
}
PcmRecorder.prototype.start = function () {
var _this = this;
navigator.mediaDevices.getUserMedia({
audio: true,
}).then((stream) => {
_this.audioInput = _this.context.createMediaStreamSource(stream);
}, (error) => {
console.error(error);
}).then(() => {
_this.audioInput.connect(_this.analyser);
_this.analyser.connect(_this.recorder);
_this.recorder.connect(_this.context.destination);
});
}
PcmRecorder.prototype.stop = function () {
if (this.audioInput) this.audioInput.disconnect();
if (this.recorder) this.recorder.disconnect();
}
PcmRecorder.prototype.init = function () {
this.context = new (window.AudioContext || window.webkitAudioContext)();
this.analyser = this.context.createAnalyser(); // 录音分析节点
// this.analyser.fftSize = this.context.sampleRate / 100;
this.analyser.fftSize = this.config.fftSize;
// pcmNode
const createScript = this.context.createScriptProcessor || this.context.createJavaScriptNode;
// recorder Analyser
this.recorder = createScript.apply(this.context,
[this.config.fftSize, this.config.numberChannels, this.config.numberChannels]);
// 音频采集
this.recorder.onaudioprocess = this.onaudioprocess.bind(this)
}
PcmRecorder.prototype.onaudioprocess = function (e) {
if (this.config.numberChannels === 1) {
const data = e.inputBuffer.getChannelData(0);
console.log(data.length);
this.cb && this.cb(data)
}
}
module.exports = PcmRecorder
\ No newline at end of file
<template>
<div class="cpt-nest-logger">
<div class="title-box" v-interact>
<div class="title pl20">
<img src="../../../../assets/images/mount_head.png" />
<div class="font">运行监控日志</div>
</div>
<div style="display: flex">
<div class="icon-box" @click="list = []">
<span class="iconfont icon-qingchushuju"></span>
<!-- <span class="icon-text pr20">清除数据</span> -->
</div>
<div class="close" @click="$emit('close')">关闭</div>
</div>
</div>
<div class="ctx-box">
<div class="head mt7">
<div class="text">消息等级</div>
<div class="text con">消息内容</div>
<div class="time">时间</div>
</div>
<div class="list-box mt7">
<div class="item-box" v-for="(item,index) in list" :key="index">
<div
class="text-box"
:style="item.id && item.id ==99 || item.id && item.id <= 2 ? 'color: #FF4040': item.id && item.id > 2 && item.id < 5 ? 'color: #FFFF40': item.id && item.id == 5 ? 'color: #8E1DB8':''"
>
<div v-if="item.id" class="type-box">
<span class="type">{{ item.id }}</span>
</div>
<div
class="text"
:style="item.id && item.id == 99 || item.id && item.id <= 2 ? 'color: #FF4040': item.id && item.id > 2 && item.id < 5 ? 'color: #FFFF40': item.id && item.id == 5 ? 'color: #8E1DB8':''"
>{{ item.cmd_title }}</div>
<div class="time">{{ item.time_strap }}</div>
</div>
</div>
</div>
<div class="wih10 mt20 h10"></div>
</div>
</div>
</template>
<script>
import { Control_API } from "../../../../../../../../../../api";
import { mapState } from "vuex";
import dayjs from "dayjs";
export default {
data() {
return {
list: [
// {
// id: 1,
// cmd_title: '测试数据1',
// time_strap: new Date().toLocaleString()
// },
// {
// id: 2,
// cmd_title: '测试数据2',
// time_strap: new Date().toLocaleString()
// },
// {
// id: 3,
// cmd_title: '测试数据3',
// time_strap: new Date().toLocaleString()
// },
],
Time: null,
};
},
computed: {
...mapState("MMCFlightControlCenter/uavApplications", ["uav"]),
},
watch: {
async uav(newVal) {
if (newVal) {
this.list = [];
await this.getUavLog();
}
},
},
async created() {
await this.getUavLog();
this.Time = setInterval(() => {
this.getUavLog();
}, 1000);
},
beforeDestroy() {
if (this.Time) clearInterval(this.Time);
},
methods: {
onClose() {
this.$emit("onCloseOperationLog");
},
async getUavLog() {
const res = await Control_API.getUavAllLog({
page: 1,
pageSize: 999,
deviceId: this.uav.hardId,
startDateId: dayjs().format("YYYY-MM-DD"),
endDateId: dayjs().format("YYYY-MM-DD"),
});
if (res.status === 1) {
this.list = res.data.data;
this.list = this.list.filter((item) => {
const current_date = new Date();
const difference =
current_date.getTime() - new Date(item.time_strap).getTime();
const hoursMilli = 1000 * 60 * 30; // 半个小时内
return Math.abs(difference) < hoursMilli;
});
}
},
},
};
</script>
<style lang="scss" scoped>
.cpt-nest-logger {
position: absolute;
width: 630px;
height: 250px;
top: 170px;
right: 560px;
z-index: 5;
display: flex;
background: rgba(9, 32, 87, 0.7);
// border: 1px solid #70DAF9;
border-radius: 10px 10px 0 0;
flex-direction: column;
.title-box {
flex-shrink: 0;
display: flex;
justify-content: space-between;
align-items: center;
height: 32px;
background: linear-gradient(
180deg,
#9198ff 0%,
rgba(45, 81, 153, 0.45) 40%,
#05091a 100%
);
box-shadow: inset 0px 0px 10px 2px #3f9dff;
border-radius: 10px 10px 0px 0px;
border: 1px solid #427dff;
.title {
display: flex;
align-items: center;
.font {
font-size: 20px;
font-family: YouSheBiaoTiHei;
color: #14faff;
line-height: 26px;
text-shadow: 0px 1px 1px rgba(2, 32, 56, 0.2);
background: linear-gradient(
135deg,
#e3aa77 0%,
#f5cda9 38%,
#f9ecd3 58%,
#fcdbb1 79%,
#edb07a 100%
);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
}
.icon-box {
display: flex;
align-items: center;
cursor: pointer;
.iconfont {
font-size: 18px;
color: #00ffff;
margin-right: 4px;
}
.icon-text {
font-family: MicrosoftYaHeiUI;
font-size: 14px;
color: #ccedff;
font-weight: 400;
}
}
}
.ctx-box {
height: calc(100% - 32px);
// flex: 1;
// overflow: hidden;
display: flex;
flex-direction: column;
padding: 0 16px;
.head {
display: flex;
justify-content: space-between;
align-items: center;
font-family: SourceHanSansCN-Bold;
font-size: 16px;
color: #ffffff;
letter-spacing: 1px;
line-height: 22px;
font-weight: 700;
.text,
.time {
width: 20%;
text-align: center;
}
.time {
width: 35%;
}
.con {
width: 50%;
}
}
.list-box {
overflow: auto;
overflow-x: hidden;
box-sizing: border-box;
.item-box {
display: flex;
align-items: center;
color: #fff;
padding: 11px 0;
.text-box {
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
.type-box {
width: 20%;
height: 20px;
text-align: center;
font-family: SourceHanSansCN-Medium;
font-size: 14px;
color: #ebf9ff;
letter-spacing: 0;
text-align: center;
font-weight: 500;
display: flex;
justify-content: center;
align-items: center;
&.ordinary {
background-color: #298ad3;
}
&.emerg {
background-color: #ff3c3c;
}
.type {
width: 100px;
text-align: center;
font-size: 10px;
white-space: nowrap;
}
}
.text {
width: 50%;
text-align: center;
font-family: SourceHanSansCN-Medium;
font-size: 14px;
color: #ebf9ff;
letter-spacing: 0;
text-align: center;
font-weight: 500;
}
.time {
width: 35%;
text-align: center;
font-family: SourceHanSansCN-Medium;
font-size: 14px;
color: #ffffff;
letter-spacing: 0;
text-align: center;
font-weight: 500;
}
}
}
.item-box:nth-of-type(2n - 1) {
background: rgba(73, 135, 210, 0.2);
}
}
}
.xb {
transform: rotate(-180deg);
background: rgba(1, 10, 46, 0.63);
border-radius: 10px 10px 0 0;
}
}
.c70d {
color: #70daf9;
}
.close {
margin-left: 20px;
margin-right: 10px;
cursor: pointer;
font-size: 14px;
font-family: MicrosoftYaHei;
color: #d2dfff;
}
</style>
<?xml version="1.0" encoding="UTF-8"?>
<svg width="20px" height="20px" viewBox="0 0 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>编组 21</title>
<g id="鹰视2023" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="无人机应用健康管理-智能电池备份-2" transform="translate(-1568.000000, -313.000000)">
<g id="编组-21" transform="translate(1568.000000, 313.000000)">
<rect id="矩形" stroke="#979797" stroke-width="0.75" fill="#D8D8D8" opacity="0" x="0.375" y="0.375" width="19.25" height="19.25"></rect>
<g id="编组-14" transform="translate(3.250000, 1.750000)" fill="#FFFFFF">
<path d="M9,7.5 C11.4852814,7.5 13.5,9.51471863 13.5,12 C13.5,14.4852814 11.4852814,16.5 9,16.5 C6.51471863,16.5 4.5,14.4852814 4.5,12 C4.5,9.51471863 6.51471863,7.5 9,7.5 Z M9,8.625 C8.58578644,8.625 8.25,8.96078644 8.25,9.375 L8.25,11.625 C8.25,11.6898089 8.25822023,11.7526979 8.27367494,11.8123188 C8.25822023,11.8723021 8.25,11.9351911 8.25,12 C8.25,12.4142136 8.58578644,12.75 9,12.75 L11.625,12.75 C12.0392136,12.75 12.375,12.4142136 12.375,12 C12.375,11.5857864 12.0392136,11.25 11.625,11.25 L9.75,11.249 L9.75,9.375 C9.75,8.96078644 9.41421356,8.625 9,8.625 Z" id="形状结合"></path>
<path d="M10.5,0 C11.3284271,-1.52179594e-16 12,0.671572875 12,1.5 L12.0009837,7.69170326 C11.1504225,7.09812944 10.1158662,6.75 9,6.75 C6.10050506,6.75 3.75,9.10050506 3.75,12 C3.75,13.1158662 4.09812944,14.1504225 4.69170326,15.0009837 L1.5,15 C0.671572875,15 1.01453063e-16,14.3284271 0,13.5 L0,1.5 C-1.01453063e-16,0.671572875 0.671572875,-5.13954221e-16 1.5,0 L10.5,0 Z M6,5.25 L3,5.25 C2.58578644,5.25 2.25,5.58578644 2.25,6 C2.25,6.41421356 2.58578644,6.75 3,6.75 L6,6.75 C6.41421356,6.75 6.75,6.41421356 6.75,6 C6.75,5.58578644 6.41421356,5.25 6,5.25 Z M9,2.25 L3,2.25 C2.58578644,2.25 2.25,2.58578644 2.25,3 C2.25,3.41421356 2.58578644,3.75 3,3.75 L9,3.75 C9.41421356,3.75 9.75,3.41421356 9.75,3 C9.75,2.58578644 9.41421356,2.25 9,2.25 Z" id="形状结合"></path>
</g>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg width="20px" height="20px" viewBox="0 0 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>详情</title>
<g id="鹰视2023" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="无人机应用健康管理-智能电池备份-2" transform="translate(-1547.000000, -313.000000)" fill="#FFFFFF" fill-rule="nonzero">
<g id="详情" transform="translate(1547.000000, 313.000000)">
<rect id="矩形" opacity="0" x="0" y="0" width="20" height="20"></rect>
<path d="M10.6857812,7.62164062 L9.19347656,7.62164062 L9.19347656,6.12933594 L10.6857812,6.12933594 L10.6857812,7.62164062 Z M10.6857812,13.5908008 L9.19347656,13.5908008 L9.19347656,9.11392578 L10.6857812,9.11392578 L10.6857812,13.5908008 Z M9.93964844,2.39861328 C5.83582031,2.39861328 2.47816406,5.75628906 2.47816406,9.86009766 C2.47816406,13.9639062 5.83582031,17.321543 9.93964844,17.321543 C14.0434375,17.321543 17.4010938,13.9638672 17.4010938,9.86007812 C17.4010938,5.75628906 14.0434375,2.39861328 9.93964844,2.39861328 L9.93964844,2.39861328 Z" id="形状"></path>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<template>
<div class="mountBox">
<div v-if="mountList.length > 0" class="list">
<div class="mount-item pr mt6" v-for="(item, index) in mountList" :key="index">
<div class="icon-box" @click="fn(item)">
<img class="cp dib w30 h30" :src="item.icon" />
</div>
</div>
</div>
<template v-if="selected_mount">
<!-- fixed -->
<component
v-if="modeFlag"
v-show="flag"
:ref="mode_mount.name"
:payload_data="payload_data"
:moveType="moveType"
:selected_mount="mode_mount"
:device="uav"
:is="mode_mount.component"
:title="mode_mount.title"
@directive="handle_directivev2"
@controlMode="controlMode"
:taskId="taskId"
@take_photo="take_photo"
@record="record"
@playAudio="playAudio"
@showCenter="showCenter"
@close="mode_mount = null"
:PoliceKeyCode="this.uav.hardId"
:payload="
mode_mount && uavMountsPayload
? uavMountsPayload[mode_mount.name]
: []
"
/>
<component
:keyFlag="keyFlag"
:payload_data="payload_data"
:uavMounts="mountList"
:moveType="moveType"
:selected_mount="selected_mount"
:device="uav"
:is="selected_mount.component"
:title="selected_mount.title"
ref="mmcmount"
@directive="handle_directive"
@controlMode="controlMode"
@controlCenter="controlCenter"
@controlOther="controlOther"
@controlStop="controlStop"
:taskId="taskId"
@take_photo="take_photo"
@record="record"
@playAudio="playAudio"
@showCenter="showCenter"
@close="selected_mount = null"
:PoliceKeyCode="this.uav.hardId"
:payload="
selected_mount && uavMountsPayload
? uavMountsPayload[selected_mount.name]
: []
"
/>
</template>
</div>
</template>
<script>
// import API from "@/api";
import { mapState } from "vuex";
export default {
name: "MountsPanel",
props: {
uavMountsPayload: {
type: Array,
default: () => []
},
keyFlag:{
type:Boolean,
default: () => false
}
},
data() {
return {
selected_mount: {},
moveType: "wrj",
payload_data:null,
modeFlag:false,
mode_mount:{},
flag: false
};
},
computed: {
...mapState("MMCFlightControlCenter/uavApplications", [
"uav",
"airlineData",
"mountList",
"airlineId"
]),
taskId(){
return this.airlineId;
}
},
created() {
this.tips = "正在识别使用中的挂载....";
},
mounted(){
},
beforeDestroy() {
this.$store.commit("device/SET_MOVE_DATA", {});
},
methods: {
//联控模式start
controlMode(mode){
this.modeFlag = mode
this.mountList.forEach(val=>{
if(val.title != this.selected_mount.title && val.name.includes("Z")){
console.log(val);
this.mode_mount = val
}
})
},
controlCenter(val){
this.$refs[this.mode_mount.name].handle_change_ptz_mode(val)
},
controlOther(type){
this.$refs[this.mode_mount.name].fangxiang(type)
},
controlStop(){
this.$refs[this.mode_mount.name].stopfxFn()
},
//联控模式end
fn(item) {
this.selected_mount = item;
console.log(this.selected_mount,"selected_mount");
this.$store.commit("fckernel/SET_SELECT_MOUNT", item);
},
handle_directive(buffer) {
let { selected_mount } = this;
if (selected_mount) {
if (this.uav.network !== 1) {
this.$emit(
"fn",
{
type: 514,
data: {
mountId: selected_mount.mountId,
payload: buffer
}
},
"wrj"
);
} else {
let buff = buffer.join(",");
let data = {
type: 200,
systemCode: "mmc",
state: 1, //0 地面站(无人机),1 客户端或者web ,2 HTTP接口
username: this.user_info.username,
height: 0,
idlingTime: 0,
data: {
cmdControlType: 7000, //520
cmdFunction: null,
cmdState: null,
cmdValue: null,
cmdBuffer: buff,
cmdName: this.selected_mount.name
},
deviceHardId: this.uav.hardId
};
this.$emit("fun", data);
}
}
},
handle_directivev2(buffer) {
let { mode_mount } = this;
if (mode_mount) {
if (this.uav.network !== 1) {
this.$emit(
"fn",
{
type: 514,
data: {
mountId: mode_mount.mountId,
payload: buffer
}
},
"wrj"
);
} else {
let buff = buffer.join(",");
let data = {
type: 200,
systemCode: "mmc",
state: 1, //0 地面站(无人机),1 客户端或者web ,2 HTTP接口
username: this.user_info.username,
height: 0,
idlingTime: 0,
data: {
cmdControlType: 7000, //520
cmdFunction: null,
cmdState: null,
cmdValue: null,
cmdBuffer: buff,
cmdName: this.mode_mount.name
},
deviceHardId: this.uav.hardId
};
this.$emit("fun", data);
}
}
},
showCenter(val){
this.$emit("showCenter",val)
},
async playAudio(val){
if(this.taskId){
let typeId = val
let dataRun = {
taskId: this.taskId,
typeId: typeId,
deviceId: this.uav.id
}
// let run = await API.FCKERNEL.saveDeviceRunMonitorLog(dataRun)
}else{
// console.log(val);
}
},
async take_photo(data){
// if(!this.taskId || this.taskId == "") return this.$message.error("暂无任务!")
if(data.data){
// data.data.data.taskID = this.taskId
console.log(data,"photo拍照");
this.$emit("fn",data)
this.$message.success("拍照成功!")
}
if(this.taskId){
let dataRun = {
taskId: this.taskId,
typeId: 2,
deviceId: this.uav.id
}
// let run = await API.FCKERNEL.saveDeviceRunMonitorLog(dataRun)
}
},
async record(data){
// if(!this.taskId || this.taskId == "") return this.$message.error("暂无任务!")
// if(data.data){
// data.data.data.taskID = this.taskId
// }
if(data.data.data.recordControl || data.data.data.status){
this.$message.success("开始录像!")
if(this.taskId){
let dataRun = {
taskId: this.taskId,
typeId: 25,
deviceId: this.uav.id
}
// let run = await API.FCKERNEL.saveDeviceRunMonitorLog(dataRun)
}
}else{
this.$message.success("停止录像!")
}
console.log(data,"record录像");
this.$emit("fn",data)
}
},
};
</script>
<style scoped lang="scss">
.mountBox {
background: rgba(9, 32, 87, 0.7);
border: 1px solid #70daf9;
position: absolute;
// top: -152px;
top: 63px;
right: 65px;
width: 142px;
height: 48px;
.list {
display: flex;
justify-content: space-around;
.mount-item {
width: 30px;
background: #ffffff;
border-radius: 4px;
border: 1px solid #70daf9;
}
}
}
</style>
<!-- 鹰视 -->
<!-- 飞行应用 -->
<!-- 挂载功能 -->
<template>
<div class="mountController_Box2" v-if="mountName">
<!-- @CameraFn="webscoketFn" v-if="mountName == 'MMC_Gimbal_Z40'" -->
<Camera @close='close' @CameraFn="webscoketFn" v-if="mountName == 'MMC_Gimbal_Z40'" />
<Shout @close='close' @ShoutFn="webscoketFn" v-if="mountName == 'MMC_Gimbal_P0_Pro'" />
<Searchlight @close='close' @SearchlightFn="webscoketFn" v-if="mountName == 'MMC_Gimbal_L50'" />
<Infrared @close='close' @InfraredFn="webscoketFn" v-if="mountName == 'MMC_Gimbal_ZT1'" />
<Throw @close='close' @ThrowFn="webscoketFn" v-if="mountName == 'MMC_Gimbal_S1'" />
<Light @close='close' @LightFn="webscoketFn" v-if="mountName == 'MMC_Gimbal_ZT30N'" />
<MountGun @close='close' @mountGunFn="webscoketFn" v-if="mountName == 'MMC_Gimbal_S79'" />
<MMCGimbalFF6 @close='close' @MMCGimbalFF6Fn="webscoketFn" v-if="mountName == 'MMC_Gimbal_FF6'" />
<MMCGimbalFE8 @close='close' @MMC_Gimbal_FE8Fn="webscoketFn" v-if="mountName == 'MMC_Gimbal_FE8'" />
<MMCGimbalFN3 @close='close' @MMCGimbalFN3Fn="webscoketFn" v-if="mountName == 'MMCGimbalFN3'" />
<MMCGimbalFB1 @close='close' @MMCGimbalFB1Fn="webscoketFn" v-if="mountName == 'MMCGimbalFB1'" />
<MMCGimbalZ40S @close='close' @CameraFn="webscoketFn" v-if="mountName == 'MMC_Gimbal_Z40S'" />
</div>
</template>
<script>
import Camera from "./mountControllerList/camera"; //高清变焦
import Shout from "./mountControllerList/shout"; //喊话器
import Searchlight from "./mountControllerList/searchlight"; //探照灯
import Infrared from "./mountControllerList/infrared"; //红外热成像
import Throw from "./mountControllerList/throw"; //飞鹰抛投器
import Light from "./mountControllerList/light"; //双光
import MountGun from "./mountControllerList/mountGun"; //霹雳火s79
import MMCGimbalFF6 from "./mountControllerList/MMCGimbalFF6"; //喷火器MMCGimbalFE8
import MMCGimbalFE8 from "./mountControllerList/MMCGimbalFE8"; //喷火器
import MMCGimbalFN3 from "./mountControllerList/MMC_Gimbal_FN3"; //飞鹰抓捕网
import MMCGimbalFB1 from "./mountControllerList/MMCGimbalFB1";
import MMCGimbalZ40S from "./mountControllerList/MMC_Gimbal_Z40S";
export default {
props: {
},
components: {
Camera,
Shout,
Searchlight,
Infrared,
Throw,
Light,
MountGun,
MMCGimbalFF6,
MMCGimbalFE8,
MMCGimbalFN3,
MMCGimbalFB1,
MMCGimbalZ40S
},
provide() {
return {
mountControllerThis: this,
};
},
data() {
return {
mountObj: {
mountName: "",
deviceHardId: "",
},
mountName: "",
cenarisoName: "",
deviceHardId: "",
};
},
methods: {
close() {
this.mountName = ''
},
webscoketFn(data) {
this.$emit("webscoketFn", data);
},
},
};
</script>
<style lang="scss" scoped>
.mountController_Box2 {
// 原本宽度540px
width: 524px;
position: absolute;
top: 365px;
z-index: 20;
right: 75px;
min-height: 290px;
/* background: rgba(0, 23, 79, 0.7); */
/* border: 1px solid #43deff;
box-shadow: 0 2px 4px 0 rgba(1, 162, 255, 0.35),
inset 0 0 40px 0 rgba(0, 184, 255, 0.5);
border-radius: 10px; */
}
</style>
\ No newline at end of file
export default {
crc_table : new Array(
0x00, 0x31, 0x62, 0x53, 0xc4, 0xf5, 0xa6, 0x97, 0xb9, 0x88, 0xdb, 0xea, 0x7d, 0x4c, 0x1f, 0x2e,
0x43, 0x72, 0x21, 0x10, 0x87, 0xb6, 0xe5, 0xd4, 0xfa, 0xcb, 0x98, 0xa9, 0x3e, 0x0f, 0x5c, 0x6d,
0x86, 0xb7, 0xe4, 0xd5, 0x42, 0x73, 0x20, 0x11, 0x3f, 0x0e, 0x5d, 0x6c, 0xfb, 0xca, 0x99, 0xa8,
0xc5, 0xf4, 0xa7, 0x96, 0x01, 0x30, 0x63, 0x52, 0x7c, 0x4d, 0x1e, 0x2f, 0xb8, 0x89, 0xda, 0xeb,
0x3d, 0x0c, 0x5f, 0x6e, 0xf9, 0xc8, 0x9b, 0xaa, 0x84, 0xb5, 0xe6, 0xd7, 0x40, 0x71, 0x22, 0x13,
0x7e, 0x4f, 0x1c, 0x2d, 0xba, 0x8b, 0xd8, 0xe9, 0xc7, 0xf6, 0xa5, 0x94, 0x03, 0x32, 0x61, 0x50,
0xbb, 0x8a, 0xd9, 0xe8, 0x7f, 0x4e, 0x1d, 0x2c, 0x02, 0x33, 0x60, 0x51, 0xc6, 0xf7, 0xa4, 0x95,
0xf8, 0xc9, 0x9a, 0xab, 0x3c, 0x0d, 0x5e, 0x6f, 0x41, 0x70, 0x23, 0x12, 0x85, 0xb4, 0xe7, 0xd6,
0x7a, 0x4b, 0x18, 0x29, 0xbe, 0x8f, 0xdc, 0xed, 0xc3, 0xf2, 0xa1, 0x90, 0x07, 0x36, 0x65, 0x54,
0x39, 0x08, 0x5b, 0x6a, 0xfd, 0xcc, 0x9f, 0xae, 0x80, 0xb1, 0xe2, 0xd3, 0x44, 0x75, 0x26, 0x17,
0xfc, 0xcd, 0x9e, 0xaf, 0x38, 0x09, 0x5a, 0x6b, 0x45, 0x74, 0x27, 0x16, 0x81, 0xb0, 0xe3, 0xd2,
0xbf, 0x8e, 0xdd, 0xec, 0x7b, 0x4a, 0x19, 0x28, 0x06, 0x37, 0x64, 0x55, 0xc2, 0xf3, 0xa0, 0x91,
0x47, 0x76, 0x25, 0x14, 0x83, 0xb2, 0xe1, 0xd0, 0xfe, 0xcf, 0x9c, 0xad, 0x3a, 0x0b, 0x58, 0x69,
0x04, 0x35, 0x66, 0x57, 0xc0, 0xf1, 0xa2, 0x93, 0xbd, 0x8c, 0xdf, 0xee, 0x79, 0x48, 0x1b, 0x2a,
0xc1, 0xf0, 0xa3, 0x92, 0x05, 0x34, 0x67, 0x56, 0x78, 0x49, 0x1a, 0x2b, 0xbc, 0x8d, 0xde, 0xef,
0x82, 0xb3, 0xe0, 0xd1, 0x46, 0x77, 0x24, 0x15, 0x3b, 0x0a, 0x59, 0x68, 0xff, 0xce, 0x9d, 0xac
)
}
\ No newline at end of file
<template>
<div class="mountControllerBox">
<div class="wih00 h40 fix mountControllerTitle" v-interact>
<div class="fl ml20 lh40 mr30 cfc fw700">破窗器 </div>
<div class="fr lh40 cfc mr20 cp" @click="$emit('close')">关闭</div>
</div>
<div class="jcsb h250">
<div class="w85 dib">
<div class="w157 cp mt70 h55 leftMountGun lh55 ml100 tc">
<div style="color: #6da953">
{{ safety_switch_state ? "未锁定" : "已锁定" }}
</div>
</div>
</div>
<div class="dib jcsb mt70 mr80 cf">
<div class="mr40 cp tc" @click="changeFlag">
<div class="bor50 w32 h32 ml15 lh32 tc" style="background-color:#15d4d2">
<img
class="dib cp w12 h12"
src="../assets/images/012.png"
/>
</div>
<div>{{ safety_switch_state ? "开启保险" : "关闭保险" }}</div>
</div>
<div class="cp" @click="gimbal_mode2_ctrl(1)">
<div class="bor50 w32 h32 lh32 tc" style="background-color: #15d4d2">
<img
class="dib cp w12 h12"
src="../assets/images/013.png"
/>
</div>
<div>发射</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { mapGetters } from "vuex";
import data from "./data/index";
import methods from "./message/index";
export default {
inject: ["mountControllerThis"],
data() {
return {
...data,
safety_switch_state: false,
controInfor: {
type: 200,
systemCode: "mmc",
state: 1, //0 地面站(无人机),1 客户端或者web ,2 HTTP接口
username: "",
height: 0,
idlingTime: 0,
data: {
// this.accident_This.mountList.mountType>1024?
cmdControlType: 7000,
cmdFunction: null,
cmdState: null,
cmdValue: null,
cmdBuffer: "",
cmdName: "MMC_Gimbal_FB1",
//
},
deviceHardId: this.mountControllerThis.deviceHardId,
},
};
},
mounted() {
this.controInfor.username = this.user_info && this.user_info.username;
},
computed: {
...mapGetters(["user_info"]),
},
methods: {
...methods,
changeFlag() {
this.safety_switch_state = !this.safety_switch_state;
},
handleClick(num, data) {
this.safety_switch_state = data;
},
},
};
</script>
<style lang="scss" scoped>
.mountControllerBox{
background: rgba(0, 23, 79, 0.7);
border-radius: 10px;
}
.form {
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
padding-left: 40px;
color: #dce9ff;
letter-spacing: 1px;
box-sizing: border-box;
.form_item {
display: flex;
margin-bottom: 15px;
.form_item_title {
display: block;
width: 85px;
}
.mono_box {
width: 28px;
height: 13px;
border-radius: 3px;
margin-top: 2px;
cursor: pointer;
}
.active {
background: url("../assets/images/mono_box.png") no-repeat !important;
background-size: 100%;
}
.mono-short,
.mono-long,
.slider,
.text {
display: flex;
justify-content: space-between;
font-size: 14px;
}
.mono-left {
margin-left: 2px;
}
.mono-right {
margin-right: 2px;
}
.mono-short {
width: 111px;
height: 17px;
background: url("../assets/images/mount_short.png") no-repeat;
background-size: 100%;
margin-bottom: 5px;
}
.mono-long {
width: 168px;
height: 17px;
background: url("../assets/images/mount_long.png") no-repeat;
background-size: 100%;
margin-bottom: 5px;
}
.imgs {
margin-top: 10px;
display: flex;
justify-content: space-between;
& > img {
cursor: pointer;
width: 32px;
height: 32px;
&:hover {
opacity: 0.7;
}
}
}
.slider_box {
width: 140px;
margin: -7px 5px 0;
}
.symbol {
box-sizing: border-box;
border-radius: 50%;
border: 1px solid #08c2d1;
width: 24px;
height: 24px;
line-height: 20px;
text-align: center;
cursor: pointer;
font-size: 20px;
padding-left: 1px;
&:hover {
opacity: 0.7;
}
}
}
.img_bottom {
display: flex;
width: 320px;
justify-content: space-between;
& > img {
cursor: pointer;
width: 130px;
height: 130px;
}
}
::v-deep {
.el-select,
.el-input {
width: 170px;
height: 26px;
}
.el-input__inner {
width: 170px;
height: 26px;
background: #000000;
border: 1px solid #08c2d1;
color: #dce9ff;
}
.el-select .el-input .el-select__caret {
line-height: 26px;
}
// 修改input清除按钮样式
.el-input__suffix {
.el-input__suffix-inner {
.el-icon-circle-close:before {
line-height: 16px;
position: absolute;
top: 5px;
right: 3px;
}
}
}
.el-button {
margin-left: 10px;
padding: 0;
background: #2aefed;
border-radius: 2px;
width: 43px;
height: 24px;
outline: none;
color: #000000;
border: none;
&:hover {
opacity: 0.7;
}
}
}
}
.caozuoImg {
background-image: url("../assets/images/caozuo.png");
background-repeat: no-repeat;
background-size: 100%;
}
.leftMountGun {
background-image: url("../assets/images/bg_5.png");
background-repeat: no-repeat;
background-size: 100%;
}
.mountControllerTitle{
background: rgba(16,65,215,0.20);
box-shadow: inset 0 0 15px 0 rgba(0,182,255,0.60);
border-radius: 10px 10px 0 0;
}
</style>
\ No newline at end of file
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论