<template>
|
<div class="AINowFly">
|
<div>智引即飞</div>
|
<el-form ref="ruleFormRef" :model="params" :rules="rules" label-width="auto" size="small" status-icon>
|
<el-form-item label="任务名称" prop="name">
|
<el-input v-model="params.name" />
|
</el-form-item>
|
<el-form-item label="关联算法" prop="ai_types">
|
<el-select v-model="params.ai_types" placeholder="请选择" multiple>
|
<el-option v-for="item in taskAlgorithm" :key="item.id" :label="item.dictValue" :value="item.dictKey" />
|
</el-select>
|
</el-form-item>
|
<el-form-item label="地址">
|
<el-input disabled type="text" v-model="di" />
|
</el-form-item>
|
<!-- todo-->
|
<el-form-item label="事件">
|
<div>默认拍照</div>
|
</el-form-item>
|
</el-form>
|
|
<div>可用机巢列表</div>
|
<el-table :data="list" @selection-change="handleSelectionChange">
|
<el-table-column type="selection" width="55" />
|
<el-table-column type="index" label="序号" />
|
<el-table-column prop="nickname" label="机巢名称" />
|
<el-table-column prop="minute" label="预计飞行时长(分钟)" />
|
<el-table-column prop="exe_distance" label="预计飞行距离(m)" />
|
</el-table>
|
<el-button type="primary" @click="nowFly">迅速起飞</el-button>
|
</div>
|
</template>
|
<script setup>
|
import { getMultipleDictionary } from '@/api/system/dictbiz'
|
import * as Cesium from 'cesium'
|
import { createTask, getFlyingNestBy } from '@/api/home/task'
|
import { cartesian3Convert } from '@/utils/cesium/mapUtil'
|
import { Cartesian3 } from 'cesium'
|
import uavImg from '@/assets/images/home/useUavHome/uavImg.png'
|
import ImageTrailMaterial from '@/utils/cesium/ImageTrailMaterial'
|
import lineImg from '@/assets/images/arrow-right-blue.png'
|
import _ from 'lodash'
|
import { ElMessage } from 'element-plus'
|
import dayjs from 'dayjs'
|
import { useStore } from 'vuex'
|
|
const now = dayjs().format('YYYYMMDDHHmm')
|
const nowTime = dayjs().format('YYYY-MM-DD HH:mm:ss')
|
|
const paramsInit = {
|
name: `智引即飞${now}`,
|
ai_types: '',
|
longitude: '',
|
latitude: '',
|
dock_sns: [],
|
type: 1,
|
begin_time: nowTime,
|
end_time: nowTime,
|
}
|
const params = ref(_.cloneDeep(paramsInit))
|
const di = computed(() => params.value.longitude + ',' + params.value.latitude)
|
|
const rules = ref({
|
name: [
|
{ required: true, message: '请输入任务名称', trigger: 'blur' },
|
{ min: 3, max: 50, message: '长度在 3 到 20 个字符', trigger: 'blur' },
|
],
|
ai_types: [{ required: true, message: '请选择算法', trigger: 'change' }],
|
})
|
|
const ruleFormRef = ref(null)
|
let handler = null
|
const taskAlgorithm = ref([])
|
|
let viewer
|
const list = ref([])
|
let eventPoint = {}
|
const store = useStore()
|
const handleSelectionChange = val => {
|
params.value.dock_sns = val.map(item => item.device_sn)
|
}
|
|
const nowFly = async () => {
|
await ruleFormRef.value.validate()
|
if (!params.value.dock_sns.length) return ElMessage.warning('请选择将要飞行的机巢')
|
if (!params.value.longitude) return ElMessage.warning('请选择飞行的点')
|
createTask(params.value).then(res => {
|
ElMessage.success('起飞成功')
|
if (params.value.dock_sns.length === 1) {
|
store.commit('setSingleUavHome', { device_sn: params.value.dock_sns[0] })
|
} else {
|
store.commit('setFootActiveIndex', 0)
|
}
|
})
|
}
|
|
const renderingLine = () => {
|
const { longitude, latitude } = eventPoint
|
list.value.forEach((item, index) => {
|
const start = Cartesian3.fromDegrees(Number(item.longitude), Number(item.latitude))
|
const end = Cartesian3.fromDegrees(Number(longitude), Number(latitude))
|
const positionsList = [start, end]
|
// 线
|
viewer.entities.add({
|
id: `AINow-line-${index}`,
|
polyline: {
|
width: 4,
|
positions: positionsList,
|
material: new ImageTrailMaterial({
|
color: { alpha: 1, blue: 1, green: 1, red: 1 },
|
speed: 20,
|
image: lineImg,
|
repeat: { x: Math.floor(40), y: 1 },
|
}),
|
clampToGround: false,
|
},
|
})
|
// 点
|
viewer.entities.add({
|
id: `AINow-point-${index}`,
|
position: start,
|
label: {
|
text: item.nickname,
|
font: '12pt Source Han Sans CN',
|
fillColor: Cesium.Color.WHITE,
|
outlineColor: Cesium.Color.BLACK,
|
outlineWidth: 2,
|
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
|
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
|
pixelOffset: new Cesium.Cartesian2(0, -9),
|
},
|
billboard: {
|
image: new Cesium.ConstantProperty(uavImg),
|
width: 24,
|
height: 24,
|
},
|
properties: {
|
customData: {
|
data: item,
|
},
|
},
|
})
|
})
|
}
|
|
const removeEntities = () => {
|
const entitiesIDs = viewer.entities.values.map(i => i.id)
|
entitiesIDs.forEach(item => {
|
item.includes('AINow-') && viewer.entities.removeById(item)
|
})
|
}
|
|
// 单击事件
|
const singleClickEvent = click => {
|
removeEntities()
|
const earthPosition = viewer.scene.pickPosition(click.position)
|
viewer.entities.add({
|
position: earthPosition,
|
id: `AINow-event-0`,
|
point: {
|
pixelSize: 10,
|
color: Cesium.Color.RED,
|
outlineColor: Cesium.Color.WHITE,
|
outlineWidth: 2,
|
},
|
})
|
const { longitude, latitude } = cartesian3Convert(earthPosition, viewer)
|
eventPoint = { longitude, latitude }
|
params.value = { ...params.value, longitude, latitude }
|
getFJList()
|
}
|
|
// 请求字典字段
|
const requestDictionary = () => {
|
getMultipleDictionary('SF').then(res => {
|
if (res.code !== 0) {
|
taskAlgorithm.value = res.data.data['SF']
|
}
|
})
|
}
|
|
// 获取飞机列表
|
const getFJList = async () => {
|
params.value.dock_sns = []
|
const getListParams = { ...eventPoint, page: 1, limit: 9999, type: 1 }
|
const res = await getFlyingNestBy(getListParams)
|
list.value = (res.data?.data || []).map(item => ({
|
...item,
|
minute: _.round(item.estimated_arrival_time / 60, 0),
|
}))
|
if (!list.value.length) ElMessage.warning('附近暂无可用无人机')
|
renderingLine()
|
}
|
|
const initMap = () => {
|
handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)
|
handler.setInputAction(singleClickEvent, Cesium.ScreenSpaceEventType.LEFT_CLICK)
|
}
|
|
const removeAll = () => {
|
removeEntities()
|
handler?.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK)
|
handler?.destroy()
|
handler = null
|
}
|
|
onBeforeUnmount(() => {
|
removeAll()
|
})
|
|
onMounted(() => {
|
requestDictionary()
|
viewer = window.$viewer
|
initMap()
|
})
|
</script>
|
<style scoped lang="scss">
|
.AINowFly {
|
position: absolute;
|
top: 200px;
|
right: 0;
|
width: 400px;
|
height: 700px;
|
background: white;
|
color: black;
|
font-size: 20px;
|
}
|
</style>
|