index.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549
  1. <template>
  2. <div class="map-container">
  3. <div id="map" class="map"></div>
  4. <div v-if="hoverInfo" :style="hoverStyle" class="hover-info">
  5. <h3>{{ hoverInfo.fieldName }}</h3>
  6. <div>
  7. <p>
  8. <span>状态:</span
  9. ><span>{{
  10. hoverInfo.analysisState === 30 ? "已完成分析" : "未完成分析"
  11. }}</span>
  12. </p>
  13. <p>
  14. <span>风场编号</span><span>{{ hoverInfo.codeNumber }}</span>
  15. </p>
  16. <p>
  17. <span>风机数量</span><span>{{ newWind.engineTotalCount }} 台</span>
  18. </p>
  19. <p>
  20. <span>总容量</span
  21. ><span
  22. >{{
  23. newWind?.ratedCapacityNumber ? newWind.ratedCapacityNumber : 0
  24. }}/KW</span
  25. >
  26. </p>
  27. <p>
  28. <span>经度</span><span>{{ hoverInfo.longitude }}°</span>
  29. </p>
  30. <p>
  31. <span>纬度</span><span>{{ hoverInfo.latitude }}°</span>
  32. </p>
  33. <p>
  34. <span>分析类型数</span
  35. ><span
  36. >{{
  37. hoverInfo.analysisTypeCount ? hoverInfo.analysisTypeCount : 0
  38. }}
  39. 个</span
  40. >
  41. </p>
  42. <p>
  43. <span>分析开始时间</span>
  44. <span>{{
  45. newWind.analysisStartTime
  46. ? $formatDateTWO(newWind.analysisStartTime)
  47. : "暂无数据"
  48. }}</span>
  49. </p>
  50. <p>
  51. <span>分析结束时间</span>
  52. <span>{{
  53. newWind.analysisEndTime
  54. ? $formatDateTWO(newWind.analysisEndTime)
  55. : "暂无数据"
  56. }}</span>
  57. </p>
  58. <p>
  59. <span>数据开始时间</span>
  60. <span>{{
  61. newWind.dataStartTime
  62. ? $formatDateTWO(newWind.dataStartTime)
  63. : "暂无数据"
  64. }}</span>
  65. </p>
  66. <p>
  67. <span>数据结束时间</span>
  68. <span>{{
  69. newWind.dataEndTime
  70. ? $formatDateTWO(newWind.dataEndTime)
  71. : "暂无数据"
  72. }}</span>
  73. </p>
  74. <!-- <p>
  75. <span>最新分析时间</span><span> {{ $formatDateTWO(hoverInfo.wfbrCreateTime) }}</span>
  76. </p> -->
  77. </div>
  78. </div>
  79. <div v-if="hoverfengji" :style="hoverfengjiStyle" class="hover-fengji">
  80. <h3>{{ hoverfengji.engineName }}</h3>
  81. <div>
  82. <p>
  83. <span>风机编号</span><span>{{ hoverfengji.engineCode }}</span>
  84. </p>
  85. <p>
  86. <span>额定容量</span
  87. ><span
  88. >{{
  89. hoverfengji?.ratedCapacity ? hoverfengji?.ratedCapacity : 0
  90. }}
  91. /KW</span
  92. >
  93. </p>
  94. <p>
  95. <span>海拔高度</span
  96. ><span>{{ hoverfengji.elevationHeight }} /米</span>
  97. </p>
  98. <p>
  99. <span>轮毂高度</span><span>{{ hoverfengji.hubHeight }} /米</span>
  100. </p>
  101. <p>
  102. <span>经度</span><span>{{ hoverfengji.longitude }}</span>
  103. </p>
  104. <p>
  105. <span>维度</span><span>{{ hoverfengji.latitude }}</span>
  106. </p>
  107. <p>
  108. 是否标杆风机
  109. <span>{{ hoverfengji.sightcing == 1 ? "是" : "否" }}</span>
  110. </p>
  111. <p>
  112. <span>额定风速</span><span>{{ hoverfengji.ratedWindSpeed }} m/s</span>
  113. </p>
  114. <p>
  115. <span>切入风速</span
  116. ><span>{{ hoverfengji.ratedCutInWindspeed }} m/s</span>
  117. </p>
  118. <p>
  119. <span>切出风速</span
  120. ><span>{{ hoverfengji.ratedCutOutWindspeed }} m/s</span>
  121. </p>
  122. </div>
  123. </div>
  124. <div v-if="hoverta" :style="hovertaStyle" class="hover-ta">
  125. <h3>{{ hoverta.anemometerName }}</h3>
  126. <div>
  127. <p>
  128. <span>测风塔编号</span><span>{{ hoverta.anemometerCode }}</span>
  129. </p>
  130. <p>
  131. <span>经度</span><span>{{ hoverta.longitude }}</span>
  132. </p>
  133. <p>
  134. <span>维度</span><span>{{ hoverta.latitude }}</span>
  135. </p>
  136. <!-- <p>
  137. <span>状态</span><span>{{ }}</span>
  138. </p> -->
  139. <p>
  140. <span>测风塔高度</span
  141. ><span>{{ hoverta.anemometerHeightStrings }}/米</span>
  142. </p>
  143. </div>
  144. </div>
  145. <!-- 这是测试 -->
  146. <el-dialog title="异常描述" :visible.sync="dialogVisible" width="50%">
  147. <el-table :data="tableData" max-height="500" style="width: 100%">
  148. <el-table-column prop="analysisTypeName" label="类型" width="300">
  149. </el-table-column>
  150. <el-table-column prop="errDesc" label="描述"> </el-table-column>
  151. </el-table>
  152. </el-dialog>
  153. </div>
  154. </template>
  155. <script>
  156. import "ol/ol.css";
  157. import { Map, View, Feature } from "ol";
  158. import TileLayer from "ol/layer/Tile.js";
  159. import { XYZ } from "ol/source";
  160. import { fromLonLat } from "ol/proj";
  161. import { Vector } from "ol/source";
  162. import { Vector as VectorLayer } from "ol/layer";
  163. import { Point } from "ol/geom";
  164. import { Icon, Style } from "ol/style";
  165. import ZoomSlider from "ol/control/ZoomSlider.js";
  166. import { defaults as defaultControls } from "ol/control.js";
  167. import icon01 from "../../assets/img/iconFC.png";
  168. import icon02 from "../../assets/img/iconFC.png";
  169. import icon03 from "../../assets/img/iconFC.png";
  170. import icon04 from "../../assets/img/iconFJ.png";
  171. import icon05 from "../../assets/img/icon05.png";
  172. import icon06 from "../../assets/img/iconFJ.png";
  173. import defaultIcon from "../../assets/img/iconFJ.png";
  174. import { queryErrDescByEngine, queryFloatingWindowInfo } from "@/api/ledger.js";
  175. import { login } from "@/api/login";
  176. export default {
  177. props: {
  178. windEngineGroupByFieldCodeDetail: {
  179. type: Object,
  180. default: () => {
  181. return {};
  182. },
  183. },
  184. },
  185. name: "T-map",
  186. data() {
  187. return {
  188. dialogVisible: false,
  189. tableData: [],
  190. hoverInfo: null,
  191. hoverStyle: {
  192. position: "absolute",
  193. left: "0px",
  194. top: "0px",
  195. },
  196. hoverfengji: null,
  197. hoverfengjiStyle: {
  198. position: "absolute",
  199. left: "0px",
  200. top: "0px",
  201. },
  202. hoverta: null,
  203. hovertaStyle: {
  204. position: "absolute",
  205. left: "0px",
  206. top: "0px",
  207. },
  208. newWind: {},
  209. };
  210. },
  211. watch: {
  212. windEngineGroupByFieldCodeDetail: {
  213. handler(data) {
  214. if (data) {
  215. }
  216. },
  217. deep: true, // 深度监听
  218. },
  219. },
  220. mounted() {
  221. this.map = new Map({
  222. target: "map",
  223. view: new View({
  224. projection: "EPSG:4326",
  225. center: fromLonLat([116.389, 39.903]), //地图中心
  226. zoom: 5, //默认缩放级别
  227. minZoom: 5, //最小缩放级别
  228. maxZoom: 15, //最大缩放级别
  229. extent: [
  230. 70.3671875, 18.14576369243164, 134.92927612304688, 55.667146064662596,
  231. ],
  232. }),
  233. layers: [
  234. new TileLayer({
  235. source: new XYZ({
  236. // url: "http://127.0.0.1:8010/tiles/{z}/{x}/{y}.png", //本地
  237. // url: "http://192.168.50.235/tiles/{z}/{x}/{y}.png", //内网
  238. url: "http://106.120.102.238:18000/tiles/{z}/{x}/{y}.png", //外网
  239. // url: "http://10.96.137.5:9080/tiles/{z}/{x}/{y}.png", //大~#@唐
  240. }),
  241. }),
  242. new VectorLayer({
  243. id: "marker",
  244. source: new Vector(),
  245. }),
  246. ],
  247. controls: defaultControls().extend([new ZoomSlider()]),
  248. });
  249. // console.log(this.map.getView().calculateExtent());
  250. this.initEvent();
  251. },
  252. methods: {
  253. /**
  254. * 地图上打点
  255. * @param data
  256. */
  257. addMarker(data = { point: [120.2, 30.35], val: "1" }) {
  258. const layer = this.map
  259. .getLayers()
  260. .getArray()
  261. .find((element) => {
  262. return element.get("id") === "marker";
  263. });
  264. const source = layer.getSource();
  265. const iconSrc = this.getIconForValue(data.val);
  266. const scale = data.val === "4" ? [0.5, 0.5] : [0.3, 0.3]; // 如果是 icon04,设置 scale 为 [0.5, 0.5],其他保持 [0.3, 0.3]
  267. const feature = new Feature({
  268. geometry: new Point(fromLonLat(data.point, "EPSG:4326")),
  269. name: "marker",
  270. data,
  271. });
  272. feature.setStyle(
  273. new Style({
  274. image: new Icon({
  275. src: iconSrc,
  276. scale: scale, // 根据条件动态设置 scale
  277. anchor: [0.5, 1],
  278. opacity: 1,
  279. }),
  280. })
  281. );
  282. source.addFeature(feature);
  283. },
  284. /**
  285. * 地图上打点
  286. * @param data
  287. */
  288. clearMarkers() {
  289. const layer = this.map
  290. .getLayers()
  291. .getArray()
  292. .find((element) => {
  293. return element.get("id") === "marker";
  294. });
  295. if (layer) {
  296. const source = layer.getSource();
  297. source.clear(); // 清空所有特征
  298. }
  299. },
  300. getIconForValue(val) {
  301. switch (val) {
  302. case "-1":
  303. case -1:
  304. return icon01;
  305. case "10":
  306. case 10:
  307. return icon01;
  308. case 0:
  309. case "0":
  310. return icon02;
  311. case 20:
  312. case "20":
  313. return icon02;
  314. case 1:
  315. case "1":
  316. return icon03;
  317. case 30:
  318. case "30":
  319. return icon03;
  320. case "4":
  321. return icon04;
  322. case "5":
  323. return icon05;
  324. case "6":
  325. return icon06;
  326. default:
  327. return defaultIcon;
  328. }
  329. },
  330. /**
  331. * 初始化地图事件
  332. */
  333. initEvent() {
  334. let lastHoveredFeature = null; // 用来记录上一次悬停的 feature
  335. this.map.on("pointermove", (evt) => {
  336. const features = this.map.getFeaturesAtPixel(evt.pixel, {
  337. hitTolerance: 1,
  338. });
  339. if (features && features.length > 0) {
  340. const feature = features.at(0);
  341. const val = feature.get("data").val;
  342. // 只有当当前悬停的 feature 和上次的不同,才触发操作
  343. if (lastHoveredFeature !== feature) {
  344. if (val == "1" || val == "30" || val == "-1") {
  345. this.hoverInfo = feature.get("data");
  346. this.hoverStyle.left = `${evt.pixel[0] + 10}px`;
  347. this.hoverStyle.top = `${evt.pixel[1] - 150}px`;
  348. this.getwind();
  349. } else if (val == "4") {
  350. this.hoverfengji = feature.get("data");
  351. this.hoverfengjiStyle.left = `${evt.pixel[0] + 10}px`;
  352. this.hoverfengjiStyle.top = `${evt.pixel[1] - 150}px`;
  353. this.currentFeatureData = feature.get("data");
  354. } else if (val == "5") {
  355. this.hoverta = feature.get("data");
  356. this.hovertaStyle.left = `${evt.pixel[0] + 10}px`;
  357. this.hovertaStyle.top = `${evt.pixel[1] - 150}px`;
  358. this.currentFeatureData = feature.get("data");
  359. } else if (val == "6") {
  360. this.currentFeatureData = feature.get("data");
  361. } else {
  362. this.hoverInfo = null;
  363. this.hoverfengji = false;
  364. this.hoverta = false;
  365. this.currentFeatureData = null;
  366. }
  367. // 更新 lastHoveredFeature
  368. lastHoveredFeature = feature;
  369. }
  370. } else {
  371. this.hoverInfo = null;
  372. this.hoverfengji = false;
  373. this.hoverta = false;
  374. this.currentFeatureData = null;
  375. lastHoveredFeature = null; // 没有特征时清空记录
  376. }
  377. });
  378. this.map.on("click", (evt) => {
  379. const features = this.map.getFeaturesAtPixel(evt.pixel, {
  380. hitTolerance: 1,
  381. });
  382. if (features && features.length > 0) {
  383. const feature = features.at(0);
  384. const val = feature.get("data").val;
  385. if (val === "6") {
  386. this.handleFeatureClick(feature.get("data"));
  387. } else {
  388. this.$emit("feature-click", feature.get("data"));
  389. }
  390. } else if (
  391. this.currentFeatureData &&
  392. this.currentFeatureData.val === "6"
  393. ) {
  394. this.handleFeatureClick(this.currentFeatureData);
  395. }
  396. });
  397. },
  398. handleFeatureClick(featureData) {
  399. let dateArr = {
  400. batchCode: this.$route.query.batchCode,
  401. engineCode: featureData.engineCode,
  402. };
  403. queryErrDescByEngine(dateArr).then((res) => {
  404. this.dialogVisible = true;
  405. this.tableData = res.data;
  406. });
  407. },
  408. getwind() {
  409. if (this.hoverInfo && this.hoverInfo.batchCode) {
  410. const param = {
  411. batchcode: this.hoverInfo.batchCode,
  412. fieldCode: this.hoverInfo.codeNumber,
  413. }; // 确保传递一个对象
  414. queryFloatingWindowInfo(param)
  415. .then((res) => {
  416. // 处理响应数据
  417. this.newWind = res.data;
  418. })
  419. .catch((err) => {
  420. console.error("获取风信息失败", err);
  421. });
  422. } else {
  423. console.warn("hoverInfo 或 batchCode 未定义");
  424. }
  425. },
  426. /**
  427. * 平移缩放
  428. * @param data
  429. */
  430. moveAndZoom(data = { point: [120.2, 30.35], zoom: 15 }) {
  431. this.map.getView().animate({
  432. center: fromLonLat(data.point, "EPSG:4326"),
  433. zoom: data.zoom,
  434. duration: 2000,
  435. });
  436. },
  437. },
  438. };
  439. </script>
  440. <style scoped lang="scss">
  441. .map-container {
  442. position: relative;
  443. width: 100%;
  444. height: 100%;
  445. }
  446. .map {
  447. width: 100%;
  448. height: 100%;
  449. }
  450. .hover-info {
  451. position: absolute;
  452. color: white;
  453. padding: 0px;
  454. z-index: 100;
  455. h3 {
  456. background-color: #008080cc;
  457. width: 240px;
  458. padding: 5px 10px;
  459. font-size: 16px;
  460. }
  461. div {
  462. background-color: #00808097;
  463. width: 240px;
  464. font-size: 12px;
  465. p {
  466. padding: 5px 10px;
  467. display: flex;
  468. justify-content: space-between;
  469. }
  470. }
  471. }
  472. .hover-fengji {
  473. position: absolute;
  474. color: white;
  475. padding: 0px;
  476. z-index: 100;
  477. h3 {
  478. background-color: #027cb4cc;
  479. width: 240px;
  480. padding: 5px 10px;
  481. font-size: 16px;
  482. }
  483. div {
  484. background-color: #027cb49e;
  485. width: 240px;
  486. font-size: 12px;
  487. p {
  488. padding: 5px 10px;
  489. display: flex;
  490. justify-content: space-between;
  491. }
  492. }
  493. }
  494. .hover-ta {
  495. position: absolute;
  496. color: white;
  497. padding: 0px;
  498. z-index: 100;
  499. h3 {
  500. background-color: #d90019b2;
  501. width: 240px;
  502. padding: 5px 10px;
  503. font-size: 16px;
  504. }
  505. div {
  506. background-color: #d9001994;
  507. width: 240px;
  508. font-size: 12px;
  509. p {
  510. padding: 5px 10px;
  511. display: flex;
  512. justify-content: space-between;
  513. }
  514. }
  515. }
  516. </style>