2023-11-20 14:12:58 +08:00

586 lines
14 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="main-content" v-if="!infoShow">
<div class="main-content-title">
<span>飞行漫游</span>
<el-icon size="16" color="#fff" @click="closeDiv"><Close /></el-icon>
</div>
<div class="btn-operate">
<el-button type="primary" @click="addRoute">新增路线</el-button>
<el-button type="primary" @click="saveJson">保存</el-button>
</div>
<div class="table-operate">
<el-table
:data="tableData"
rowKey="id"
:header-cell-style="{ backgroundColor: '#3359B5', color: '#fff', borderColor: '#3F5C8E' }"
>
<el-table-column prop="name" align="center" label="名称" />
<el-table-column align="center" label="操作">
<template #default="{ row, $index }">
<span style="color: white; cursor: pointer; margin-right: 10px" @click="flyToModel(row, $index)">漫游</span>
<span style="color: white; cursor: pointer" @click="deleteRoute(row, $index)">删除</span>
</template>
</el-table-column>
</el-table>
</div>
</div>
<!-- 漫游数据信息弹框 -->
<div class="fly-data" v-if="infoShow">
<div class="main-content-title">
<span>漫游路线</span>
<el-icon size="16" color="#fff" @click="infoShow = false"><Close /></el-icon>
</div>
<div class="control-btn">
<el-button type="primary" @click="stopFly">停止漫游</el-button>
</div>
<div class="item-classify">
<div class="item-classify-item">
<div>路线名称</div>
<div>{{ rowObj.name ? rowObj.name : "" }}</div>
</div>
<div class="item-classify-item">
<div>视角模式</div>
<div>
<el-select v-model="viewParams.viewModel" :teleported="false" @change="viewChange">
<el-option v-for="item in modelOptions" :key="item.value" :label="item.name" :value="item.value" />
</el-select>
</div>
</div>
<div class="item-classify-item">
<div>视角距离</div>
<div>
<el-input-number v-model="viewParams.viewDistance" controls-position="right" @blur="viewChange" />
</div>
</div>
<div class="item-classify-item">
<div>总长度</div>
<div>{{ formState.td_alllength }}</div>
</div>
<div class="item-classify-item">
<div>已漫游长度</div>
<div>{{ formState.td_length }}</div>
</div>
<div class="item-classify-item">
<div>总时长</div>
<div>{{ formState.td_alltimes }}</div>
</div>
<div class="item-classify-item">
<div>已漫游时间</div>
<div>{{ formState.td_times }}</div>
</div>
<div class="item-classify-item">
<div>经度</div>
<div>{{ formState.td_jd }}</div>
</div>
<div class="item-classify-item">
<div>纬度</div>
<div>{{ formState.td_wd }}</div>
</div>
<div class="item-classify-item">
<div>漫游高程</div>
<div>{{ formState.td_gd }}</div>
</div>
</div>
<div class="progress-line">
<el-progress :percentage="formState.percent" :status="formState.percent == 100 ? 'success' : ''" />
</div>
</div>
</template>
<script lang="ts" setup>
//引入cesium基础库
import "mars3d-cesium/Build/Cesium/Widgets/widgets.css";
import * as Cesium from "mars3d-cesium";
//导入mars3d主库
import "mars3d/dist/mars3d.css";
import * as mars3d from "mars3d";
import { ref, watch, onMounted, onUnmounted, reactive, computed } from "vue";
import type { UnwrapRef } from "vue";
import { ElMessage } from "element-plus";
import { GlobalStore } from "@/stores";
import { getSystemConfig } from "@/api/modules/mapCommon";
const props = defineProps(["mapInstance", "graphicInstance"]);
const emits = defineEmits(["hiddenConfim", "saveJson"]);
const importRef = ref();
interface FormState {
td_alllength: string;
td_length: string;
td_alltimes: string;
td_times: string;
td_jd: string;
td_wd: string;
td_gd: string;
percent: number;
}
const formState: UnwrapRef<FormState> = reactive({
td_alllength: "",
td_length: "",
td_alltimes: "",
td_times: "",
td_jd: "",
td_wd: "",
td_gd: "",
percent: 0
});
const rowObj = ref<any>({});
const modelOptions = ref([
{ name: "无", value: "" },
{ name: "跟随视角", value: "gs" },
{ name: "锁定第一视角", value: "dy" },
{ name: "锁定上帝视角", value: "sd" }
]);
const viewParams = ref({
viewModel: "",
viewDistance: 500
});
const infoShow = ref(false);
const globalStore = GlobalStore();
const tableData = ref<any>([]);
const layerJson = ref<any>([]);
const clearBool = ref(true);
const initGraphicLength = ref(0);
let map: any = props.mapInstance;
let graphicLayer: any = props.graphicInstance;
let dataIndex = 0 as any;
onMounted(() => {
getConfig();
});
// 获取配置
const getConfig = async () => {
let requestData = {
configKey: "layerConfig"
};
const { result } = await getSystemConfig(requestData);
console.log(result, "6666666");
if (result) {
layerJson.value = JSON.parse(result.configValue);
console.log(layerJson.value);
if (layerJson.value.length > 0) {
initGraphicLength.value = layerJson.value.length;
layerJson.value.map((item: any, index: number) => {
if (item.type == "fixedRoute") {
const obj = {
id: item.id,
name: item.name
};
tableData.value.unshift(obj);
++dataIndex;
}
});
}
}
};
// 保存配置的图上JSON数据
const saveJson = async () => {
// if (graphicLayer.length == 0) {
// ElMessage("当前没有任何数据,无需保存!");
// return;
// }
clearBool.value = false;
emits("saveJson", graphicLayer);
};
// 视角模式切换
const viewChange = () => {
let routeData = graphicLayer.getGraphicById(rowObj.value.id);
if (routeData.type != "fixedRoute") {
routeData = graphicLayer.getGraphicById(rowObj.value.id + "-" + (dataIndex - 1));
}
console.log(routeData);
routeData.setCameraOptions({
type: viewParams.value.viewModel,
radius: viewParams.value.viewDistance,
followedX: 500,
followedZ: 500
});
};
// 停止漫游
const stopFly = () => {
let routeData = graphicLayer.getGraphicById(rowObj.value.id);
if (routeData.type != "fixedRoute") {
routeData = graphicLayer.getGraphicById(rowObj.value.id + "-" + (dataIndex - 1));
}
routeData && routeData.stop();
infoShow.value = false;
};
// 删除漫游路线
const deleteRoute = (row: any, index: number) => {
let polyline = graphicLayer.getGraphicById(row.id);
let routeData = graphicLayer.getGraphicById(row.id);
console.log(polyline);
if (routeData.type != "fixedRoute") {
routeData = graphicLayer.getGraphicById(row.id + "-" + (dataIndex - 1));
}
if (polyline.type != "polyline") {
let findIndex = row.id.lastIndexOf("-");
polyline = graphicLayer.getGraphicById(row.id.substring(0, findIndex));
}
polyline && polyline.remove(true);
routeData && routeData.remove(true);
tableData.value.splice(index, 1);
dataIndex = tableData.value.length;
};
// 模型路线漫游
const flyToModel = (row: any, index: number) => {
let routeData = graphicLayer.getGraphicById(row.id);
if (routeData.type != "fixedRoute") {
routeData = graphicLayer.getGraphicById(row.id + "-" + (dataIndex - 1));
}
routeData.on(mars3d.EventType.change, (event: any) => {
console.log("漫游改变change");
showInfo(routeData.info);
});
rowObj.value = row;
// 启动漫游
routeData.flyTo();
routeData.start();
infoShow.value = true;
};
// 生成路线
const productRoute = (obj: any) => {
console.log(obj);
const item = {
id: obj.id,
name: "路线-" + dataIndex
};
tableData.value.unshift(item);
console.log(obj.id + "-" + dataIndex);
const newRoutePath = new mars3d.graphic.FixedRoute({
id: obj.id + "-" + dataIndex,
name: "路线-" + dataIndex,
speed: 200,
positions: obj.points || obj.positions,
model: {
url: "//data.mars3d.cn/gltf/mars/MQ-9-Predator.glb",
scale: 1,
minimumPixelSize: 60
},
path: {
color: "#ffff00",
opacity: 0.5,
width: 1,
leadTime: 0
},
coneTrack: {
angle: 15, // 半场角度
color: "rgba(255,0,255,0.5)"
},
updateClock: false,
point: {
color: "#ffff00",
pixelSize: 5,
distanceDisplayCondition: true,
distanceDisplayCondition_near: 80000,
distanceDisplayCondition_far: Number.MAX_VALUE
},
label: {
text: "测试",
font_size: 20,
pixelOffsetX: 0,
pixelOffsetY: -20,
scaleByDistance: true,
scaleByDistance_far: 80000,
scaleByDistance_farValue: 0.4,
distanceDisplayCondition: true,
distanceDisplayCondition_far: 80000
},
attr: {
classKey: "FixedRoute"
}
});
console.log(newRoutePath);
graphicLayer.addGraphic(newRoutePath);
// console.log(newRoutePath.info);
// ui面板信息展示
// newRoutePath.on(mars3d.EventType.change, (event: any) => {
// console.log("漫游改变change");
// showInfo(newRoutePath.info);
// });
dataIndex++;
};
// 获取漫游信息
const showInfo = (item: any) => {
const params = item;
if (!params) {
return;
}
let val = Math.ceil((item.second * 100) / item.second_all);
if (val < 1) {
val = 1;
}
if (val > 100) {
val = 100;
}
formState.percent = val;
formState.td_jd = item.point?.lng;
formState.td_wd = item.point?.lat;
formState.td_gd = mars3d.MeasureUtil.formatDistance(item.point?.alt);
formState.td_times = mars3d.Util.formatTime(item.second);
formState.td_alltimes = mars3d.Util.formatTime(item.second_all);
formState.td_length = mars3d.MeasureUtil.formatDistance(item.distance) || "0米";
formState.td_alllength = mars3d.MeasureUtil.formatDistance(item.distance_all);
};
// 绘制路线
const addRoute = () => {
graphicLayer.startDraw({
type: "polyline",
style: {
pixelSize: 12,
color: "#3388ff"
},
success: function (graphic: any) {
console.log(graphic);
productRoute(graphic);
// eslint-disable-next-line no-console
// console.log(JSON.stringify(graphic.coordinates));
}
});
};
const closeDiv = () => {
emits("hiddenConfim");
};
onUnmounted(() => {
map = null;
if (clearBool.value) {
let arr = graphicLayer.getGraphics();
console.log(arr);
for (let i = arr.length - 1; i >= initGraphicLength.value; i--) {
const graphic = graphicLayer.getGraphicById(arr[i].id);
graphic && graphicLayer.removeGraphic(graphic);
}
// graphicLayer.clear();
}
});
</script>
<style scoped lang="scss">
@mixin flex {
display: flex;
align-items: center;
}
// 菜单弹框出现动画
@keyframes fadeIn {
0% {
opacity: 0;
transform: translate3d(100%, 0, 0);
}
100% {
opacity: 1;
transform: none;
}
}
.main-content {
position: absolute;
top: 60px;
right: 10px;
padding-bottom: 10px;
background-image: none !important;
border: 1px solid #008aff70;
border-radius: 2px !important;
background-color: rgba(23, 49, 71, 0.8);
width: 300px;
box-shadow: 0 4px 15px 1px #02213bb3;
animation: fadeIn 1s;
&-title {
@include flex;
width: 100%;
height: 40px;
padding: 0 5px 0 10px;
background-image: url("@/assets/images/Mars3DIcon/subClassTitle.png");
background-size: 100% 100%;
background-repeat: no-repeat;
span {
font-size: 16px;
color: #0089fe;
margin-right: auto;
}
:deep() {
.el-icon {
cursor: pointer;
}
}
}
.btn-operate {
@include flex;
justify-content: center;
margin-top: 10px;
:deep() {
.el-button {
margin-left: 10px;
}
}
}
.table-operate {
width: 95%;
margin: 0 auto;
margin-top: 10px;
}
}
.fly-data {
position: absolute;
bottom: 60px;
right: 10px;
padding-bottom: 10px;
background-image: none !important;
border: 1px solid #008aff70;
border-radius: 2px !important;
background-color: rgba(23, 49, 71, 0.8);
width: 300px;
box-shadow: 0 4px 15px 1px #02213bb3;
animation: fadeIn 1s;
.main-content-title {
@include flex;
width: 100%;
height: 40px;
padding: 0 5px 0 10px;
background-color: #173147;
span {
font-size: 16px;
color: #0089fe;
margin-right: auto;
}
:deep() {
.el-icon {
cursor: pointer;
}
}
}
.control-btn {
margin: 10px 0 0 10px;
}
.item-classify {
padding: 10px;
display: flex;
flex-direction: column;
&-item {
display: flex;
color: white;
margin-bottom: 5px;
> div:nth-child(1) {
width: 100px;
height: 42px;
@include flex;
justify-content: center;
border: 2px solid white;
text-align: center;
padding: 5px;
}
> div:nth-child(2) {
flex: 1;
height: 42px;
@include flex;
justify-content: center;
line-height: 30px;
border: 2px solid white;
border-left: 0;
text-align: center;
padding: 5px;
}
}
}
.progress-line {
padding: 10px;
height: 30px;
@include flex;
:deep() {
.el-progress {
width: 100%;
}
.el-progress__text {
color: white;
}
}
}
}
// element 组件样式
:deep() {
.el-input__wrapper {
background-color: transparent !important;
}
.el-input__inner {
color: white;
}
.el-button {
background: rgba(51, 89, 181, 0.6);
border-radius: 6px;
border: 0;
}
.el-table {
background-color: transparent;
tr {
background-color: transparent;
}
}
.el-table__border-left-patch {
background-color: #3f5c8e;
}
.el-table--border .el-table__inner-wrapper::after {
background-color: #3f5c8e;
}
.el-table--border::after {
background-color: #3f5c8e;
}
.el-table__inner-wrapper::before {
background-color: #3f5c8e;
}
.el-table td.el-table__cell {
border-color: #3f5c8e;
}
.el-table--border .el-table__cell {
border-color: #3f5c8e;
}
.cell {
color: white;
}
.el-table__row:hover {
background-color: transparent;
}
.el-table__body tr:hover > td {
// background-color: #008bff !important;
background-color: transparent !important;
}
//修改总体选项的样式 最外层
.el-select__popper.el-popper {
border: 0;
background-color: transparent;
box-shadow: none;
inset: 42px auto auto 0px !important;
}
.el-select-dropdown {
background: rgba(11, 22, 51, 0.7);
box-shadow: 0px 4px 4px 0px rgba(0, 0, 0, 0.25);
opacity: 1;
border: 1px solid #3b60a7;
border-radius: 0px;
}
//修改单个的选项的样式
.el-select-dropdown__item {
background-color: transparent;
color: #fff;
text-align: center;
}
//item选项的hover样式
.el-select-dropdown__item.hover,
.el-select-dropdown__item:hover {
color: white;
background: linear-gradient(90deg, rgba(49, 96, 179, 0) 0%, #3160b3 51%, rgba(49, 96, 179, 0) 100%);
}
.el-popper__arrow::before {
display: none;
}
.el-input-number__increase,
.el-input-number__decrease {
background-color: transparent;
color: white;
}
}
</style>