|
@@ -1,6 +1,7 @@
|
|
|
<template>
|
|
|
<div class="map-container">
|
|
|
<div id="map" class="map"></div>
|
|
|
+ <!-- 以下为悬浮信息等 -->
|
|
|
<div v-if="hoverInfo" :style="hoverStyle" class="hover-info">
|
|
|
<h3>{{ hoverInfo.fieldName }}</h3>
|
|
|
<div>
|
|
@@ -35,8 +36,7 @@
|
|
|
><span
|
|
|
>{{
|
|
|
hoverInfo.analysisTypeCount ? hoverInfo.analysisTypeCount : 0
|
|
|
- }}
|
|
|
- 个</span
|
|
|
+ }}个</span
|
|
|
>
|
|
|
</p>
|
|
|
<p>
|
|
@@ -85,8 +85,7 @@
|
|
|
><span
|
|
|
>{{
|
|
|
hoverfengji?.ratedCapacity ? hoverfengji?.ratedCapacity : 0
|
|
|
- }}
|
|
|
- /KW</span
|
|
|
+ }}/KW</span
|
|
|
>
|
|
|
</p>
|
|
|
<p>
|
|
@@ -119,29 +118,27 @@
|
|
|
</p>
|
|
|
</div>
|
|
|
</div>
|
|
|
+
|
|
|
<div v-if="hoverta" :style="hovertaStyle" class="hover-ta">
|
|
|
<h3>{{ hoverta.anemometerName }}</h3>
|
|
|
<div>
|
|
|
<p>
|
|
|
<span>测风塔编号</span><span>{{ hoverta.anemometerCode }}</span>
|
|
|
</p>
|
|
|
-
|
|
|
<p>
|
|
|
<span>经度</span><span>{{ hoverta.longitude }}</span>
|
|
|
</p>
|
|
|
<p>
|
|
|
- <span>维度</span><span>{{ hoverta.latitude }}</span>
|
|
|
+ <span>纬度</span><span>{{ hoverta.latitude }}</span>
|
|
|
</p>
|
|
|
- <!-- <p>
|
|
|
- <span>状态</span><span>{{ }}</span>
|
|
|
- </p> -->
|
|
|
<p>
|
|
|
<span>测风塔高度</span
|
|
|
><span>{{ hoverta.anemometerHeightStrings }}/米</span>
|
|
|
</p>
|
|
|
</div>
|
|
|
</div>
|
|
|
- <!-- 这是测试 -->
|
|
|
+
|
|
|
+ <!-- 异常描述弹窗 -->
|
|
|
<el-dialog title="异常描述" :visible.sync="dialogVisible" width="50%">
|
|
|
<el-table :data="tableData" max-height="500" style="width: 100%">
|
|
|
<el-table-column prop="analysisTypeName" label="类型" width="300">
|
|
@@ -161,9 +158,13 @@ import { fromLonLat } from "ol/proj";
|
|
|
import { Vector } from "ol/source";
|
|
|
import { Vector as VectorLayer } from "ol/layer";
|
|
|
import { Point } from "ol/geom";
|
|
|
-import { Icon, Style } from "ol/style";
|
|
|
+import { Icon, Style, Stroke, Fill } from "ol/style";
|
|
|
import ZoomSlider from "ol/control/ZoomSlider.js";
|
|
|
import { defaults as defaultControls } from "ol/control.js";
|
|
|
+import GeoJSON from "ol/format/GeoJSON";
|
|
|
+
|
|
|
+// 假设你已经有正确的山西省边界数据文件(GeoJSON 格式)
|
|
|
+import shanxiBoundary from "./shanxi.json";
|
|
|
|
|
|
import icon01 from "../../assets/img/iconFC.png";
|
|
|
import icon02 from "../../assets/img/iconFC.png";
|
|
@@ -179,9 +180,7 @@ export default {
|
|
|
props: {
|
|
|
windEngineGroupByFieldCodeDetail: {
|
|
|
type: Object,
|
|
|
- default: () => {
|
|
|
- return {};
|
|
|
- },
|
|
|
+ default: () => ({}),
|
|
|
},
|
|
|
},
|
|
|
name: "T-map",
|
|
@@ -210,33 +209,23 @@ export default {
|
|
|
newWind: {},
|
|
|
};
|
|
|
},
|
|
|
- watch: {
|
|
|
- windEngineGroupByFieldCodeDetail: {
|
|
|
- handler(data) {
|
|
|
- if (data) {
|
|
|
- }
|
|
|
- },
|
|
|
- deep: true, // 深度监听
|
|
|
- },
|
|
|
- },
|
|
|
mounted() {
|
|
|
this.map = new Map({
|
|
|
target: "map",
|
|
|
view: new View({
|
|
|
projection: "EPSG:4326",
|
|
|
- center: fromLonLat([116.389, 39.903]), //地图中心
|
|
|
- zoom: 3, //默认缩放级别
|
|
|
- minZoom: 3, //最小缩放级别
|
|
|
- maxZoom: 15, //最大缩放级别
|
|
|
- // extent: [ 104.5, 33.5, 121.0, 41.5], //山西
|
|
|
- extent: [69, 18, 136, 54], //全国
|
|
|
+ center: fromLonLat([116.389, 39.903]),
|
|
|
+ zoom: 3,
|
|
|
+ minZoom: 3,
|
|
|
+ maxZoom: 15,
|
|
|
+ extent: [69, 18, 136, 54],
|
|
|
}),
|
|
|
layers: [
|
|
|
new TileLayer({
|
|
|
source: new XYZ({
|
|
|
+ url: "http://106.120.102.238:18000/tiles/{z}/{x}/{y}.png", //外网
|
|
|
// url: "http://127.0.0.1:8010/tiles/{z}/{x}/{y}.png", //本地
|
|
|
- url: "http://192.168.50.235/tiles/{z}/{x}/{y}.png", //内网
|
|
|
- // url: "http://106.120.102.238:18000/tiles/{z}/{x}/{y}.png", //外网
|
|
|
+ // url: "http://192.168.50.235/tiles/{z}/{x}/{y}.png", //内网
|
|
|
// url: "http://10.96.137.5:9080/tiles/{z}/{x}/{y}.png", //大~#@唐
|
|
|
}),
|
|
|
}),
|
|
@@ -247,21 +236,53 @@ export default {
|
|
|
],
|
|
|
controls: defaultControls().extend([new ZoomSlider()]),
|
|
|
});
|
|
|
- // console.log(this.map.getView().calculateExtent());
|
|
|
- // 不需要定位到某个城市的时候就把这个注释掉
|
|
|
+
|
|
|
+ // -------------【添加山西省真实边界线】-------------
|
|
|
if (this.$route.path === "/home/cockpitManage") {
|
|
|
- const targetExtent = [106.8, 34.3, 118.6, 41.2]; // 乌海、乌兰察布、山海关、西安的范围
|
|
|
+ // 通过导入的 JSON 文件加载边界数据(GeoJSON 格式),并解析成矢量要素
|
|
|
+ const shanxiSource = new Vector({
|
|
|
+ features: new GeoJSON().readFeatures(shanxiBoundary, {
|
|
|
+ featureProjection: "EPSG:4326",
|
|
|
+ }),
|
|
|
+ });
|
|
|
+ // 创建矢量图层,仅显示边界线(填充颜色设为透明)
|
|
|
+ const shanxiLayer = new VectorLayer({
|
|
|
+ source: shanxiSource,
|
|
|
+ style: new Style({
|
|
|
+ stroke: new Stroke({
|
|
|
+ color: "rgba(59, 130, 246, 0.5)",
|
|
|
+ width: 3,
|
|
|
+ }),
|
|
|
+ fill: new Fill({
|
|
|
+ color: "rgba(59, 130, 246, 0.05)", // 透明填充
|
|
|
+ }),
|
|
|
+ }),
|
|
|
+ });
|
|
|
+ this.map.addLayer(shanxiLayer);
|
|
|
|
|
|
- this.map.getView().fit(targetExtent, { duration: 2000 }); // 将地图视图缩放到指定范围,持续时间为 1000ms
|
|
|
- }
|
|
|
+ const markerLayer = this.map
|
|
|
+ .getLayers()
|
|
|
+ .getArray()
|
|
|
+ .find((layer) => {
|
|
|
+ return layer.get("id") === "marker";
|
|
|
+ });
|
|
|
+ if (markerLayer) {
|
|
|
+ markerLayer.setZIndex(10);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 同时设置高亮图层 zIndex 较低
|
|
|
+ shanxiLayer.setZIndex(1);
|
|
|
+ // -------------【结束】-------------
|
|
|
+
|
|
|
+ // if (this.$route.path === "/home/cockpitManage") {
|
|
|
+ const targetExtent = [106.8, 34.3, 118.6, 41.2];
|
|
|
+ this.map.getView().fit(targetExtent, { duration: 2000 });
|
|
|
+ // }
|
|
|
|
|
|
- this.initEvent();
|
|
|
+ this.initEvent();
|
|
|
+ }
|
|
|
},
|
|
|
methods: {
|
|
|
- /**
|
|
|
- * 地图上打点
|
|
|
- * @param data
|
|
|
- */
|
|
|
addMarker(data = { point: [120.2, 30.35], val: "1" }) {
|
|
|
const layer = this.map
|
|
|
.getLayers()
|
|
@@ -272,7 +293,7 @@ export default {
|
|
|
const source = layer.getSource();
|
|
|
|
|
|
const iconSrc = this.getIconForValue(data.val);
|
|
|
- const scale = data.val === "4" ? [0.5, 0.5] : [0.3, 0.3]; // 如果是 icon04,设置 scale 为 [0.5, 0.5],其他保持 [0.3, 0.3]
|
|
|
+ const scale = data.val === "4" ? [0.5, 0.5] : [0.3, 0.3];
|
|
|
|
|
|
const feature = new Feature({
|
|
|
geometry: new Point(fromLonLat(data.point, "EPSG:4326")),
|
|
@@ -284,7 +305,7 @@ export default {
|
|
|
new Style({
|
|
|
image: new Icon({
|
|
|
src: iconSrc,
|
|
|
- scale: scale, // 根据条件动态设置 scale
|
|
|
+ scale: scale,
|
|
|
anchor: [0.5, 1],
|
|
|
opacity: 1,
|
|
|
}),
|
|
@@ -293,10 +314,6 @@ export default {
|
|
|
|
|
|
source.addFeature(feature);
|
|
|
},
|
|
|
- /**
|
|
|
- * 地图上打点
|
|
|
- * @param data
|
|
|
- */
|
|
|
clearMarkers() {
|
|
|
const layer = this.map
|
|
|
.getLayers()
|
|
@@ -306,7 +323,7 @@ export default {
|
|
|
});
|
|
|
if (layer) {
|
|
|
const source = layer.getSource();
|
|
|
- source.clear(); // 清空所有特征
|
|
|
+ source.clear();
|
|
|
}
|
|
|
},
|
|
|
getIconForValue(val) {
|
|
@@ -339,106 +356,100 @@ export default {
|
|
|
return defaultIcon;
|
|
|
}
|
|
|
},
|
|
|
-
|
|
|
- /**
|
|
|
- * 初始化地图事件
|
|
|
- */
|
|
|
initEvent() {
|
|
|
- let lastHoveredFeature = null; // 用来记录上一次悬停的 feature
|
|
|
+ let lastHoveredFeature = null;
|
|
|
|
|
|
- // 计算悬浮框位置
|
|
|
function calculateHoverTop(mouseY, hoverHeight) {
|
|
|
- const windowHeight = window.innerHeight; // 获取窗口高度
|
|
|
- const offset = 10; // 适当的偏移量
|
|
|
-
|
|
|
- // 如果鼠标接近底部,向上展示
|
|
|
+ const windowHeight = window.innerHeight;
|
|
|
+ const offset = 10;
|
|
|
if (mouseY + hoverHeight + offset > windowHeight) {
|
|
|
- return mouseY - hoverHeight - offset; // 向上调整
|
|
|
+ return mouseY - hoverHeight - offset;
|
|
|
}
|
|
|
- // 否则,默认居中
|
|
|
- return mouseY - hoverHeight / 2; // 使其居中于鼠标位置
|
|
|
+ return mouseY - hoverHeight / 2;
|
|
|
}
|
|
|
|
|
|
function calculateHoverLeft(mouseX, hoverWidth) {
|
|
|
- const windowWidth = window.innerWidth; // 获取窗口宽度
|
|
|
- const offset = 10; // 适当的偏移量
|
|
|
-
|
|
|
- // 如果鼠标接近右边缘,向左显示
|
|
|
+ const windowWidth = window.innerWidth;
|
|
|
+ const offset = 10;
|
|
|
if (mouseX + hoverWidth + offset > windowWidth) {
|
|
|
- return mouseX - hoverWidth - offset; // 向左调整
|
|
|
+ return mouseX - hoverWidth - offset;
|
|
|
}
|
|
|
-
|
|
|
- // 如果鼠标接近左边缘,保持适当的右偏移
|
|
|
if (mouseX - hoverWidth - offset < 0) {
|
|
|
- return offset; // 距离左边一定的距离
|
|
|
+ return offset;
|
|
|
}
|
|
|
-
|
|
|
- return mouseX + offset; // 否则,鼠标右侧
|
|
|
+ return mouseX + offset;
|
|
|
}
|
|
|
this.map.on("pointermove", (evt) => {
|
|
|
const features = this.map.getFeaturesAtPixel(evt.pixel, {
|
|
|
hitTolerance: 1,
|
|
|
});
|
|
|
-
|
|
|
if (features && features.length > 0) {
|
|
|
const feature = features.at(0);
|
|
|
- const val = feature.get("data").val;
|
|
|
-
|
|
|
- // 只有当当前悬停的 feature 和上次的不同,才触发操作
|
|
|
+ const data = feature.get("data");
|
|
|
+ // 如果没有 data 属性,则不处理,但允许事件冒泡
|
|
|
+ if (!data) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const val = data.val;
|
|
|
+ // 如果当前悬停的 feature 与上一次不同,则处理
|
|
|
if (lastHoveredFeature !== feature) {
|
|
|
- // 计算悬浮框的位置
|
|
|
- const hoverHeight = 250; // 假设悬浮框的高度
|
|
|
- const hoverWidth = 200; // 假设悬浮框的宽度
|
|
|
- const topPosition = calculateHoverTop(evt.pixel[1], hoverHeight); // 动态计算top值
|
|
|
- const leftPosition = calculateHoverLeft(evt.pixel[0], hoverWidth); // 动态计算left值
|
|
|
+ const hoverHeight = 250;
|
|
|
+ const hoverWidth = 200;
|
|
|
+ const topPosition = calculateHoverTop(evt.pixel[1], hoverHeight);
|
|
|
+ const leftPosition = calculateHoverLeft(evt.pixel[0], hoverWidth);
|
|
|
|
|
|
if (val == "1" || val == "30" || val == "-1" || val == "10") {
|
|
|
- this.hoverInfo = feature.get("data");
|
|
|
+ this.hoverInfo = data;
|
|
|
this.hoverStyle.left = `${leftPosition}px`;
|
|
|
this.hoverStyle.top = `${topPosition}px`;
|
|
|
this.getwind();
|
|
|
} else if (val == "4") {
|
|
|
- this.hoverfengji = feature.get("data");
|
|
|
+ this.hoverfengji = data;
|
|
|
this.hoverfengjiStyle.left = `${leftPosition}px`;
|
|
|
this.hoverfengjiStyle.top = `${topPosition}px`;
|
|
|
- this.currentFeatureData = feature.get("data");
|
|
|
+ this.currentFeatureData = data;
|
|
|
} else if (val == "5") {
|
|
|
- this.hoverta = feature.get("data");
|
|
|
+ this.hoverta = data;
|
|
|
this.hovertaStyle.left = `${leftPosition}px`;
|
|
|
this.hovertaStyle.top = `${topPosition}px`;
|
|
|
- this.currentFeatureData = feature.get("data");
|
|
|
+ this.currentFeatureData = data;
|
|
|
} else if (val == "6") {
|
|
|
- this.currentFeatureData = feature.get("data");
|
|
|
+ this.currentFeatureData = data;
|
|
|
} else {
|
|
|
this.hoverInfo = null;
|
|
|
- this.hoverfengji = false;
|
|
|
- this.hoverta = false;
|
|
|
+ this.hoverfengji = null;
|
|
|
+ this.hoverta = null;
|
|
|
this.currentFeatureData = null;
|
|
|
}
|
|
|
-
|
|
|
- // 更新 lastHoveredFeature
|
|
|
lastHoveredFeature = feature;
|
|
|
}
|
|
|
} else {
|
|
|
+ // 没有特征时,清空所有悬浮信息
|
|
|
this.hoverInfo = null;
|
|
|
- this.hoverfengji = false;
|
|
|
- this.hoverta = false;
|
|
|
+ this.hoverfengji = null;
|
|
|
+ this.hoverta = null;
|
|
|
this.currentFeatureData = null;
|
|
|
- lastHoveredFeature = null; // 没有特征时清空记录
|
|
|
+ lastHoveredFeature = null;
|
|
|
}
|
|
|
});
|
|
|
|
|
|
+ // click 事件处理
|
|
|
this.map.on("click", (evt) => {
|
|
|
const features = this.map.getFeaturesAtPixel(evt.pixel, {
|
|
|
hitTolerance: 1,
|
|
|
});
|
|
|
if (features && features.length > 0) {
|
|
|
const feature = features.at(0);
|
|
|
- const val = feature.get("data").val;
|
|
|
+ const data = feature.get("data");
|
|
|
+ // 如果没有 data,直接返回,让事件继续冒泡
|
|
|
+ if (!data) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const val = data.val;
|
|
|
if (val === "6") {
|
|
|
- this.handleFeatureClick(feature.get("data"));
|
|
|
+ this.handleFeatureClick(data);
|
|
|
} else {
|
|
|
- this.$emit("feature-click", feature.get("data"));
|
|
|
+ this.$emit("feature-click", data);
|
|
|
}
|
|
|
} else if (
|
|
|
this.currentFeatureData &&
|
|
@@ -448,7 +459,6 @@ export default {
|
|
|
}
|
|
|
});
|
|
|
},
|
|
|
-
|
|
|
handleFeatureClick(featureData) {
|
|
|
let dateArr = {
|
|
|
batchCode: this.$route.query.batchCode,
|
|
@@ -459,18 +469,14 @@ export default {
|
|
|
this.tableData = res.data;
|
|
|
});
|
|
|
},
|
|
|
-
|
|
|
getwind() {
|
|
|
- console.log(this.hoverInfo, "hoverInfo");
|
|
|
-
|
|
|
if (this.hoverInfo && this.hoverInfo.batchCode) {
|
|
|
const param = {
|
|
|
batchcode: this.hoverInfo.batchCode,
|
|
|
fieldCode: this.hoverInfo.codeNumber,
|
|
|
- }; // 确保传递一个对象
|
|
|
+ };
|
|
|
queryFloatingWindowInfo(param)
|
|
|
.then((res) => {
|
|
|
- // 处理响应数据
|
|
|
this.newWind = res.data;
|
|
|
})
|
|
|
.catch((err) => {
|
|
@@ -480,11 +486,6 @@ export default {
|
|
|
console.warn("hoverInfo 或 batchCode 未定义");
|
|
|
}
|
|
|
},
|
|
|
-
|
|
|
- /**
|
|
|
- * 平移缩放
|
|
|
- * @param data
|
|
|
- */
|
|
|
moveAndZoom(data = { point: [120.2, 30.35], zoom: 15 }) {
|
|
|
this.map.getView().animate({
|
|
|
center: fromLonLat(data.point, "EPSG:4326"),
|
|
@@ -501,7 +502,7 @@ export default {
|
|
|
position: relative;
|
|
|
width: 100%;
|
|
|
height: 100%;
|
|
|
- overflow: hidden; /* 禁止滚动条 */
|
|
|
+ overflow: hidden;
|
|
|
}
|
|
|
|
|
|
.map {
|
|
@@ -512,21 +513,18 @@ export default {
|
|
|
.hover-info {
|
|
|
position: absolute;
|
|
|
color: white;
|
|
|
- padding: 0px;
|
|
|
+ padding: 0;
|
|
|
z-index: 100;
|
|
|
-
|
|
|
h3 {
|
|
|
background-color: #008080cc;
|
|
|
width: 240px;
|
|
|
padding: 5px 10px;
|
|
|
font-size: 16px;
|
|
|
}
|
|
|
-
|
|
|
div {
|
|
|
background-color: #00808097;
|
|
|
width: 240px;
|
|
|
font-size: 12px;
|
|
|
-
|
|
|
p {
|
|
|
padding: 5px 10px;
|
|
|
display: flex;
|
|
@@ -538,21 +536,18 @@ export default {
|
|
|
.hover-fengji {
|
|
|
position: absolute;
|
|
|
color: white;
|
|
|
- padding: 0px;
|
|
|
+ padding: 0;
|
|
|
z-index: 100;
|
|
|
-
|
|
|
h3 {
|
|
|
background-color: #027cb4cc;
|
|
|
width: 240px;
|
|
|
padding: 5px 10px;
|
|
|
font-size: 16px;
|
|
|
}
|
|
|
-
|
|
|
div {
|
|
|
background-color: #027cb49e;
|
|
|
width: 240px;
|
|
|
font-size: 12px;
|
|
|
-
|
|
|
p {
|
|
|
padding: 5px 10px;
|
|
|
display: flex;
|
|
@@ -564,21 +559,18 @@ export default {
|
|
|
.hover-ta {
|
|
|
position: absolute;
|
|
|
color: white;
|
|
|
- padding: 0px;
|
|
|
+ padding: 0;
|
|
|
z-index: 100;
|
|
|
-
|
|
|
h3 {
|
|
|
background-color: #d90019b2;
|
|
|
width: 240px;
|
|
|
padding: 5px 10px;
|
|
|
font-size: 16px;
|
|
|
}
|
|
|
-
|
|
|
div {
|
|
|
background-color: #d9001994;
|
|
|
width: 240px;
|
|
|
font-size: 12px;
|
|
|
-
|
|
|
p {
|
|
|
padding: 5px 10px;
|
|
|
display: flex;
|