【类 型】:feat
【原 因】: 【过 程】:1.优化飞机状态组件 在飞将列表里面加入 在线字段 解锁字段 2.增加概况多架飞机 状态组件 【影 响】: # 类型 包含: # feat:新功能(feature) # fix:修补bug # docs:文档(documentation) # style: 格式(不影响代码运行的变动) # refactor:重构(即不是新增功能,也不是修改bug的代码变动) # test:增加测试 # chore:构建过程或辅助工具的变动
This commit is contained in:
parent
e7506728af
commit
e14aa9a975
@ -8,6 +8,7 @@
|
|||||||
import mapboxgl from 'mapbox-gl'
|
import mapboxgl from 'mapbox-gl'
|
||||||
import { MapboxStyleSwitcherControl, FollowControl, CustomFullscreenControl, NoFlyControl, RestrictflyControl, SaveToFileControl, PolygonToggleControl } from '@/utils/mapboxgl_plugs'
|
import { MapboxStyleSwitcherControl, FollowControl, CustomFullscreenControl, NoFlyControl, RestrictflyControl, SaveToFileControl, PolygonToggleControl } from '@/utils/mapboxgl_plugs'
|
||||||
import planeIcon from '@/assets/svg/plane.svg'
|
import planeIcon from '@/assets/svg/plane.svg'
|
||||||
|
// import unlineIcon from '@/assets/svg/plane_unline.svg'
|
||||||
import civilIcon from '@/assets/svg/civil.svg'
|
import civilIcon from '@/assets/svg/civil.svg'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -1,15 +1,16 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="mainBox flex column no-select">
|
<div class="mainBox flex column no-select">
|
||||||
<!-- 心跳 -->
|
<!-- 心跳 ps:黑色只网络通 绿色飞控有效心跳-->
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<div class="tag flex mac mc iconfont"
|
<div class="tag flex mac mc iconfont" :class="[
|
||||||
:class="online ? heartAnimation ? 'icon-heart online' : 'icon-heart1 online' : 'icon-xinsui offline'">
|
online ? (heartAnimation ? 'icon-heart online' : 'icon-heart1 online') : 'icon-xinsui offline',
|
||||||
|
plane.heartBeat ? 'useful-heart' : ''
|
||||||
|
]">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- 锁定状态 -->
|
<!-- 解锁状态 -->
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<div class="tag flex mac mc iconfont" :class="isLockState ? 'icon-suoding' : 'icon-jiesuo'">
|
<div class="tag flex mac mc iconfont" :class="isUnlock ? 'icon-jiesuo' : 'icon-suoding'"></div>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<!-- 飞机模式 -->
|
<!-- 飞机模式 -->
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
@ -62,7 +63,9 @@
|
|||||||
<!-- 飞机载重 钩子状态 -->
|
<!-- 飞机载重 钩子状态 -->
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<div v-if="loadweight" class="plane-mode p-l-5 p-r-5 mc mac">
|
<div v-if="loadweight" class="plane-mode p-l-5 p-r-5 mc mac">
|
||||||
<font class="plane-mode-text">{{hookstatus}} {{ loadweight }}克</font>
|
<font class="plane-mode-text" v-if="hookstatus || loadweight">
|
||||||
|
{{ hookstatus || '' }} {{ loadweight ? loadweight + '克' : '' }}
|
||||||
|
</font>
|
||||||
</div>
|
</div>
|
||||||
<div class="tag flex mac mc iconfont icon-mianxingdiaogou">
|
<div class="tag flex mac mc iconfont icon-mianxingdiaogou">
|
||||||
</div>
|
</div>
|
||||||
@ -78,9 +81,7 @@ export default {
|
|||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
/* 心跳 */
|
/* 心跳 */
|
||||||
heartAnimation: false, // 控制心跳动画图标
|
heartAnimation: false // 控制心跳动画图标
|
||||||
online: false,
|
|
||||||
isOnlineSetTimeout: null
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
@ -92,6 +93,10 @@ export default {
|
|||||||
components: {
|
components: {
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
// 飞机在线状态
|
||||||
|
online () {
|
||||||
|
return this.plane?.online ?? false
|
||||||
|
},
|
||||||
// 心跳随机数
|
// 心跳随机数
|
||||||
heartRandom () {
|
heartRandom () {
|
||||||
if (this.plane && this.plane.planeState) {
|
if (this.plane && this.plane.planeState) {
|
||||||
@ -99,14 +104,9 @@ export default {
|
|||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
},
|
},
|
||||||
// 锁定状态
|
// 解锁状态
|
||||||
isLockState () {
|
isUnlock () {
|
||||||
if (this.plane && this.plane.planeState) {
|
return this.plane?.planeState?.isUnlock ?? false
|
||||||
if (Number(this.plane.planeState.heartBeat) & 128) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
},
|
},
|
||||||
// 飞机模式
|
// 飞机模式
|
||||||
getPlaneMode () {
|
getPlaneMode () {
|
||||||
@ -180,20 +180,11 @@ export default {
|
|||||||
watch: {
|
watch: {
|
||||||
heartRandom: {
|
heartRandom: {
|
||||||
handler () {
|
handler () {
|
||||||
console.log('心跳:', this.plane.heartBeat)
|
|
||||||
// 心跳动画
|
// 心跳动画
|
||||||
this.heartAnimation = true
|
this.heartAnimation = true
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.heartAnimation = false
|
this.heartAnimation = false
|
||||||
}, 500)
|
}, 500)
|
||||||
// 在线状态
|
|
||||||
if (this.isOnlineSetTimeout) { // 进入本次心跳 删除掉线计时 既以下会重新计时
|
|
||||||
clearInterval(this.isOnlineSetTimeout)
|
|
||||||
}
|
|
||||||
this.online = true
|
|
||||||
this.isOnlineSetTimeout = setTimeout(() => { // 计时10秒后 掉线
|
|
||||||
this.online = false
|
|
||||||
}, 10000)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -203,9 +194,6 @@ export default {
|
|||||||
created () {
|
created () {
|
||||||
},
|
},
|
||||||
destroyed () {
|
destroyed () {
|
||||||
if (this.isOnlineSetTimeout) {
|
|
||||||
clearInterval(this.isOnlineSetTimeout)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -249,6 +237,11 @@ export default {
|
|||||||
|
|
||||||
.plane-mode-text {
|
.plane-mode-text {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
white-space: nowrap; /* 防止内容换行 */
|
white-space: nowrap;
|
||||||
|
/* 防止内容换行 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.useful-heart {
|
||||||
|
color: $success-color;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -1,17 +1,44 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="mainBox flex column no-select">
|
<div class="mainBox flex column no-select">
|
||||||
<!-- 心跳 -->
|
<div class="flex stat-row">
|
||||||
<!-- <div class="flex">
|
<div class="plane-mode p-l-5 p-r-5 mc mac">
|
||||||
<div class="tag flex mac mc iconfont"
|
<font class="plane-mode-text">总架数:{{ totalCount }}</font>
|
||||||
:class="online ? heartAnimation ? 'icon-heart online' : 'icon-heart1 online' : 'icon-xinsui offline'">
|
|
||||||
</div>
|
</div>
|
||||||
</div> -->
|
<div class="tag flex mac mc iconfont icon-zongshu"></div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="flex stat-row">
|
||||||
|
<div class="plane-mode p-l-5 p-r-5 mc mac">
|
||||||
|
<font class="plane-mode-text">在线数:{{ onlineCount }}</font>
|
||||||
|
</div>
|
||||||
|
<div class="tag flex mac mc iconfont icon-zaixian1"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex stat-row">
|
||||||
|
<div class="plane-mode p-l-5 p-r-5 mc mac">
|
||||||
|
<font class="plane-mode-text">总作业架数:{{ unlockedCount }}</font>
|
||||||
|
</div>
|
||||||
|
<div class="tag flex mac mc iconfont icon-wurenjijiesuo"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex stat-row">
|
||||||
|
<div class="plane-mode p-l-5 p-r-5 mc mac">
|
||||||
|
<font class="plane-mode-text">总作业时长:{{ formattedDuration }}</font>
|
||||||
|
</div>
|
||||||
|
<div class="tag flex mac mc iconfont icon-shichang"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex stat-row">
|
||||||
|
<div class="plane-mode p-l-5 p-r-5 mc mac">
|
||||||
|
<font class="plane-mode-text">作业总数:{{ totalWorkingDistance.toFixed(1) }} 米</font>
|
||||||
|
</div>
|
||||||
|
<div class="tag flex mac mc iconfont icon-pin-distance-line"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import geodist from 'geodist'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Statistics',
|
name: 'Statistics',
|
||||||
@ -20,7 +47,7 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
plane: {
|
planes: {
|
||||||
type: Object,
|
type: Object,
|
||||||
deep: true
|
deep: true
|
||||||
}
|
}
|
||||||
@ -28,6 +55,52 @@ export default {
|
|||||||
components: {
|
components: {
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
totalCount () {
|
||||||
|
return Object.keys(this.planes || {}).length
|
||||||
|
},
|
||||||
|
onlineCount () {
|
||||||
|
return Object.values(this.planes || {}).filter(p => p.planeState?.online).length
|
||||||
|
},
|
||||||
|
totalWorkingDuration () {
|
||||||
|
// 所有处于解锁状态的飞机,加上当前时长(当前时间 - startTime)
|
||||||
|
const now = Math.floor(Date.now() / 1000)
|
||||||
|
return Object.values(this.planes || {}).reduce((total, p) => {
|
||||||
|
const s = p.planeState?.flyDataSave?.startTime
|
||||||
|
const isUnlock = p.planeState?.isUnlock
|
||||||
|
if (isUnlock && s) {
|
||||||
|
return total + (now - s)
|
||||||
|
}
|
||||||
|
return total
|
||||||
|
}, 0)
|
||||||
|
},
|
||||||
|
totalWorkingDistance () {
|
||||||
|
let totalDistance = 0
|
||||||
|
Object.values(this.planes || {}).forEach(p => {
|
||||||
|
const path = p.planeState?.flyDataSave?.path || []
|
||||||
|
for (let i = 1; i < path.length; i++) {
|
||||||
|
const prev = path[i - 1]
|
||||||
|
const curr = path[i]
|
||||||
|
if (prev && curr) {
|
||||||
|
totalDistance += geodist(
|
||||||
|
{ lat: prev[1], lon: prev[0] },
|
||||||
|
{ lat: curr[1], lon: curr[0] },
|
||||||
|
{ exact: true, unit: 'meters' }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return totalDistance
|
||||||
|
},
|
||||||
|
unlockedCount () {
|
||||||
|
return Object.values(this.planes || {}).filter(p => p.planeState?.isUnlock).length
|
||||||
|
},
|
||||||
|
formattedDuration () {
|
||||||
|
const sec = this.totalWorkingDuration
|
||||||
|
const h = Math.floor(sec / 3600).toString().padStart(2, '0')
|
||||||
|
const m = Math.floor((sec % 3600) / 60).toString().padStart(2, '0')
|
||||||
|
const s = (sec % 60).toString().padStart(2, '0')
|
||||||
|
return `${h}:${m}:${s}`
|
||||||
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
|
|
||||||
@ -83,4 +156,11 @@ export default {
|
|||||||
display: inline-block;
|
display: inline-block;
|
||||||
white-space: nowrap; /* 防止内容换行 */
|
white-space: nowrap; /* 防止内容换行 */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.item {
|
||||||
|
padding: 0 6px;
|
||||||
|
height: 29px;
|
||||||
|
line-height: 29px;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -65,7 +65,7 @@ const routes = [
|
|||||||
redirect: '/model/index',
|
redirect: '/model/index',
|
||||||
meta: {
|
meta: {
|
||||||
title: '机型管理',
|
title: '机型管理',
|
||||||
icon: 'el-icon-edit-outline',
|
icon: 'iconfont icon-chuiqigudingyi',
|
||||||
roles: ['admin', 'editor'],
|
roles: ['admin', 'editor'],
|
||||||
tapName: 'plane'
|
tapName: 'plane'
|
||||||
},
|
},
|
||||||
|
@ -348,7 +348,7 @@ const store = new Vuex.Store({
|
|||||||
const res = await api.get('getAirList')
|
const res = await api.get('getAirList')
|
||||||
res.data.airList.forEach(plane => {
|
res.data.airList.forEach(plane => {
|
||||||
plane.planeState = { // 飞机状态初始化字段
|
plane.planeState = { // 飞机状态初始化字段
|
||||||
flyDataMark: false, // 飞机解锁标记成真
|
isUnlock: false, // 飞机解锁标记成真
|
||||||
flyDataSave: { // 飞机加锁截至 待上传飞行数据之后 再清空此值
|
flyDataSave: { // 飞机加锁截至 待上传飞行数据之后 再清空此值
|
||||||
startTime: null, // 解锁时的时间戳(秒)
|
startTime: null, // 解锁时的时间戳(秒)
|
||||||
endTime: null, // 加锁时的时间戳(秒)
|
endTime: null, // 加锁时的时间戳(秒)
|
||||||
@ -358,6 +358,8 @@ const store = new Vuex.Store({
|
|||||||
},
|
},
|
||||||
heartBeat: null, // 心跳
|
heartBeat: null, // 心跳
|
||||||
heartRandom: null, // 每次接收到心跳创建一个随机数 用于watch监听
|
heartRandom: null, // 每次接收到心跳创建一个随机数 用于watch监听
|
||||||
|
online: false, // 是否在线
|
||||||
|
onlineTimeout: null, // 存放定时器引用
|
||||||
voltagBattery: null, // 电压信息
|
voltagBattery: null, // 电压信息
|
||||||
currentBattery: null, // 电流信息
|
currentBattery: null, // 电流信息
|
||||||
batteryRemaining: null, // 电池电量
|
batteryRemaining: null, // 电池电量
|
||||||
|
@ -1 +1 @@
|
|||||||
@import 'https://at.alicdn.com/t/c/font_3703467_cqwk36imkj.css'; //iconfont阿里巴巴
|
@import 'https://at.alicdn.com/t/c/font_3703467_17bw22w7wt3g.css'; //iconfont阿里巴巴
|
@ -3,7 +3,7 @@
|
|||||||
<map-box ref="mapbox" @map-ready="onMapReady">
|
<map-box ref="mapbox" @map-ready="onMapReady">
|
||||||
<template #content>
|
<template #content>
|
||||||
<div v-show="mapReady">
|
<div v-show="mapReady">
|
||||||
<!-- <Statistics :plane="plane" /> -->
|
<Statistics :planes="airList" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</map-box>
|
</map-box>
|
||||||
@ -13,7 +13,7 @@
|
|||||||
<script>
|
<script>
|
||||||
import MapBox from '@/components/MapBox'
|
import MapBox from '@/components/MapBox'
|
||||||
import { waitForMapCanvasReady } from '@/utils'
|
import { waitForMapCanvasReady } from '@/utils'
|
||||||
// import Statistics from '@/components/Statistics'
|
import Statistics from '@/components/Statistics'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Home',
|
name: 'Home',
|
||||||
@ -23,8 +23,8 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
MapBox
|
MapBox,
|
||||||
// Statistics
|
Statistics
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
airList () {
|
airList () {
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<template #content>
|
<template #content>
|
||||||
<div v-show="mapReady">
|
<div v-show="mapReady">
|
||||||
<!-- <SwarmStatus :planes="planeList" /> -->
|
<!-- <SwarmStatus :planes="planeList" /> -->
|
||||||
<SwarmControllerTabs :planes="planeList" @mapXOffset="mapXOffset" @makeRoute="makeRoute" @clearRoute="clearRoute" />
|
<SwarmControllerTabs :planes="planeList"/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</map-box>
|
</map-box>
|
||||||
|
@ -151,13 +151,26 @@ export default {
|
|||||||
plane.planeState.heartRandom = Math.random()
|
plane.planeState.heartRandom = Math.random()
|
||||||
plane.planeState.heartBeat = jsonData.heartBeat
|
plane.planeState.heartBeat = jsonData.heartBeat
|
||||||
|
|
||||||
const oldMark = plane.planeState.flyDataMark
|
/* 判断飞机是否在线 */
|
||||||
|
// 设置为在线
|
||||||
|
plane.planeState.online = true
|
||||||
|
// 清除旧的离线定时器
|
||||||
|
if (plane.planeState.onlineTimeout) {
|
||||||
|
clearTimeout(plane.planeState.onlineTimeout)
|
||||||
|
}
|
||||||
|
// 重新设定掉线判断定时器(如10秒内无心跳,则为离线)
|
||||||
|
plane.planeState.onlineTimeout = setTimeout(() => {
|
||||||
|
plane.planeState.online = false
|
||||||
|
}, 10000)
|
||||||
|
|
||||||
|
/* 飞行数据上传 */
|
||||||
|
const oldMark = plane.planeState.isUnlock
|
||||||
const newMark = (Number(jsonData.heartBeat) & 128) !== 0
|
const newMark = (Number(jsonData.heartBeat) & 128) !== 0
|
||||||
|
|
||||||
// 解锁状态变更检测:用于控制飞行数据的采集与上传
|
// 解锁状态变更检测:用于控制飞行数据的采集与上传
|
||||||
if (!oldMark && newMark) {
|
if (!oldMark && newMark) {
|
||||||
// 从加锁切换为解锁:初始化飞行数据记录
|
// 从加锁切换为解锁:初始化飞行数据记录
|
||||||
plane.planeState.flyDataMark = true
|
plane.planeState.isUnlock = true
|
||||||
plane.planeState.flyDataSave = {
|
plane.planeState.flyDataSave = {
|
||||||
startTime: Math.floor(Date.now() / 1000), // 解锁时间(秒)
|
startTime: Math.floor(Date.now() / 1000), // 解锁时间(秒)
|
||||||
startBattery: plane.planeState.batteryRemaining,
|
startBattery: plane.planeState.batteryRemaining,
|
||||||
@ -166,7 +179,7 @@ export default {
|
|||||||
path: []
|
path: []
|
||||||
}
|
}
|
||||||
} else if (oldMark && !newMark) {
|
} else if (oldMark && !newMark) {
|
||||||
plane.planeState.flyDataMark = false
|
plane.planeState.isUnlock = false
|
||||||
|
|
||||||
this.handleFlightDataUpload(plane) // 上传飞行数据
|
this.handleFlightDataUpload(plane) // 上传飞行数据
|
||||||
|
|
||||||
@ -192,7 +205,7 @@ export default {
|
|||||||
plane.planeState.position.shift() // 删除最早的经纬度
|
plane.planeState.position.shift() // 删除最早的经纬度
|
||||||
}
|
}
|
||||||
// 如果是解锁状态,记录轨迹用于上传
|
// 如果是解锁状态,记录轨迹用于上传
|
||||||
if (plane.planeState.flyDataMark && plane.planeState.flyDataSave?.path) {
|
if (plane.planeState.isUnlock && plane.planeState.flyDataSave?.path) {
|
||||||
plane.planeState.flyDataSave.path.push([
|
plane.planeState.flyDataSave.path.push([
|
||||||
position.lon / 10e6,
|
position.lon / 10e6,
|
||||||
position.lat / 10e6,
|
position.lat / 10e6,
|
||||||
|
Loading…
Reference in New Issue
Block a user