数字孪生Web 后台dt( digital twin)2.0版本 统一命名格式
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

336 lines
10 KiB

<template>
<div>
<a-row :gutter="[0, 16]">
<!-- <a-col :span="11" :offset="1">
<div>场景编号:</div>
<a-input class="inputWidthCss1" v-model:value="subObject.sceneCode" :disabled="true"></a-input>
</a-col> -->
<a-col :span="23">
<slot name="header"></slot>
</a-col>
<a-col :span="11" :offset="1">
<div>站点名称:</div>
<a-input class="inputWidthCss1" v-model:value="subObject.sceneName" placeholder="请输入场景编号名称"
:disabled="disable"></a-input>
</a-col>
<a-col :span="11" :offset="1">
<div>站点视距:</div>
<a-input-number class="inputWidthCss1" v-model:value="subObject.viewDistance"
:disabled="disable"></a-input-number>
</a-col>
<a-col :span="11" :offset="1">
<div>站点类型:</div>
<a-select v-model:value="subObject.sceneType" :disabled="disable">
<template :key="Number(sceneType.value)" v-for="sceneType in sceneTypes">
<a-select-option :value="Number(sceneType.value)">{{ sceneType.text }}</a-select-option>
</template>
</a-select>
</a-col>
<a-col :span="11" :offset="1">
<div>飞入时间:</div>
<a-input-number class="inputWidthCss1" v-model:value="subObject.duration" :disabled="disable"></a-input-number>
</a-col>
<!-- <a-col :span="11" :offset="1">
<div>所属区域:</div>
<j-dict-select-tag class="inputWidthCss1" placeholder="请选择场景类型" v-model:value="subObject.sceneType"
dictCode="SceneType" />
</a-col> -->
<!-- <a-col :span="11" :offset="1">
<div>父场景编号:</div>
<a-select v-model:value="subObject.parentSceneCode" :show-search="true" :filterOption="filterOption">
<a-select-option :value="parentCode" v-for="parentCode in parentCodeArr">{{ parentCode }}</a-select-option>
</a-select>
</a-col> -->
<a-col :span="22" :offset="1">
<div class="centerText">拾取中心坐标和相机数据<img :src="locationPng" class="dwImg" @click="mapShow" /></div>
</a-col>
<!-- <a-col :span="11" :offset="1">
<div class="centerText">旋转<img :src="locationPng" class="dwImg" @click="mapShow" /></div>
</a-col> -->
<a-col :span="11" :offset="1">
<div>
<div>中心经度:</div><a-input-number class="inputWidthCss1" v-model:value="subObject.lon" :disabled="disable" />
</div>
<div>
<div>中心纬度:</div><a-input-number class="inputWidthCss1" v-model:value="subObject.lat" :disabled="disable" />
</div>
<div>
<div>中心高度:</div><a-input-number class="inputWidthCss1" v-model:value="subObject.altitude" :disabled="disable" />
</div>
</a-col>
<a-col :span="11" :offset="1">
<div>
<div>相机经度:</div><a-input-number class="inputWidthCss1" v-model:value="subObject.cameraLon"
:disabled="disable" />
</div>
<div>
<div>相机纬度:</div><a-input-number class="inputWidthCss1" v-model:value="subObject.cameraLat"
:disabled="disable" />
</div>
<div>
<div>相机高度:</div><a-input-number class="inputWidthCss1" v-model:value="subObject.cameraAltitude"
:disabled="disable" />
</div>
</a-col>
<a-col :span="11" :offset="1">
<div>站点图标:</div>
<a-upload name="avatar" list-type="picture-card" class="avatar-uploader" :show-upload-list="false"
:customRequest="preViewOk" :before-upload="preBeforeUpload" :accept="previewType.toString()"
:disabled="disable">
<img v-if="preViewUrl" :src="subObject.icon" alt="avatar" class="preViewImg"
style="width:102px;height:102px;object-fit: contain;" />
<div v-else>
<div class="ant-upload-text">上传图标</div>
</div>
</a-upload>
</a-col>
<a-col :span="11" :offset="1">
<div>
<div>相机偏航角:</div><a-input-number class="inputWidthCss1" v-model:value="subObject.rotationX"
:disabled="disable" />
</div>
<div>
<div>相机俯仰角:</div><a-input-number class="inputWidthCss1" v-model:value="subObject.rotationY"
:disabled="disable" />
</div>
<div>
<div>相机翻转角:</div><a-input-number class="inputWidthCss1" v-model:value="subObject.rotationZ"
:disabled="disable" />
</div>
</a-col>
</a-row>
<EarthMapModal :visible="mapVisible" :enableTile="false" :enablePointer="true"
@closeWin="() => { mapVisible = false }" @checkPosition="checkPosition"
:hasMoveMethod="(subObject && subObject.id) ? true : false" @moveChinaPosition="moveChinaPosition"></EarthMapModal>
</div>
</template>
<script setup>
import { toRefs, ref, watch, computed, onMounted } from 'vue';
import locationPng from '@/assets/images/getLocation.png';
import EarthMapModal from '../MapModel/EarthMapModal.vue';
import { defHttp } from '@/utils/http/axios';
import { message } from 'ant-design-vue';
import { EditOutlined } from '@ant-design/icons-vue';
// 新增场景
const addScene = (params) => {
return defHttp.post({ url: "/military/msMapScene/add", params: params }, { isTransformResponse: false });
}
// 编辑场景
const editScene = (params) => { return defHttp.put({ url: "/military/msMapScene/edit", params: params }, { isTransformResponse: false }); }
// 获取场景类型字典
const getSceneType = () => {
return defHttp.get({ url: "/sys/dict/getDictItems/SceneType" }, { isTransformResponse: false });
}
// 上传图片
const fileUpload = (file) => {
return defHttp.post({ url: "/sys/common/upload", params: file }, { isTransformResponse: false });
}
// 属性
const props = defineProps(['subObject', "parentCodeArr", "nextNodeIndex", "parentNodeCode", "disable"]);
// 包装ref
const { parentCodeArr, nextNodeIndex, parentNodeCode, subObject, disable } = toRefs(props);
const emit = defineEmits(['closeWin', 'updateDataSource']);
const sceneTypes = ref([]);
// 创建编码
const createCode = function () {
if (!nextNodeIndex.value) {
return;
}
const nextNodeIndexStr = nextNodeIndex.value.toString();
const nextNodeIndexLen = nextNodeIndexStr.length;
let currentCode = "";
for (let i = 0; i < 5 - nextNodeIndexLen; i++) {
currentCode += "0";
}
currentCode += nextNodeIndexStr;
let sceneCode = null;
if (parentNodeCode.value.length > 0) {
sceneCode = parentNodeCode.value + "-" + currentCode;
} else {
sceneCode = currentCode;
}
return sceneCode;
}
// 提交
const handleOk = function () {
if (!subObject.value.sceneName || subObject.value.sceneName.length <= 0) {
message.warn("站点名称不能为空!");
return;
}
let submitUrl = "";
if (subObject.value.id) {
// 更新
return editScene(subObject.value).then(
(res) => {
if (res.code == 200) {
emit('updateDataSource', true);
return subObject;
}
}
);
} else {
// 新增
return addScene(subObject.value).then(
(res) => {
if (res.code == 200) {
emit('updateDataSource', true);
}
}
);
}
}
// 挂载后获取场景类型
onMounted(
async () => {
sceneTypes.value = await getSceneType().then(
(response) => {
if (response.success) {
return response.result;
}
}
);
}
)
// 打开地图时飞入到指定位置
const moveChinaPosition = function () {
window.earth.camera.fov = subObject.value.viewDistance;
window.earth.camera.position = [subObject.value.lon, subObject.value.lat, subObject.value.altitude];
window.earth.camera.rotation = [subObject.value.rotationX, subObject.value.rotationY, subObject.value.rotationZ]
}
// const stop = watch(
// visible, (value, oldValue) => {
// if (value) {
// initMap()
// stop();
// }
// }
// )
// 弹窗地图框属性
const mapVisible = ref(false);
const mapShow = function () {
mapVisible.value = true;
}
// 关闭地图时设置,视角位置,视距信息
const checkPosition = function (position, cameraPosition, rotation, fov) {
subObject.value.lon = position[0];
subObject.value.lat = position[1];
subObject.value.altitude = position[2];
subObject.value.cameraLon = cameraPosition[0];
subObject.value.cameraLat = cameraPosition[1];
subObject.value.cameraAltitude = cameraPosition[2];
subObject.value.rotationX = rotation[0];
subObject.value.rotationY = rotation[1];
subObject.value.rotationZ = rotation[2];
subObject.value.viewDistance = fov;
}
// 图片预览的计算属性
const preViewUrl = computed(
{
get: () => {
return subObject.value.icon;
},
set: (value) => {
if (value) {
if (value.indexOf("/dt/sys/common/static/") > -1) {
subObject.value.icon = value;
} else {
subObject.value.icon = '/dt/sys/common/static/' + value;
}
} else {
subObject.value.icon = null;
}
}
}
);
// 上传图片
const preViewOk = function (fileInfo) {
const file = fileInfo.file
let formData = new FormData()
formData.append('file', file)
formData.append('biz', 'models/preView')
const requestCallBack = response => {
if (!response.success) {
return
}
const msg = response.message
if ('上传失败!' == msg) {
message.error('上传失败!')
preViewUrl.value = null;
} else {
preViewUrl.value = msg
message.info("上传成功!");
}
}
fileUpload(formData).then(requestCallBack).catch(
() => {
message.error('上传失败!')
}
)
}
// 上传图片的检查类型
const previewType = ref([".jpg", ".png", ".icon"]);
// 上传之前检查类型
const preBeforeUpload = function (file) {
const fileName = file.name
const fileType = fileName.substring(fileName.lastIndexOf('.'), fileName.length).toLowerCase()
let isFileType = false
for (let type of previewType.value) {
if (type == fileType) {
isFileType = true
break
}
}
if (!isFileType) {
message.error('上传文件类型异常')
}
return isFileType
}
// 向父元素抛出的方法和属性
defineExpose({
preViewUrl,
handleOk,
createCode,
});
</script>
<style scoped>
.inputWidthCss1 {
width: 90%;
}
.centerText {
width: 100%;
font-weight: bold;
line-height: 1.8rem;
display: flex;
justify-content: center;
align-items: center;
}
.dwImg {
width: 10%;
height: 10%;
margin-left: 3%;
cursor: pointer !important;
}
:deep(.ant-select) {
width: 90%;
}
</style>