【类 型】:feat
【原 因】:完成集群飞机控制主页面 和 控制组件 【过 程】: 【影 响】: # 类型 包含: # feat:新功能(feature) # fix:修补bug # docs:文档(documentation) # style: 格式(不影响代码运行的变动) # refactor:重构(即不是新增功能,也不是修改bug的代码变动) # test:增加测试 # chore:构建过程或辅助工具的变动
This commit is contained in:
parent
9f48971c72
commit
e7506728af
@ -207,12 +207,12 @@
|
||||
</div>
|
||||
<div class="butIconBox gap10 flex">
|
||||
<el-button size="medium" type="primary" class="flex1 butIcon"
|
||||
@click="publishFun('{unlock:1}'); speakText('解锁飞机')">
|
||||
@click="confirmation('确认对飞机解锁?请确保飞行环境安全。', '解锁操作', '{unlock:1}'); speakText('解锁飞机')">
|
||||
<i class="iconfont icon-jiesuo f-s-24"></i>
|
||||
<div class="m-t-5">解锁</div>
|
||||
</el-button>
|
||||
<el-button size="medium" type="primary" class="flex1 butIcon"
|
||||
@click="confirmation('飞机加锁,螺旋桨将停转,请谨慎操作!', '加锁操作', '{lock:1}'); speakText('加锁,请注意安全')">
|
||||
@click="confirmation('飞机加锁,螺旋桨将停转,请谨慎操作!', '加锁操作', '{lock:1}'); speakText('加锁飞机,请注意安全')">
|
||||
<i class=" iconfont icon-suoding f-s-24"></i>
|
||||
<div class="m-t-5">加锁</div>
|
||||
</el-button>
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -300,6 +300,16 @@ const routes = [
|
||||
tapName: 'plane'
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: '/planes/swarm',
|
||||
component: () => import('@/views/layout/components/main/planes/swarm'),
|
||||
meta: {
|
||||
title: '集群控制',
|
||||
icon: 'iconfont icon-a-jiqunkongzhianniu_huaban1',
|
||||
roles: ['admin', 'editor'],
|
||||
tapName: 'plane'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/planes/index/:id/:name', // 动态加载路由时加ID参数
|
||||
component: () => import('@/views/layout/components/main/planes/index'),
|
||||
|
@ -9,7 +9,8 @@ const state = {
|
||||
/* 页面参数 */
|
||||
orderSerch: null, // 订单列表页搜索条件
|
||||
toMessageIdArr: [], // 用户管理 发布公告页面 id临时传参
|
||||
toFlyDataIdArr: [] // 飞机飞行数据 临时传参
|
||||
toFlyDataIdArr: [], // 飞机飞行数据 临时传参
|
||||
swarmIdArr: []// 选中的 集群控制飞机ID组
|
||||
}
|
||||
|
||||
const mutations = {
|
||||
@ -64,7 +65,12 @@ const mutations = {
|
||||
// 飞机飞行数据 传递id数组
|
||||
setToFlyDataIdArr (state, idArr) {
|
||||
state.toFlyDataIdArr = idArr
|
||||
},
|
||||
// 设置 '选取的集群飞机'id组
|
||||
setSwarmIdArr (state, idArr) {
|
||||
state.swarmIdArr = idArr
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const actions = {
|
||||
|
@ -1 +1 @@
|
||||
@import 'https://at.alicdn.com/t/c/font_3703467_793cqnnxv0f.css'; //iconfont阿里巴巴
|
||||
@import 'https://at.alicdn.com/t/c/font_3703467_cqwk36imkj.css'; //iconfont阿里巴巴
|
@ -73,7 +73,7 @@ export default {
|
||||
async handler () {
|
||||
try {
|
||||
// 等待地图画布准备好
|
||||
await waitForMapCanvasReady(this.map)
|
||||
await waitForMapCanvasReady(this.$refs.mapbox.map)
|
||||
// 画布准备好后执行你自己的逻辑
|
||||
this.onMapReady()
|
||||
} catch (err) {
|
||||
|
@ -23,15 +23,21 @@
|
||||
<el-form-item label="经度" label-width="80px">
|
||||
<el-input v-model="guidedLonLat.lon" placeholder="请输经度" label="经度"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="高度设置" label-width="80px">
|
||||
<el-form-item label="高度" label-width="80px">
|
||||
<el-input-number v-model="guidedAlt" label="高度设置"></el-input-number>
|
||||
<font class="m-l-5">米</font>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button size="medium" @click="dialogVisible = false">关闭</el-button>
|
||||
<el-button size="medium" type="primary"
|
||||
@click="publishFun(`{guidedMode:{lon:${guidedLonLat.lon},lat:${guidedLonLat.lat},alt:${guidedAlt}}`); isReserveGuidedMaker = true; dialogVisible = false">飞至</el-button>
|
||||
<el-button size="medium" type="primary" @click="() => {
|
||||
if (flyToSinglePlane(guidedLonLat.lon, guidedLonLat.lat, guidedAlt)) {
|
||||
isReserveGuidedMaker = true;
|
||||
dialogVisible = false;
|
||||
}
|
||||
}">
|
||||
飞至
|
||||
</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
@ -128,6 +134,25 @@ export default {
|
||||
}
|
||||
this.guidedAlt = height
|
||||
},
|
||||
// 单架飞机点飞指令,参数:lon, lat, alt
|
||||
flyToSinglePlane (lon, lat, alt) {
|
||||
const lonNum = Number(lon)
|
||||
const latNum = Number(lat)
|
||||
const altNum = Number(alt)
|
||||
|
||||
if (
|
||||
isNaN(lonNum) || isNaN(latNum) || isNaN(altNum) ||
|
||||
lonNum < -180 || lonNum > 180 ||
|
||||
latNum < -90 || latNum > 90
|
||||
) {
|
||||
this.$message.warning('请输入有效的经纬度(经度-180~180,纬度-90~90)和高度')
|
||||
return false
|
||||
}
|
||||
|
||||
const cmd = `{guidedMode:{lon:${lonNum.toFixed(7)},lat:${latNum.toFixed(7)},alt:${altNum.toFixed(1)}}}`
|
||||
this.publishFun(cmd)
|
||||
return true
|
||||
},
|
||||
// 地图组件回调地图加载完成后 执行
|
||||
onMapReady () {
|
||||
this.mapReady = true// 标记地图加载完成
|
||||
@ -190,7 +215,7 @@ export default {
|
||||
async handler () {
|
||||
try {
|
||||
// 等待地图画布准备好
|
||||
await waitForMapCanvasReady(this.map)
|
||||
await waitForMapCanvasReady(this.$refs.mapbox.map)
|
||||
// 画布准备好后执行你自己的逻辑
|
||||
this.onMapReady()
|
||||
} catch (err) {
|
||||
|
@ -1,13 +1,12 @@
|
||||
<template>
|
||||
<div class="h-100">
|
||||
<!-- 地图组件 -->
|
||||
<map-box ref="mapbox" :enableShowNofly="true" :enableGuided="true" :enableFollow="true"
|
||||
:enblueScale="!$store.state.app.isWideScreen" @longPress="handleLongPress" @map-ready="onMapReady">
|
||||
<map-box ref="mapbox" :enableShowNofly="true" :enableGuided="true" :enblueScale="!$store.state.app.isWideScreen"
|
||||
@longPress="handleLongPress" @map-ready="onMapReady">
|
||||
<template #content>
|
||||
<div v-show="mapReady">
|
||||
<BatteryStatus :plane="plane" />
|
||||
<PlaneStatus :plane="plane" />
|
||||
<ControllerTabs :plane="plane" @mapXOffset="mapXOffset" @makeRoute="makeRoute" @clearRoute="clearRoute" />
|
||||
<!-- <SwarmStatus :planes="planeList" /> -->
|
||||
<SwarmControllerTabs :planes="planeList" @mapXOffset="mapXOffset" @makeRoute="makeRoute" @clearRoute="clearRoute" />
|
||||
</div>
|
||||
</template>
|
||||
</map-box>
|
||||
@ -17,21 +16,20 @@
|
||||
<!-- 点飞设置弹出框 -->
|
||||
<template v-if="dialogItem == 'guidedBox'">
|
||||
<el-form label-position="left">
|
||||
<el-form-item label="纬度" label-width="80px">
|
||||
<el-form-item label="中心纬度" label-width="80px">
|
||||
<el-input v-model="guidedLonLat.lat" placeholder="请输维度" label="纬度"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="经度" label-width="80px">
|
||||
<el-form-item label="中心经度" label-width="80px">
|
||||
<el-input v-model="guidedLonLat.lon" placeholder="请输经度" label="经度"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="高度设置" label-width="80px">
|
||||
<el-form-item label="中心高度" label-width="80px">
|
||||
<el-input-number v-model="guidedAlt" label="高度设置"></el-input-number>
|
||||
<font class="m-l-5">米</font>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button size="medium" @click="dialogVisible = false">关闭</el-button>
|
||||
<el-button size="medium" type="primary"
|
||||
@click="publishFun(`{guidedMode:{lon:${guidedLonLat.lon},lat:${guidedLonLat.lat},alt:${guidedAlt}}`); isReserveGuidedMaker = true; dialogVisible = false">飞至</el-button>
|
||||
<el-button size="medium" type="primary" @click="onSwarmFlyTo">飞至</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
@ -40,14 +38,12 @@
|
||||
|
||||
<script>
|
||||
import MapBox from '@/components/MapBox'
|
||||
import ControllerTabs from '@/components/ControllerTabs'
|
||||
import BatteryStatus from '@/components/BatteryStatus'
|
||||
import PlaneStatus from '@/components/PlaneStatus'
|
||||
import mqtt from '@/utils/mqtt'
|
||||
// import SwarmStatus from '@/components/SwarmStatus.vue'
|
||||
import SwarmControllerTabs from '@/components/SwarmControllerTabs.vue'
|
||||
import { waitForMapCanvasReady } from '@/utils'
|
||||
|
||||
export default {
|
||||
name: 'Planes',
|
||||
name: 'Swarm',
|
||||
data () {
|
||||
return {
|
||||
dialogTitle: '', // 弹出框 标题
|
||||
@ -56,40 +52,20 @@ export default {
|
||||
guidedLonLat: {}, // 点飞 的经纬度
|
||||
guidedAlt: '', // 点飞的高度
|
||||
isReserveGuidedMaker: false, // 关闭指点飞行操作窗口时 标记是否删除图标
|
||||
planesId: this.$route.params.id,
|
||||
localCount: 0, // 本地存储计数器
|
||||
mapReady: false// 地图加载完成后 回调时 设置此值 让地图组件插槽内容 滞后显示
|
||||
mapReady: false // 地图加载完成后 回调时 设置此值 让地图组件插槽内容 滞后显示
|
||||
}
|
||||
},
|
||||
components: {
|
||||
MapBox,
|
||||
ControllerTabs,
|
||||
BatteryStatus,
|
||||
PlaneStatus
|
||||
// SwarmStatus,
|
||||
SwarmControllerTabs
|
||||
},
|
||||
computed: {
|
||||
plane () {
|
||||
if (this.$store.state.airList.length > 0) {
|
||||
return this.$store.state.airList.find(plane => plane.id === this.planesId)
|
||||
}
|
||||
return null
|
||||
},
|
||||
position () {
|
||||
if (this.plane) {
|
||||
if (this.plane.planeState.position.length > 0) {
|
||||
return this.plane.planeState.position
|
||||
} else {
|
||||
return []
|
||||
}
|
||||
} else {
|
||||
return []
|
||||
}
|
||||
},
|
||||
noflyData () {
|
||||
return this.$store.state.noflyData
|
||||
},
|
||||
ADSBList () {
|
||||
return this.$store.state.ADSBList
|
||||
// 选中的集群控制飞机s
|
||||
planeList () {
|
||||
const allPlanes = this.$store.state.airList
|
||||
const idArr = this.$store.state.app.swarmIdArr
|
||||
return allPlanes.filter(plane => idArr.includes(plane.id))
|
||||
},
|
||||
/**
|
||||
* @description: 侧边栏显隐
|
||||
@ -98,6 +74,12 @@ export default {
|
||||
return this.$store.state.app.isCollapse
|
||||
}
|
||||
},
|
||||
created () {
|
||||
// 没有参数 跳转到飞机列表页
|
||||
if (this.$store.state.app.swarmIdArr.length < 2) {
|
||||
this.$router.replace('/register/index')
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/** 弹出框 关闭事件回调 */
|
||||
closeCallback () {
|
||||
@ -111,86 +93,136 @@ export default {
|
||||
openCallback () {
|
||||
},
|
||||
// 地图长按事件 记录地图经纬度
|
||||
// 地图长按事件 记录地图经纬度
|
||||
handleLongPress (lonLat) {
|
||||
this.isReserveGuidedMaker = false
|
||||
this.dialogTitle = '指点飞行'
|
||||
this.dialogTitle = '集群指点'
|
||||
this.dialogVisible = true
|
||||
this.dialogItem = 'guidedBox'
|
||||
this.guidedLonLat = lonLat // 设置点击的经纬度
|
||||
this.guidedLonLat = lonLat // 点击的新位置中心点
|
||||
|
||||
// 安全获取飞机当前高度
|
||||
let height = 0
|
||||
if (this.plane && this.plane.planeState && Array.isArray(this.plane.planeState.position)) {
|
||||
const posLen = this.plane.planeState.position.length
|
||||
if (posLen > 0 && Array.isArray(this.plane.planeState.position[posLen - 1])) {
|
||||
height = this.plane.planeState.position[posLen - 1][2] || 0
|
||||
}
|
||||
// 获取所有飞机的高度并求平均
|
||||
const validHeights = this.planeList.map(p => {
|
||||
const pos = p?.planeState?.position
|
||||
const last = Array.isArray(pos) && pos.length > 0 ? pos[pos.length - 1] : null
|
||||
return Array.isArray(last) ? last[2] || 0 : 0
|
||||
}).filter(h => typeof h === 'number')
|
||||
|
||||
const avgAlt = validHeights.length
|
||||
? (validHeights.reduce((sum, h) => sum + h, 0) / validHeights.length).toFixed(1)
|
||||
: 0
|
||||
|
||||
this.guidedAlt = Number(avgAlt)
|
||||
},
|
||||
// 集群指点飞行 保持所有飞机拓扑关系飞到指定位置
|
||||
onSwarmFlyTo () {
|
||||
const targetLon = Number(this.guidedLonLat.lon)
|
||||
const targetLat = Number(this.guidedLonLat.lat)
|
||||
const targetAlt = Number(this.guidedAlt)
|
||||
|
||||
if (
|
||||
isNaN(targetLon) || isNaN(targetLat) || isNaN(targetAlt) ||
|
||||
targetLon < -180 || targetLon > 180 ||
|
||||
targetLat < -90 || targetLat > 90
|
||||
) {
|
||||
this.$message.warning('请输入有效的经纬度(经度-180~180,纬度-90~90)和高度')
|
||||
return
|
||||
}
|
||||
|
||||
// 所有飞机当前中心点
|
||||
const currentCenter = this.getSwarmCenter()
|
||||
|
||||
if (!currentCenter) {
|
||||
this.$message.error('无法获取飞行器中心位置,检查飞机是否都已定位')
|
||||
return
|
||||
}
|
||||
|
||||
// 计算每架飞机相对于当前中心的偏移量
|
||||
const commands = this.planeList.map(p => {
|
||||
const pos = p?.planeState?.position
|
||||
const last = Array.isArray(pos) && pos.length > 0 ? pos[pos.length - 1] : null
|
||||
if (!Array.isArray(last)) return null
|
||||
|
||||
const offsetLon = last[0] - currentCenter.lon
|
||||
const offsetLat = last[1] - currentCenter.lat
|
||||
const offsetAlt = last[2] - currentCenter.alt
|
||||
|
||||
const newLon = targetLon + offsetLon
|
||||
const newLat = targetLat + offsetLat
|
||||
const newAlt = targetAlt + offsetAlt
|
||||
|
||||
return {
|
||||
id: p.id,
|
||||
cmd: `{guidedMode:{lon:${newLon.toFixed(7)},lat:${newLat.toFixed(7)},alt:${newAlt.toFixed(1)}}}`
|
||||
}
|
||||
}).filter(Boolean)
|
||||
|
||||
// 发送控制指令
|
||||
commands.forEach(({ id, cmd }) => {
|
||||
this.publishFun(cmd, id)
|
||||
})
|
||||
|
||||
this.isReserveGuidedMaker = true
|
||||
this.dialogVisible = false
|
||||
},
|
||||
// 获取集群中心点
|
||||
getSwarmCenter () {
|
||||
const positions = this.planeList.map(p => {
|
||||
const pos = p?.planeState?.position
|
||||
const last = Array.isArray(pos) && pos.length > 0 ? pos[pos.length - 1] : null
|
||||
return Array.isArray(last) ? last : null
|
||||
}).filter(Boolean)
|
||||
|
||||
if (!positions.length) return null
|
||||
|
||||
const sum = positions.reduce((acc, pos) => {
|
||||
acc.lon += pos[0]
|
||||
acc.lat += pos[1]
|
||||
acc.alt += pos[2] || 0
|
||||
return acc
|
||||
}, { lon: 0, lat: 0, alt: 0 })
|
||||
|
||||
const count = positions.length
|
||||
return {
|
||||
lon: sum.lon / count,
|
||||
lat: sum.lat / count,
|
||||
alt: sum.alt / count
|
||||
}
|
||||
this.guidedAlt = height
|
||||
},
|
||||
// 地图组件回调地图加载完成后 执行
|
||||
onMapReady () {
|
||||
this.mapReady = true// 标记地图加载完成
|
||||
this.makePlane(this.plane)
|
||||
this.mapReady = true // 标记地图加载完成
|
||||
this.makePlanes(this.planeList)
|
||||
},
|
||||
/**
|
||||
* @description: 创建飞机图标
|
||||
*/
|
||||
makePlane (plane) {
|
||||
let planeDefaultLonLat
|
||||
if (localStorage.getItem(plane.name)) { // 从本地缓存 拿飞机得初始位置
|
||||
planeDefaultLonLat = JSON.parse(localStorage.getItem(plane.name))
|
||||
plane.lon = planeDefaultLonLat.lon
|
||||
plane.lat = planeDefaultLonLat.lat
|
||||
} else {
|
||||
// 缺省 给经纬度 小数点后随机第五位 即有个10米左右的随机距离
|
||||
plane.lon = 100 + Number((Math.random() * 0.01).toFixed(5))
|
||||
plane.lat = 40 + Number((Math.random() * 0.01).toFixed(5))
|
||||
}
|
||||
makePlanes (planes) {
|
||||
this.$refs.mapbox.removePlanes()// 先清除画布上现有的飞机
|
||||
this.$refs.mapbox.makePlane(plane)// 创建飞机
|
||||
this.$refs.mapbox.goto({ lon: plane.lon, lat: plane.lat })// 跳转到飞机位置
|
||||
},
|
||||
/**
|
||||
* @description: 创建航线
|
||||
*/
|
||||
makeRoute (routeData) {
|
||||
this.$refs.mapbox.makeRoute(routeData)
|
||||
},
|
||||
/**
|
||||
* @description: 清楚航线
|
||||
*/
|
||||
clearRoute () {
|
||||
this.$refs.mapbox.clearRoute()
|
||||
},
|
||||
/**
|
||||
* @description: 屏幕横移
|
||||
* @param {*} val 正数向左移动 负数向右移动
|
||||
* @param {*} y 正数向上移动 负数向下移动
|
||||
*/
|
||||
mapXOffset (x, y) {
|
||||
this.$refs.mapbox.mapXOffset(x, y)
|
||||
},
|
||||
/**
|
||||
* @description: 发布 mqtt 信息
|
||||
* @param {*} jsonData {'item':val} // item: questAss飞行航点任务 setQuestState 设置飞机状态 resetQuestState设置飞机初始状态 chan1油门通道1 chan2油门通道2 chan3油门通道3 chan4油门通道4 hookConteroller钩子控制 cameraController云台相机控制
|
||||
*/
|
||||
publishFun (jsonData) {
|
||||
if (this.plane) {
|
||||
mqtt.publishFun(`cmd/${this.plane.macadd}`, jsonData)
|
||||
} else {
|
||||
this.$message.warning('与飞机通信未接通,请稍后')
|
||||
}
|
||||
planes.forEach((plane, index) => { // 创建所有飞机
|
||||
let planeDefaultLonLat
|
||||
if (localStorage.getItem(plane.name) !== null) { // 从本地缓存 拿飞机得初始位置
|
||||
planeDefaultLonLat = JSON.parse(localStorage.getItem(plane.name))
|
||||
plane.lon = planeDefaultLonLat.lon
|
||||
plane.lat = planeDefaultLonLat.lat
|
||||
} else {
|
||||
// 缺省 给经纬度 小数点后随机第五位 即有个10米左右的随机距离
|
||||
plane.lon = 100 + Number((Math.random() * 0.01).toFixed(5))
|
||||
plane.lat = 40 + Number((Math.random() * 0.01).toFixed(5))
|
||||
}
|
||||
this.$refs.mapbox.makePlane(plane, index)
|
||||
})
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
},
|
||||
watch: {
|
||||
plane: {
|
||||
/**
|
||||
* @description: 飞机列表更新时候 更新地图
|
||||
*/
|
||||
planeList: {
|
||||
async handler () {
|
||||
try {
|
||||
// 等待地图画布准备好
|
||||
await waitForMapCanvasReady(this.map)
|
||||
await waitForMapCanvasReady(this.$refs.mapbox.map)
|
||||
// 画布准备好后执行你自己的逻辑
|
||||
this.onMapReady()
|
||||
} catch (err) {
|
||||
@ -200,47 +232,13 @@ export default {
|
||||
immediate: true
|
||||
},
|
||||
/**
|
||||
* @description: 更新飞机位置 并画出轨迹 跟随飞机
|
||||
* @description: 侧边栏显隐
|
||||
*/
|
||||
position: {
|
||||
handler (val) {
|
||||
const len = val.length
|
||||
if (len > 2) {
|
||||
const lon = val[len - 1][0]
|
||||
const lat = val[len - 1][1]
|
||||
this.localCount++// 计数器 叠加
|
||||
if (this.localCount % 100 === 1) {
|
||||
localStorage.setItem(this.plane.name, `{ "lon": ${lon}, "lat": ${lat} }`)
|
||||
}
|
||||
this.$refs.mapbox.setPlaneLonLat({ lon: lon, lat: lat }, 0, val)// 更新飞机位置 并画出轨迹 跟随飞机
|
||||
}
|
||||
},
|
||||
deep: true
|
||||
},
|
||||
ADSBList: {
|
||||
handler (newList) {
|
||||
if (this.$refs.mapbox && typeof this.$refs.mapbox.makeADSBPlanes === 'function') {
|
||||
this.$refs.mapbox.makeADSBPlanes(newList)
|
||||
}
|
||||
},
|
||||
immediate: true,
|
||||
deep: true
|
||||
},
|
||||
/**
|
||||
* @description: 侧边栏缩进有变化时 地图重新自适应
|
||||
*/
|
||||
isCollapse: {
|
||||
handler (val) {
|
||||
if (val) {
|
||||
this.$nextTick(() => {
|
||||
this.$refs.mapbox.handleResize()
|
||||
})
|
||||
}
|
||||
}
|
||||
isCollapse () {
|
||||
return this.$store.state.app.isCollapse
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
|
@ -2,19 +2,21 @@
|
||||
<div class="app-container">
|
||||
<!-- 组合按钮 -->
|
||||
<el-button-group class="m-r-20 m-b-20">
|
||||
<el-button type="primary" icon="el-icon-plus" @click="$router.replace('/register/add')">添加</el-button>
|
||||
<el-button type="danger" icon="el-icon-delete" @click="deleteAir(countSelIdArr($refs.myTable.selection))">删除
|
||||
</el-button>
|
||||
<el-button type="warning" icon="el-icon-edit" @click="toEditPage()">编辑</el-button>
|
||||
<el-button type="success" icon="el-icon-data-line" @click="toFlyDataPage(countSelIdArr($refs.myTable.selection))">飞行数据</el-button>
|
||||
<el-button type="primary" icon="el-icon-plus" @click="$router.replace('/register/add')">添加</el-button>
|
||||
<el-button type="danger" icon="el-icon-delete" @click="deleteAir(countSelIdArr($refs.myTable.selection))">删除
|
||||
</el-button>
|
||||
<el-button type="warning" icon="el-icon-edit" @click="toEditPage()">编辑</el-button>
|
||||
<el-button type="warning" class="swarmButton" icon="iconfont icon-a-jiqunkongzhianniu_huaban1" @click="toSwarmPage()">集群控制</el-button>
|
||||
<el-button type="success" icon="el-icon-data-line"
|
||||
@click="toFlyDataPage(countSelIdArr($refs.myTable.selection))">飞行数据</el-button>
|
||||
</el-button-group>
|
||||
<!-- 用户select选项 -->
|
||||
<el-button-group class="m-b-20">
|
||||
<SelectionShopId v-model="form.shop_id" :allSel="true" />
|
||||
</el-button-group>
|
||||
<!-- 飞机表格 -->
|
||||
<el-table class="w-100" ref="myTable"
|
||||
:data="airListArr.slice((currentPage - 1) * pageSize, currentPage * pageSize)" border tooltip-effect="dark">
|
||||
<el-table class="w-100" ref="myTable" :data="airListArr.slice((currentPage - 1) * pageSize, currentPage * pageSize)"
|
||||
border tooltip-effect="dark">
|
||||
<el-table-column align="center" type="selection" width="40">
|
||||
</el-table-column>
|
||||
<el-table-column align="center" prop="id" label="id" width="50">
|
||||
@ -117,6 +119,20 @@ export default {
|
||||
this.$message.error('只能选择一条记录')
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @description: 跳转到编辑页面
|
||||
*/
|
||||
toSwarmPage () {
|
||||
const selId = this.countSelIdArr(this.$refs.myTable.selection)
|
||||
if (selId.length < 2) {
|
||||
this.$message.error('请选择至少两架飞机')
|
||||
return
|
||||
}
|
||||
// 用缓存传参 swarmIdArr
|
||||
this.$store.commit('app/setSwarmIdArr', selId)
|
||||
// 跳转到集群控制页面
|
||||
this.$router.push('/planes/swarm')
|
||||
},
|
||||
/**
|
||||
* @description: 跳转到飞机数据统计页面
|
||||
*/
|
||||
@ -155,6 +171,11 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
.swarmButton {
|
||||
background-color: #7C4DFF;
|
||||
border-color: #7C4DFF
|
||||
}
|
||||
|
||||
.no-wrap-btn-group {
|
||||
white-space: nowrap;
|
||||
/* 禁止换行 */
|
||||
|
@ -111,25 +111,34 @@ export default {
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @description: 动态加载路由
|
||||
*/
|
||||
* @description: 动态加载无人机子路由,并保留静态配置(如集群控制)
|
||||
* @param {Array} planes - 飞机对象数组,每个对象包含 id 和 name
|
||||
*/
|
||||
loadRoute (planes) {
|
||||
const arr = new Array(0)
|
||||
planes.map((item, index) => {
|
||||
arr[index] = {
|
||||
path: '/planes/index/' + item.id + '/' + item.name,
|
||||
component: () => import('@/views/layout/components/main/planes/index.vue'),
|
||||
meta: {
|
||||
title: item.name,
|
||||
icon: 'iconfont icon-wurenji',
|
||||
roles: ['admin', 'editor'],
|
||||
tapName: 'plane'
|
||||
}
|
||||
// 1. 将每架飞机转换为一个路由配置对象
|
||||
const dynamicPlaneRoutes = planes.map((item) => ({
|
||||
path: '/planes/index/' + item.id + '/' + item.name, // 动态路径,携带飞机ID和名称
|
||||
component: () => import('@/views/layout/components/main/planes/index.vue'), // 对应的组件路径
|
||||
meta: {
|
||||
title: item.name, // 用于左侧菜单或标签页显示
|
||||
icon: 'iconfont icon-wurenji', // 图标(可替换)
|
||||
roles: ['admin', 'editor'], // 权限控制
|
||||
tapName: 'plane' // 自定义标记
|
||||
// activeMenu: '/planes/swarm' // 可选:保持菜单高亮在“集群控制”
|
||||
}
|
||||
})
|
||||
this.routes.map((element) => {
|
||||
if (element.meta.title === '无人机') {
|
||||
element.children = arr
|
||||
}))
|
||||
|
||||
// 2. 遍历顶层路由配置,找到 path 为 "/planes" 的主路由
|
||||
this.routes.forEach((element) => {
|
||||
if (element.path === '/planes') {
|
||||
// 3. 过滤原本 children 中的静态路由(排除旧的动态飞机 index 路由)
|
||||
const staticChildren = element.children?.filter(child => !child.path.startsWith('/planes/index/')) || []
|
||||
|
||||
// 4. 合并:静态子路由(如 /planes/swarm) + 动态生成的飞机子路由
|
||||
element.children = [
|
||||
...staticChildren,
|
||||
...dynamicPlaneRoutes
|
||||
]
|
||||
}
|
||||
})
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user