Merge branch 'main' of http://123.132.248.154:10000/gitY/DiKongGanZhiPingTai
|
After Width: | Height: | Size: 307 B |
|
After Width: | Height: | Size: 186 B |
|
After Width: | Height: | Size: 859 B |
|
After Width: | Height: | Size: 347 B |
|
After Width: | Height: | Size: 410 B |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 802 B |
|
After Width: | Height: | Size: 968 B |
|
|
@ -0,0 +1,486 @@
|
|||
<template>
|
||||
<div class="title-div">
|
||||
<div class="title-span-div">
|
||||
<div class="title-icon"></div>
|
||||
<div class="title-span">创建算法</div>
|
||||
</div>
|
||||
<div class="close-button" @click="emits('changeAddModal',false)"></div>
|
||||
</div>
|
||||
<div class="interval"></div>
|
||||
<div class="modal-content">
|
||||
<div class="left-content">
|
||||
<div class="item-title">模型名称</div>
|
||||
<a-input class="name-input" v-model:value="modelName" placeholder="请输入相关名称" />
|
||||
<div class="item-title">模型描述</div>
|
||||
<a-textarea class="item-desc" v-model:value="modelDescription" placeholder="请输入相关描述" :rows="4" />
|
||||
<div class="item-title">模型封面</div>
|
||||
<div class="item-image">
|
||||
<div class="empty-image" @click="changeSelectImageModal(true)">
|
||||
<div class="empty-image-content">
|
||||
<div class="empty-image-icon"></div>
|
||||
<div class="empty-image-span">请选择文件上传</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="right-content">
|
||||
<div class="item-title">模型类型</div>
|
||||
<a-segmented class="item-type" v-model:value="modelType" :options="modelTypeOptions"></a-segmented>
|
||||
<template v-if="modelType == '0'">
|
||||
<div class="item-title">模型规模</div>
|
||||
<a-segmented class="item-type" v-model:value="modelScale" :options="modelScaleOptions"></a-segmented>
|
||||
<div class="item-title">模型文件</div>
|
||||
<a-upload
|
||||
v-model:file-list="modelFile"
|
||||
accept=".zip"
|
||||
:maxCount="1"
|
||||
:custom-request="customRequest"
|
||||
>
|
||||
<a-button class="select-model-file-button" type="primary" :icon="h(PlusOutlined)">选择模型文件</a-button>
|
||||
<!-- <template #itemRender="{ file, actions }">
|
||||
<a-space>
|
||||
<span>{{ file.name }}</span>
|
||||
</a-space>
|
||||
</template> -->
|
||||
</a-upload>
|
||||
<div class="upload-hint">(*请上传模型压缩文件,支持pt格式)</div>
|
||||
<div class="item-title">模型标签</div>
|
||||
<div class="item-label-div">
|
||||
<div class="label-title-div">
|
||||
<div class="label-title-span">请根据模型实际情况填写信息</div>
|
||||
<div class="add-button" @click="addLabelRow">
|
||||
<div class="button-icon"></div>
|
||||
<div class="button-span">添加行</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="label-interval"></div>
|
||||
<div class="label-table-title">
|
||||
<div class="table-title-item" style="padding-left: 6px;">枚举值</div>
|
||||
<div class="table-title-item">名称</div>
|
||||
<div class="table-title-item">推荐置信度</div>
|
||||
<div class="table-title-item" style="width: 55px;justify-content: center;">操作</div>
|
||||
</div>
|
||||
<div class="label-table-content">
|
||||
<div class="table-row" v-for="(item,index) in modelLabelList" :key="index">
|
||||
<div class="table-item">
|
||||
<a-input class="table-item-input" v-model:value="item.test"/>
|
||||
</div>
|
||||
<div class="table-item">
|
||||
<a-input class="table-item-input" />
|
||||
</div>
|
||||
<div class="table-item">
|
||||
<a-input class="table-item-input" />
|
||||
</div>
|
||||
<div class="table-item" style="width: 55px; justify-content: center">
|
||||
<div class="del-table-row" @click="delLabelRow(index)"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="item-title">推流地址</div>
|
||||
<a-input class="name-input" v-model:value="modelPushAddress" placeholder="请输入地址" />
|
||||
<div class="item-title">拉流地址</div>
|
||||
<a-input class="name-input" v-model:value="modelPullAddress" placeholder="请输入地址" />
|
||||
<div class="item-title">服务地址</div>
|
||||
<a-input class="name-input" v-model:value="modelServeAddress" placeholder="请输入地址" />
|
||||
<div class="item-title">密钥</div>
|
||||
<a-textarea class="item-key" v-model:value="modelKey" placeholder="请输入密钥" :rows="4" />
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<div class="interval"></div>
|
||||
<div class="footer">
|
||||
<a-button class="cancel-button" @click="emits('changeAddModal',false)">取消</a-button>
|
||||
<a-button class="save-button" type="primary">确定</a-button>
|
||||
</div>
|
||||
<a-modal v-model:open="selectImageModal" title="选择封面" width="1000px" :footer="null" :destroyOnClose="true">
|
||||
<SelectImageModal @changeSelectImageModal="changeSelectImageModal"/>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, h, defineEmits, defineProps } from "vue"
|
||||
import { uploadFile } from '@/api/formrender/index';
|
||||
import { PlusOutlined, } from '@ant-design/icons-vue';
|
||||
import SelectImageModal from "./SelectImageModal.vue";
|
||||
const props = defineProps([''])
|
||||
const emits = defineEmits(['changeAddModal'])
|
||||
const modelName = ref('')
|
||||
const modelDescription = ref('')
|
||||
const modelType = ref('0')
|
||||
const modelScale = ref('N')
|
||||
const modelPullAddress = ref('')
|
||||
const modelPushAddress = ref('')
|
||||
const modelServeAddress = ref('')
|
||||
const modelKey = ref('')
|
||||
const modelFile = ref([])
|
||||
const modelFilePath = ref()
|
||||
const modelLabelList = ref([])
|
||||
const selectImageModal = ref(false)
|
||||
const modelTypeOptions = ref([
|
||||
{ label: '本地模型', value: '0' },
|
||||
{ label: '远程模型', value: '1' }
|
||||
])
|
||||
const modelScaleOptions = ref([
|
||||
{ label: 'N', value: 'N' },
|
||||
{ label: 'S', value: 'S' },
|
||||
{ label: 'M', value: 'M' },
|
||||
{ label: 'L', value: 'L' },
|
||||
{ label: 'XI', value: 'XI' },
|
||||
])
|
||||
const customRequest = (file) => {
|
||||
const formData = new FormData()
|
||||
formData.append('files', file.file)
|
||||
uploadFile(formData).then(res => {
|
||||
modelFilePath.value = res[0].filePath
|
||||
// emits('update:shppath',res[0].filePath)
|
||||
})
|
||||
}
|
||||
const addLabelRow = () => {
|
||||
// TODO
|
||||
modelLabelList.value.push({
|
||||
test:''
|
||||
})
|
||||
}
|
||||
const delLabelRow = (index) => {
|
||||
modelLabelList.value.splice(index,1)
|
||||
}
|
||||
const changeSelectImageModal = (type: boolean) => {
|
||||
selectImageModal.value = type
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.title-div{
|
||||
width: 100%;
|
||||
height: 64px;
|
||||
padding-top: 15px;
|
||||
padding-left: 26px;
|
||||
padding-right: 35px;
|
||||
padding-bottom: 14px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
.title-span-div{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.title-icon{
|
||||
width: 3px;
|
||||
height: 18px;
|
||||
background: #0B60BD;
|
||||
box-shadow: 0px 10px 30px 0px rgba(0,0,6,0.15);
|
||||
margin-right: 9px;
|
||||
}
|
||||
.title-span{
|
||||
font-family: PingFangSC-Medium;
|
||||
font-weight: 500;
|
||||
font-size: 20px;
|
||||
color: #11131B;
|
||||
line-height: 33px;
|
||||
text-shadow: 0px 10px 30px rgba(0,0,6,0.15);
|
||||
}
|
||||
}
|
||||
.close-button{
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
background-image: url('/public/ailist/add_algorithm_close_button.png');
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
.interval{
|
||||
width: 631px;
|
||||
height: 1px;
|
||||
box-shadow: 0px 10px 30px 0px rgba(0,0,6,0.15);
|
||||
border: 1px solid #DBDBDB;
|
||||
opacity: 0.66;
|
||||
}
|
||||
.modal-content{
|
||||
display: flex;
|
||||
padding-top: 14px;
|
||||
padding-left: 27px;
|
||||
padding-right: 35px;
|
||||
padding-bottom: 28px;
|
||||
.item-title{
|
||||
font-family: PingFangSC-Medium;
|
||||
font-weight: 500;
|
||||
font-size: 16px;
|
||||
color: #222738;
|
||||
line-height: 33px;
|
||||
text-shadow: 0px 10px 30px rgba(0,0,6,0.15);
|
||||
margin-bottom: 9px;
|
||||
}
|
||||
.name-input{
|
||||
height: 40px;
|
||||
// box-shadow: 0px 10px 30px 0px rgba(0,0,6,0.15);
|
||||
border-radius: 2px;
|
||||
border: 1px solid #CCCCCC;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.left-content{
|
||||
width: 253px;
|
||||
margin-right: 46px;
|
||||
.item-desc{
|
||||
height: 151px;
|
||||
// box-shadow: 0px 10px 30px 0px rgba(0,0,6,0.15);
|
||||
border-radius: 2px;
|
||||
border: 1px solid #CCCCCC;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.item-image{
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 155px;
|
||||
background: #F5F5F5;
|
||||
// box-shadow: 0px 10px 30px 0px rgba(0,0,6,0.15);
|
||||
border: 2px dashed rgba(28,29,34,0.08);
|
||||
.empty-image{
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 209px;
|
||||
height: 119px;
|
||||
background: #FFFFFF;
|
||||
box-shadow: 0px 10px 30px 0px rgba(0,0,6,0.15), 0px 8px 6px 0px rgba(28,29,34,0.06);
|
||||
border-radius: 2px;
|
||||
border: 1px solid #CCCCCC;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
.empty-image-content{
|
||||
width: 98px;
|
||||
height: 63px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
.empty-image-icon{
|
||||
width: 26px;
|
||||
height: 28px;
|
||||
background-image: url('/public/ailist/algorithm_upload_icon.png');
|
||||
margin-bottom: 1px;
|
||||
}
|
||||
.empty-image-span{
|
||||
font-family: PingFangSC-Regular;
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
color: #222738;
|
||||
line-height: 33px;
|
||||
text-shadow: 0px 10px 30px rgba(0,0,6,0.15);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.right-content{
|
||||
width: 269px;
|
||||
.item-type{
|
||||
width: 262px;
|
||||
height: 40px;
|
||||
background: rgba(28,29,34,0.04);
|
||||
border-radius: 20px;
|
||||
margin-bottom: 6px;
|
||||
// box-shadow: 0px 10px 30px 0px rgba(0,0,6,0.15);
|
||||
:deep(.ant-segmented-group){
|
||||
height: 36px;
|
||||
}
|
||||
:deep(.ant-segmented-item){
|
||||
width: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 18px;
|
||||
font-family: PingFangSC-Regular;
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
color: rgba(28,29,34,0.5);
|
||||
line-height: 20px;
|
||||
text-shadow: 0px 10px 30px rgba(0,0,6,0.15);
|
||||
}
|
||||
:deep(.ant-segmented-item-selected){
|
||||
font-weight: 500;
|
||||
color: #1C1D22;
|
||||
}
|
||||
}
|
||||
.select-model-file-button{
|
||||
width: 151px;
|
||||
height: 40px;
|
||||
background: #0D68CB;
|
||||
box-shadow: 0px 10px 30px 0px rgba(0,0,6,0.15);
|
||||
border-radius: 2px;
|
||||
font-family: PingFangSC-Regular;
|
||||
font-weight: 400;
|
||||
font-size: 16px;
|
||||
color: #FFFFFF;
|
||||
line-height: 33px;
|
||||
text-shadow: 0px 10px 30px rgba(0,0,6,0.15);
|
||||
}
|
||||
.upload-hint{
|
||||
font-family: PingFangSC-Regular;
|
||||
font-weight: 400;
|
||||
font-size: 12px;
|
||||
color: #333333;
|
||||
line-height: 28px;
|
||||
text-shadow: 0px 10px 30px rgba(0,0,6,0.15);
|
||||
}
|
||||
.item-label-div{
|
||||
width: 100%;
|
||||
height: 155px;
|
||||
background: #F5F5F5;
|
||||
// box-shadow: 0px 10px 30px 0px rgba(0,0,6,0.15);
|
||||
border-radius: 2px;
|
||||
padding-top: 3px;
|
||||
padding-left: 8px;
|
||||
padding-right: 10px;
|
||||
.label-title-div{
|
||||
width: 100%;
|
||||
height: 34px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 4px;
|
||||
.label-title-span{
|
||||
font-family: PingFangSC-Regular;
|
||||
font-weight: 400;
|
||||
font-size: 12px;
|
||||
color: #222738;
|
||||
line-height: 33px;
|
||||
text-shadow: 0px 10px 30px rgba(0,0,6,0.15);
|
||||
}
|
||||
.add-button{
|
||||
width: 66px;
|
||||
height: 26px;
|
||||
background: #FFFFFF;
|
||||
// box-shadow: 0px 10px 30px 0px rgba(0,0,6,0.15), 0px 8px 6px 0px rgba(28,29,34,0.06);
|
||||
border: 1px solid rgba(28,29,34,0.06);
|
||||
border-radius: 13px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-left: 8px;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
.button-icon{
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
background-image: url('/public/ailist/algorithm_add_row_icon.png');
|
||||
margin-right: 4px;
|
||||
}
|
||||
.button-span{
|
||||
font-family: PingFangSC-Regular;
|
||||
font-weight: 400;
|
||||
font-size: 12px;
|
||||
color: #0D68CB;
|
||||
line-height: 33px;
|
||||
text-shadow: 0px 10px 30px rgba(0,0,6,0.15);
|
||||
}
|
||||
}
|
||||
}
|
||||
.label-interval{
|
||||
height: 1px;
|
||||
box-shadow: 0px 10px 30px 0px rgba(0,0,6,0.15);
|
||||
background:#DBDBDB;
|
||||
opacity: 0.66;
|
||||
margin-left: -8px;
|
||||
margin-right: -10px;
|
||||
}
|
||||
.label-table-title{
|
||||
height: 30px;
|
||||
display: flex;
|
||||
margin-bottom: 4px;
|
||||
.table-title-item{
|
||||
display: flex;
|
||||
width: 66px;
|
||||
font-family: PingFangSC-Regular;
|
||||
font-weight: 400;
|
||||
font-size: 12px;
|
||||
color: #222738;
|
||||
line-height: 33px;
|
||||
text-shadow: 0px 10px 30px rgba(0,0,6,0.15);
|
||||
}
|
||||
}
|
||||
.label-table-content{
|
||||
height: 75px;
|
||||
overflow: auto;
|
||||
scrollbar-width: none;
|
||||
::-webkit-scrollbar {
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.table-row{
|
||||
width: 100%;
|
||||
height: 26px;
|
||||
display: flex;
|
||||
margin-bottom: 1px;
|
||||
.table-item{
|
||||
width: 65px;
|
||||
height: 26px;
|
||||
background: #FFFFFF;
|
||||
// box-shadow: 0px 10px 30px 0px rgba(0,0,6,0.15), 0px 8px 6px 0px rgba(28,29,34,0.06);
|
||||
border-radius: 2px 0px 0px 2px;
|
||||
margin-right: 1px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
// padding-left: 9px;
|
||||
.table-item-input{
|
||||
height: 26px;
|
||||
border: 0px;
|
||||
}
|
||||
.table-item-input:focus{
|
||||
box-shadow: none
|
||||
}
|
||||
.del-table-row{
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
background-image: url('/public/ailist/del_table_row.png');
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.item-key{
|
||||
height: 88px;
|
||||
// box-shadow: 0px 10px 30px 0px rgba(0,0,6,0.15);
|
||||
border-radius: 2px;
|
||||
border: 1px solid #CCCCCC;
|
||||
}
|
||||
}
|
||||
}
|
||||
.footer{
|
||||
height: 85px;
|
||||
padding-right: 34px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: end;
|
||||
.cancel-button{
|
||||
width: 101px;
|
||||
height: 40px;
|
||||
box-shadow: 0px 10px 30px 0px rgba(0,0,6,0.15);
|
||||
border-radius: 4px;
|
||||
border: 1px solid #979797;
|
||||
font-family: PingFangSC-Medium;
|
||||
font-weight: 500;
|
||||
font-size: 16px;
|
||||
color: #222738;
|
||||
line-height: 33px;
|
||||
text-shadow: 0px 10px 30px rgba(0,0,6,0.15);
|
||||
margin-right: 14px;
|
||||
}
|
||||
.save-button{
|
||||
width: 146px;
|
||||
height: 40px;
|
||||
background: #0D68CB;
|
||||
box-shadow: 0px 10px 30px 0px rgba(0,0,6,0.15);
|
||||
border-radius: 4px;
|
||||
font-family: PingFangSC-Medium;
|
||||
font-weight: 500;
|
||||
font-size: 16px;
|
||||
color: #FFFFFF;
|
||||
line-height: 33px;
|
||||
text-shadow: 0px 10px 30px rgba(0,0,6,0.15);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,166 @@
|
|||
<template>
|
||||
<div class="cropper-tool">
|
||||
<div class="container">
|
||||
<div class="left">
|
||||
<div style="padding-left: 20px;">
|
||||
<a-upload :fileList="[]" accept="image/*" :beforeUpload="onFileChange">
|
||||
<a-button size="small" type="primary">选择图片</a-button>
|
||||
</a-upload>
|
||||
</div>
|
||||
<div style="margin-top:8px">
|
||||
<img style="width: 640px;height: 266px;" ref="sourceImg" crossorigin="anonymous" />
|
||||
</div>
|
||||
<div class="controls">
|
||||
<button @click="zoomIn">放大</button>
|
||||
<button @click="zoomOut">缩小</button>
|
||||
<button @click="rotateLeft">左旋</button>
|
||||
<button @click="rotateRight">右旋</button>
|
||||
<button @click="flipHorizontal">水平翻转</button>
|
||||
<button @click="flipVertical">垂直翻转</button>
|
||||
<button @click="reset">重置</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="right">
|
||||
<div style="margin-bottom:10px">裁切预览(固定 300×200)</div>
|
||||
<div class="preview" ref="previewBox" style="width:300px;height:200px;">
|
||||
<span v-if="!croppedUrl">(无)</span>
|
||||
<img v-if="croppedUrl" :src="croppedUrl" alt="预览" />
|
||||
</div>
|
||||
<div style="margin-top:8px; display:flex; gap:8px;">
|
||||
<a v-if="croppedUrl" :href="croppedUrl" download="cropped.png">下载裁切图</a>
|
||||
<button @click="clear">清空</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<a-button style="margin-right: 15px;" @click="emits('changeSelectImageModal',false)">取消</a-button>
|
||||
<a-button type="primary" @click="submitImage">确定</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, defineEmits } from 'vue';
|
||||
import Cropper from 'cropperjs';
|
||||
import 'cropperjs/dist/cropper.css';
|
||||
import { dataURLtoBlob } from '@/utils/file/base64Conver';
|
||||
import { uploadFile } from '@/api/formrender/index';
|
||||
const emits = defineEmits(['changeSelectImageModal'])
|
||||
const sourceImg = ref(null);
|
||||
const cropper = ref(null);
|
||||
const flipH = ref(1);
|
||||
const flipV = ref(1);
|
||||
const zoomValue = ref(1);
|
||||
const croppedUrl = ref('');
|
||||
|
||||
const onFileChange = (e) => {
|
||||
console.log(e)
|
||||
const file = e
|
||||
if (!file) return;
|
||||
const url = URL.createObjectURL(file);
|
||||
sourceImg.value.src = url;
|
||||
sourceImg.value.onload = () => {
|
||||
if (cropper.value) {
|
||||
cropper.value.destroy();
|
||||
}
|
||||
cropper.value = new Cropper(sourceImg.value, {
|
||||
viewMode: 1,
|
||||
aspectRatio: 3 / 2, // 固定比例 300:200
|
||||
autoCropArea: 1,
|
||||
movable: true,
|
||||
zoomable: true,
|
||||
rotatable: true,
|
||||
scalable: true,
|
||||
responsive: true,
|
||||
background: true,
|
||||
cropBoxResizable: false,
|
||||
cropBoxMovable: false,
|
||||
dragMode: 'move',
|
||||
ready() {
|
||||
zoomValue.value = 1;
|
||||
flipH.value = 1;
|
||||
flipV.value = 1;
|
||||
croppedUrl.value = '';
|
||||
getCropped()
|
||||
},
|
||||
crop() {
|
||||
getCropped()
|
||||
}
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
const zoomIn = () => cropper.value?.zoom(0.1);
|
||||
const zoomOut = () => cropper.value?.zoom(-0.1);
|
||||
const rotateLeft = () => cropper.value?.rotate(-90);
|
||||
const rotateRight = () => cropper.value?.rotate(90);
|
||||
const flipHorizontal = () => {
|
||||
flipH.value = -flipH.value;
|
||||
cropper.value?.scaleX(flipH.value);
|
||||
};
|
||||
const flipVertical = () => {
|
||||
flipV.value = -flipV.value;
|
||||
cropper.value?.scaleY(flipV.value);
|
||||
};
|
||||
const reset = () => {
|
||||
cropper.value?.reset();
|
||||
zoomValue.value = 1;
|
||||
flipH.value = 1;
|
||||
flipV.value = 1;
|
||||
};
|
||||
|
||||
const getCropped = () => {
|
||||
const canvas = cropper.value.getCroppedCanvas({ width: 300, height: 200 });
|
||||
if (!canvas) return;
|
||||
croppedUrl.value = canvas.toDataURL('image/png');
|
||||
console.log('croppedUrl.value',croppedUrl.value)
|
||||
};
|
||||
|
||||
const clear = () => {
|
||||
if (cropper.value) {
|
||||
cropper.value.destroy();
|
||||
cropper.value = null;
|
||||
}
|
||||
sourceImg.value.src = '';
|
||||
croppedUrl.value = '';
|
||||
};
|
||||
const submitImage = (format='image/jpeg', quality = 0.9) => {
|
||||
// const blob = dataURLtoBlob(croppedUrl.value);
|
||||
// const formData = new FormData();
|
||||
// formData.append('files', blob);
|
||||
// uploadFile(formData).then(res => {
|
||||
// console.log(res)
|
||||
// })
|
||||
if (!cropper.value) return;
|
||||
cropper.value.getCroppedCanvas({ width: 300, height: 200 })
|
||||
.toBlob(async (blob) => {
|
||||
if (!blob) return;
|
||||
|
||||
// 用 FormData 上传
|
||||
const formData = new FormData();
|
||||
formData.append('files', blob, `cropped.jpeg`);
|
||||
|
||||
uploadFile(formData).then(res => {
|
||||
console.log(res)
|
||||
})
|
||||
}, format, quality);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.container { display: flex; gap: 20px; }
|
||||
.left { width: 640px; }
|
||||
.right { width: 320px; }
|
||||
img { max-width: 100%; display: block; max-height: 480px; background: #f3f3f3; }
|
||||
.controls { margin-top: 10px; display:flex; flex-wrap:wrap; gap:8px; }
|
||||
.preview { border:1px solid #ddd; display:flex; align-items:center; justify-content:center; overflow:hidden; background:#fafafa }
|
||||
.footer{
|
||||
margin-top: 12px;
|
||||
height: 53px;
|
||||
border-top: 1px solid #eee;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: end;
|
||||
padding-right: 40px;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,136 +1,403 @@
|
|||
<template>
|
||||
<PageWrapper dense contentFullHeight fixedHeight contentClass="flex">
|
||||
<div class="w-1/4 xl:w-1/5 leftbox flex column">
|
||||
<div class="flex ai-c jc-sb">
|
||||
<div class="textbox">
|
||||
<p>算法库</p>
|
||||
<span>行业生态算法厂商</span>
|
||||
<div class="w-1/4 xl:w-1/5 leftbox">
|
||||
<div class="left-title-div">
|
||||
<div class="span-div">
|
||||
<div class="span-title">算法库</div>
|
||||
<div class="span-subtitle">行业生态算法厂商</div>
|
||||
</div>
|
||||
<a-button type="primary" size="small" @click="createAddClick">
|
||||
<template #icon><PlusOutlined /></template>
|
||||
创建
|
||||
</a-button>
|
||||
<a-button class="add-algorithm" type="primary" :icon="h(PlusOutlined)" @click="changeAddModal(true)">创建</a-button>
|
||||
</div>
|
||||
<div class="flex ai-c jc-c column flex-1">
|
||||
<div class="descbox">
|
||||
<p>请先创建自定义算法,基于算法新增实例<br />了解更多:<BookOutlined :style="{fontSize: '14px', color: '#0A99EB'}" /> 说明书</p>
|
||||
<div class="left-interval"></div>
|
||||
<div class="show-algorithm-list-div">
|
||||
<div class="empty-list">
|
||||
<div class="empty-image"></div>
|
||||
<div class="empty-span-title">暂无数据</div>
|
||||
<div class="empty-span-subtitle">请先创建自定义算法,基于算法新增实例</div>
|
||||
<div style="display: flex;align-items: center;margin-bottom: 28px;">
|
||||
<div class="empty-span-subtitle" style="display: inline;">了解更多:</div>
|
||||
<div class="empty-icon-image"></div>
|
||||
<div class="empty-span-subtitle" style="display: inline;">说明书 </div>
|
||||
</div>
|
||||
<a-button class="empty-add-algorithm" type="primary" :icon="h(PlusOutlined)" @click="changeAddModal(true)">创建自定义算法</a-button>
|
||||
</div>
|
||||
<a-button type="primary" @click="createAddClick">
|
||||
<template #icon><PlusOutlined /></template>
|
||||
创建自定义算法
|
||||
</a-button>
|
||||
</div>
|
||||
</div>
|
||||
<BasicTable
|
||||
class="w-3/4 xl:w-4/5"
|
||||
@register="registerTable"
|
||||
@fetch-success="onFetchSuccess"
|
||||
:searchInfo="searchInfo"
|
||||
>
|
||||
|
||||
</BasicTable>
|
||||
<Modal
|
||||
@submitsuccess="submitsuccess"
|
||||
@register="registerModal"
|
||||
@submit-reload="submitReload"
|
||||
/>
|
||||
<div class="w-3/4 xl:w-4/5 right-out-div">
|
||||
<div class="search-div">
|
||||
<div class="search-span-icon"></div>
|
||||
<div class="search-span">算法库</div>
|
||||
<div class="search-input-div">
|
||||
<a-input-search
|
||||
class="search-input"
|
||||
v-model:value="searchValue"
|
||||
placeholder="按照实例搜索"
|
||||
enter-button="搜索"
|
||||
@search="onSearch"
|
||||
>
|
||||
<template #prefix>
|
||||
<div class="search-input-icon"></div>
|
||||
</template>
|
||||
</a-input-search>
|
||||
</div>
|
||||
</div>
|
||||
<div class="search-interval">
|
||||
<div class="interval-icon"></div>
|
||||
</div>
|
||||
<div class="show-list-div">
|
||||
<div class="list-div">
|
||||
<div class="item" v-for="value in 8">
|
||||
<div class="image-div">
|
||||
<img class="image-item" src="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png">
|
||||
<div class="image-span">
|
||||
<div class="image-span-icon"></div>
|
||||
<div class="image-span-info">#排水沟盖板缺</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="info-div">
|
||||
<div class="info-icon"></div>
|
||||
<div class="info-span-div">
|
||||
<div class="info-span-title">高速排水沟盖板缺失检测算法</div>
|
||||
<div class="info-span-subtitle">识别高速公路两侧的排水沟盖板缺……</div>
|
||||
</div>
|
||||
<a-button class="show-info-button" type="primary">查看</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pagination-div">
|
||||
<a-pagination
|
||||
size="small"
|
||||
:total="50"
|
||||
show-size-changer
|
||||
show-quick-jumper
|
||||
:show-total="total => `共 ${total} 条数据`"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<a-modal width="631px" v-model:open="addAlgorithmModal" :footer="null" :closable="false" :destroyOnClose="true" :maskClosable="false" :keyboard="false">
|
||||
<AddAlgorithmModal @changeAddModal="changeAddModal"/>
|
||||
</a-modal>
|
||||
</PageWrapper>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { reactive, nextTick, ref } from 'vue';
|
||||
import { PlusOutlined, BookOutlined } from '@ant-design/icons-vue';
|
||||
import { BasicTable, useTable } from '@/components/Table';
|
||||
import { getButtonList, getMenuDetail, deleteButton } from '@/api/demo/system';
|
||||
import { ref,h } from 'vue';
|
||||
import { PlusOutlined, } from '@ant-design/icons-vue';
|
||||
import { PageWrapper } from '@/components/Page';
|
||||
import { columns, searchFormSchema } from './index.data';
|
||||
import { useMessage } from '@/hooks/web/useMessage';
|
||||
import Modal from './modal.vue';
|
||||
import { useModal } from '@/components/Modal';
|
||||
import AddAlgorithmModal from './AddAlgorithmModal.vue';
|
||||
|
||||
const { createConfirm, createMessage } = useMessage();
|
||||
defineOptions({ name: 'MenuManagement' });
|
||||
const searchInfo = reactive<Recordable>({});
|
||||
|
||||
const [registerTable, { reload, expandAll, getSelectRows, clearSelectedRowKeys }] = useTable({
|
||||
title: '算法列表',
|
||||
// api: getButtonList,
|
||||
columns,
|
||||
rowKey: 'id',
|
||||
formConfig: {
|
||||
labelWidth: 120,
|
||||
schemas: searchFormSchema,
|
||||
},
|
||||
isTreeTable: true,
|
||||
striped: false,
|
||||
useSearchForm: true,
|
||||
showTableSetting: true,
|
||||
bordered: true,
|
||||
showIndexColumn: false,
|
||||
rowSelection: {
|
||||
//多选框
|
||||
// type: 'checkbox',
|
||||
type: 'radio',
|
||||
},
|
||||
handleSearchInfoFn(info) {
|
||||
return info;
|
||||
},
|
||||
});
|
||||
const [registerModal, { openModal }] = useModal();
|
||||
function createAddClick(){
|
||||
openModal(true, {
|
||||
|
||||
});
|
||||
const searchValue = ref('');
|
||||
const addAlgorithmModal = ref(false)
|
||||
const onSearch = () => {
|
||||
}
|
||||
const changeAddModal = (type: boolean) => {
|
||||
addAlgorithmModal.value = type
|
||||
}
|
||||
|
||||
function onFetchSuccess() {
|
||||
// 演示默认展开所有表项
|
||||
nextTick(expandAll);
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
.flex{
|
||||
display: flex;
|
||||
}
|
||||
.flex-1{
|
||||
flex: 1;
|
||||
}
|
||||
.column{
|
||||
flex-direction: column;
|
||||
}
|
||||
.ai-c{
|
||||
align-items: center;
|
||||
}
|
||||
.jc-sb{
|
||||
justify-content: space-between;
|
||||
}
|
||||
.jc-c{
|
||||
justify-content: center;
|
||||
}
|
||||
<style lang="scss" scoped>
|
||||
.leftbox{
|
||||
background: #fff;
|
||||
margin: 16px 0 16px 16px;
|
||||
padding: 16px;
|
||||
.textbox{
|
||||
p{
|
||||
.left-title-div{
|
||||
width: 100%;
|
||||
height: 82px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-left: 16px;
|
||||
padding-right: 33px;
|
||||
justify-content: space-between;
|
||||
.span-div{
|
||||
width: 104px;
|
||||
height: 42px;
|
||||
.span-title{
|
||||
font-family: PingFangSC-Medium;
|
||||
font-weight: 500;
|
||||
font-size: 16px;
|
||||
color: #060606;
|
||||
line-height: 22px;
|
||||
}
|
||||
.span-subtitle{
|
||||
font-family: PingFangSC-Regular;
|
||||
font-weight: 400;
|
||||
font-size: 13px;
|
||||
color: #393939;
|
||||
line-height: 18px;
|
||||
}
|
||||
}
|
||||
.add-algorithm{
|
||||
width: 80px;
|
||||
height: 30px;
|
||||
background: #0B60BD;
|
||||
border-radius: 0px;
|
||||
}
|
||||
}
|
||||
.left-interval{
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
border: 1px solid rgba(28,29,34,0.08);
|
||||
opacity: 0.46;
|
||||
}
|
||||
.show-algorithm-list-div{
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: calc(100% - 84px );
|
||||
.empty-list{
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 280px;
|
||||
height: 311px;
|
||||
background: #FFFFFF;
|
||||
box-shadow: 5px 18px 32px 0px rgba(0,0,0,0.1);
|
||||
border: 2px dashed rgba(28,29,34,0.08);
|
||||
border-radius: 10px;
|
||||
padding-top: 28px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
.empty-image{
|
||||
width: 114px;
|
||||
height: 120px;
|
||||
background-image: url('/public/ailist/empty_image.png');
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.empty-span-title{
|
||||
font-family: PingFangSC-Regular;
|
||||
font-weight: 400;
|
||||
font-size: 13px;
|
||||
color: #000000;
|
||||
line-height: 18px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.empty-span-subtitle{
|
||||
font-family: PingFangSC-Regular;
|
||||
font-weight: 400;
|
||||
font-size: 13px;
|
||||
color: #393939;
|
||||
line-height: 18px;
|
||||
}
|
||||
.empty-icon-image{
|
||||
width: 16px;
|
||||
height: 14px;
|
||||
background-image: url('/public/ailist/empty_icon_image.png');
|
||||
line-height: 18px;
|
||||
display: inline;
|
||||
cursor: pointer;
|
||||
}
|
||||
.empty-add-algorithm{
|
||||
width: 167px;
|
||||
height: 30px;
|
||||
background: #0D68CB;
|
||||
border-radius: 0px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.right-out-div{
|
||||
padding: 16px 16px 16px 33px;
|
||||
.search-div{
|
||||
position: relative;
|
||||
height: 57px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.search-span-icon{
|
||||
width: 20px;
|
||||
height: 18px;
|
||||
background-image: url('/public/ailist/search_span_icon.png');
|
||||
margin-right: 10px;
|
||||
}
|
||||
.search-span{
|
||||
font-family: PingFangSC-Medium;
|
||||
font-weight: 500;
|
||||
font-size: 16px;
|
||||
color: #060606;
|
||||
line-height: 22px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
span{
|
||||
font-weight: 400;
|
||||
font-size: 13px;
|
||||
color: #393939;
|
||||
line-height: 18px;
|
||||
.search-input-div{
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
right: 0px;
|
||||
width: 304px;
|
||||
height: 38px;
|
||||
.search-input{
|
||||
:deep(.ant-input-affix-wrapper){
|
||||
font-family: PingFangSC-Regular;
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
line-height: 28px;
|
||||
height: 38px;
|
||||
border-top-left-radius: 19px;
|
||||
border-bottom-left-radius: 19px;
|
||||
}
|
||||
:deep(.ant-input-search-button,){
|
||||
font-family: PingFangSC-Regular;
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
color: #FFFFFF;
|
||||
line-height: 28px;
|
||||
height: 38px;
|
||||
border-top-right-radius: 19px;
|
||||
border-bottom-right-radius: 19px;
|
||||
}
|
||||
:deep(.ant-input){
|
||||
padding-left: 20px;
|
||||
}
|
||||
.search-input-icon{
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
background-image: url('/public/ailist/search_input_icon.png');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.descbox{
|
||||
font-weight: 400;
|
||||
font-size: 13px;
|
||||
color: #393939;
|
||||
line-height: 18px;
|
||||
text-align: center;
|
||||
.search-interval{
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 2px;
|
||||
background:rgba(28,29,34,0.08);
|
||||
margin-bottom: 22px;
|
||||
.interval-icon{
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
width: 137px;
|
||||
height: 2px;
|
||||
background: #0B60BD;
|
||||
}
|
||||
}
|
||||
.show-list-div{
|
||||
width: 100%;
|
||||
height: calc( 100% - 81px );
|
||||
background: #FFFFFF;
|
||||
border: 2px dashed rgba(28,29,34,0.08);
|
||||
border-radius: 10px;
|
||||
padding: 32px;
|
||||
.list-div{
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: 90px;
|
||||
.item{
|
||||
width: 300px;
|
||||
height: 268px;
|
||||
background: #FFFFFF;
|
||||
box-shadow: 5px 18px 32px 0px rgba(28,29,34,0.1);
|
||||
border-radius: 10px;
|
||||
margin-right: 10px;
|
||||
margin-bottom: 20px;
|
||||
.image-div{
|
||||
position: relative;
|
||||
width: 300px;
|
||||
height: 200px;
|
||||
margin-bottom: 12px;
|
||||
.image-item{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-top-left-radius: 10px;
|
||||
border-top-right-radius: 10px;
|
||||
}
|
||||
.image-span{
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
bottom: 0px;
|
||||
width: 205px;
|
||||
height: 20px;
|
||||
background: linear-gradient( 270deg, rgba(7,7,7,0) 0%, #111111 100%);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-left: 9px;
|
||||
.image-span-icon{
|
||||
width: 4px;
|
||||
height: 4px;
|
||||
background: #FFA048;
|
||||
border-radius: 50%;
|
||||
margin-right: 5px;
|
||||
}
|
||||
.image-span-info{
|
||||
font-family: PingFangSC-Regular;
|
||||
font-weight: 400;
|
||||
font-size: 11px;
|
||||
color: #FFFFFF;
|
||||
line-height: 15px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.info-div{
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-left: 7px;
|
||||
.info-icon{
|
||||
width: 3px;
|
||||
height: 34px;
|
||||
background: #0B60BD;
|
||||
margin-right: 5px;
|
||||
}
|
||||
.info-span-div{
|
||||
width: 187px;
|
||||
margin-right: 22px;
|
||||
.info-span-title{
|
||||
font-family: PingFangSC-Medium;
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
color: #1C1D22;
|
||||
line-height: 20px;
|
||||
margin-bottom: 5px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.info-span-subtitle{
|
||||
font-family: PingFangSC-Regular;
|
||||
font-weight: 400;
|
||||
font-size: 11px;
|
||||
color: rgba(28,29,34,0.5);
|
||||
line-height: 15px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
.show-info-button{
|
||||
width: 54px;
|
||||
height: 23px;
|
||||
border-radius: 12px;
|
||||
background: #0B60BD;
|
||||
:deep(span){
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
font-family: PingFangSC-Regular;
|
||||
font-weight: 400;
|
||||
font-size: 11px;
|
||||
color: #FFFFFF;
|
||||
line-height: 15px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.item:nth-child(4n){
|
||||
margin-right: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
.pagination-div{
|
||||
padding-right: 32px;
|
||||
width: 100%;
|
||||
height: 66px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: end;
|
||||
}
|
||||
}
|
||||
.right-box{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,184 +0,0 @@
|
|||
<template>
|
||||
<BasicModal
|
||||
v-bind="$attrs"
|
||||
@register="registerModal"
|
||||
:canFullscreen="false"
|
||||
:defaultFullscreen="false"
|
||||
:showCancelBtn="true"
|
||||
:showOkBtn="true"
|
||||
:draggable="false"
|
||||
title="创建算法"
|
||||
@ok="submitClick"
|
||||
>
|
||||
<div class="flex titlesbox">
|
||||
<div class="li" v-for="(item,index) in tabList">
|
||||
<span :class="index==tabIndex?'active':''" @click="tabsClick(index)">{{item}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 视频算法 -->
|
||||
<div class="formsbox" v-if="tabIndex == 0">
|
||||
<a-form
|
||||
:model="formState"
|
||||
ref="formRef"
|
||||
:label-col="{ span: 6 }"
|
||||
:wrapper-col="{ span: 18 }"
|
||||
autocomplete="off"
|
||||
>
|
||||
<a-form-item
|
||||
label="算法名称"
|
||||
name="username"
|
||||
:rules="[{ required: true, message: '请输入' }]"
|
||||
>
|
||||
<a-input v-model:value="formState.username" />
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label="概要描述"
|
||||
name="username"
|
||||
:rules="[{ required: true, message: '请输入' }]"
|
||||
>
|
||||
<a-textarea v-model:value="formState.username" />
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label="算力名称"
|
||||
name="username"
|
||||
:rules="[{ required: true, message: '请输入' }]"
|
||||
>
|
||||
<a-input v-model:value="formState.username" />
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label="推流地址"
|
||||
name="username"
|
||||
:rules="[{ required: true, message: '请输入' }]"
|
||||
>
|
||||
<a-input v-model:value="formState.username" />
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label="拉流地址"
|
||||
name="username"
|
||||
:rules="[{ required: true, message: '请输入' }]"
|
||||
>
|
||||
<a-input v-model:value="formState.username" />
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label="服务地址"
|
||||
name="username"
|
||||
:rules="[{ required: true, message: '请输入' }]"
|
||||
>
|
||||
<a-input v-model:value="formState.username" />
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label="秘钥"
|
||||
name="username"
|
||||
:rules="[{ required: true, message: '请输入' }]"
|
||||
>
|
||||
<a-input v-model:value="formState.username" />
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</div>
|
||||
<!-- 图片算法 -->
|
||||
<div class="formsbox" v-if="tabIndex == 1">
|
||||
<a-form
|
||||
:model="formState"
|
||||
ref="formRef"
|
||||
:label-col="{ span: 6 }"
|
||||
:wrapper-col="{ span: 18 }"
|
||||
autocomplete="off"
|
||||
>
|
||||
<a-form-item
|
||||
label="算法名称"
|
||||
name="username"
|
||||
:rules="[{ required: true, message: '请输入' }]"
|
||||
>
|
||||
<a-input v-model:value="formState.username" />
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label="概要描述"
|
||||
name="username"
|
||||
:rules="[{ required: true, message: '请输入' }]"
|
||||
>
|
||||
<a-textarea v-model:value="formState.username" />
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label="算力名称"
|
||||
name="username"
|
||||
:rules="[{ required: true, message: '请输入' }]"
|
||||
>
|
||||
<a-input v-model:value="formState.username" />
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label="服务地址"
|
||||
name="username"
|
||||
:rules="[{ required: true, message: '请输入' }]"
|
||||
>
|
||||
<a-input v-model:value="formState.username" />
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label="秘钥"
|
||||
name="username"
|
||||
:rules="[{ required: true, message: '请输入' }]"
|
||||
>
|
||||
<a-input v-model:value="formState.username" />
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</div>
|
||||
</BasicModal>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, defineEmits, reactive, toRaw } from 'vue';
|
||||
import { BasicModal, useModalInner } from '@/components/Modal';
|
||||
const tabIndex = ref(0);
|
||||
const tabList = ["视频算法","图片算法"];
|
||||
const tabsClick = (index) =>{
|
||||
tabIndex.value = index
|
||||
}
|
||||
const formRef = ref();
|
||||
interface FormState {
|
||||
username: string;
|
||||
password: string;
|
||||
remember: boolean;
|
||||
}
|
||||
|
||||
const formState = reactive<FormState>({
|
||||
username: '',
|
||||
password: '',
|
||||
remember: true,
|
||||
});
|
||||
const submitClick = ()=>{
|
||||
console.log('submit')
|
||||
formRef.value.validate().then(() => {
|
||||
console.log('values', formState, toRaw(formState));
|
||||
})
|
||||
.catch(error => {
|
||||
console.log('error', error);
|
||||
});
|
||||
}
|
||||
const [registerModal, { closeModal }] = useModalInner((data: any) => {
|
||||
|
||||
});
|
||||
</script>
|
||||
<style scoped>
|
||||
.titlesbox{
|
||||
width: 92%;
|
||||
margin-left: 4%;
|
||||
line-height: 40px;
|
||||
border-bottom: 1px solid #F5F6FA;
|
||||
.li{
|
||||
width: 50%;
|
||||
text-align: center;
|
||||
span{
|
||||
color: #222738;
|
||||
cursor: pointer;
|
||||
line-height: 40px;
|
||||
display: inline-block;
|
||||
}
|
||||
.active{
|
||||
border-bottom: 3px solid #3A57E8;
|
||||
}
|
||||
}
|
||||
}
|
||||
.formsbox{
|
||||
width: 92%;
|
||||
margin-left: 4%;
|
||||
padding-top: 20px;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -495,7 +495,15 @@
|
|||
const searchParams = ref();
|
||||
const [
|
||||
registerTable,
|
||||
{ reload, getDataSource, getSelectRows, setSelectedRows, clearSelectedRowKeys },
|
||||
{
|
||||
reload,
|
||||
getDataSource,
|
||||
getSelectRows,
|
||||
setSelectedRows,
|
||||
clearSelectedRowKeys,
|
||||
getPaginationRef,
|
||||
setPagination,
|
||||
},
|
||||
] = useTable({
|
||||
api: GetMediaFile,
|
||||
rowKey: 'id',
|
||||
|
|
@ -585,6 +593,11 @@
|
|||
nowParentKey.value = f.id;
|
||||
floders.value = floders.value.splice(0, index + 1);
|
||||
clearSelectedRowKeys();
|
||||
if (current) {
|
||||
setPagination({
|
||||
current: current,
|
||||
});
|
||||
}
|
||||
reload().then((res) => {
|
||||
showTableData.value = res;
|
||||
});
|
||||
|
|
@ -719,6 +732,7 @@
|
|||
// 目前展示图片的列表
|
||||
const previewRecordList: any = ref([]);
|
||||
// 查看-打开这个文件夹或者展示这个图片
|
||||
let current = 1;
|
||||
async function lookRecord(record) {
|
||||
// 展示这个图片后者视频
|
||||
if (record.objectKey) {
|
||||
|
|
@ -751,6 +765,8 @@
|
|||
id: nowParentKey.value,
|
||||
name: record.name,
|
||||
});
|
||||
current = getPaginationRef().current;
|
||||
setPagination({ current: 1 });
|
||||
reload().then((res) => {
|
||||
showTableData.value = res;
|
||||
});
|
||||
|
|
|
|||
|
|
@ -36,6 +36,8 @@ import {ref,watch,onMounted,defineEmits} from 'vue';
|
|||
import airLineList from '../workplan/components/airLineList.vue';
|
||||
import createAirLine from '../workplan/components/createAirLine.vue'
|
||||
import importAirLine from '../workplan/components/importAirLine.vue'
|
||||
|
||||
|
||||
import Map from '../workplan/components/map.vue'
|
||||
import AirPolygon from './components/airPolygon.vue';
|
||||
import {getAirLine} from '@/api/sys/workplan';
|
||||
|
|
@ -47,10 +49,19 @@ import { XMLParser, XMLBuilder } from 'fast-xml-parser';
|
|||
|
||||
const emits = defineEmits(["updateAirLineLise"])
|
||||
|
||||
// 模式 add edit detail
|
||||
// 当前目录
|
||||
const currentFolder = ref(null);
|
||||
|
||||
// 更新当前目录
|
||||
const setCurrentFolder = (folder)=>{
|
||||
currentFolder.value = folder;
|
||||
importAirLineShow.value = true;
|
||||
}
|
||||
|
||||
// 航线模式 add edit detail
|
||||
const editMode = ref("add");
|
||||
|
||||
// airLine form
|
||||
// 航线表单数据
|
||||
const airLineForm = ref({
|
||||
"id": null,
|
||||
"airLineName": null,
|
||||
|
|
@ -74,197 +85,11 @@ const airLineForm = ref({
|
|||
// "lineData":null,
|
||||
});
|
||||
|
||||
// template.kml
|
||||
const templateKmlConfig = ref({
|
||||
"author": 17861857725,
|
||||
"createTime": 1749689844431,
|
||||
"updateTime": 1753241338101,
|
||||
"missionConfig": {
|
||||
"flyToWaylineMode": "pointToPoint",
|
||||
"finishAction": "goHome",
|
||||
"exitOnRCLost": "goContinue",
|
||||
"executeRCLostAction": "goBack",
|
||||
"takeOffSecurityHeight": 20,
|
||||
"takeOffRefPoint": "",
|
||||
"takeOffRefPointAGLHeight": 4.169064385,
|
||||
"globalTransitionalSpeed": 15,
|
||||
"globalRTHHeight": 100,
|
||||
"droneInfo": {
|
||||
"droneEnumValue": 100,
|
||||
"droneSubEnumValue": 1
|
||||
},
|
||||
"autoRerouteInfo": {
|
||||
"transitionalAutoRerouteMode": 1,
|
||||
"missionAutoRerouteMode": 1
|
||||
},
|
||||
"waylineAvoidLimitAreaMode": 0,
|
||||
"payloadInfo": {
|
||||
"payloadEnumValue": 99,
|
||||
"payloadSubEnumValue": 0,
|
||||
"payloadPositionIndex": 0
|
||||
}
|
||||
},
|
||||
"Folder": {
|
||||
"templateType": "mapping2d",
|
||||
"templateId": 0,
|
||||
"waylineCoordinateSysParam": {
|
||||
"coordinateMode": "WGS84",
|
||||
"heightMode": "EGM96",
|
||||
"globalShootHeight": 90,
|
||||
"surfaceFollowModeEnable": 1,
|
||||
"isRealtimeSurfaceFollow": 0,
|
||||
"surfaceRelativeHeight": 90,
|
||||
"dsmFile": "wpmz/res/dsm/wgs84_ASTGTMV003_N35E118_dem_7.tif"
|
||||
},
|
||||
"autoFlightSpeed": 12.7,
|
||||
"Placemark": {
|
||||
"caliFlightEnable": 0,
|
||||
"elevationOptimizeEnable": 1,
|
||||
"smartObliqueEnable": 0,
|
||||
"quickOrthoMappingEnable": 0,
|
||||
"facadeWaylineEnable": 0,
|
||||
"isLookAtSceneSet": 0,
|
||||
"shootType": "time",
|
||||
"direction": 83,
|
||||
"margin": 0,
|
||||
"efficiencyFlightModeEnable": 0,
|
||||
"overlap": {
|
||||
"orthoCameraOverlapH": 80,
|
||||
"orthoCameraOverlapW": 70,
|
||||
"inclinedCameraOverlapH": 80,
|
||||
"inclinedCameraOverlapW": 70
|
||||
},
|
||||
"Polygon": {
|
||||
"outerBoundaryIs": {
|
||||
"LinearRing": {
|
||||
"coordinates": "118.293794766158,35.1353688096117,0\n 118.295429169407,35.1353304409052,0\n 118.295487507293,35.1332925168381,0\n 118.293672196844,35.1331918267775,0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ellipsoidHeight": 90,
|
||||
"height": 90
|
||||
},
|
||||
"payloadParam": {
|
||||
"payloadPositionIndex": 0,
|
||||
"focusMode": "firstPoint",
|
||||
"meteringMode": "average",
|
||||
"returnMode": "singleReturnStrongest",
|
||||
"samplingRate": 240000,
|
||||
"scanningMode": "repetitive",
|
||||
"imageFormat": "visable",
|
||||
"photoSize": ""
|
||||
}
|
||||
}
|
||||
})
|
||||
// 航线template.kml
|
||||
const templateKmlConfig = ref({})
|
||||
|
||||
// wayline.wpml
|
||||
const waylineWpmlConfig = ref({
|
||||
"missionConfig": {
|
||||
"flyToWaylineMode": "pointToPoint",
|
||||
"finishAction": "goHome",
|
||||
"exitOnRCLost": "goContinue",
|
||||
"executeRCLostAction": "goBack",
|
||||
"takeOffSecurityHeight": 20,
|
||||
"globalTransitionalSpeed": 15,
|
||||
"globalRTHHeight": 100,
|
||||
"droneInfo": {
|
||||
"droneEnumValue": 100,
|
||||
"droneSubEnumValue": 1
|
||||
},
|
||||
"autoRerouteInfo": {
|
||||
"transitionalAutoRerouteMode": 1,
|
||||
"missionAutoRerouteMode": 1
|
||||
},
|
||||
"waylineAvoidLimitAreaMode": 0,
|
||||
"payloadInfo": {
|
||||
"payloadEnumValue": 99,
|
||||
"payloadSubEnumValue": 0,
|
||||
"payloadPositionIndex": 0
|
||||
}
|
||||
},
|
||||
"Folder": {
|
||||
"templateId": 0,
|
||||
"executeHeightMode": "WGS84",
|
||||
"waylineId": 0,
|
||||
"distance": 1259.17163085938,
|
||||
"duration": 145.652896165848,
|
||||
"autoFlightSpeed": 12.7,
|
||||
"startActionGroup": {
|
||||
"action": [
|
||||
{
|
||||
"actionId": 0,
|
||||
"actionActuatorFunc": "gimbalRotate",
|
||||
"actionActuatorFuncParam": {
|
||||
"gimbalHeadingYawBase": "aircraft",
|
||||
"gimbalRotateMode": "absoluteAngle",
|
||||
"gimbalPitchRotateEnable": 1,
|
||||
"gimbalPitchRotateAngle": -90,
|
||||
"gimbalRollRotateEnable": 0,
|
||||
"gimbalRollRotateAngle": 0,
|
||||
"gimbalYawRotateEnable": 1,
|
||||
"gimbalYawRotateAngle": 0,
|
||||
"gimbalRotateTimeEnable": 0,
|
||||
"gimbalRotateTime": 10,
|
||||
"payloadPositionIndex": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"actionId": 1,
|
||||
"actionActuatorFunc": "hover",
|
||||
"actionActuatorFuncParam": {
|
||||
"hoverTime": 0.5
|
||||
}
|
||||
},
|
||||
{
|
||||
"actionId": 2,
|
||||
"actionActuatorFunc": "setFocusType",
|
||||
"actionActuatorFuncParam": {
|
||||
"cameraFocusType": "manual",
|
||||
"payloadPositionIndex": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"actionId": 3,
|
||||
"actionActuatorFunc": "focus",
|
||||
"actionActuatorFuncParam": {
|
||||
"focusX": 0,
|
||||
"focusY": 0,
|
||||
"focusRegionWidth": 0,
|
||||
"focusRegionHeight": 0,
|
||||
"isPointFocus": 0,
|
||||
"isInfiniteFocus": 1,
|
||||
"payloadPositionIndex": 0,
|
||||
"isCalibrationFocus": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"actionId": 4,
|
||||
"actionActuatorFunc": "hover",
|
||||
"actionActuatorFuncParam": {
|
||||
"hoverTime": 1
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"Placemark": []
|
||||
}
|
||||
})
|
||||
|
||||
// 当前目录
|
||||
const currentFolder = ref(null);
|
||||
|
||||
// 更新当前目录
|
||||
const setCurrentFolder = (folder)=>{
|
||||
currentFolder.value = folder;
|
||||
importAirLineShow.value = true;
|
||||
}
|
||||
|
||||
|
||||
const flyToTherePosition = ref({
|
||||
lng:null,
|
||||
lat:null,
|
||||
alt:null,
|
||||
})
|
||||
// 航线wayline.wpml
|
||||
const waylineWpmlConfig = ref({})
|
||||
|
||||
|
||||
const flyToThere = (e)=>{
|
||||
|
|
@ -278,22 +103,6 @@ const aircraftShow = ref(false);
|
|||
const createAirLineShow = ref(false);
|
||||
const importAirLineShow = ref(false);
|
||||
|
||||
const selectAriLine = ()=> {
|
||||
ariLineShow.value = true;
|
||||
aircraftShow.value = false;
|
||||
}
|
||||
|
||||
const selectAircraft = ()=>{
|
||||
aircraftShow.value = true;
|
||||
ariLineShow.value = false;
|
||||
}
|
||||
|
||||
const cancleCraete = ()=>{
|
||||
workPlanFormShow.value = false;
|
||||
ariLineShow.value = false;
|
||||
aircraftShow.value = false;
|
||||
planListShow.value = true;
|
||||
}
|
||||
|
||||
const checkedAriLine = ref({});
|
||||
|
||||
|
|
@ -306,23 +115,11 @@ const checkAriLine = (item)=>{
|
|||
|
||||
const checkedDronePort = ref({});
|
||||
|
||||
const checkDronePort = (item)=>{
|
||||
if(item){
|
||||
aircraftShow.value = false;
|
||||
checkedDronePort.value = item;
|
||||
}
|
||||
}
|
||||
|
||||
const formData = ref(null);
|
||||
|
||||
const toCreateWorkPlan = (data)=> {
|
||||
formData.value = data;
|
||||
planListShow.value = false;
|
||||
workPlanFormShow.value = true;
|
||||
}
|
||||
|
||||
// 创建航线
|
||||
const globalFolder = ref(null);
|
||||
|
||||
const handlerCreateAirLine = (folder)=>{
|
||||
globalFolder.value = folder;
|
||||
createAirLineShow.value = true;
|
||||
|
|
@ -337,21 +134,33 @@ const cancleImportAirLine = ()=>{
|
|||
importAirLineShow.value = false;
|
||||
}
|
||||
|
||||
const handlerCreateAirLineForm = (form)=>{
|
||||
// 创建航线
|
||||
const handlerCreateAirLineForm =async (form)=>{
|
||||
|
||||
console.log("form",form);
|
||||
|
||||
// 根据航线类型处理设置template.kml、wayline.wpml
|
||||
if(form.airLineType == 'waypoint'){
|
||||
const {templateKml,waylineWpml} = await import("../workplan/waylineConfig/waypointConfig");
|
||||
templateKmlConfig.value = templateKml;
|
||||
waylineWpmlConfig.value = waylineWpml;
|
||||
}else if(form.airLineType == 'mapping2d'){
|
||||
const {templateKml,waylineWpml} = await import("../workplan/waylineConfig/mapping2dConfig");
|
||||
templateKmlConfig.value = templateKml;
|
||||
waylineWpmlConfig.value = waylineWpml;
|
||||
}
|
||||
|
||||
console.log("templateKmlConfig999",templateKmlConfig.value);
|
||||
|
||||
// 关闭全部窗口
|
||||
workPlanFormShow.value = false;
|
||||
ariLineShow.value = false;
|
||||
aircraftShow.value = false;
|
||||
planListShow.value = false;
|
||||
createAirLineShow.value = false;
|
||||
|
||||
// 航线表单
|
||||
airLineForm.value = form
|
||||
airLineForm.value.folder = globalFolder.value;
|
||||
|
||||
console.log("airLineFor121m",airLineForm.value);
|
||||
// 更新航线表单
|
||||
airLineForm.value = form
|
||||
|
||||
// 更新目录参数
|
||||
airLineForm.value.folder = globalFolder.value ? globalFolder.value : "";
|
||||
}
|
||||
|
||||
const successCreatePlan = ()=>{
|
||||
|
|
@ -370,8 +179,6 @@ const exitDraw = ()=>{
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// 预览航线
|
||||
const wayline = ref({});
|
||||
const waylineInfo = ref(null)
|
||||
|
|
@ -400,7 +207,6 @@ const planDetail =async (item) => {
|
|||
|
||||
|
||||
// 获取wpml文件
|
||||
|
||||
const currentPreviewWayLine = ref(null);
|
||||
|
||||
const airLineDetail =async (item) => {
|
||||
|
|
@ -441,10 +247,8 @@ const extractKmz = async (kmzBlob)=>{
|
|||
}
|
||||
|
||||
onMounted(()=>{
|
||||
|
||||
let element = window.document.getElementsByClassName("mars3d-locationbar")[0] as HTMLElement;
|
||||
element.style.bottom = '40px';
|
||||
|
||||
let element = window.document.getElementsByClassName("mars3d-locationbar")[0] as HTMLElement;
|
||||
element.style.bottom = '40px';
|
||||
})
|
||||
|
||||
|
||||
|
|
@ -483,6 +287,7 @@ const importSuccess = () => {
|
|||
airLineListRef.value.getAirList();
|
||||
importAirLineShow.value = false;
|
||||
}
|
||||
|
||||
</script>
|
||||
<style scoped>
|
||||
.map-out-container{
|
||||
|
|
|
|||
|
|
@ -2,7 +2,11 @@
|
|||
<div class="params-item">
|
||||
<div class="params-label">俯仰角度:</div>
|
||||
<div class="params-value">
|
||||
<a-slider v-model:value="props.params.gimbalPitchRotateAngle" :min="-180" :max="180" :step="0.01" />
|
||||
<a-slider
|
||||
v-model:value="props.params.gimbalPitchRotateAngle"
|
||||
:min="-90" :max="30" :step="0.01"
|
||||
@change="paramChagne"
|
||||
/>
|
||||
</div>
|
||||
<div class="params-value-text">
|
||||
{{ props.params.gimbalPitchRotateAngle }} °
|
||||
|
|
@ -14,13 +18,16 @@
|
|||
|
||||
import {defineProps,defineComponent,defineOptions} from 'vue';
|
||||
|
||||
const props = defineProps(["params"])
|
||||
|
||||
const props = defineProps(["params","info"])
|
||||
const emits = defineEmits(["paramChagne"])
|
||||
|
||||
defineComponent({
|
||||
name: 'gimbalRotate'
|
||||
})
|
||||
|
||||
const paramChagne = ()=> {
|
||||
emits("paramChagne",props.info);
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
<div class="params-value">
|
||||
<a-input-number v-model:value="props.params.hoverTime"></a-input-number>
|
||||
</div>
|
||||
<div class="params-unit">秒</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
@ -35,6 +36,10 @@ defineComponent({
|
|||
flex:1;
|
||||
}
|
||||
|
||||
.params-item .params-unit{
|
||||
line-height:30px;
|
||||
padding:0px 5px 0px 15px;
|
||||
}
|
||||
|
||||
::v-deep .ant-input-number{
|
||||
color:#fff!important;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,55 @@
|
|||
<template>
|
||||
<div class="params-item">
|
||||
<div class="params-label">间隔时间:</div>
|
||||
<div class="params-value">
|
||||
<a-input-number v-model:value="props.params.hoverTime"></a-input-number>
|
||||
</div>
|
||||
<div class="params-unit">秒</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
|
||||
import {defineProps,defineComponent,defineOptions} from 'vue';
|
||||
|
||||
const props = defineProps(["params"])
|
||||
|
||||
|
||||
defineComponent({
|
||||
name: 'multipleTiming'
|
||||
})
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.params-item{
|
||||
width:100%;
|
||||
display: flex;
|
||||
gap:20px;
|
||||
}
|
||||
.params-item .params-label{
|
||||
line-height:30px;
|
||||
}
|
||||
|
||||
.params-item .params-value{
|
||||
flex:1;
|
||||
}
|
||||
|
||||
.params-item .params-unit{
|
||||
line-height:30px;
|
||||
padding:0px 5px 0px 15px;
|
||||
}
|
||||
|
||||
::v-deep .ant-input-number{
|
||||
color:#fff!important;
|
||||
background:#3F4150!important;
|
||||
border:0px !important;
|
||||
}
|
||||
|
||||
::v-deep .ant-input-number-input{
|
||||
color:#fff!important;
|
||||
border:0px !important;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
@ -1,8 +1,11 @@
|
|||
<template>
|
||||
<div class="params-item">
|
||||
<div class="params-label">偏航角度</div>
|
||||
<div class="params-label">偏航角度:</div>
|
||||
<div class="params-value">
|
||||
<a-slider v-model:value="props.params.aircraftHeading" :min="-180" :max="180" :step="0.01" />
|
||||
<a-slider
|
||||
v-model:value="props.params.aircraftHeading"
|
||||
:min="-180" :max="180" :step="0.01"
|
||||
@change="paramChagne" />
|
||||
</div>
|
||||
<div class="params-value-text">
|
||||
{{ props.params.aircraftHeading }} °
|
||||
|
|
@ -12,16 +15,20 @@
|
|||
|
||||
<script lang="ts" setup>
|
||||
|
||||
import {defineProps,defineComponent,defineOptions} from 'vue';
|
||||
|
||||
const props = defineProps(["params"])
|
||||
import {defineProps,defineComponent,defineEmits} from 'vue';
|
||||
|
||||
const props = defineProps(["params","info"])
|
||||
const emits = defineEmits(["paramChagne"])
|
||||
|
||||
defineComponent({
|
||||
name: 'rotateYaw'
|
||||
})
|
||||
|
||||
|
||||
const paramChagne = ()=> {
|
||||
emits("paramChagne",props.info);
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
|
|
|||
|
|
@ -153,7 +153,9 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="pagenation">
|
||||
<a-pagination v-model:current="pageQuery.page" :total="ariLineCount" show-less-items @change="onPageChange" />
|
||||
<a-pagination size="small" v-model:current="pageQuery.page"
|
||||
v-model:page-size="pageQuery.limit" :total="ariLineCount"
|
||||
:defaultPageSize="10" show-less-items show-size-changer @change="onPageChange" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -245,7 +247,7 @@
|
|||
|
||||
const props = defineProps(["title"])
|
||||
|
||||
import {templateTypeOptions} from '../waylineConfig/index';
|
||||
import {templateTypeOptions} from '../waylineConfig/waylineParamsOptions';
|
||||
|
||||
import JSZip from 'jszip';
|
||||
import axios from 'axios';
|
||||
|
|
|
|||
|
|
@ -2,18 +2,16 @@
|
|||
<div class="container">
|
||||
<div class="title">
|
||||
<LeftOutlined @click="backPage" />
|
||||
<div>航点航线</div>
|
||||
<SaveOutlined @click="saveAirLine"/>
|
||||
<div style="flex:1;">
|
||||
<a-input v-model:value="props.airLineForm.airLineName" size="middle" placeholder="航线名称" />
|
||||
</div>
|
||||
|
||||
<a-button type="primary" size="middle" @click="areaOptionsShow = !areaOptionsShow">
|
||||
航线设置
|
||||
<ControlOutlined />
|
||||
</a-button>
|
||||
|
||||
<div style="flex:1;">
|
||||
<a-input v-model:value="props.airLineForm.airLineName" size="middle" placeholder="航线名称" />
|
||||
</div>
|
||||
|
||||
<SaveOutlined @click="saveAirLine" style="font-size:20px;" />
|
||||
</div>
|
||||
|
||||
<!-- 航线信息 -->
|
||||
|
|
@ -165,7 +163,7 @@
|
|||
<div class="item">
|
||||
<div class="label">全局航线飞行速度</div>
|
||||
<div class="content">
|
||||
<a-input style="width:100px;" placeholder="" v-model:value="missionConfig.globalTransitionalSpeed"></a-input>
|
||||
<a-input style="width:100px;" placeholder="" v-model:value="props.templateKmlConfig.Folder.autoFlightSpeed"></a-input>
|
||||
</div>
|
||||
<div class="unit"> m/s</div>
|
||||
</div>
|
||||
|
|
@ -343,12 +341,14 @@ import {ref,defineEmits,defineProps} from 'vue'
|
|||
import { SaveOutlined,LeftOutlined,AppstoreOutlined,DownOutlined,ControlOutlined,InfoCircleOutlined} from '@ant-design/icons-vue';
|
||||
|
||||
// 航点动作汇总
|
||||
import { airPointActions } from '../waylineConfig/action'
|
||||
import { airPointActions } from '../waylineConfig/actionConfig'
|
||||
import { XMLParser, XMLBuilder } from 'fast-xml-parser';
|
||||
|
||||
import {uploadXmlFile,addAirLine} from '@/api/sys/workplan';
|
||||
import {uploadXmlFile,addAirLine,editAirLine} from '@/api/sys/workplan';
|
||||
import { Modal, message } from 'ant-design-vue';
|
||||
import {missionConfigOptions,folderConfigOptions} from '../waylineConfig/index.ts';
|
||||
import {missionConfigOptions,folderConfigOptions} from '../waylineConfig/waylineParamsOptions.ts';
|
||||
import JSZip from "jszip";
|
||||
import { saveAs } from "file-saver";
|
||||
|
||||
const emits = defineEmits(["setTakeOffPoint","checkPoint","exitDraw","addAction"])
|
||||
|
||||
|
|
@ -520,93 +520,11 @@ const pointInfo = ref({
|
|||
|
||||
// 处理航点数据
|
||||
const handlerPointInfo = ()=>{
|
||||
|
||||
if(props.airPoints?.length<=0){
|
||||
message.warning("请添加航点!");
|
||||
return null;
|
||||
}
|
||||
|
||||
props.airPoints?.forEach((item,index)=>{
|
||||
|
||||
console.log("item123",item);
|
||||
|
||||
let point = {
|
||||
"Point": {
|
||||
"coordinates": item.lng+","+item.lat
|
||||
},
|
||||
"index": index,
|
||||
"executeHeight": item.alt,
|
||||
"waypointSpeed": 10,
|
||||
"waypointHeadingParam": {
|
||||
"waypointHeadingMode": "followWayline", // 飞行器偏航角模式 :
|
||||
"waypointHeadingAngle": item.aircraftHorizontalAngle, // 飞行器偏航角 [-180, 180] 当且仅当“wpml:waypointHeadingMode”为“smoothTransition”时必需
|
||||
"waypointPoiPoint": "0.000000,0.000000,0.000000", // 兴趣点 仅当wpml:waypointHeadingMode为towardPOI时必需
|
||||
"waypointHeadingAngleEnable": 0,
|
||||
"waypointHeadingPathMode": "followBadArc", // 飞行器偏航角转动方向
|
||||
"waypointHeadingPoiIndex": 0
|
||||
},
|
||||
"waypointTurnParam": {
|
||||
"waypointTurnMode": "toPointAndStopWithDiscontinuityCurvature",
|
||||
"waypointTurnDampingDist": 0
|
||||
},
|
||||
"useStraightLine": 1,
|
||||
"actionGroup": {
|
||||
"actionGroupId": 0,
|
||||
"actionGroupStartIndex": 0,
|
||||
"actionGroupEndIndex": 0,
|
||||
"actionGroupMode": "sequence",
|
||||
"actionTrigger": {
|
||||
"actionTriggerType": "reachPoint"
|
||||
},
|
||||
"action": [
|
||||
{
|
||||
"actionId": 0,
|
||||
"actionActuatorFunc": "rotateYaw",
|
||||
"actionActuatorFuncParam": {
|
||||
"aircraftHeading": 0,
|
||||
"aircraftPathMode": "counterClockwise"
|
||||
}
|
||||
},
|
||||
{
|
||||
"actionId": 1,
|
||||
"actionActuatorFunc": "gimbalRotate",
|
||||
"actionActuatorFuncParam": {
|
||||
"gimbalHeadingYawBase": "north",
|
||||
"gimbalRotateMode": "absoluteAngle",
|
||||
"gimbalPitchRotateEnable": 1,
|
||||
"gimbalPitchRotateAngle": 0,
|
||||
"gimbalRollRotateEnable": 0,
|
||||
"gimbalRollRotateAngle": 0,
|
||||
"gimbalYawRotateEnable": 0,
|
||||
"gimbalYawRotateAngle": 0,
|
||||
"gimbalRotateTimeEnable": 0,
|
||||
"gimbalRotateTime": 0,
|
||||
"payloadPositionIndex": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"actionId": 2,
|
||||
"actionActuatorFunc": "zoom",
|
||||
"actionActuatorFuncParam": {
|
||||
"focalLength": 24,
|
||||
"isUseFocalFactor": 0,
|
||||
"payloadPositionIndex": 0
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"waypointGimbalHeadingParam": {
|
||||
"waypointGimbalPitchAngle": item.cameraVerticalAngle, // 云台 垂直俯仰角参数 [-90, -30]
|
||||
"waypointGimbalYawAngle": 0 // 云台 水平偏航角度
|
||||
},
|
||||
"isRisky": 0,
|
||||
"waypointWorkType": 0
|
||||
}
|
||||
folder.value.Placemark.push(point);
|
||||
})
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
// waylines.json 数据
|
||||
|
|
@ -626,52 +544,194 @@ const waylinesJson = ref(
|
|||
// 保存航线
|
||||
const saveAirLine = ()=>{
|
||||
|
||||
// 处理template.json
|
||||
handlerTemplateKml();
|
||||
|
||||
// 处理航点
|
||||
handlerWaylineWpml();
|
||||
|
||||
|
||||
let handlerResult = handlerPointInfo();
|
||||
|
||||
if(handlerResult){
|
||||
const builder = new XMLBuilder();
|
||||
|
||||
let lineData = {...waylinesJson.value}
|
||||
// 将template中的 missionConfig 赋值 给wayline
|
||||
props.waylineWpmlConfig.missionConfig = JSON.parse(JSON.stringify(props.templateKmlConfig.missionConfig))
|
||||
|
||||
let obj = handlerPrefixWpml(lineData);
|
||||
const builder = new XMLBuilder({
|
||||
format: true, // 启用换行和缩进
|
||||
indentBy: " ", // 缩进字符(默认2空格,可自定义为 \t 等)
|
||||
suppressEmptyNode: true, // 可选:是否忽略空节点
|
||||
});
|
||||
|
||||
let xmlString = builder.build(obj);
|
||||
// 带wpml前缀的 template json数据
|
||||
let templateJson = {kml:{Document:props.templateKmlConfig}}
|
||||
let templateWpmlJson = handlerPrefixWpml(templateJson);
|
||||
let templateXmlStr = builder.build(templateWpmlJson);
|
||||
let templateXmlStrTemp = templateXmlStr.replace(/<\/?\d+>/g, "")
|
||||
let templateXml = templateXmlStrTemp.replace("<kml>",`<?xml version="1.0" encoding="UTF-8"?><kml xmlns="http://www.opengis.net/kml/2.2" xmlns:wpml="http://www.dji.com/wpmz/1.0.6">`)
|
||||
|
||||
let xmlString2 = xmlString.replace(/<\/?\d+>/g, "")
|
||||
// 带wpml前缀的 wayline json数据
|
||||
// delete props.waylineWpmlConfig.missionConfig.takeOffRefPoint
|
||||
// delete props.waylineWpmlConfig.missionConfig.takeOffRefPointAGLHeight
|
||||
// delete props.waylineWpmlConfig.missionConfig.autoRerouteInfo
|
||||
|
||||
let xmlString3 = xmlString2.replace("<kml>",`<?xml version="1.0" encoding="UTF-8"?><kml xmlns="http://www.opengis.net/kml/2.2" xmlns:wpml="http://www.dji.com/wpmz/1.0.6">`)
|
||||
|
||||
console.log("xmlString3",xmlString3);
|
||||
return null;
|
||||
handlerCreateFile(xmlString3);
|
||||
let waylineJosn = {kml:{Document:props.waylineWpmlConfig}}
|
||||
let waylienWpmlJson = handlerPrefixWpml(waylineJosn);
|
||||
let waylineXmlStr = builder.build(waylienWpmlJson);
|
||||
let waylineXmlStrTemp = waylineXmlStr.replace(/<\/?\d+>/g, "")
|
||||
let waylineXml = waylineXmlStrTemp.replace("<kml>",`<?xml version="1.0" encoding="UTF-8"?><kml xmlns="http://www.opengis.net/kml/2.2" xmlns:wpml="http://www.dji.com/wpmz/1.0.6">`)
|
||||
|
||||
// 创建压缩文件
|
||||
handlerCreateFile(templateXml,waylineXml);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 处理wmpl:前缀
|
||||
const handlerPrefixWpml = (obj) => {
|
||||
for (const key in obj) {
|
||||
// 处理生成template.json
|
||||
const handlerTemplateKml = () => {
|
||||
|
||||
// 如果是对象
|
||||
if (typeof obj[key] === 'object' && obj[key] !== null) {
|
||||
// 处理时间和日期
|
||||
handlerCreateOrUpdateTime();
|
||||
|
||||
handlerPrefixWpml(obj[key]); // 递归处理嵌套对象
|
||||
// 计算数据处理
|
||||
// handlerAirLineHeight();
|
||||
|
||||
const newAttrs = {};
|
||||
for (const attrName in obj[key]) {
|
||||
|
||||
// 检查属性名是否首字母小写
|
||||
if (/^[a-z]/.test(attrName)) {
|
||||
newAttrs[`wmpl:${attrName}`] = obj[key][attrName];
|
||||
} else {
|
||||
newAttrs[attrName] = obj[key][attrName];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 处理创建时间 编辑时间
|
||||
const handlerCreateOrUpdateTime = () => {
|
||||
|
||||
let date = new Date();
|
||||
|
||||
if(props.editModel == 'add'){
|
||||
props.templateKmlConfig.createTime = date.getTime();
|
||||
props.templateKmlConfig.updateTime = date.getTime();
|
||||
}else if(props.editModel == 'edit'){
|
||||
props.templateKmlConfig.updateTime = date.getTime();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// 处理生成wayline.json
|
||||
const handlerWaylineWpml = () => {
|
||||
|
||||
// 处理基础配置
|
||||
props.waylineWpmlConfig.missionConfig = JSON.parse(JSON.stringify(props.templateKmlConfig.missionConfig));
|
||||
|
||||
// 处理统计数据
|
||||
handlerStatistics();
|
||||
|
||||
// 处理航点
|
||||
handelrAirPoint();
|
||||
|
||||
}
|
||||
|
||||
const handlerStatistics = () => {
|
||||
|
||||
}
|
||||
|
||||
// 处理航点 和 绑定动作信息
|
||||
const handelrAirPoint = () => {
|
||||
props.airPoints?.forEach((item,index)=>{
|
||||
let point = {
|
||||
"Point": {
|
||||
"coordinates": item.lng+","+item.lat
|
||||
},
|
||||
"index": index,
|
||||
"executeHeight": 172.948304450636,
|
||||
"waypointSpeed": props.templateKmlConfig.Folder.autoFlightSpeed,
|
||||
"waypointHeadingParam": {
|
||||
"waypointHeadingMode": "followWayline",
|
||||
"waypointHeadingAngle": 0,
|
||||
"waypointPoiPoint": "0.000000,0.000000,0.000000",
|
||||
"waypointHeadingAngleEnable": 0,
|
||||
"waypointHeadingPathMode": "followBadArc",
|
||||
"waypointHeadingPoiIndex": 0
|
||||
},
|
||||
"waypointTurnParam": {
|
||||
"waypointTurnMode": "toPointAndStopWithDiscontinuityCurvature",
|
||||
"waypointTurnDampingDist": 0
|
||||
},
|
||||
"useStraightLine": 1,
|
||||
"waypointGimbalHeadingParam": {
|
||||
"waypointGimbalPitchAngle": 0,
|
||||
"waypointGimbalYawAngle": 0
|
||||
},
|
||||
"isRisky": 0,
|
||||
"waypointWorkType": 0
|
||||
}
|
||||
|
||||
if(item.actions.length>0){
|
||||
point.actionGroup = {
|
||||
"actionGroupId": 0,
|
||||
"actionGroupStartIndex": index,
|
||||
"actionGroupEndIndex": index,
|
||||
"actionGroupMode": "sequence",
|
||||
"actionTrigger": {
|
||||
"actionTriggerType": "reachPoint"
|
||||
},
|
||||
"action": []
|
||||
};
|
||||
item.actions.forEach((action,idx)=>{
|
||||
let actor = action.config;
|
||||
actor.actionId = idx
|
||||
point.actionGroup.action.push(actor);
|
||||
})
|
||||
}
|
||||
props.waylineWpmlConfig.Folder.Placemark.push(point);
|
||||
props.templateKmlConfig.Folder.Placemark.push(point);
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
|
||||
// 处理wpml:前缀
|
||||
const handlerPrefixWpml = (obj) => {
|
||||
|
||||
for (const key in obj) {
|
||||
|
||||
|
||||
if (typeof obj[key] === 'object' && obj[key] !== null && !Array.isArray(obj[key])) { // 如果是对象
|
||||
|
||||
handlerPrefixWpml(obj[key]); // 递归处理嵌套对象
|
||||
|
||||
const newAttrs = {};
|
||||
|
||||
for (const attrName in obj[key] ) {
|
||||
|
||||
// 检查属性名是否首字母小写
|
||||
if (/^[a-z]/.test(attrName) && attrName != 'outerBoundaryIs' && attrName != 'coordinates') {
|
||||
newAttrs[`wpml:${attrName}`] = obj[key][attrName];
|
||||
} else {
|
||||
newAttrs[attrName] = obj[key][attrName];
|
||||
}
|
||||
}
|
||||
|
||||
obj[key] = newAttrs;
|
||||
|
||||
}else if(typeof obj[key] === 'object' && obj[key] !== null && Array.isArray(obj[key])){ // 如果是数组
|
||||
|
||||
handlerPrefixWpml(obj[key]); // 递归处理嵌套对象
|
||||
|
||||
const newAttrs = [];
|
||||
|
||||
for (const attrName in obj[key]) {
|
||||
// 检查属性名是否首字母小写
|
||||
if (/^[a-z]/.test(attrName)) {
|
||||
newAttrs[`wpml:${attrName}`] = obj[key][attrName];
|
||||
} else {
|
||||
newAttrs[attrName] = obj[key][attrName];
|
||||
}
|
||||
}
|
||||
|
||||
obj[key] = newAttrs;
|
||||
}
|
||||
obj[key] = newAttrs;
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -695,15 +755,35 @@ const submitForm = ref({
|
|||
})
|
||||
|
||||
// 生成xml文件,创建航线
|
||||
const handlerCreateFile =async (content)=>{
|
||||
const blob = new Blob([content], { type: 'wmpl/plain' });
|
||||
const handlerCreateFile =async (templateXml,waylineXml)=>{
|
||||
|
||||
console.log("waylineXml",templateXml,waylineXml);
|
||||
|
||||
const blob =await convertXmlToKmz(templateXml,waylineXml);
|
||||
|
||||
// 创建FormData对象用于上传
|
||||
const formData = new FormData();
|
||||
formData.append('xmlFile', blob);
|
||||
let res = await uploadXmlFile(formData);
|
||||
|
||||
formData.append('xmlFile', blob,"航点航线.kmz");
|
||||
|
||||
let res = await uploadXmlFile(props.airLineForm.folder,formData);
|
||||
|
||||
if(res){
|
||||
submitForm.value.wpml = res.path;
|
||||
let addAirLineRes =await addAirLine(submitForm.value);
|
||||
props.airLineForm.wpml = res.path;
|
||||
// props.airLineForm.lineData = {type:2}
|
||||
|
||||
let addAirLineRes = null;
|
||||
|
||||
if(props.editModel == 'add'){
|
||||
|
||||
addAirLineRes =await addAirLine(props.airLineForm);
|
||||
|
||||
}else if(props.editModel == 'edit'){
|
||||
|
||||
addAirLineRes =await editAirLine(props.airLineForm);
|
||||
|
||||
}
|
||||
|
||||
if(addAirLineRes){
|
||||
message.success("操作成功!");
|
||||
backPage();
|
||||
|
|
@ -715,6 +795,28 @@ const handlerCreateFile =async (content)=>{
|
|||
}
|
||||
}
|
||||
|
||||
// xml文本转换为wpml和kml文件
|
||||
const convertXmlToKmz =async (templateXml,waylineXml)=>{
|
||||
|
||||
|
||||
const zip = new JSZip();
|
||||
|
||||
// 1. 创建 "wmpz" 文件夹
|
||||
const wmpzFolder = zip.folder("wpmz");
|
||||
|
||||
// 2. 向文件夹中添加文件
|
||||
wmpzFolder.file("waylines.wpml", waylineXml);
|
||||
wmpzFolder.file("template.kml", templateXml);
|
||||
|
||||
// 3. 生成 KMZ (ZIP) 文件
|
||||
const kmzBlob = await zip.generateAsync({ type: "blob" });
|
||||
|
||||
// 下载航线文件
|
||||
// saveAs(kmzBlob, "output.kmz");
|
||||
|
||||
return kmzBlob;
|
||||
}
|
||||
|
||||
|
||||
// 退出绘制
|
||||
const backPage = ()=>{
|
||||
|
|
@ -727,7 +829,6 @@ const addAirPointAction = (action) => {
|
|||
|
||||
// 处理动作添加逻辑
|
||||
emits("addAction",action);
|
||||
|
||||
|
||||
if(action.value == ""){
|
||||
|
||||
|
|
|
|||
|
|
@ -127,19 +127,23 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="item-content">
|
||||
<component :is="componentMap[item.value]" :params="item.config.actionActuatorFuncParam" :key="index"></component>
|
||||
<component
|
||||
:is="componentMap[item.value]"
|
||||
:params="item.config.actionActuatorFuncParam"
|
||||
:info="item"
|
||||
:key="index"
|
||||
@paramChagne="paramChagne"
|
||||
></component>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {ref,defineProps,watch,shallowRef,defineAsyncComponent,defineOptions } from 'vue';
|
||||
import {ref,defineProps,watch,shallowRef,defineAsyncComponent,defineOptions,defineEmits} from 'vue';
|
||||
|
||||
import { DeleteOutlined,LeftOutlined,RightOutlined } from '@ant-design/icons-vue'
|
||||
|
||||
|
|
@ -163,8 +167,11 @@ const componentMap = {
|
|||
};
|
||||
|
||||
const props = defineProps(['currentAirPoint','airPoints'])
|
||||
const emits = defineEmits(["paramChagne"])
|
||||
|
||||
|
||||
const paramChagne = (info) => {
|
||||
emits("paramChagne",info);
|
||||
}
|
||||
|
||||
watch(
|
||||
()=>props.currentAirPoint,
|
||||
|
|
|
|||
|
|
@ -250,7 +250,7 @@
|
|||
<script lang="ts" setup>
|
||||
import {ref,defineEmits,defineProps,watch} from 'vue'
|
||||
import { SaveOutlined,LeftOutlined,InfoCircleOutlined } from '@ant-design/icons-vue';
|
||||
import {missionConfigOptions,folderConfigOptions} from '../waylineConfig/index.ts';
|
||||
import {missionConfigOptions,folderConfigOptions} from '../waylineConfig/waylineParamsOptions.ts';
|
||||
import {uploadXmlFile,addAirLine,editAirLine} from '@/api/sys/workplan';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { XMLParser, XMLBuilder } from 'fast-xml-parser';
|
||||
|
|
@ -771,7 +771,6 @@ const handlerPrefixWpml = (obj) => {
|
|||
|
||||
// 检查属性名是否首字母小写
|
||||
if (/^[a-z]/.test(attrName) && attrName != 'outerBoundaryIs' && attrName != 'coordinates') {
|
||||
console.log("attrName",attrName);
|
||||
newAttrs[`wpml:${attrName}`] = obj[key][attrName];
|
||||
} else {
|
||||
newAttrs[attrName] = obj[key][attrName];
|
||||
|
|
@ -814,7 +813,7 @@ const handlerCreateFile =async (templateXml,waylineXml)=>{
|
|||
|
||||
formData.append('xmlFile', blob,"面状航线.kmz");
|
||||
|
||||
let res = await uploadXmlFile("默认文件夹/面状航线",formData);
|
||||
let res = await uploadXmlFile(props.airLineForm.folder,formData);
|
||||
|
||||
if(res){
|
||||
props.airLineForm.wpml = res.path;
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@
|
|||
</div>
|
||||
</a-form-item> -->
|
||||
|
||||
<a-form-item ref="workspaceId" label="选择项目" name="workspaceId">
|
||||
<!-- <a-form-item ref="workspaceId" label="选择项目" name="workspaceId">
|
||||
<div class="">
|
||||
<a-select
|
||||
v-model:value="submitForm.workspaceId"
|
||||
|
|
@ -46,7 +46,7 @@
|
|||
|
||||
</a-select>
|
||||
</div>
|
||||
</a-form-item>
|
||||
</a-form-item> -->
|
||||
|
||||
|
||||
<a-form-item ref="name" label="选择航线" name="name">
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@
|
|||
<airPointConfig
|
||||
:currentAirPoint="currentAirPoint"
|
||||
:airPoints="airPoints"
|
||||
@paramChagne="paramChagne"
|
||||
></airPointConfig>
|
||||
</div>
|
||||
|
||||
|
|
@ -66,7 +67,6 @@
|
|||
import airPolygon from './airPolygon.vue';
|
||||
import airPointConfig from './airPointConfig.vue';
|
||||
|
||||
|
||||
// const props = defineProps([
|
||||
// 'airLineForm',
|
||||
// 'flyToTherePosition',
|
||||
|
|
@ -296,12 +296,11 @@
|
|||
watch(
|
||||
() => props.waylineInfo,
|
||||
(newVal,oldVal) => {
|
||||
|
||||
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
|
||||
// 航线预览:生成点
|
||||
const generatePreviewPoint = (placemark)=>{
|
||||
|
||||
|
|
@ -358,24 +357,30 @@ const generatePreviewPoint = (placemark)=>{
|
|||
let moveTool: mars3d.thing.MatrixMove2;
|
||||
|
||||
// 监听航点变化
|
||||
watch(
|
||||
currentAirPoint,
|
||||
(newVal, oldVal) => {
|
||||
// 更新航点
|
||||
updateAirPoint(newVal);
|
||||
// 更新镜头
|
||||
handlerDrawCamera(newVal);
|
||||
},
|
||||
{ deep: true },
|
||||
);
|
||||
// watch(
|
||||
// currentAirPoint,
|
||||
// (newVal, oldVal) => {
|
||||
// // console.log("newVal123",newVal);
|
||||
// // 更新航点
|
||||
// // updateAirPoint(newVal);
|
||||
// // 更新镜头
|
||||
// // handlerDrawCamera(newVal);
|
||||
// },
|
||||
// { deep: true },
|
||||
// );
|
||||
|
||||
const clickPoint = (id) => {
|
||||
|
||||
airPoints.value?.forEach((item, index) => {
|
||||
if (item.id == id) {
|
||||
currentAirPoint.value = item;
|
||||
// 更新镜头
|
||||
handlerDrawCamera(currentAirPoint.value);
|
||||
airPointConfigShow.value = true;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
};
|
||||
|
||||
const checkPoint = (e) => {
|
||||
|
|
@ -686,7 +691,6 @@ const initMap = () => {
|
|||
// 绘制航线
|
||||
graphicLayer.on(mars3d.EventType.click, (e) => {
|
||||
// 设置当前选中点
|
||||
|
||||
clickPoint(e.graphic.options.id);
|
||||
});
|
||||
|
||||
|
|
@ -1575,7 +1579,8 @@ const handlerDrawLine = () => {
|
|||
// let lineString = turf.lineString(positions);
|
||||
// lineInfo.value.length = turf.length(lineString).toFixed(2);
|
||||
};
|
||||
|
||||
|
||||
// 全局航点数组
|
||||
const uavPoints = ref([]);
|
||||
|
||||
// 绘制航点
|
||||
|
|
@ -1584,40 +1589,32 @@ const handlerDrawPoint = (e) => {
|
|||
moveTool.destroy();
|
||||
moveTool = null;
|
||||
}
|
||||
|
||||
// 设置航线默认高度
|
||||
let position = mars3d.LngLatPoint.fromCartesian(e.position);
|
||||
|
||||
let uuid = buildUUID();
|
||||
|
||||
// 获取默认航线高度
|
||||
let globalHeight = props.templateKmlConfig.Folder.globalHeight;
|
||||
|
||||
// 航点三维模型
|
||||
let uavAngleGraphic = new mars3d.graphic.ModelEntity({
|
||||
id:uuid,
|
||||
name: "航向",
|
||||
position: [position._lng, position._lat, position._alt],
|
||||
position: [position._lng, position._lat, globalHeight],
|
||||
style: {
|
||||
url: "/map/uav-angle.gltf",
|
||||
scale: 0.1,
|
||||
heading: 90,
|
||||
heading:90,
|
||||
distanceDisplayCondition: true,
|
||||
distanceDisplayCondition_near: 0,
|
||||
distanceDisplayPoint: {
|
||||
color: "#00ff00",
|
||||
pixelSize: 8
|
||||
},
|
||||
label: {
|
||||
text: "",
|
||||
font_size: 18,
|
||||
color: "#ffffff",
|
||||
pixelOffsetY: -50,
|
||||
distanceDisplayCondition: true,
|
||||
distanceDisplayCondition_far: 10000,
|
||||
distanceDisplayCondition_near: 0
|
||||
}
|
||||
},
|
||||
attr: { remark: "示例1" }
|
||||
}
|
||||
})
|
||||
graphicLayer.addGraphic(uavAngleGraphic)
|
||||
|
||||
|
||||
// 地面投影点
|
||||
let stickGraphic = new mars3d.graphic.PointEntity({
|
||||
id: 'stick' + uuid,
|
||||
|
|
@ -1632,13 +1629,13 @@ const handlerDrawPoint = (e) => {
|
|||
},
|
||||
});
|
||||
stickGroundPointLayer.addGraphic(stickGraphic);
|
||||
|
||||
|
||||
// 航点 投影点连接线
|
||||
let lineGraphic = new mars3d.graphic.PolylineEntity({
|
||||
id: 'line' + uuid,
|
||||
positions: [
|
||||
[position._lng, position._lat, position._alt],
|
||||
[position._lng, position._lat, 0],
|
||||
[position._lng, position._lat, globalHeight],
|
||||
[position._lng, position._lat, 0],
|
||||
],
|
||||
style: {
|
||||
color: '#f5f5f5',
|
||||
|
|
@ -1646,34 +1643,83 @@ const handlerDrawPoint = (e) => {
|
|||
},
|
||||
});
|
||||
lineGroundPointLayer.addGraphic(lineGraphic);
|
||||
|
||||
|
||||
// 航点列表
|
||||
let airPointInfo = {
|
||||
id: uuid,
|
||||
name: '航点',
|
||||
lng: position._lng,
|
||||
lat: position._lat,
|
||||
alt: position._alt,
|
||||
alt: globalHeight,
|
||||
aircraftHorizontalAngle: 0,
|
||||
cameraHorizontalAngle: 0,
|
||||
cameraVerticalAngle: 0,
|
||||
focalLength: 2,
|
||||
actions:[],
|
||||
actions:[
|
||||
{ // 设置无人机偏航角
|
||||
"name":"飞行器偏航角",
|
||||
"value":"rotateYaw",
|
||||
"type":"action",
|
||||
"config":{
|
||||
"actionId": null,
|
||||
"actionActuatorFunc": "rotateYaw",
|
||||
"actionActuatorFuncParam": {
|
||||
"aircraftHeading": 0,
|
||||
"aircraftPathMode": "counterClockwise"
|
||||
}
|
||||
},
|
||||
},{ // 设置旋转云台俯仰角
|
||||
"name":"云台俯仰角",
|
||||
"value":"gimbalRotate",
|
||||
"type":"action",
|
||||
"config":{
|
||||
"actionId": 3,
|
||||
"actionActuatorFunc": "gimbalRotate",
|
||||
"actionActuatorFuncParam": {
|
||||
"gimbalHeadingYawBase": "north",
|
||||
"gimbalRotateMode": "absoluteAngle",
|
||||
"gimbalPitchRotateEnable": 1,
|
||||
"gimbalPitchRotateAngle": 0,
|
||||
"gimbalRollRotateEnable": 0,
|
||||
"gimbalRollRotateAngle": 0,
|
||||
"gimbalYawRotateEnable": 0,
|
||||
"gimbalYawRotateAngle": 0,
|
||||
"gimbalRotateTimeEnable": 0,
|
||||
"gimbalRotateTime": 0,
|
||||
"payloadPositionIndex": 0
|
||||
}
|
||||
}
|
||||
},{ // 调整相机焦距
|
||||
"name":"相机焦距",
|
||||
"value":"zoom",
|
||||
"type":"action",
|
||||
"config":{
|
||||
"actionId": null,
|
||||
"actionActuatorFunc": "zoom",
|
||||
"actionActuatorFuncParam": {
|
||||
"focalLength": 24,
|
||||
"isUseFocalFactor": 0,
|
||||
"payloadPositionIndex": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
};
|
||||
airPoints.value?.push(airPointInfo);
|
||||
|
||||
uavPoints.value.push(graphic);
|
||||
|
||||
// 当前航点
|
||||
currentAirPoint.value = airPoints.value[airPoints.value?.length - 1];
|
||||
|
||||
// 更新镜头
|
||||
handlerDrawCamera(airPointInfo);
|
||||
|
||||
// 更新航线
|
||||
handlerDrawLine();
|
||||
};
|
||||
|
||||
// 绘制镜头
|
||||
const handlerDrawCamera = (e) => {
|
||||
|
||||
// 判断是否已经添加
|
||||
const graphic = graphicLayer.getGraphicById("cameraGraphic");
|
||||
if(graphic){ // 如果存在更新数据
|
||||
|
|
@ -1692,8 +1738,8 @@ const handlerDrawCamera = (e) => {
|
|||
topSteps: 2,
|
||||
flat: true,
|
||||
cameraHpr: true,
|
||||
heading:e.aircraftHorizontalAngle,
|
||||
pitch: e.cameraVerticalAngle+90, // 俯仰角 0 - 360度
|
||||
heading:e.aircraftHorizontalAngle - 90, // 偏航角
|
||||
pitch: e.cameraVerticalAngle - 90, // 俯仰角 0 - 360度
|
||||
roll: 0,
|
||||
}
|
||||
})
|
||||
|
|
@ -1712,8 +1758,8 @@ const handlerDrawCamera = (e) => {
|
|||
topShow: true,
|
||||
topSteps: 2,
|
||||
cameraHpr: true,
|
||||
heading:e.aircraftHorizontalAngle,
|
||||
pitch: e.cameraVerticalAngle+90, // 俯仰角 0 - 360度
|
||||
heading:e.aircraftHorizontalAngle - 90,
|
||||
pitch: e.cameraVerticalAngle - 90, // 俯仰角 0 - 360度
|
||||
roll: 0,
|
||||
}
|
||||
})
|
||||
|
|
@ -1733,24 +1779,14 @@ const updateAirPoint = (e) => {
|
|||
style: {
|
||||
url: "/map/uav-angle.gltf",
|
||||
scale: 0.1,
|
||||
heading: e.aircraftHorizontalAngle,
|
||||
heading: e.aircraftHorizontalAngle + 90,
|
||||
distanceDisplayCondition: true,
|
||||
distanceDisplayCondition_near: 0,
|
||||
distanceDisplayPoint: {
|
||||
color: "#00ff00",
|
||||
pixelSize: 8
|
||||
},
|
||||
label: {
|
||||
text: "",
|
||||
font_size: 18,
|
||||
color: "#ffffff",
|
||||
pixelOffsetY: -50,
|
||||
distanceDisplayCondition: true,
|
||||
distanceDisplayCondition_far: 10000,
|
||||
distanceDisplayCondition_near: 0
|
||||
}
|
||||
},
|
||||
attr: { remark: "示例1" }
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
@ -1816,27 +1852,73 @@ const updateAirPoint = (e) => {
|
|||
handlerDrawLine();
|
||||
};
|
||||
|
||||
|
||||
// 航点动作参数改变
|
||||
const paramChagne = (info) => {
|
||||
console.log("info1232",info);
|
||||
|
||||
// 判断事件类型
|
||||
if(info.value == 'rotateYaw'){ // 飞行器偏航角
|
||||
|
||||
// 设置参数
|
||||
currentAirPoint.value.aircraftHorizontalAngle = info.config.actionActuatorFuncParam.aircraftHeading;
|
||||
|
||||
// 更新镜头
|
||||
handlerDrawCamera(currentAirPoint.value);
|
||||
|
||||
// 更新航点
|
||||
updateAirPoint(currentAirPoint.value);
|
||||
}
|
||||
|
||||
if(info.value == "gimbalRotate"){ // 云台俯仰角
|
||||
|
||||
// 设置参数
|
||||
currentAirPoint.value.cameraVerticalAngle = info.config.actionActuatorFuncParam.gimbalPitchRotateAngle
|
||||
// 更新镜头
|
||||
handlerDrawCamera(currentAirPoint.value);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// 事件处理
|
||||
const updateCamera = () => {
|
||||
|
||||
}
|
||||
|
||||
// 删除航点
|
||||
const deleteAirPoint = (e) => {
|
||||
let id = e.graphic.id;
|
||||
|
||||
|
||||
// 删除航点
|
||||
let point = graphicLayer.getGraphicById(id);
|
||||
if (point) {
|
||||
graphicLayer.removeGraphic(point);
|
||||
let uavModel = graphicLayer.getGraphicById(id);
|
||||
if (uavModel) {
|
||||
graphicLayer.removeGraphic(uavModel);
|
||||
}
|
||||
|
||||
// 删除相机
|
||||
let camera = graphicLayer.getGraphicById('camera' + id);
|
||||
let camera = graphicLayer.getGraphicById("cameraGraphic");
|
||||
if (camera) {
|
||||
graphicLayer.removeGraphic(camera);
|
||||
graphicLayer.removeGraphic(camera);
|
||||
}
|
||||
|
||||
// 删除贴地点
|
||||
let point = lineGroundPointLayer.getGraphicById("line"+id);
|
||||
if (point) {
|
||||
lineGroundPointLayer.removeGraphic(point);
|
||||
}
|
||||
|
||||
// 删除连接线
|
||||
let line = stickGroundPointLayer.getGraphicById("stick"+id);
|
||||
if (line) {
|
||||
stickGroundPointLayer.removeGraphic(line);
|
||||
}
|
||||
|
||||
// 删除数据
|
||||
airPoints.value?.forEach((item, index) => {
|
||||
if (item.id == id) {
|
||||
airPoints.value?.splice(index, 1);
|
||||
}
|
||||
if (item.id == id) {
|
||||
airPoints.value?.splice(index, 1);
|
||||
}
|
||||
});
|
||||
|
||||
// 更新航线
|
||||
|
|
@ -2511,11 +2593,9 @@ function addRectSensor(route) {
|
|||
|
||||
/////////////////////////////////动作处理//////////////////////////////////////
|
||||
const addAction = (action) => {
|
||||
|
||||
// 当前航点添加动作
|
||||
|
||||
console.log("action",action);
|
||||
currentAirPoint.value.actions.push(action);
|
||||
console.log("currentAirPoint",currentAirPoint.value)
|
||||
currentAirPoint.value.actions.push(JSON.parse(JSON.stringify(action)));
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,55 @@
|
|||
<template>
|
||||
<div class="params-item">
|
||||
<div class="params-label">间隔距离:</div>
|
||||
<div class="params-value">
|
||||
<a-input-number v-model:value="props.params.hoverTime"></a-input-number>
|
||||
</div>
|
||||
<div class="params-unit">米</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
|
||||
import {defineProps,defineComponent,defineOptions} from 'vue';
|
||||
|
||||
const props = defineProps(["params"])
|
||||
|
||||
|
||||
defineComponent({
|
||||
name: 'multipleDistance'
|
||||
})
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.params-item{
|
||||
width:100%;
|
||||
display: flex;
|
||||
gap:20px;
|
||||
}
|
||||
.params-item .params-label{
|
||||
line-height:30px;
|
||||
}
|
||||
|
||||
.params-item .params-value{
|
||||
flex:1;
|
||||
}
|
||||
|
||||
.params-item .params-unit{
|
||||
line-height:30px;
|
||||
padding:0px 5px 0px 15px;
|
||||
}
|
||||
|
||||
::v-deep .ant-input-number{
|
||||
color:#fff!important;
|
||||
background:#3F4150!important;
|
||||
border:0px !important;
|
||||
}
|
||||
|
||||
::v-deep .ant-input-number-input{
|
||||
color:#fff!important;
|
||||
border:0px !important;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
@ -225,14 +225,12 @@
|
|||
}
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
const onPageChange = (e)=>{
|
||||
pageQuery.value.page = e;
|
||||
getTaskList();
|
||||
}
|
||||
|
||||
|
||||
// 任务状态
|
||||
const planStatusOptions = ref([
|
||||
{
|
||||
|
|
|
|||
|
|
@ -16,11 +16,10 @@ export const calculateHeight = (gsd,uavModel) => {
|
|||
|
||||
// 飞行高度= GSD(cm)×实际焦距(mm)/像元尺寸(um)
|
||||
|
||||
let abc = (gsd * uavModel['focalLength'] / uavModel['pixelLength']);
|
||||
height = (gsd * uavModel['focalLength'] / uavModel['pixelLength']);
|
||||
|
||||
console.log("abc",abc);
|
||||
|
||||
height = ( (gsd / 100) * (uavModel['focalLength'] / 1000) * uavModel['imageWidth'] ) / ( uavModel['sensorLength'] / 1000 );
|
||||
// height = ( (gsd / 100) * (uavModel['focalLength'] / 1000) * uavModel['imageWidth'] ) / ( uavModel['sensorLength'] / 1000 );
|
||||
|
||||
return height.toFixed(2);
|
||||
}
|
||||
|
|
@ -30,8 +29,16 @@ export const calculateHeight = (gsd,uavModel) => {
|
|||
|
||||
// 输入高度计算gsd
|
||||
export const calculateGsd = (height,uavModel) => {
|
||||
|
||||
|
||||
|
||||
let gsd = 0;
|
||||
gsd = ( (height*1000) * uavModel['sensorLength'] ) / (uavModel['focalLength'] * uavModel['imageWidth']) / 10;
|
||||
|
||||
gsd = (uavModel['pixelLength'] * height) / uavModel['focalLength'] ;
|
||||
|
||||
|
||||
// gsd = ( (height*1000) * uavModel['sensorLength'] ) / (uavModel['focalLength'] * uavModel['imageWidth']) / 10;
|
||||
|
||||
return gsd.toFixed(2);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ export const airPointActions = {
|
|||
"gimbalHeadingYawBase": "north",
|
||||
"gimbalRotateMode": "absoluteAngle",
|
||||
"gimbalPitchRotateEnable": 1,
|
||||
"gimbalPitchRotateAngle": -65.7,
|
||||
"gimbalPitchRotateAngle": 0,
|
||||
"gimbalRollRotateEnable": 0,
|
||||
"gimbalRollRotateAngle": 0,
|
||||
"gimbalYawRotateEnable": 0,
|
||||
|
|
@ -0,0 +1,176 @@
|
|||
|
||||
// 面状航线默认template.kml数据
|
||||
export const templateKml = {
|
||||
"author": 17861857725,
|
||||
"createTime": 1749689844431,
|
||||
"updateTime": 1753241338101,
|
||||
"missionConfig": {
|
||||
"flyToWaylineMode": "pointToPoint",
|
||||
"finishAction": "goHome",
|
||||
"exitOnRCLost": "goContinue",
|
||||
"executeRCLostAction": "goBack",
|
||||
"takeOffSecurityHeight": 20,
|
||||
"takeOffRefPoint": "",
|
||||
"takeOffRefPointAGLHeight": 4.169064385,
|
||||
"globalTransitionalSpeed": 15,
|
||||
"globalRTHHeight": 100,
|
||||
"droneInfo": {
|
||||
"droneEnumValue": 100,
|
||||
"droneSubEnumValue": 1
|
||||
},
|
||||
"autoRerouteInfo": {
|
||||
"transitionalAutoRerouteMode": 1,
|
||||
"missionAutoRerouteMode": 1
|
||||
},
|
||||
"waylineAvoidLimitAreaMode": 0,
|
||||
"payloadInfo": {
|
||||
"payloadEnumValue": 99,
|
||||
"payloadSubEnumValue": 0,
|
||||
"payloadPositionIndex": 0
|
||||
}
|
||||
},
|
||||
"Folder": {
|
||||
"templateType": "mapping2d",
|
||||
"templateId": 0,
|
||||
"waylineCoordinateSysParam": {
|
||||
"coordinateMode": "WGS84",
|
||||
"heightMode": "EGM96",
|
||||
"globalShootHeight": 90,
|
||||
"surfaceFollowModeEnable": 1,
|
||||
"isRealtimeSurfaceFollow": 0,
|
||||
"surfaceRelativeHeight": 90,
|
||||
"dsmFile": "wpmz/res/dsm/wgs84_ASTGTMV003_N35E118_dem_7.tif"
|
||||
},
|
||||
"autoFlightSpeed": 12.7,
|
||||
"Placemark": {
|
||||
"caliFlightEnable": 0,
|
||||
"elevationOptimizeEnable": 1,
|
||||
"smartObliqueEnable": 0,
|
||||
"quickOrthoMappingEnable": 0,
|
||||
"facadeWaylineEnable": 0,
|
||||
"isLookAtSceneSet": 0,
|
||||
"shootType": "time",
|
||||
"direction": 83,
|
||||
"margin": 0,
|
||||
"efficiencyFlightModeEnable": 0,
|
||||
"overlap": {
|
||||
"orthoCameraOverlapH": 80,
|
||||
"orthoCameraOverlapW": 70,
|
||||
"inclinedCameraOverlapH": 80,
|
||||
"inclinedCameraOverlapW": 70
|
||||
},
|
||||
"Polygon": {
|
||||
"outerBoundaryIs": {
|
||||
"LinearRing": {
|
||||
"coordinates": "118.293794766158,35.1353688096117,0\n 118.295429169407,35.1353304409052,0\n 118.295487507293,35.1332925168381,0\n 118.293672196844,35.1331918267775,0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ellipsoidHeight": 90,
|
||||
"height": 90
|
||||
},
|
||||
"payloadParam": {
|
||||
"payloadPositionIndex": 0,
|
||||
"focusMode": "firstPoint",
|
||||
"meteringMode": "average",
|
||||
"returnMode": "singleReturnStrongest",
|
||||
"samplingRate": 240000,
|
||||
"scanningMode": "repetitive",
|
||||
"imageFormat": "visable",
|
||||
"photoSize": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 面状航线默认wayline.wpml数据
|
||||
export const waylineWpml = {
|
||||
"missionConfig": {
|
||||
"flyToWaylineMode": "pointToPoint",
|
||||
"finishAction": "goHome",
|
||||
"exitOnRCLost": "goContinue",
|
||||
"executeRCLostAction": "goBack",
|
||||
"takeOffSecurityHeight": 20,
|
||||
"globalTransitionalSpeed": 15,
|
||||
"globalRTHHeight": 100,
|
||||
"droneInfo": {
|
||||
"droneEnumValue": 100,
|
||||
"droneSubEnumValue": 1
|
||||
},
|
||||
"autoRerouteInfo": {
|
||||
"transitionalAutoRerouteMode": 1,
|
||||
"missionAutoRerouteMode": 1
|
||||
},
|
||||
"waylineAvoidLimitAreaMode": 0,
|
||||
"payloadInfo": {
|
||||
"payloadEnumValue": 99,
|
||||
"payloadSubEnumValue": 0,
|
||||
"payloadPositionIndex": 0
|
||||
}
|
||||
},
|
||||
"Folder": {
|
||||
"templateId": 0,
|
||||
"executeHeightMode": "WGS84",
|
||||
"waylineId": 0,
|
||||
"distance": 1259.17163085938,
|
||||
"duration": 145.652896165848,
|
||||
"autoFlightSpeed": 12.7,
|
||||
"startActionGroup": {
|
||||
"action": [
|
||||
{
|
||||
"actionId": 0,
|
||||
"actionActuatorFunc": "gimbalRotate",
|
||||
"actionActuatorFuncParam": {
|
||||
"gimbalHeadingYawBase": "aircraft",
|
||||
"gimbalRotateMode": "absoluteAngle",
|
||||
"gimbalPitchRotateEnable": 1,
|
||||
"gimbalPitchRotateAngle": -90,
|
||||
"gimbalRollRotateEnable": 0,
|
||||
"gimbalRollRotateAngle": 0,
|
||||
"gimbalYawRotateEnable": 1,
|
||||
"gimbalYawRotateAngle": 0,
|
||||
"gimbalRotateTimeEnable": 0,
|
||||
"gimbalRotateTime": 10,
|
||||
"payloadPositionIndex": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"actionId": 1,
|
||||
"actionActuatorFunc": "hover",
|
||||
"actionActuatorFuncParam": {
|
||||
"hoverTime": 0.5
|
||||
}
|
||||
},
|
||||
{
|
||||
"actionId": 2,
|
||||
"actionActuatorFunc": "setFocusType",
|
||||
"actionActuatorFuncParam": {
|
||||
"cameraFocusType": "manual",
|
||||
"payloadPositionIndex": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"actionId": 3,
|
||||
"actionActuatorFunc": "focus",
|
||||
"actionActuatorFuncParam": {
|
||||
"focusX": 0,
|
||||
"focusY": 0,
|
||||
"focusRegionWidth": 0,
|
||||
"focusRegionHeight": 0,
|
||||
"isPointFocus": 0,
|
||||
"isInfiniteFocus": 1,
|
||||
"payloadPositionIndex": 0,
|
||||
"isCalibrationFocus": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"actionId": 4,
|
||||
"actionActuatorFunc": "hover",
|
||||
"actionActuatorFuncParam": {
|
||||
"hoverTime": 1
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"Placemark": []
|
||||
}
|
||||
}
|
||||
|
|
@ -97,6 +97,18 @@ export const missionConfigOptions = {
|
|||
label:"悬停",
|
||||
value:"hover"
|
||||
}
|
||||
],
|
||||
globalWaypointTurnMode:[
|
||||
{
|
||||
label:"不过点,提前转弯",
|
||||
value:"coordinateTurn"
|
||||
},{
|
||||
label:"直线飞行,到点停",
|
||||
value:"toPointAndStopWithDiscontinuityCurvature"
|
||||
},{
|
||||
label:"平滑过点,提前转弯",
|
||||
value:"toPointAndStopWithContinuityCurvature"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
|
||||
// 航点航线默认template.kml数据
|
||||
export const templateKml = {
|
||||
"author": 17861857725,
|
||||
"createTime": 1753927747220,
|
||||
"updateTime": 1753928575789,
|
||||
"missionConfig": {
|
||||
"flyToWaylineMode": "safely",
|
||||
"finishAction": "goHome",
|
||||
"exitOnRCLost": "goContinue",
|
||||
"executeRCLostAction": "goBack",
|
||||
"takeOffSecurityHeight": 20,
|
||||
"takeOffRefPoint": "35.134614,118.296656,77.867669",
|
||||
"takeOffRefPointAGLHeight": 0,
|
||||
"globalTransitionalSpeed": 15,
|
||||
"globalRTHHeight": 100,
|
||||
"droneInfo": {
|
||||
"droneEnumValue": 100,
|
||||
"droneSubEnumValue": 1
|
||||
},
|
||||
"waylineAvoidLimitAreaMode": 0,
|
||||
"payloadInfo": {
|
||||
"payloadEnumValue": 99,
|
||||
"payloadSubEnumValue": 2,
|
||||
"payloadPositionIndex": 0
|
||||
}
|
||||
},
|
||||
"Folder": {
|
||||
"templateType": "waypoint",
|
||||
"templateId": 0,
|
||||
"waylineCoordinateSysParam": {
|
||||
"coordinateMode": "WGS84",
|
||||
"heightMode": "EGM96"
|
||||
},
|
||||
"autoFlightSpeed": 10,
|
||||
"globalHeight": 124,
|
||||
"caliFlightEnable": 0,
|
||||
"gimbalPitchMode": "manual",
|
||||
"globalWaypointHeadingParam": {
|
||||
"waypointHeadingMode": "followWayline",
|
||||
"waypointHeadingAngle": 0,
|
||||
"waypointPoiPoint": "0.000000,0.000000,0.000000",
|
||||
"waypointHeadingPathMode": "followBadArc",
|
||||
"waypointHeadingPoiIndex": 0
|
||||
},
|
||||
"globalWaypointTurnMode": "toPointAndStopWithDiscontinuityCurvature",
|
||||
"globalUseStraightLine": 1,
|
||||
"Placemark": [],
|
||||
"payloadParam": {
|
||||
"payloadPositionIndex": 0,
|
||||
"focusMode": "firstPoint",
|
||||
"meteringMode": "average",
|
||||
"returnMode": "singleReturnStrongest",
|
||||
"samplingRate": 240000,
|
||||
"scanningMode": "repetitive",
|
||||
"imageFormat": "visable,ir",
|
||||
"photoSize": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 航点航线默认wayline.wpml数据
|
||||
export const waylineWpml = {
|
||||
"missionConfig": {
|
||||
"flyToWaylineMode": "safely",
|
||||
"finishAction": "goHome",
|
||||
"exitOnRCLost": "goContinue",
|
||||
"executeRCLostAction": "goBack",
|
||||
"takeOffSecurityHeight": 20,
|
||||
"globalTransitionalSpeed": 15,
|
||||
"globalRTHHeight": 100,
|
||||
"droneInfo": {
|
||||
"droneEnumValue": 100,
|
||||
"droneSubEnumValue": 1
|
||||
},
|
||||
"waylineAvoidLimitAreaMode": 0,
|
||||
"payloadInfo": {
|
||||
"payloadEnumValue": 99,
|
||||
"payloadSubEnumValue": 2,
|
||||
"payloadPositionIndex": 0
|
||||
}
|
||||
},
|
||||
"Folder": {
|
||||
"templateId": 0,
|
||||
"executeHeightMode": "WGS84",
|
||||
"waylineId": 0,
|
||||
"distance": 4453.73876953125,
|
||||
"duration": 636.023902893066,
|
||||
"autoFlightSpeed": 10,
|
||||
"Placemark": []
|
||||
}
|
||||
}
|
||||