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.
428 lines
10 KiB
428 lines
10 KiB
2 months ago
|
<template>
|
||
|
<div class="safe-operation">
|
||
|
<div id="reservoir-map-container"></div>
|
||
|
|
||
|
<!-- 按钮,浮窗 -->
|
||
|
<!-- <el-input
|
||
|
class="search-input"
|
||
|
placeholder="请输入内容"
|
||
|
style="width: 240px"
|
||
|
size="small"
|
||
|
>
|
||
|
<el-button
|
||
|
type="default"
|
||
|
slot="append"
|
||
|
icon="el-icon-search"
|
||
|
size="small"
|
||
|
></el-button>
|
||
|
</el-input> -->
|
||
|
<div class="tool-btn">
|
||
|
<div class="btn cursor-pointer" @click="showTreeBox = !showTreeBox">
|
||
|
<img class="icon" src="@/assets/icons/layer.png" alt="" />
|
||
|
图层管理
|
||
|
</div>
|
||
|
<div class="line"></div>
|
||
|
<div class="btn cursor-pointer" @click="handleChangeMode">
|
||
|
<img class="icon" src="@/assets/icons/change23D.png" alt="" />
|
||
|
{{ mapSceneType === 3 ? "三" : "二" }}维地图
|
||
|
</div>
|
||
|
</div>
|
||
|
|
||
|
<!-- 树结构浮窗 -->
|
||
|
<Transition name="fade">
|
||
|
<div class="tree-box" v-if="showTreeBox">
|
||
|
<el-tree
|
||
|
@check-change="handleCheckTree"
|
||
|
:data="treeData"
|
||
|
default-expand-all
|
||
|
node-key="id"
|
||
|
ref="tree"
|
||
|
show-checkbox
|
||
|
highlight-current
|
||
|
:props="defaultProps"
|
||
|
>
|
||
|
<template #default="{ node, data }">
|
||
|
<div class="flex items-center">
|
||
|
<img
|
||
|
v-if="node.level > 1"
|
||
|
src="@/assets/common/icon-layer.png"
|
||
|
alt=""
|
||
|
/>
|
||
|
<img v-else src="@/assets/common/icon-folder.png" alt="" />
|
||
|
<span style="margin-left: 4px">{{
|
||
|
data.nameCn || data.text
|
||
|
}}</span>
|
||
|
</div>
|
||
|
</template>
|
||
|
</el-tree>
|
||
|
</div>
|
||
|
</Transition>
|
||
|
|
||
|
<div class="legend-icon">
|
||
|
<div class="row">
|
||
|
<img class="icon" src="@/assets/image/reservoir_big.png" alt="" />
|
||
|
<span>大型</span>
|
||
|
</div>
|
||
|
<div class="row">
|
||
|
<img class="icon" src="@/assets/image/reservoir_normal.png" alt="" />
|
||
|
<span>中型</span>
|
||
|
</div>
|
||
|
<div class="row">
|
||
|
<img class="icon" src="@/assets/image/reservoir_small.png" alt="" />
|
||
|
<span>小型</span>
|
||
|
</div>
|
||
|
</div>
|
||
|
|
||
|
<!-- 弹窗 -->
|
||
|
<el-dialog
|
||
|
:title="`${(resInfoData && resInfoData.resName) || '未知'}(${
|
||
|
(resInfoData && resInfoData.resCode) || '??'
|
||
|
})`"
|
||
|
:visible.sync="showDialog"
|
||
|
:destroy-on-close="true"
|
||
|
width="1080px"
|
||
|
>
|
||
|
<ProjectDetail
|
||
|
ref="detailRef"
|
||
|
:resCode="commonResCode"
|
||
|
@getResInfo="handleGetResInfo"
|
||
|
></ProjectDetail>
|
||
|
</el-dialog>
|
||
|
</div>
|
||
|
</template>
|
||
|
<script>
|
||
|
import mitt from "mitt";
|
||
|
|
||
|
import ProjectDetail from "./components/ProjectDetail.vue";
|
||
|
|
||
|
import { getSceneListData, getLayerData } from "@/api/mapCommon";
|
||
|
|
||
|
import {
|
||
|
addLayer,
|
||
|
removeLayer,
|
||
|
zoomToLayer,
|
||
|
} from "@/views/aiSupervision/waterSetting/runScene/layerTree/index";
|
||
|
|
||
|
import { queryLayersByPos, getSelectedLayersLegend } from "@/utils/mapUtils";
|
||
|
|
||
|
import { throttle } from "lodash-es";
|
||
|
import { devRun } from "@/utils";
|
||
|
|
||
|
const emitter = mitt();
|
||
|
|
||
|
let viewer, htmlLayer;
|
||
|
// let graphicsList = [];
|
||
|
|
||
|
window.panelClickFunc = function (e) {
|
||
|
console.log("panelClickFunc >>>>> ", e);
|
||
|
emitter.emit("openDialog", e);
|
||
|
};
|
||
|
export default {
|
||
|
components: { ProjectDetail },
|
||
|
data() {
|
||
|
return {
|
||
|
showDialog: false,
|
||
|
// 水库信息
|
||
|
resInfoData: null,
|
||
|
// 当前水库code
|
||
|
commonResCode: null,
|
||
|
mapSceneType: 2, // 2: 2D, 3: 3D
|
||
|
showTreeBox: false,
|
||
|
defaultProps: {
|
||
|
children: "layers",
|
||
|
label: "nameCn",
|
||
|
},
|
||
|
layerList: [],
|
||
|
checkList: [],
|
||
|
treeData: [],
|
||
|
};
|
||
|
},
|
||
|
methods: {
|
||
|
initData() {
|
||
|
getSceneListData({
|
||
|
name: "水库安全运行",
|
||
|
}).then((res) => {
|
||
|
let id = res.records?.[0]?.id;
|
||
|
getLayerData(id).then((res) => {
|
||
|
this.treeData = res.data.children;
|
||
|
});
|
||
|
});
|
||
|
},
|
||
|
handleChangeMode() {
|
||
|
this.mapSceneType = this.mapSceneType === 3 ? 2 : 3;
|
||
|
viewer?.changeSceneMode(this.mapSceneType);
|
||
|
let position = new sycim.Position(113.27, 23.13, 600000, 0, -90, 0);
|
||
|
viewer?.flyToPosition(
|
||
|
position,
|
||
|
() => {
|
||
|
console.log("移动结束 >>>>> ");
|
||
|
},
|
||
|
1
|
||
|
);
|
||
|
},
|
||
|
handleGetResInfo(data) {
|
||
|
console.log("handleGetResInfo >>>>> ", data);
|
||
|
this.resInfoData = data;
|
||
|
},
|
||
|
initMap() {
|
||
|
viewer = new sycim.Viewer("reservoir-map-container");
|
||
|
window.viewer = viewer;
|
||
|
let baseLayer = sycim.ImageryLayerFactory.createImageryLayer(
|
||
|
sycim.ImageryType.ARCGIS,
|
||
|
{
|
||
|
url: "https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer",
|
||
|
}
|
||
|
);
|
||
|
viewer.addBaseLayer(baseLayer);
|
||
|
let layer = new sycim.EntityLayer("layer");
|
||
|
viewer.addLayer(layer);
|
||
|
// plot = new sycim.Plot(viewer);
|
||
|
|
||
|
htmlLayer = new sycim.HtmlLayer("layer");
|
||
|
viewer.addLayer(htmlLayer);
|
||
|
|
||
|
viewer.setOptions({
|
||
|
globe: {
|
||
|
depthTestAgainstTerrain: true,
|
||
|
},
|
||
|
});
|
||
|
// 三维模型才需要
|
||
|
// viewer.on(
|
||
|
// sycim.SceneEventType.CAMERA_CHANGED,
|
||
|
// () => {
|
||
|
// viewer.setOptions({
|
||
|
// globe: {
|
||
|
// depthTestAgainstTerrain: viewer.cameraPosition.alt > 10000 ? false : true
|
||
|
// }
|
||
|
// });
|
||
|
// },
|
||
|
// viewer
|
||
|
// );
|
||
|
setTimeout(() => {
|
||
|
viewer.scene.camera.setView({
|
||
|
destination: new Cesium.Cartesian3.fromDegrees(113.27, 23.13, 600000),
|
||
|
// orientation: {
|
||
|
// heading: 0,
|
||
|
// pitch: -90,
|
||
|
// roll: 0,
|
||
|
// },
|
||
|
duration: 2,
|
||
|
});
|
||
|
this.viewerAddEventListener();
|
||
|
}, 300);
|
||
|
},
|
||
|
|
||
|
handleAddHtmlLayer(position, data) {
|
||
|
console.log("添加DivIcon >>>>> ", position, data);
|
||
|
htmlLayer?.clear();
|
||
|
let divIcon = new sycim.DivIcon(
|
||
|
`${position.lng}, ${position.lat}`,
|
||
|
`
|
||
|
<div class="sycim-panel" onclick="panelClickFunc('${
|
||
|
data.attributes?.showCode
|
||
|
}')">
|
||
|
<div class="panel-text">${data.attributes?.showName || "未知"}
|
||
|
</div>
|
||
|
</div>
|
||
|
`
|
||
|
);
|
||
|
divIcon.setStyle({
|
||
|
// 设置可视距离
|
||
|
distanceDisplayCondition: {
|
||
|
near: 0, //最近距离
|
||
|
far: 8000000, //最远距离
|
||
|
},
|
||
|
//设置视距缩放
|
||
|
scaleByDistance: {
|
||
|
near: 0, //最近距离
|
||
|
nearValue: 1.5, //最近距离值
|
||
|
far: 50000, //最远距离值
|
||
|
farValue: 1, //最远距离值
|
||
|
},
|
||
|
horizontalOrigin: sycim.Cesium.HorizontalOrigin.CENTER,
|
||
|
verticalOrigin: sycim.Cesium.VerticalOrigin.BOTTOM,
|
||
|
});
|
||
|
htmlLayer.addGraphic(divIcon);
|
||
|
},
|
||
|
|
||
|
// 监听鼠标移动事件
|
||
|
viewerAddEventListener() {
|
||
|
window.viewer.on(
|
||
|
sycim.MouseEventType.MOUSE_MOVE,
|
||
|
throttle((e) => {
|
||
|
if (!e.wgs84SurfacePosition) {
|
||
|
return;
|
||
|
}
|
||
|
queryLayersByPos(e.wgs84SurfacePosition, this.layerList, (res) => {
|
||
|
console.log("res >>>>> ", res);
|
||
|
if (res) {
|
||
|
this.handleAddHtmlLayer(e.wgs84SurfacePosition, res);
|
||
|
} else {
|
||
|
htmlLayer?.clear();
|
||
|
}
|
||
|
});
|
||
|
}, 100),
|
||
|
window.viewer
|
||
|
);
|
||
|
},
|
||
|
|
||
|
openDialog(e) {
|
||
|
console.log("打开弹窗获取resCode >>>>> ", e);
|
||
|
let code = e;
|
||
|
// devRun(() => {
|
||
|
// code = "440111000008";
|
||
|
// });
|
||
|
this.commonResCode = code;
|
||
|
this.showDialog = true;
|
||
|
},
|
||
|
// 点击
|
||
|
handleClickTree(data, node) {
|
||
|
if (node.isLeaf && !data.children) {
|
||
|
let resId = this.checkList.find((v) => v === data.id);
|
||
|
if (resId) {
|
||
|
this.checkList = this.checkList.filter((v) => v != resId);
|
||
|
this.layerList = this.layerList.filter((v) => v.id != resId);
|
||
|
removeLayer(data);
|
||
|
} else {
|
||
|
this.checkList = [...this.checkList, data.id];
|
||
|
addLayer(data);
|
||
|
this.layerList.push(data);
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
handleCheckTree(data, checked) {
|
||
|
console.log("data, checked >>>>> ", data, checked);
|
||
|
if (data.pid === "root" || data.layers) return;
|
||
|
if (checked) {
|
||
|
this.checkList = [...this.checkList, data.id];
|
||
|
addLayer(data);
|
||
|
this.layerList.push(data);
|
||
|
} else {
|
||
|
this.checkList = this.checkList.filter((v) => v != data.id);
|
||
|
this.layerList = this.layerList.filter((v) => v.id != data.id);
|
||
|
removeLayer(data);
|
||
|
}
|
||
|
},
|
||
|
},
|
||
|
created() {
|
||
|
this.initData();
|
||
|
emitter.on("openDialog", this.openDialog);
|
||
|
},
|
||
|
mounted() {
|
||
|
setTimeout(() => {
|
||
|
this.initMap();
|
||
|
}, 50);
|
||
|
},
|
||
|
beforeDestroy() {
|
||
|
window.viewer = null;
|
||
|
htmlLayer = null;
|
||
|
},
|
||
|
};
|
||
|
</script>
|
||
|
<style scoped lang="scss">
|
||
|
.safe-operation {
|
||
|
position: relative;
|
||
|
width: 100%;
|
||
|
height: 100%;
|
||
|
overflow: hidden;
|
||
|
#reservoir-map-container {
|
||
|
width: 100%;
|
||
|
height: 100%;
|
||
|
}
|
||
|
|
||
|
.search-input {
|
||
|
position: absolute;
|
||
|
font-size: 14px;
|
||
|
z-index: 9;
|
||
|
right: 148px;
|
||
|
top: 20px;
|
||
|
}
|
||
|
|
||
|
.tool-btn {
|
||
|
border-radius: 4px;
|
||
|
font-size: 14px;
|
||
|
padding: 12px;
|
||
|
background: #fff;
|
||
|
position: absolute;
|
||
|
z-index: 9;
|
||
|
right: 12px;
|
||
|
top: 12px;
|
||
|
display: flex;
|
||
|
align-items: center;
|
||
|
.btn {
|
||
|
user-select: none;
|
||
|
display: flex;
|
||
|
align-items: center;
|
||
|
font-size: 14px;
|
||
|
.icon {
|
||
|
width: 18px;
|
||
|
height: 18px;
|
||
|
}
|
||
|
}
|
||
|
.line {
|
||
|
width: 2px;
|
||
|
background: #e7e7e7;
|
||
|
height: 12px;
|
||
|
margin: 0 8px;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
.tree-box {
|
||
|
position: absolute;
|
||
|
z-index: 9;
|
||
|
right: 12px;
|
||
|
top: 66px;
|
||
|
border-radius: 4px;
|
||
|
padding: 2px;
|
||
|
background: #fff;
|
||
|
width: 280px;
|
||
|
min-height: 300px;
|
||
|
max-height: 600px;
|
||
|
padding: 12px 0;
|
||
|
overflow: auto;
|
||
|
}
|
||
|
|
||
|
.legend-icon {
|
||
|
border-radius: 4px;
|
||
|
padding: 8px 10px;
|
||
|
background: #fff;
|
||
|
width: 80px;
|
||
|
position: absolute;
|
||
|
z-index: 9;
|
||
|
right: 20px;
|
||
|
bottom: 20px;
|
||
|
.row {
|
||
|
display: flex;
|
||
|
align-items: center;
|
||
|
font-size: 14px;
|
||
|
margin-bottom: 4px;
|
||
|
.icon {
|
||
|
width: 16px;
|
||
|
height: 16px;
|
||
|
margin-right: 4px;
|
||
|
}
|
||
|
|
||
|
&:last-child {
|
||
|
margin-bottom: 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
.my-icon {
|
||
|
width: 16px;
|
||
|
height: 16px;
|
||
|
}
|
||
|
}
|
||
|
</style>
|
||
|
<style lang="scss">
|
||
|
.sycim-panel {
|
||
|
padding: 10px;
|
||
|
background: #fff;
|
||
|
border-radius: 2px;
|
||
|
cursor: pointer;
|
||
|
.panel-text {
|
||
|
color: #000;
|
||
|
font-size: 14px;
|
||
|
}
|
||
|
}
|
||
|
</style>
|