提交 875c6d55 作者: 温凯

合并分支 'master' 到 'v4_master'

Master

查看合并请求 !5
......@@ -66,7 +66,12 @@ Vue.use(MMCSTL);
* 修正机库指令
* 增加是否定支持定时任务的判断
* 修正多个缺陷
## v1.6.0
* MQTT新增账号密码
## v1.6.1
* fix: 文件名大小写错误
## v2.0.0
* 合并V4分支更新到v2.0.0版本
## 项目结构
```
......
This source diff could not be displayed because it is too large. You can view the blob instead.
{
"name": "mmc-stl-vue2",
"version": "1.5.0",
"version": "2.0.0",
"description": "科比特前端标准化组件",
"main": "index.js",
"scripts": {
......
......@@ -29,4 +29,17 @@ export default class TaskInfo {
data
});
}
}
/**
* 全部单位
* @param {*} params
* @returns
*/
static listAll(params) {
return request({
url: '/admin-api/system/dept/simple-list',
method: 'get',
params,
});
}
}
\ No newline at end of file
......@@ -15,28 +15,30 @@
<el-form-item label="航线名称" required>
<el-input clearable v-model="name"></el-input>
</el-form-item>
<el-form-item label="所属单位:" required>
<el-cascader ref="CascaderRef" v-model="departmentId" :options="orgList" clearable :show-all-levels="false"
placeholder="请选择所属单位" :props="{
children: 'children',
label: 'name',
value: 'id',
checkStrictly: true,
emitPath: false,
}" @change="changeNode"></el-cascader>
</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
>
<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
item.name
}}
</span>
<span style="font-size: 12px; color: #999; margin-left: 12px">{{ item.address }}</span>
......@@ -58,27 +60,23 @@
<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-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}}</el-form-item>
<el-form-item label="航线总里程">{{ distance }}m</el-form-item>
<el-form-item label="预计飞行时间">{{ time }}</el-form-item>
</el-form>
<div class="ae-btns">
<el-button type="primary" @click="onSave" :loading="saveLoading">保存</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>
<Actions v-if="showActions" @close="showActions = false" @save="onActionsSave" :selectActions="curForm.actions">
</Actions>
</div>
</template>
<script>
import { Map, AirLine } from "../../../../../../../../../../../../api";
import { Map, AirLine, TaskInfo } from "../../../../../../../../../../../../api";
import { mapState } from "vuex";
import Utils from "../../../../../../../../../../../../components/cesiumLayer/lib/cesium/utils";
import { nanoid } from "nanoid";
......@@ -115,7 +113,9 @@ export default {
inject: ["rootNode"],
data() {
return {
orgList: [],
name: "", //航线名
departmentId: "", //部门id
form: [], //表单集合
pageIndex: 0, //当前页码
locationIcon: null, //定位图标
......@@ -158,6 +158,7 @@ export default {
},
mounted() {
let viewer = this.cesiumViewer;
this.getOrgList()
this.dataSource = new Cesium.CustomDataSource("airway_edit");
viewer.dataSources.add(this.dataSource);
this.handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas); //获取事件对象
......@@ -184,6 +185,7 @@ export default {
Cesium.ScreenSpaceEventType.LEFT_CLICK
);
this.pickerPointInit();
},
beforeDestroy() {
this.handler.removeInputAction(
......@@ -201,12 +203,87 @@ export default {
this.dataSource.show = false;
},
methods: {
async getOrgList() {
let data = await TaskInfo.listAll();
let res = data.data;
const config = {
id: "id",
parentId: "parentId",
childrenList: "children",
};
const childrenListMap = {};
const nodeIds = {};
const tree = [];
for (const d of res) {
const parentId = d[config.parentId];
if (childrenListMap[parentId] == null) {
childrenListMap[parentId] = [];
}
nodeIds[d[config.id]] = d;
childrenListMap[parentId].push(d);
}
for (const d of res) {
const parentId = d[config.parentId];
if (nodeIds[parentId] == null) {
tree.push(d);
}
}
for (const t of tree) {
adaptToChildrenList(t);
}
function adaptToChildrenList(o) {
if (childrenListMap[o[config.id]] !== null) {
o[config.childrenList] = childrenListMap[o[config.id]];
}
if (o[config.childrenList]) {
for (const c of o[config.childrenList]) {
adaptToChildrenList(c);
}
}
}
this.orgList = tree;
},
convertToSeconds(timeString) {
const regex = /(\d+)\s*(小时|分钟|秒)/g;
let totalSeconds = 0;
let match;
while ((match = regex.exec(timeString)) !== null) {
const value = parseInt(match[1], 10);
const unit = match[2];
switch (unit) {
case '小时':
totalSeconds += value * 3600; // 1小时 = 3600秒
break;
case '分钟':
totalSeconds += value * 60; // 1分钟 = 60秒
break;
case '秒':
totalSeconds += value; // 直接加秒
break;
}
}
return totalSeconds;
},
changeNode() {
this.$refs.CascaderRef.dropDownVisible = false;
},
// 保存航线
async onSave() {
if (!this.name) {
this.$message.warning("请输入航线名称");
return;
}
if (!this.departmentId) {
this.$message.warning("请选择所属机构");
return;
}
if (this.form.length === 0) {
this.$message.warning("请点击地图选择航点");
return;
......@@ -248,15 +325,19 @@ export default {
content: waypoints,
distance: this.distance,
dutyOrganizationId: "",
departmentId: this.departmentId,
name: this.name,
speed: this.form[0].speed,
flyTime: this.convertToSeconds(this.time)
};
try {
let res = await AirLine.add({
flightName: airway.name || `${this.userInfo.username}-巡查}`,
pointCount: airway.content.length,
distance: airway.distance,
departmentId: airway.departmentId,
sourceType: 1,
flyTime:airway.flyTime,
linePointSaveReqVOS: airway.content.map((point) => ({
latitude: point.coordinate.latitude,
longitude: point.coordinate.longitude,
......@@ -279,7 +360,7 @@ export default {
this.$message.success("创建航线成功");
this.$emit("addDone", res.data);
this.$emit("close");
} catch (e) {}
} catch (e) { }
this.saveLoading = false;
// 通过事件创建会出现重复创建的情况, 改为标准化里创建
......@@ -302,7 +383,6 @@ export default {
* 动作保存
*/
onActionsSave(actions) {
console.log("动作", actions);
this.curForm.actions = actions;
this.showActions = false;
},
......@@ -606,8 +686,8 @@ export default {
<style lang="scss" scoped>
.airway-edit {
position: absolute;
top: -50px;
width: 450px;
top: 0px;
width: 351px;
z-index: 2;
.dialog-content {
......
......@@ -143,6 +143,7 @@ export default {
}
},
beforeDestroy() {
this.showAirwayEdit = false;
this.bus.$off("startTask", this.onStartTask);
this.clearAirwayEntities();
},
......@@ -223,7 +224,7 @@ export default {
<style lang="scss" scoped>
.taskListBox {
height: 100%;
width: 416px;
width: 100%;
background: #222222;
border-radius: 12px;
transition: 0.3s;
......
......@@ -193,7 +193,7 @@ export default {
background: rgba(9, 32, 87, 0.7);
// border: 1px solid #70daf9;
position: absolute;
top: -5px;
top: 50px;
left: 550px;
width: 512x;
z-index: 1;
......
......@@ -176,7 +176,7 @@ export default {
.task-add {
height: 250px;
position: absolute;
top: -5px;
top: 50px;
left: 550px;
width: 520px;
z-index: 1;
......
......@@ -63,7 +63,7 @@ export default {
<style lang="scss" scoped>
.task-list {
width: 416px;
width: 350px;
height: 254px;
background: #222222;
border-radius: 10px 10px 0 0;
......
......@@ -63,7 +63,7 @@ export default {
<style lang="scss" scoped>
.task-list {
width: 416px;
width: 350px;
height: 254px;
background: #222222;
border-radius: 10px 10px 0 0;
......
......@@ -200,6 +200,7 @@ export default {
width: 48px;
height: 48px;
cursor: pointer;
z-index: 1;
&::before {
font-size: 24px;
......
......@@ -15,6 +15,16 @@
<el-form-item label="航线名称" required>
<el-input clearable v-model="name"></el-input>
</el-form-item>
<el-form-item label="所属单位:" required>
<el-cascader ref="CascaderRef" v-model="departmentId" :options="orgList" clearable :show-all-levels="false"
placeholder="请选择所属单位" :props="{
children: 'children',
label: 'name',
value: 'id',
checkStrictly: true,
emitPath: false,
}" @change="changeNode"></el-cascader>
</el-form-item>
<el-form-item label="航线速度" prop="speed">
<el-input clearable v-model="curForm.speed"></el-input>
</el-form-item>
......@@ -86,7 +96,7 @@
</template>
<script>
import { Map, AirLine } from "../../../../../../../../../../api";
import { Map, AirLine,TaskInfo } from "../../../../../../../../../../api";
import { mapState } from "vuex";
import Utils from "../../../../../../../../../../components/cesiumLayer/lib/cesium/utils";
import { nanoid } from "nanoid";
......@@ -123,7 +133,9 @@ export default {
inject: ["rootNode"],
data() {
return {
orgList: [],
name: "", //航线名
departmentId:'',//部门id
flightLabel:"",//航线标签
form: [], //表单集合
pageIndex: 0, //当前页码
......@@ -168,6 +180,7 @@ export default {
},
mounted() {
let viewer = this.cesiumViewer;
this.getOrgList();
this.dataSource = new Cesium.CustomDataSource(this.dataSourceName);
viewer.dataSources.add(this.dataSource);
this.handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas); //获取事件对象
......@@ -212,6 +225,77 @@ export default {
this.dataSource.show = false;
},
methods: {
changeNode() {
this.$refs.CascaderRef.dropDownVisible = false;
},
async getOrgList() {
let data = await TaskInfo.listAll();
let res = data.data;
const config = {
id: "id",
parentId: "parentId",
childrenList: "children",
};
const childrenListMap = {};
const nodeIds = {};
const tree = [];
for (const d of res) {
const parentId = d[config.parentId];
if (childrenListMap[parentId] == null) {
childrenListMap[parentId] = [];
}
nodeIds[d[config.id]] = d;
childrenListMap[parentId].push(d);
}
for (const d of res) {
const parentId = d[config.parentId];
if (nodeIds[parentId] == null) {
tree.push(d);
}
}
for (const t of tree) {
adaptToChildrenList(t);
}
function adaptToChildrenList(o) {
if (childrenListMap[o[config.id]] !== null) {
o[config.childrenList] = childrenListMap[o[config.id]];
}
if (o[config.childrenList]) {
for (const c of o[config.childrenList]) {
adaptToChildrenList(c);
}
}
}
this.orgList = tree;
},
convertToSeconds(timeString) {
const regex = /(\d+)\s*(小时|分钟|秒)/g;
let totalSeconds = 0;
let match;
while ((match = regex.exec(timeString)) !== null) {
const value = parseInt(match[1], 10);
const unit = match[2];
switch (unit) {
case '小时':
totalSeconds += value * 3600; // 1小时 = 3600秒
break;
case '分钟':
totalSeconds += value * 60; // 1分钟 = 60秒
break;
case '秒':
totalSeconds += value; // 直接加秒
break;
}
}
return totalSeconds;
},
async getLabel() {
this.rootNode.$emit("getLabelList", {
callback: (data) => {
......@@ -225,6 +309,10 @@ export default {
this.$message.warning("请输入航线名称");
return;
}
if (!this.departmentId) {
this.$message.warning("请选择所属机构");
return;
}
if (this.form.length === 0) {
this.$message.warning("请点击地图选择航点");
return;
......@@ -269,15 +357,19 @@ export default {
content: waypoints,
distance: this.distance,
dutyOrganizationId: "",
departmentId: this.departmentId, //部门id
name: this.name,
speed: this.form[0].speed,
flyTime: this.convertToSeconds(this.time)
};
try {
let res = await AirLine.add({
flightName: airway.name || `${this.userInfo.username}-巡查}`,
pointCount: airway.content.length,
distance: airway.distance,
departmentId: airway.departmentId,
sourceType: 1,
flyTime:airway.flyTime,
linePointSaveReqVOS: airway.content.map((point) => ({
latitude: point.coordinate.latitude,
longitude: point.coordinate.longitude,
......@@ -629,9 +721,8 @@ export default {
<style lang="scss" scoped>
.airway-edit {
position: absolute;
top: -50px;
width: 450px;
top: 0px;
width: 352px;
.dialog-content {
display: flex;
flex-direction: column;
......
......@@ -210,7 +210,7 @@ export default {
<style lang="scss" scoped>
.taskListBox {
height: 200px;
width: 416px;
width: 350px;
background: #222222;
border-radius: 12px;
transition: 0.3s;
......
......@@ -543,9 +543,8 @@ export default {
<style lang="scss" scoped>
.airway-edit {
position: absolute;
top: -50px;
width: 450px;
top: 0px;
width: 352px;
.dialog-content {
display: flex;
flex-direction: column;
......
......@@ -234,7 +234,7 @@ export default {
<style lang="scss" scoped>
.taskListBox {
min-height: 254px;
width: 416px;
width:350px;
background: #222222;
border-radius: 12px;
transition: 0.3s;
......
......@@ -139,6 +139,7 @@ export default {
height: 48px;
background: #ffffff;
border-radius: 2px;
top: -29px;
display: flex;
justify-content: center;
align-items: center;
......
......@@ -2,15 +2,10 @@
<div class="mountBox">
<div class="main" v-if="show">
<div v-if="mountList.length > 0" class="list">
<div
class="mount-item pr mt6"
:class="{
active:
(selectMount && selectMount.gimbalName) === item.gimbalName,
}"
v-for="(item, index) in mountList"
:key="index"
>
<div class="mount-item pr mt6" :class="{
active:
(selectMount && selectMount.gimbalName) === item.gimbalName,
}" v-for="(item, index) in mountList" :key="index">
<div class="icon-box" @click="onSelectMount(item)">
<img class :src="item.icon" />
</div>
......@@ -18,17 +13,9 @@
</div>
</div>
<template v-if="selectMount">
<component
:is="selectMount.gimbalName"
v-if="selectMount"
class="mount-panel"
:keyFlag="nxNormal"
:payload_data="selectMountPayload"
@directive="mountDirective"
@take_photo="mountTakePhoto"
@record="mountRecord"
@close="mountClose"
/>
<component :is="selectMount.gimbalName" v-if="selectMount" class="mount-panel" :keyFlag="nxNormal"
:payload_data="selectMountPayload" @directive="mountDirective" @take_photo="mountTakePhoto"
@record="mountRecord" @close="mountClose" />
</template>
</div>
</template>
......@@ -48,6 +35,11 @@ export default {
...mountComponents,
},
props: {
// 是否机库页面使用
isHangar: {
type: Boolean,
default: false,
},
show: {
type: Boolean,
default: false,
......@@ -78,11 +70,30 @@ export default {
return this.uavRealTimeData?.healthData?.NX?.warningLevel === "NORMAL";
},
},
created() {},
mounted() {},
beforeDestroy() {},
created() { },
mounted() { },
beforeDestroy() { },
methods: {
onSelectMount(item) {
/**
* 接管判断, 机库模块中不需要判断接管
*/
async isTakeOver() {
if (this.isHangar) {
return await this.$store.dispatch(
"MMCFlightControlCenter/hangar/isTakeOver"
);
} else {
return await this.$store.dispatch(
"MMCFlightControlCenter/uav/isTakeOver"
);
}
},
async onSelectMount(item) {
// 判断是否已接管
if (!(await this.isTakeOver())) {
this.$message.warning("请先接管设备");
return;
}
this.$store.commit("MMCFlightControlCenter/uav/setState", {
key: "selectMount",
value: item,
......
......@@ -2,72 +2,38 @@
<div class="control-right">
<!-- 挂载-警灯-无人机 -->
<div class="control-list" style="top: 13%">
<div
class="control-item"
:class="showHealth ? 'active' : ''"
@click="onSwitchShow('showHealth')"
>
<img :class="{active:showHealth}" src="./assets/images/health.svg" />
<div class="control-item" :class="showHealth ? 'active' : ''" @click="onSwitchShow('showHealth')">
<img :class="{ active: showHealth }" src="./assets/images/health.svg" />
<span class="">健康管理</span>
</div>
<!-- 机库信息 -->
<slot name="hangar"></slot>
<div
class="control-item"
:class="showMount ? 'active' : ''"
@click="onSwitchShow('showMount')"
>
<img :class="{active:showMount}" src="./assets/images/mount.svg" />
<div class="control-item" :class="showMount ? 'active' : ''" @click="onSwitchShow('showMount')">
<img :class="{ active: showMount }" src="./assets/images/mount.svg" />
<span class="">挂载</span>
</div>
<div
class="control-item"
:class="showControlList ? 'active' : ''"
@click="onSwitchShow('showControlList')"
>
<img :class="{active:showControlList}" src="./assets/images/uav.svg" />
<div class="control-item" :class="showControlList ? 'active' : ''" @click="onSwitchShow('showControlList')">
<img :class="{ active: showControlList }" src="./assets/images/uav.svg" />
<span class="">无人机</span>
</div>
<div
v-if="!isHangar && uav.network === 2"
class="control-item"
:class="showAlarmLamp ? 'active' : ''"
@click="onSwitchShow('showAlarmLamp')"
>
<img :class="{active:showAlarmLamp}" src="./assets/images/lamp.svg" />
<div v-if="!isHangar && uav.network === 2" class="control-item" :class="showAlarmLamp ? 'active' : ''"
@click="onSwitchShow('showAlarmLamp')">
<img :class="{ active: showAlarmLamp }" src="./assets/images/lamp.svg" />
<span class="">警灯</span>
</div>
<div
class="control-item"
:class="showViewLib ? 'active' : ''"
@click="onSwitchShow('showViewLib')"
>
<img :class="{active:showViewLib}" src="./assets/images/files.svg" />
<div class="control-item" :class="showViewLib ? 'active' : ''" @click="onSwitchShow('showViewLib')">
<img :class="{ active: showViewLib }" src="./assets/images/files.svg" />
<span class="">视图库</span>
</div>
<ViewLib v-if="showViewLib"></ViewLib>
</div>
<ControlList
@clearId="$emit('clearId')"
@closeIconShow="iconShow = false"
@exit="showControlList = false"
:show="showControlList"
:isHangar="isHangar"
></ControlList>
<ControlList @clearId="$emit('clearId')" @closeIconShow="iconShow = false" @exit="showControlList = false"
:show="showControlList" :isHangar="isHangar"></ControlList>
<Health v-if="showHealth" @exit="showHealth = false"></Health>
<Mount v-if="showMount" :show="showMount"></Mount>
<Mount v-if="showMount" :isHangar="isHangar" :show="showMount"></Mount>
<!-- 喊话器 -->
<MMCGimbalP1
class="PagerP1"
v-show="showMMCGimbalP1"
ref="MMCGimbalP1"
@close="showMMCGimbalP1 = false"
/>
<MountController
@webscoketFn="(data) => fun(data)"
v-if="uav && uav.deviceId"
ref="MountControllerRef"
/>
<MMCGimbalP1 class="PagerP1" v-show="showMMCGimbalP1" ref="MMCGimbalP1" @close="showMMCGimbalP1 = false" />
<MountController @webscoketFn="(data) => fun(data)" v-if="uav && uav.deviceId" ref="MountControllerRef" />
<AlarmLamp v-if="showAlarmLamp" :uav="uav" @close="showAlarmLamp = false" />
<slot name="dialog"></slot>
</div>
......@@ -118,8 +84,8 @@ export default {
},
watch: {
// 打开航线编辑时关闭所有窗口
showAirwayEdit(newVal){
if(newVal){
showAirwayEdit(newVal) {
if (newVal) {
this.showAlarmLamp = false;
this.showHealth = false;
this.showMMCGimbalP1 = false;
......@@ -130,6 +96,20 @@ export default {
}
},
methods: {
/**
* 接管判断, 机库模块中不需要判断接管
*/
async isTakeOver() {
if (this.isHangar) {
return await this.$store.dispatch(
"MMCFlightControlCenter/hangar/isTakeOver"
);
} else {
return await this.$store.dispatch(
"MMCFlightControlCenter/uav/isTakeOver"
);
}
},
hideAll(key) {
let arr = [
"showAlarmLamp",
......@@ -148,7 +128,15 @@ export default {
/**
* 切换展示
*/
onSwitchShow(key) {
async onSwitchShow(key) {
if (key == 'showHealth' && !this?.uav?.isOnline) {
return this.$message.info('无人机不在线!');
}
// 判断是否已接管
if (!(await this.isTakeOver())) {
this.$message.warning("请先接管设备");
return;
}
this.$emit("switchCallback");
this.hideAll(key);
this[key] = !this[key];
......@@ -185,7 +173,7 @@ export default {
box-sizing: border-box;
overflow: hidden;
> img {
>img {
width: 24px;
}
......@@ -197,6 +185,7 @@ export default {
border: 1px solid #3C3C3C;
color: #3388ff;
}
.active {
filter: drop-shadow(#3388ff 100px 0);
transform: translateX(-100px);
......
......@@ -481,6 +481,7 @@ export default {
align-items: center;
font-family: MicrosoftYaHei;
font-size: 16px;
z-index: 2;
color: #ffffff;
line-height: 21px;
padding: 0 4px;
......
# vue2
# node版本 >= 18.12.0
## Project setup
```
yarn install
......
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论