【类 型】:feat

【原  因】:飞行数据传到服务器
【过  程】:订阅飞机状态时候 检测到解锁 就记录飞行数据 切换到加锁之后  将数据长传   数据包括 加解锁时间戳 使用电量 经纬高 飞行距离
【影  响】:

# 类型 包含:
# feat:新功能(feature)
# fix:修补bug
# docs:文档(documentation)
# style: 格式(不影响代码运行的变动)
# refactor:重构(即不是新增功能,也不是修改bug的代码变动)
# test:增加测试
# chore:构建过程或辅助工具的变动
This commit is contained in:
air 2025-06-14 18:37:59 +08:00
parent c97c8e6d8a
commit 607ab15cf9
4 changed files with 91 additions and 19 deletions

View File

@ -18,6 +18,7 @@
"mqtt": "^2.18.9", "mqtt": "^2.18.9",
"normalize.css": "^8.0.1", "normalize.css": "^8.0.1",
"nprogress": "^0.2.0", "nprogress": "^0.2.0",
"geodist": "^0.2.1",
"vue": "^2.6.11", "vue": "^2.6.11",
"vue-router": "^3.6.5", "vue-router": "^3.6.5",
"vue-template-compiler": "^2.7.16", "vue-template-compiler": "^2.7.16",
@ -38,7 +39,6 @@
"eslint-plugin-promise": "^4.2.1", "eslint-plugin-promise": "^4.2.1",
"eslint-plugin-standard": "^4.0.0", "eslint-plugin-standard": "^4.0.0",
"eslint-plugin-vue": "^6.2.2", "eslint-plugin-vue": "^6.2.2",
"geodist": "^0.2.1",
"sass": "^1.64.1", "sass": "^1.64.1",
"sass-loader": "^8.0.2" "sass-loader": "^8.0.2"
}, },
@ -46,4 +46,4 @@
"main": ".eslintrc.js", "main": ".eslintrc.js",
"author": "", "author": "",
"license": "ISC" "license": "ISC"
} }

View File

@ -304,7 +304,13 @@ const store = new Vuex.Store({
res.data.airList.forEach(plane => { res.data.airList.forEach(plane => {
plane.planeState = { // 飞机状态初始化字段 plane.planeState = { // 飞机状态初始化字段
flyDataMark: false, // 飞机解锁标记成真 flyDataMark: false, // 飞机解锁标记成真
flyDataSave: [], // 飞机加锁截至 待上传飞行数据之后 再清空此值 flyDataSave: { // 飞机加锁截至 待上传飞行数据之后 再清空此值
startTime: null, // 解锁时的时间戳(秒)
endTime: null, // 加锁时的时间戳(秒)
startBattery: null, // 解锁时的电池电量(百分比)
endBattery: null, // 加锁时的电池电量(百分比)
path: [] // 飞行路径数组,每项是 [lon, lat, alt]
},
heartBeat: null, // 心跳 heartBeat: null, // 心跳
heartRandom: null, // 每次接收到心跳创建一个随机数 用于watch监听 heartRandom: null, // 每次接收到心跳创建一个随机数 用于watch监听
voltagBattery: null, // 电压信息 voltagBattery: null, // 电压信息

View File

@ -179,8 +179,14 @@ export async function getFlyData (idArr, startTime, endTime) {
return res return res
} }
/** /**
*@abstract 上传保存飞机 飞行数据 检测心跳 解锁开始记录数据 加锁上传数据 * @abstract 上传保存飞机飞行数据解锁至加锁 即飞行结束触发
* @param {Object} data 包含 id, start_time, end_time, gps_path, distance, power_used
*/ */
export async function saveFlyData () { export async function saveFlyData (data) {
const params = new URLSearchParams()
for (const key in data) {
params.append(key, data[key])
}
const res = await api.post('saveFlyData', params, 'Plane')
return res
} }

View File

@ -19,6 +19,8 @@
<script> <script>
import mqtt from '@/utils/mqtt' import mqtt from '@/utils/mqtt'
import geodist from 'geodist'
import { saveFlyData } from '@/utils/api/table'
import Menubar from '@/views/layout/components/menubar' import Menubar from '@/views/layout/components/menubar'
import Headbar from '@/views/layout/components/headbar' import Headbar from '@/views/layout/components/headbar'
import BlogBox from '@/views/layout/components/BlogBox' import BlogBox from '@/views/layout/components/BlogBox'
@ -31,6 +33,50 @@ export default {
} }
}, },
methods: { methods: {
//
async handleFlightDataUpload (plane) {
const flyData = { ...plane.planeState.flyDataSave }
const path = flyData.path || []
const distanceList = []
//
flyData.endTime = Math.floor(Date.now() / 1000)
flyData.endBattery = plane.planeState.batteryRemaining
//
let totalDistance = 0
for (let i = 1; i < path.length; i++) {
const prev = path[i - 1]
const curr = path[i]
const dist = geodist(
{ lat: prev[1], lon: prev[0] },
{ lat: curr[1], lon: curr[0] },
{ exact: true, unit: 'meters' }
)
totalDistance += dist
distanceList.push(dist)
}
//
const batteryDrop = (flyData.startBattery || 0) - (flyData.endBattery || 0)
const totalCapacity = plane.planeState.battCapacity || 1
const powerUsed = Math.round((batteryDrop / 100) * totalCapacity)
//
const uploadData = {
plane_id: plane.id,
start_time: flyData.startTime,
end_time: flyData.endTime,
gps_path: JSON.stringify(path),
distance: Math.round(totalDistance),
power_used: powerUsed
}
try {
await saveFlyData(uploadData)
} catch (err) {
console.error('上传飞行数据失败', err)
}
}
}, },
components: { components: {
Menubar, Menubar,
@ -82,7 +128,7 @@ export default {
// //
mqtt.doSubscribe('planeState/+', (mqttRes) => { mqtt.doSubscribe('planeState/+', (mqttRes) => {
res.forEach(plane => { res.forEach(plane => {
if (mqttRes.topic.indexOf(plane.macadd) > -1) { if (plane.macadd && mqttRes.topic.indexOf(plane.macadd) > -1) {
try { try {
// mqtt // mqtt
const jsonData = JSON.parse(mqttRes.msg.trim()) const jsonData = JSON.parse(mqttRes.msg.trim())
@ -90,28 +136,38 @@ export default {
// mqtt // mqtt
for (const key in jsonData) { for (const key in jsonData) {
if (key === 'heartBeat') { if (key === 'heartBeat') {
const oldMark = plane.planeState.flyDataMark console.log('接收到心跳信息', plane)
const newMark = (Number(jsonData.heartBeat) & 128) !== 0
// watch // watch
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
const newMark = (Number(jsonData.heartBeat) & 128) !== 0
// //
if (!oldMark && newMark) { if (!oldMark && newMark) {
// //
plane.planeState.flyDataMark = true plane.planeState.flyDataMark = true
plane.planeState.flyDataSave = {
startTime: Math.floor(Date.now() / 1000), //
startBattery: plane.planeState.batteryRemaining,
endTime: null,
endBattery: null,
path: []
}
} else if (oldMark && !newMark) { } else if (oldMark && !newMark) {
//
plane.planeState.flyDataMark = false plane.planeState.flyDataMark = false
const uploadData = [...plane.planeState.flyDataSave] this.handleFlightDataUpload(plane) //
console.log(`上传飞机 ${plane.macadd} 的飞行数据:`, uploadData)
// TODO:
// await api.post('uploadFlightPath', { macadd: plane.macadd, data: uploadData })
// //
plane.planeState.flyDataSave = [] plane.planeState.flyDataSave = {
startTime: null, //
endTime: null, //
startBattery: null, //
endBattery: null, //
path: []
}
} }
} else if (key === 'position') { } else if (key === 'position') {
// 便 // 便
@ -126,8 +182,12 @@ export default {
plane.planeState.position.shift() // plane.planeState.position.shift() //
} }
// //
if (plane.planeState.flyDataMark) { if (plane.planeState.flyDataMark && plane.planeState.flyDataSave?.path) {
plane.planeState.flyDataSave.push([position.lon / 10e6, position.lat / 10e6, Number(position.alt)]) plane.planeState.flyDataSave.path.push([
position.lon / 10e6,
position.lat / 10e6,
Number(position.alt)
])
} }
} else if (key === 'homePosition') { } else if (key === 'homePosition') {
const homePosition = JSON.parse(jsonData.homePosition)// home const homePosition = JSON.parse(jsonData.homePosition)// home