提交 7d9ec497 作者: 温凯

合并master 分支

上级 8937020d
......@@ -66,7 +66,12 @@ Vue.use(MMCSTL);
* 修正机库指令
* 增加是否定支持定时任务的判断
* 修正多个缺陷
## v1.6.0
* MQTT新增账号密码
## v1.6.1
* fix: 文件名大小写错误
## v2.0.0
* 合并V4分支更新到v2.0.0版本
## 项目结构
```
......
{
"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
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论