123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641 |
- <template>
- <div class="map-container">
- <div id="map" class="map"></div>
- <!-- 以下为悬浮信息等 -->
- <div
- v-if="hoverInfo"
- :style="hoverStyle"
- class="hover-info"
- @mouseenter="hovering = true"
- @mouseleave="onHoverLeave"
- >
- <h3>{{ hoverInfo.fieldName }}</h3>
- <div>
- <p>
- <span>状态:</span
- ><span>{{
- hoverInfo.analysisState === 30 ? "已完成分析" : "未完成分析"
- }}</span>
- </p>
- <p>
- <span>风场编号</span><span>{{ hoverInfo.codeNumber }}</span>
- </p>
- <p>
- <span>风机数量</span><span>{{ newWind.engineTotalCount }} 台</span>
- </p>
- <p>
- <span>总容量</span
- ><span
- >{{
- newWind?.ratedCapacityNumber ? newWind.ratedCapacityNumber : 0
- }}/KW</span
- >
- </p>
- <p>
- <span>经度</span><span>{{ hoverInfo.longitude }}°</span>
- </p>
- <p>
- <span>纬度</span><span>{{ hoverInfo.latitude }}°</span>
- </p>
- <p>
- <span>分析模型数</span
- ><span
- >{{
- hoverInfo.analysisTypeCount ? hoverInfo.analysisTypeCount : 0
- }}个</span
- >
- </p>
- <p>
- <span>分析开始时间</span>
- <span>{{
- newWind.analysisStartTime
- ? $formatDateTWO(newWind.analysisStartTime)
- : "暂无数据"
- }}</span>
- </p>
- <p>
- <span>分析结束时间</span>
- <span>{{
- newWind.analysisEndTime
- ? $formatDateTWO(newWind.analysisEndTime)
- : "暂无数据"
- }}</span>
- </p>
- <p>
- <span>数据开始时间</span>
- <span>{{
- newWind.dataStartTime
- ? $formatDateTWO(newWind.dataStartTime)
- : "暂无数据"
- }}</span>
- </p>
- <p>
- <span>数据结束时间</span>
- <span>{{
- newWind.dataEndTime
- ? $formatDateTWO(newWind.dataEndTime)
- : "暂无数据"
- }}</span>
- </p>
- </div>
- </div>
- <div
- v-if="hoverfengji"
- :style="hoverfengjiStyle"
- class="hover-fengji"
- @mouseenter="hoveringFengji = true"
- @mouseleave="onFengjiLeave"
- >
- <h3>{{ hoverfengji.engineName }}</h3>
- <div>
- <p>
- <span>风机编号</span><span>{{ hoverfengji.engineCode }}</span>
- </p>
- <p>
- <span>额定容量</span
- ><span
- >{{
- hoverfengji?.ratedCapacity ? hoverfengji?.ratedCapacity : 0
- }}/KW</span
- >
- </p>
- <p>
- <span>海拔高度</span
- ><span>{{ hoverfengji.elevationHeight }} /米</span>
- </p>
- <p>
- <span>轮毂高度</span><span>{{ hoverfengji.hubHeight }} /米</span>
- </p>
- <p>
- <span>经度</span><span>{{ hoverfengji.longitude }}</span>
- </p>
- <p>
- <span>维度</span><span>{{ hoverfengji.latitude }}</span>
- </p>
- <p>
- 是否标杆风机
- <span>{{ hoverfengji.sightcing == 1 ? "是" : "否" }}</span>
- </p>
- <p>
- <span>额定风速</span><span>{{ hoverfengji.ratedWindSpeed }} m/s</span>
- </p>
- <p>
- <span>切入风速</span
- ><span>{{ hoverfengji.ratedCutInWindspeed }} m/s</span>
- </p>
- <p>
- <span>切出风速</span
- ><span>{{ hoverfengji.ratedCutOutWindspeed }} m/s</span>
- </p>
- </div>
- </div>
- <div
- v-if="hoverta"
- :style="hovertaStyle"
- class="hover-ta"
- @mouseenter="hoveringTa = true"
- @mouseleave="onTaLeave"
- >
- <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>
- </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">
- </el-table-column>
- <el-table-column prop="errDesc" label="描述"> </el-table-column>
- </el-table>
- </el-dialog>
- </div>
- </template>
- <script>
- import "ol/ol.css";
- import { Map, View, Feature } from "ol";
- import TileLayer from "ol/layer/Tile.js";
- import { XYZ } from "ol/source";
- 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, 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";
- import icon03 from "../../assets/img/iconFC.png";
- import icon04 from "../../assets/img/iconFJ.png";
- import icon05 from "../../assets/img/icon05.png";
- import icon06 from "../../assets/img/iconFJ.png";
- import defaultIcon from "../../assets/img/iconFJ.png";
- // import icon01 from "../../assets/img/icon01.png";
- // import icon02 from "../../assets/img/icon02.png";
- // import icon03 from "../../assets/img/icon03.png";
- // import icon04 from "../../assets/img/icon04.png";
- // import icon05 from "../../assets/img/icon05.png";
- // import icon06 from "../../assets/img/iconFJ.png";
- // import defaultIcon from "../../assets/img/iconFJ.png";
- import { queryErrDescByEngine, queryFloatingWindowInfo } from "@/api/ledger.js";
- import { login } from "@/api/login";
- export default {
- props: {
- windEngineGroupByFieldCodeDetail: {
- type: Object,
- default: () => ({}),
- },
- },
- name: "T-map",
- data() {
- return {
- dialogVisible: false,
- tableData: [],
- hoverInfo: null,
- hovering: false,
- hideTimer: null,
- hoverStyle: {
- position: "absolute",
- left: "0px",
- top: "0px",
- },
- hoverfengji: null,
- hoverfengjiStyle: {
- position: "absolute",
- left: "0px",
- top: "0px",
- },
- hoverta: null,
- hovertaStyle: {
- position: "absolute",
- left: "0px",
- top: "0px",
- },
- hoveringFengji: false,
- hoveringTa: false,
- fengjiTimer: null,
- taTimer: null,
- newWind: {},
- };
- },
- 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: [69, 18, 136, 54],
- }),
- layers: [
- new TileLayer({
- source: new XYZ({
- // url: "http://10.96.137.5:9080/tiles/{z}/{x}/{y}.png", //大~#@唐
- // url: "http://192.168.0.1/tiles/{z}/{x}/{y}.png", //华电
- // url: "http://192.168.50.235/tiles/{z}/{x}/{y}.png", //中广核
- url: process.env.VUE_APP_MAPVIEW,
- }),
- }),
- new VectorLayer({
- id: "marker",
- source: new Vector(),
- }),
- ],
- controls: defaultControls().extend([new ZoomSlider()]),
- });
- // -------------【添加山西省真实边界线】------------- 定位全国的时候注释这个代码
- // if (this.$route.path === "/home/cockpitManage") {
- // // 通过导入的 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);
- // const markerLayer = this.map
- // .getLayers()
- // .getArray()
- // .find((layer) => {
- // return layer.get("id") === "marker";
- // });
- // if (markerLayer) {
- // markerLayer.setZIndex(10);
- // }
- // // 同时设置高亮图层 zIndex 较低
- // shanxiLayer.setZIndex(1);
- // // -------------【结束】-------------
- // const targetExtent = [106.8, 34.3, 118.6, 41.2];
- // this.map.getView().fit(targetExtent, { duration: 2000 });
- // }
- // 这个放在外面
- this.initEvent();
- },
- methods: {
- onHoverLeave() {
- this.hovering = false;
- clearTimeout(this.hideTimer);
- this.hideTimer = setTimeout(() => {
- if (!this.hovering) {
- this.hoverInfo = null;
- }
- }, 100); // 这里延迟100ms防止意外移出
- },
- onFengjiLeave() {
- this.hoveringFengji = false;
- clearTimeout(this.fengjiTimer);
- this.fengjiTimer = setTimeout(() => {
- if (!this.hoveringFengji) {
- this.hoverfengji = null;
- }
- }, 100); // 你可以根据实际需要调大一点时间
- },
- onTaLeave() {
- this.hoveringTa = false;
- clearTimeout(this.taTimer);
- this.taTimer = setTimeout(() => {
- if (!this.hoveringTa) {
- this.hoverta = null;
- }
- }, 100);
- },
- addMarker(data = { point: [120.2, 30.35], val: "1" }) {
- const layer = this.map
- .getLayers()
- .getArray()
- .find((element) => {
- return element.get("id") === "marker";
- });
- const source = layer.getSource();
- const iconSrc = this.getIconForValue(data.val);
- 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")),
- name: "marker",
- data,
- });
- feature.setStyle(
- new Style({
- image: new Icon({
- src: iconSrc,
- scale: scale,
- anchor: [0.5, 1],
- opacity: 1,
- }),
- })
- );
- source.addFeature(feature);
- },
- clearMarkers() {
- const layer = this.map
- .getLayers()
- .getArray()
- .find((element) => {
- return element.get("id") === "marker";
- });
- if (layer) {
- const source = layer.getSource();
- source.clear();
- }
- },
- getIconForValue(val) {
- switch (val) {
- case "-1":
- case -1:
- return icon01;
- case "10":
- case 10:
- return icon01;
- case 0:
- case "0":
- return icon02;
- case 20:
- case "20":
- return icon02;
- case 1:
- case "1":
- return icon03;
- case 30:
- case "30":
- return icon03;
- case "4":
- return icon04;
- case "5":
- return icon05;
- case "6":
- return icon06;
- default:
- return defaultIcon;
- }
- },
- initEvent() {
- let lastHoveredFeature = null;
- const calculateHoverTop = (mouseY, hoverHeight) => {
- const componentHeight = this.$el.clientHeight;
- const offset = 10;
- if (mouseY + hoverHeight + offset > componentHeight) {
- return mouseY - hoverHeight - offset;
- }
- return mouseY - hoverHeight / 2;
- };
- const calculateHoverLeft = (mouseX, hoverWidth) => {
- const componentWidth = this.$el.clientWidth;
- const offset = 10;
- if (mouseX + hoverWidth + offset > componentWidth) {
- return mouseX - hoverWidth - offset;
- }
- if (mouseX - hoverWidth - offset < 0) {
- return 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 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);
- const leftPosition = calculateHoverLeft(evt.pixel[0], hoverWidth);
- if (val == "1" || val == "30" || val == "-1" || val == "10") {
- this.hoverInfo = data;
- this.hoverStyle.left = `${leftPosition}px`;
- this.hoverStyle.top = `${topPosition}px`;
- this.getwind();
- } else if (val == "4") {
- this.hoverfengji = data;
- this.hoverfengjiStyle.left = `${leftPosition}px`;
- this.hoverfengjiStyle.top = `${topPosition}px`;
- this.currentFeatureData = data;
- } else if (val == "5") {
- this.hoverta = data;
- this.hovertaStyle.left = `${leftPosition}px`;
- this.hovertaStyle.top = `${topPosition}px`;
- this.currentFeatureData = data;
- } else if (val == "6") {
- this.currentFeatureData = data;
- } else {
- this.hoverInfo = false;
- this.hoverfengji = false;
- this.hoverta = false;
- this.currentFeatureData = false;
- }
- lastHoveredFeature = feature;
- }
- } else {
- // 没有特征时,清空所有悬浮信息
- if (!this.hoveringInfo) this.hoverInfo = null;
- if (!this.hoveringFengji) this.hoverfengji = null;
- if (!this.hoveringTa) this.hoverta = null;
- this.currentFeatureData = 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 data = feature.get("data");
- // 如果没有 data,直接返回,让事件继续冒泡
- if (!data) {
- return;
- }
- const val = data.val;
- if (val === "6") {
- this.handleFeatureClick(data);
- } else {
- this.$emit("feature-click", data);
- }
- } else if (
- this.currentFeatureData &&
- this.currentFeatureData.val === "6"
- ) {
- this.handleFeatureClick(this.currentFeatureData);
- }
- });
- },
- handleFeatureClick(featureData) {
- let dateArr = {
- batchCode: this.$route.query.batchCode,
- engineCode: featureData.engineCode,
- };
- queryErrDescByEngine(dateArr).then((res) => {
- this.dialogVisible = true;
- this.tableData = res.data;
- });
- },
- getwind() {
- // 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) => {
- console.error("获取风信息失败", err);
- });
- // } else {
- // console.warn("hoverInfo 或 batchCode 未定义");
- // }
- },
- moveAndZoom(data = { point: [120.2, 30.35], zoom: 15 }) {
- this.map.getView().animate({
- center: fromLonLat(data.point, "EPSG:4326"),
- zoom: data.zoom,
- duration: 2000,
- });
- },
- },
- };
- </script>
- <style scoped lang="scss">
- .map-container {
- position: relative;
- width: 100%;
- height: 100%;
- overflow: hidden;
- }
- .map {
- width: 100%;
- height: 100%;
- }
- .hover-info {
- position: absolute;
- color: white;
- padding: 0;
- z-index: 100;
- h3 {
- background-color: var(--header-bg);
- width: 240px;
- padding: 5px 10px;
- font-size: 16px;
- }
- div {
- background-color: var(--content-bg);
- width: 240px;
- font-size: 12px;
- p {
- padding: 5px 10px;
- display: flex;
- justify-content: space-between;
- }
- }
- }
- .hover-fengji {
- position: absolute;
- color: white;
- padding: 0;
- z-index: 100;
- h3 {
- background-color: var(--header-bg);
- width: 240px;
- padding: 5px 10px;
- font-size: 16px;
- }
- div {
- background-color: var(--content-bg);
- width: 240px;
- font-size: 12px;
- p {
- padding: 5px 10px;
- display: flex;
- justify-content: space-between;
- }
- }
- }
- .hover-ta {
- position: absolute;
- color: white;
- 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;
- justify-content: space-between;
- }
- }
- }
- </style>
|