From 387f1df6e631d768fd03ab15fc7160df1a79401a Mon Sep 17 00:00:00 2001
From: GuLiMmo <2820890765@qq.com>
Date: Thu, 23 Nov 2023 17:44:28 +0800
Subject: [PATCH] 航线库修改
---
src/pages/page-web/projects/wayline.vue | 410 ++++++++++++++++++++++++++++++++++++++++++++++-----------
1 files changed, 327 insertions(+), 83 deletions(-)
diff --git a/src/pages/page-web/projects/wayline.vue b/src/pages/page-web/projects/wayline.vue
index e532830..c2bc916 100644
--- a/src/pages/page-web/projects/wayline.vue
+++ b/src/pages/page-web/projects/wayline.vue
@@ -1,81 +1,118 @@
<template>
- <div class="project-wayline-wrapper height-100">
+ <div class="project-wayline-wrapper height-100" ref="projectWayLine">
<a-spin :spinning="loading" :delay="300" tip="加载中" size="large">
- <div style="height: 50px; line-height: 50px; border-bottom: 1px solid #4f4f4f; font-weight: 450;">
- <a-row>
- <a-col :span="1"></a-col>
- <a-col :span="15">航线库</a-col>
- <a-col :span="8" v-if="importVisible" class="flex-row flex-justify-end flex-align-center">
- <a-upload
- name="file"
- :multiple="false"
- :before-upload="beforeUpload"
- :show-upload-list="false"
- :customRequest="uploadFile"
- >
- <a-button type="text" style="color: white;">
- <SelectOutlined />
- </a-button>
- </a-upload>
- </a-col>
- </a-row>
- </div>
- <div :style="{ height : height + 'px'}" class="scrollbar">
- <div id="data" class="height-100 uranus-scrollbar" v-if="waylinesData.data.length !== 0" @scroll="onScroll">
- <div v-for="wayline in waylinesData.data" :key="wayline.id">
- <div class="wayline-panel" style="padding-top: 5px;" @click="selectRoute(wayline)">
- <div class="title">
- <a-tooltip :title="wayline.name">
- <div class="pr10" style="width: 120px; white-space: nowrap; text-overflow: ellipsis; overflow: hidden;">{{ wayline.name }}</div>
- </a-tooltip>
- <div class="ml10"><UserOutlined /></div>
- <a-tooltip :title="wayline.user_name">
- <div class="ml5 pr10" style="width: 80px; white-space: nowrap; text-overflow: ellipsis; overflow: hidden;">{{ wayline.user_name }}</div>
- </a-tooltip>
- <div class="fz20">
- <a-dropdown>
- <a style="color: white;">
- <EllipsisOutlined />
- </a>
- <template #overlay>
- <a-menu theme="dark" class="more" style="background: #3c3c3c;">
- <a-menu-item @click="downloadWayline(wayline.id, wayline.name)">
- <span>下载</span>
- </a-menu-item>
- <a-menu-item @click="showWaylineTip(wayline.id)">
- <span>删除</span>
- </a-menu-item>
- </a-menu>
- </template>
- </a-dropdown>
+ <div style="height: 50px; line-height: 50px; border-bottom: 1px solid #4f4f4f; font-weight: 450;">
+ <a-row>
+ <a-col :span="1"></a-col>
+ <a-col :span="15">{{ isPointListOpen ? '航点列表' : '航线库' }}</a-col>
+ <a-col :span="8" v-if="importVisible" class="flex-row flex-justify-end flex-align-center">
+ <a-upload name="file" :multiple="false" :before-upload="beforeUpload" :show-upload-list="false"
+ :customRequest="uploadFile">
+ <a-button type="text" style="color: white;">
+ <SelectOutlined />
+ </a-button>
+ </a-upload>
+ </a-col>
+ </a-row>
+ </div>
+ <div :style="{ height: height + 'px' }" class="scrollbar" v-if="!isPointListOpen">
+ <div id="data" class="height-100 uranus-scrollbar" v-if="waylinesData.data.length !== 0" @scroll="onScroll">
+ <div v-for="wayline in waylinesData.data" :key="wayline.id">
+ <div class="wayline-panel" style="padding-top: 5px;" @click="selectRoute(wayline)">
+ <div class="title">
+ <a-tooltip :title="wayline.name">
+ <div class="pr10" style="width: 120px; white-space: nowrap; text-overflow: ellipsis; overflow: hidden;">
+ {{ wayline.name }}</div>
+ </a-tooltip>
+ <div class="ml10">
+ <UserOutlined />
+ </div>
+ <a-tooltip :title="wayline.user_name">
+ <div class="ml5 pr10"
+ style="width: 80px; white-space: nowrap; text-overflow: ellipsis; overflow: hidden;">{{
+ wayline.user_name }}</div>
+ </a-tooltip>
+ <div class="fz20">
+ <!-- <span style="margin-right: 10px;">
+ <EditOutlined style="font-size: 15px;" />
+ </span> -->
+ <a-dropdown>
+ <a style="color: white;">
+ <EllipsisOutlined />
+ </a>
+ <template #overlay>
+ <a-menu theme="dark" class="more" style="background: #3c3c3c;">
+ <a-menu-item @click="openEditModal(wayline)">
+ <span>重命名</span>
+ </a-menu-item>
+ <a-menu-item @click="downloadWayline(wayline.id, wayline.name)">
+ <span>下载</span>
+ </a-menu-item>
+ <a-menu-item @click="showWaylineTip(wayline.id)">
+ <span>删除</span>
+ </a-menu-item>
+ </a-menu>
+ </template>
+ </a-dropdown>
+ </div>
</div>
- </div>
- <div class="ml10 mt5" style="color: hsla(0,0%,100%,0.65);">
- <span><RocketOutlined /></span>
- <span class="ml5">{{ Object.keys(EDeviceType)[Object.values(EDeviceType).indexOf(wayline.drone_model_key)] }}</span>
- <span class="ml10"><CameraFilled style="border-top: 1px solid; padding-top: -3px;" /></span>
- <span class="ml5" v-for="payload in wayline.payload_model_keys" :key="payload.id">
- {{ Object.keys(EDeviceType)[Object.values(EDeviceType).indexOf(payload)] }}
- </span>
- </div>
- <div class="mt5 ml10" style="color: hsla(0,0%,100%,0.35);">
- <span class="mr10">更新时间: {{ new Date(wayline.update_time).toLocaleString() }}</span>
+ <div class="ml10 mt5" style="color: hsla(0,0%,100%,0.65);">
+ <span>
+ <RocketOutlined />
+ </span>
+ <span class="ml5">{{ Object.keys(EDeviceType)[Object.values(EDeviceType).indexOf(wayline.drone_model_key)]
+ }}</span>
+ <span class="ml10">
+ <CameraFilled style="border-top: 1px solid; padding-top: -3px;" />
+ </span>
+ <span class="ml5" v-for="payload in wayline.payload_model_keys" :key="payload.id">
+ {{ Object.keys(EDeviceType)[Object.values(EDeviceType).indexOf(payload)] }}
+ </span>
+ </div>
+ <div class="mt5 ml10" style="color: hsla(0,0%,100%,0.35);">
+ <span class="mr10">更新时间: {{ new Date(wayline.update_time).toLocaleString() }}</span>
+ </div>
</div>
</div>
</div>
- </div>
- <div v-else>
- <a-empty :image-style="{ height: '60px', marginTop: '60px' }" />
- </div>
- <a-modal v-model:visible="deleteTip" okText="确定" cancelText="取消" width="450px" :closable="false" :maskClosable="false" centered :okButtonProps="{ danger: true }" @ok="deleteWayline">
+ <div v-else>
+ <a-empty :image-style="{ height: '60px', marginTop: '60px' }" />
+ </div>
+ <a-modal v-model:visible="deleteTip" okText="确定" cancelText="取消" width="450px" :closable="false"
+ :maskClosable="false" centered :okButtonProps="{ danger: true }" @ok="deleteWayline">
<p class="pt10 pl20" style="height: 50px;">确定要删除该文件吗?</p>
<template #title>
- <div class="flex-row flex-justify-center">
- <span>删除</span>
- </div>
+ <div class="flex-row flex-justify-center">
+ <span>删除</span>
+ </div>
</template>
- </a-modal>
- </div>
+ </a-modal>
+ <!-- 编辑 -->
+ <a-modal class="edit-modal-box" v-model:visible="editVisible" title="编辑航线名称" :get-container="() => projectWayLine"
+ :cancel-button-props="{
+ ghost: true,
+ }" @ok="handleEditName">
+ <div class="wayline-title">航线名称</div>
+ <a-input v-model:value="currentWayLine.name" placeholder="请输入航线名称" />
+ </a-modal>
+ </div>
+ <ul class="targt-point scrollbar" :style="{ height: height + 'px' }" v-else>
+ <div class="back-btn" @click="isPointListOpen = !isPointListOpen">
+ <ArrowLeftOutlined />
+ <span>返回上一页</span>
+ </div>
+ <li
+ v-for="(position, index) in tragetPointArr"
+ :key="index"
+ :class="{ selectedColor : index === selectedPoint }"
+ @click="tragetPointClick(position, index)">
+ <div class="graph">
+ <div class="left" :style="{borderTopColor: index === selectedPoint ? '#FF9900' : '#2D8CF0'}"></div>
+ <div class="right">{{ index + 1 }}</div>
+ </div>
+ <div class="graph-right"></div>
+ </li>
+ </ul>
</a-spin>
</div>
</template>
@@ -86,7 +123,7 @@
import { onMounted, onUpdated, ref } from 'vue'
import { deleteWaylineFile, downloadWaylineFile, getWaylineFiles, importKmzFile, getWayLineFile } from '/@/api/wayline'
import { ELocalStorageKey, ERouterName } from '/@/types'
-import { EllipsisOutlined, RocketOutlined, CameraFilled, UserOutlined, SelectOutlined } from '@ant-design/icons-vue'
+import { ArrowLeftOutlined, EllipsisOutlined, RocketOutlined, CameraFilled, UserOutlined, SelectOutlined, EditOutlined } from '@ant-design/icons-vue'
import { EDeviceType } from '/@/types/device'
import { useMyStore } from '/@/store'
import { WaylineFile } from '/@/types/wayline'
@@ -97,13 +134,16 @@
import { getRoot } from '/@/root'
import * as Cesium from 'cesium'
import { cesiumOperation } from '/@/hooks/use-cesium-tsa'
+import { stat } from 'fs'
+
+const projectWayLine = ref<HTMLDivElement>()
const loading = ref(false)
-const { appContext } = getCurrentInstance()
+const { appContext }: any = getCurrentInstance()
const global = appContext.config.globalProperties
const store = useMyStore()
-let kmlDataSource = null
-const pagination :IPage = {
+let kmlDataSource: { entities: { values: { _children: any }[] }; show: boolean } | null | any = null
+const pagination: IPage = {
page: 1,
total: -1,
page_size: 10
@@ -112,6 +152,8 @@
const waylinesData = reactive({
data: [] as WaylineFile[]
})
+// 当前点击的信息
+const currentWayLine = ref<any>({})
const root = getRoot()
const workspaceId = computed(() => store.state.common.projectId || localStorage.getItem(ELocalStorageKey.WorkspaceId))
@@ -119,8 +161,14 @@
const deleteWaylineId = ref<string>('')
const canRefresh = ref(true)
const importVisible = ref<boolean>(root.$router.currentRoute.value.name === ERouterName.WAYLINE)
+const editVisible = ref<boolean>(false)
const height = ref()
-const { removeById, } = cesiumOperation()
+const { removeById, addClickEvent, getEntityById } = cesiumOperation()
+
+const isPointListOpen = ref<boolean>(false)
+const tragetPointArr = ref<Cesium.Cartesian3[]>([])
+const selectedPoint = ref<number | null>(null)
+const tPointIdList = ref<string[]>([])
onMounted(() => {
const parent = document.getElementsByClassName('scrollbar').item(0)?.parentNode as HTMLDivElement
@@ -143,6 +191,11 @@
global.$viewer.dataSources.remove(kmlDataSource)
}
removeById('kmzLine')
+ removeById('clickBox')
+ store.commit('SET_WAYLINE_INFO', {
+ isShow: false,
+ wayline: {}
+ })
})
function getWaylines () {
@@ -206,12 +259,19 @@
}).finally(() => {
loading.value = false
})
+ // 清除选中点柱形和隐藏按钮
+ store.commit('SET_WAYLINE_INFO', {
+ isShow: false,
+ wayline: {}
+ })
+ removeById('clickBox')
+ isPointListOpen.value = !isPointListOpen.value
}
/**
* 加载kml文件
* @param file
*/
-function initKmlFile (file:string) {
+function initKmlFile (file: string) {
removeById('kmzLine')
const options = {
camera: global.$viewer.scene.camera,
@@ -230,24 +290,32 @@
kmlEntity.value = kmlDataSource.entities.values
kmlDataSource.show = true
const kmlEntityArr = kmlDataSource.entities.values[0]._children
- const cartesianArr = []
+ const cartesianArr: any[] = []
for (let i = 0; i < kmlEntityArr.length; i++) {
const entity = kmlEntityArr[i]
- entity.point = new Cesium.PointGraphics({
- pixelSize: 12,
- color: Cesium.Color.RED,
- outlineColor: Cesium.Color.WHITE,
+ tPointIdList.value.push(entity._id)
+ const billboard = createBillboard(`${i + 1}`, '#2D8CF0')
+ entity._id = 'tragetPoint' + i
+ entity.billboard = new Cesium.BillboardGraphics({
+ image: billboard,
+ pixelOffset: new Cesium.Cartesian2(0, -20)
})
- entity.billboard = null
+ entity.point = new Cesium.PointGraphics({
+ pixelSize: 20,
+ color: Cesium.Color.GHOSTWHITE,
+ outlineColor: Cesium.Color.BLACK,
+ })
cartesianArr.push(entity.position._value)
}
+ tragetPointArr.value = cartesianArr
+ const stripe = createStripe()
const lineEntity = global.$viewer.entities.add({
name: 'entityLine',
id: 'kmzLine',
polyline: {
positions: cartesianArr,
- width: 10,
- material: new Cesium.PolylineArrowMaterialProperty(Cesium.Color.CYAN),
+ width: 20,
+ material: new Cesium.PolylineArrowMaterialProperty(Cesium.Color.MEDIUMSPRINGGREEN),
clampToGround: false, // 关闭贴地效果,保留高度
},
})
@@ -257,6 +325,31 @@
})
})
}
+
+function tragetPointClick (position: Cesium.Cartesian3, index: number) {
+ selectedPoint.value = index
+ store.commit('SET_WAYLINE_INFO', {
+ isShow: true,
+ wayline: currentWayLine
+ })
+ if (getEntityById('clickBox')) {
+ removeById('clickBox')
+ }
+ // 创建盒子
+ const entity = {
+ id: 'clickBox',
+ position,
+ box: {
+ dimensions: new Cesium.Cartesian3(10.0, 10.0, 99999),
+ material: Cesium.Color.MEDIUMSPRINGGREEN.withAlpha(0.1),
+ outline: true,
+ outlineColor: Cesium.Color.MEDIUMSPRINGGREEN.withAlpha(0.8),
+ heightReference: true
+ }
+ }
+ global.$viewer.entities.add(entity)
+}
+
function onScroll (e: any) {
const element = e.srcElement
if (element.scrollTop + element.clientHeight >= element.scrollHeight - 5 && Math.ceil(pagination.total / pagination.page_size) > pagination.page && canRefresh.value) {
@@ -264,6 +357,7 @@
getWaylines()
}
}
+
interface FileItem {
uid: string;
name?: string;
@@ -303,6 +397,61 @@
})
}
+// 创建广告牌
+const createBillboard = (title: string, color: string) => {
+ // 创建canvas绘制广告牌
+ const billboard = document.createElement('canvas')
+ billboard.width = 30
+ billboard.height = 30
+ const ctx: HTMLCanvasElement | any = billboard.getContext('2d')
+ ctx.beginPath()
+ ctx.moveTo(0, 0)
+ ctx.lineTo(30, 0)
+ ctx.lineTo(15, 22)
+ ctx.fillStyle = color
+ ctx.fill()
+ ctx.font = '18px serif'
+ ctx.fillStyle = '#ffffff'
+ ctx.fillText(title, 10, 15)
+ ctx.closePath()
+ return billboard
+}
+
+// 创建条纹
+const createStripe = () => {
+ // 创建canvas绘制广告牌
+ const stripe = document.createElement('canvas')
+ stripe.width = 40
+ stripe.height = 40
+ const ctx: HTMLCanvasElement | any = stripe.getContext('2d')
+ ctx.beginPath()
+ ctx.moveTo(0, 20)
+ ctx.lineTo(0, 40)
+ ctx.lineTo(20, 20)
+ ctx.lineTo(20, 0)
+ ctx.fillStyle = '#fff'
+ ctx.fill()
+ ctx.closePath()
+ ctx.beginPath()
+ ctx.moveTo(20, 0)
+ ctx.lineTo(20, 20)
+ ctx.lineTo(40, 40)
+ ctx.lineTo(40, 20)
+ ctx.fillStyle = '#fff'
+ ctx.fill()
+ ctx.closePath()
+ return stripe
+}
+
+const openEditModal = (wayline: any) => {
+ currentWayLine.value = wayline
+ editVisible.value = true
+}
+
+const handleEditName = () => {
+ editVisible.value = false
+}
+
</script>
<style lang="scss" scoped>
@@ -316,6 +465,7 @@
font-size: 13px;
border-radius: 2px;
cursor: pointer;
+
.title {
display: flex;
flex-direction: row;
@@ -325,9 +475,103 @@
margin: 0px 10px 0 10px;
}
}
+
.uranus-scrollbar {
overflow: auto;
scrollbar-width: thin;
scrollbar-color: #c5c8cc transparent;
}
+
+.project-wayline-wrapper {
+ .targt-point {
+ padding: 0;
+ margin: 0;
+ list-style-type: none;
+ .back-btn {
+ cursor: pointer;
+ padding: 10px;
+ border-bottom: 1px solid #4f4f4f;
+ span {
+ margin-left: 10px;
+ }
+ &:hover {
+ color: #2d8cf0;
+ }
+ }
+ li {
+ cursor: pointer;
+ padding: 10px 0;
+ margin: 0 7px;
+ display: flex;
+ .graph {
+ width: 40px;
+ display: flex;
+ align-items: center;
+ .left {
+ width: 0;
+ height: 0;
+ border-top: 15px solid #2D8CF0;
+ border-right: 10px solid transparent;
+ border-left: 10px solid transparent;
+ }
+ .right {
+ margin-left: 3px;
+ }
+ }
+ .graph-right {
+ width: calc(100% - 40px);
+ border-bottom: 1px solid #4f4f4f;
+ }
+ &:hover {
+ background-color: #3C3C3C;
+ }
+ }
+ }
+
+ :deep(.ant-modal) {
+ .ant-modal-close {
+ height: 40px;
+ width: 40px;
+
+ .ant-modal-close-x {
+ width: 100%;
+ height: 100%;
+ line-height: 40px;
+ color: #fff;
+ }
+ }
+
+ .ant-modal-header {
+ text-align: center;
+ padding: 10px;
+ border: 0;
+ background-color: #282828;
+
+ .ant-modal-title {
+ color: #fff;
+ font-size: 15px;
+ }
+ }
+
+ .ant-modal-body,
+ .ant-modal-footer {
+ background-color: #1C1C1C;
+ border: 0;
+
+ .wayline-title {
+ color: #c5c8cc;
+ margin-bottom: 10px;
+ }
+
+ .ant-input {
+ background-color: transparent;
+ color: #fff;
+ }
+ }
+ }
+}
+
+.selectedColor {
+ background-color: #3C3C3C;
+}
</style>
--
Gitblit v1.9.3