food/src/components/Statistics.vue
air 356ea21847 【类 型】:feat
【原  因】:飞机在poprp弹出框 实时显示飞机状态  包括集群控制  和  概念页面
【过  程】:
【影  响】:

# 类型 包含:
# feat:新功能(feature)
# fix:修补bug
# docs:文档(documentation)
# style: 格式(不影响代码运行的变动)
# refactor:重构(即不是新增功能,也不是修改bug的代码变动)
# test:增加测试
# chore:构建过程或辅助工具的变动
2025-06-23 21:13:50 +08:00

167 lines
4.0 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="mainBox flex column no-select">
<div class="flex stat-row">
<div class="plane-mode p-l-5 p-r-5 mc mac">
<font class="plane-mode-text">总架数{{ totalCount }}</font>
</div>
<div class="tag flex mac mc iconfont icon-zongshu"></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>
<script>
import geodist from 'geodist'
export default {
name: 'Statistics',
data () {
return {
}
},
props: {
planes: {
type: Array,
deep: true
}
},
components: {
},
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: {
},
methods: {
},
created () {
},
destroyed () {
}
}
</script>
<style lang="scss" scoped>
@import "@/styles/theme.scss";
.mainBox {
position: absolute;
width: 29px;
top: 40px;
left: 10px;
z-index: 90;
box-shadow: 0 1px 3px rgba(0, 0, 0, .3);
background-color: white;
border-radius: 4px;
}
.mainBox .flex:not(:first-child) {
border-top: 1px solid #ddd;
}
.tag {
height: 29px;
min-width: 29px;
cursor: pointer;
border: 0;
font-size: 22px;
}
.plane-mode {
position: absolute;
left: 29px;
height: 29px;
display: flex;
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
background-color: rgba(255, 255, 255, 0.5);
}
.plane-mode-text {
display: inline-block;
white-space: nowrap; /* 防止内容换行 */
}
.item {
padding: 0 6px;
height: 29px;
line-height: 29px;
font-size: 13px;
}
</style>