Browse Source

添加地图显示

xiaohaizhao 6 months ago
parent
commit
761a57f8f8
2 changed files with 891 additions and 359 deletions
  1. 400 359
      src/system/IOT/pressureControl/index.vue
  2. 491 0
      src/system/IOT/pressureControl/modules/devices.vue

File diff suppressed because it is too large
+ 400 - 359
src/system/IOT/pressureControl/index.vue


+ 491 - 0
src/system/IOT/pressureControl/modules/devices.vue

@@ -0,0 +1,491 @@
+<template>
+  <!--地图-->
+  <div
+    class="M-map"
+    :style="isShowMap ? 'display:inline-block' : 'display:none'"
+  >
+    <div class="but-box">
+      <a-button type="primary" size="small" round @click="isShowMap = false"
+        >切换列表</a-button
+      >
+    </div>
+    <baidu-map
+      class="map"
+      ref="map"
+      :center="latlng"
+      :zoom="zoom"
+      :scroll-wheel-zoom="true"
+      @ready="mapReady"
+      @click="mapClick"
+      :mapStyle="mapConfig"
+    >
+      <bm-marker
+        v-for="item in list"
+        :position="{ lat: item.latitude, lng: item.longitude }"
+        @click="devicedClick($event, item)"
+        :icon="{ url: MarkerIcon, size: { width: 25, height: 25 } }"
+      >
+        <bm-label
+          :content="item.devicename"
+          :labelStyle="{ border: 'none', color: '#000' }"
+          :offset="{ width: -35, height: 16 }"
+        />
+      </bm-marker>
+    </baidu-map>
+
+    <!--设备信息面板-->
+    <div
+      class="info-panel"
+      :style="infoPanel.baseInfo ? 'display:inline-block' : 'display:none'"
+    >
+      <div class="info-header">
+        <div class="left">
+          <span>设备信息</span>
+        </div>
+        <div class="right">
+          <customBtn
+            :btn="true"
+            :btn-options="[{ label: '控制面板' }]"
+            @clickBtn="deviceClick(infoPanel.baseInfo)"
+          ></customBtn>
+        </div>
+      </div>
+      <div class="map-deviced-info">
+        <p>
+          设备名称:<span>{{ infoPanel.baseInfo.devicename }}</span>
+        </p>
+        <p>
+          设备编码:<span>{{ infoPanel.baseInfo.serialnumber }}</span>
+        </p>
+        <p>
+          状态:<a-tag type="info">{{ infoPanel.baseInfo.status }}</a-tag>
+        </p>
+        <p>
+          区域:<span>{{ infoPanel.baseInfo.areaname }}</span>
+        </p>
+        <p>
+          设备地点:<span>{{ infoPanel.baseInfo.address }}</span>
+        </p>
+        <p>
+          固件版本:<span>{{ infoPanel.baseInfo.version }}</span>
+        </p>
+        <p>
+          上次在线时间:<span>{{ infoPanel.baseInfo.lastconnecttime }}</span>
+        </p>
+      </div>
+      <p>监测指数</p>
+      <div class="data-info">
+        <p v-for="item in infoPanel.dataInfo">
+          {{ item.paramname }}:<span>{{ item.lastvalue }}{{ item.unit }}</span>
+        </p>
+      </div>
+    </div>
+  </div>
+  <div
+    style="margin: 10rem 20rem 10rem 20rem"
+    :style="!isShowMap ? 'display:inline-block' : 'display:none'"
+  >
+    <a-button type="primary" size="small" round @click="isShowMap = true"
+      >切换地图</a-button
+    >
+  </div>
+  <div
+    class="device-wrapper"
+    :style="!isShowMap ? 'display:inline-block' : 'display:none'"
+    v-load-directive="deviceLoad"
+  >
+    <div class="device-list" v-if="deviceList.length">
+      <ContentBox
+        v-for="(item, index) in deviceList"
+        :key="index"
+        bgColor="rgb(255,255,255,0.25)"
+        color="#16FFF6"
+        @click="deviceClick(item)"
+      >
+        <div style="height: 30rem"></div>
+        <div class="siteinfo">
+          <div class="siteinfo-wrapper">
+            <EnvironmentOutlined />
+            <span>{{ item.sitename || "暂无站点" }}</span>
+          </div>
+        </div>
+        <div
+          class="device-title"
+          :style="[
+            { '--bg': item.eventstatus ? 'red' : 'rgba(255, 164, 6)' },
+            { '--icon': item.status == '离线' ? '#cccccc' : '#27AD00' },
+          ]"
+        >
+          <i class="used"></i>
+          <a-tooltip>
+            <template #title>
+              <span>{{ item.devicename }}</span>
+            </template>
+            <span>{{ item.devicename }}</span>
+          </a-tooltip>
+        </div>
+        <img style="width: 100%" :src="item.attinfos[0].url" alt="" />
+      </ContentBox>
+    </div>
+    <a-empty :image="simpleImage" v-else>
+      <template #description>
+        <span style="color: #ffffff">暂无数据</span>
+      </template>
+    </a-empty>
+  </div>
+</template>
+
+<script setup>
+import { ref, defineProps, onMounted, inject } from "vue";
+import Api from "@/api/api";
+import { useRouter } from "vue-router";
+import ContentBox from "./Box.vue";
+import { EnvironmentOutlined } from "@ant-design/icons-vue";
+import { Empty } from "ant-design-vue";
+import mapConfig from "../../IoTdashboard/modules/mapConfig.js";
+import customBtn from "../../controlPanel/modules/customBtn.vue";
+import MarkerIcon from "../../../../assets/map/marker1.svg";
+const simpleImage = Empty.PRESENTED_IMAGE_SIMPLE;
+const router = useRouter();
+let isShowMap = ref(true);
+
+/* 地图 */
+let infoPanel = ref({
+    baseInfo: "",
+    dataInfo: "",
+  }),
+  latlng = ref({
+    lat: 39.9,
+    lng: 116.39,
+  }),
+  zoom = ref(3),
+  list = ref([]);
+
+let mapReady = ({ Bmap, map }) => {
+  let lngLatArr = list.value.map((item) => {
+    return item.longitude + "," + item.latitude;
+  });
+  map.value = map;
+  autoRange(map, lngLatArr);
+};
+
+let mapClick = (e) => {
+  if (infoPanel.value.baseInfo)
+    infoPanel.value = { baseInfo: "", dataInfo: "" };
+};
+
+let devicedClick = async (map, data) => {
+  console.log(map, data, "触发");
+  let res = await Api.requested({
+    id: 20230711165702,
+    content: {
+      w_deviceid: data.w_deviceid,
+    },
+  });
+  infoPanel.value = {
+    baseInfo: data,
+    dataInfo: res.data,
+  };
+  console.log("infoPanel", infoPanel);
+};
+
+let autoRange = (map, points_arr) => {
+  if (points_arr.length === 0) {
+    return;
+  }
+  /**
+   * 先计算中心点坐标
+   * 1. 找出所有点中最大最小经纬度
+   * 2. 计算中心点坐标
+   *
+   *
+   * bssw 为左下角
+   * bsne 为右上角
+   *
+   * 目标点的纬度需要大于左下角点的纬度并且小于右上角的纬度
+   * 目标点的经度需要大于左下角点的经度并且小于右上角的经度
+   *
+   */
+  let max_lng = points_arr[0].split(",")[0],
+    min_lat = points_arr[0].split(",")[1],
+    max_lat = points_arr[0].split(",")[1],
+    min_lng = points_arr[0].split(",")[0];
+  for (let i = 0; i < points_arr.length - 1; i++) {
+    let lng_lat = points_arr[i + 1].split(",");
+    //   max = max < arr[i+1] ? arr[i+1] : max
+    max_lng = max_lng < lng_lat[0] ? lng_lat[0] : max_lng;
+    min_lng = min_lng > lng_lat[0] ? lng_lat[0] : min_lng;
+    max_lat = max_lat < lng_lat[1] ? lng_lat[1] : max_lat;
+    min_lat = min_lat > lng_lat[1] ? lng_lat[1] : min_lat;
+  }
+  // console.log((Number(max_lng) + Number(min_lng)) / 2,(Number(max_lat)+Number(min_lat))/2);
+  let n_lng = (Number(max_lng) + Number(min_lng)) / 2;
+  let n_lat = (Number(max_lat) + Number(min_lat)) / 2;
+
+  /**
+   * 计算层级
+   *  百度地图比例尺与级别关系
+   */
+  let bs = map.getBounds(); //获取可视区域
+  let bssw = bs.getSouthWest(); //可视区域左下角
+  let bsne = bs.getNorthEast(); //可视区域右上角
+  // 百度地图比例尺与级别关系,参考https://blog.csdn.net/tjj3027/article/details/81015138
+  const map_rule = [
+    500000, 250000, 100000, 50000, 25000, 10000, 5000, 2500, 1250, 1000, 500,
+    250, 100, 50, 25, 10, 5, 2.5, 1,
+  ];
+
+  let zoomA = [4, 4];
+  for (let j = 0; j < 2; j++) {
+    let viewSize, searchSize;
+    if (j === 0) {
+      viewSize = bsne.lng - bssw.lng; // 当前可视宽度右上角经度-左下角经度
+      searchSize = (max_lng - min_lng) * 1.1; // 搜索结果的最大宽度 经度最大值-经度最小值
+    } else {
+      viewSize = bsne.lat - bssw.lat; // 当前可视高度右上角纬度-左下角纬度
+      searchSize = (max_lat - min_lat) * 1.1; // 搜索结果的最大宽度 纬度最大值-纬度最小值
+    }
+
+    let minDiff = 0;
+    for (let i = 0; i < map_rule.length; i++) {
+      let diff =
+        (viewSize * map_rule[i]) / map_rule[zoom.value - 1] - searchSize;
+      if (diff > 0) {
+        if (minDiff == 0 || diff < minDiff) {
+          zoomA[j] = i + 1;
+          minDiff = diff;
+        }
+      }
+    }
+  }
+  let zoom1 = zoomA[0] > zoomA[1] ? zoomA[1] : zoomA[0];
+  // 设定地图最大缩放层级为18,最小为4
+  zoom1 = zoom1 >= 18 ? 18 : zoom1;
+  zoom1 = zoom1 <= 4 ? 4 : zoom1;
+  /*
+   *  图移动到新的中点,调整好层级
+   *  这里使用 map.centerAndZoom(new BMap.Point(n_lng, n_lat),zoom)
+   *	屏幕可能会过度晃动,暂时知道原因,所以用了下面的方案
+   **/
+  zoom.value = zoom1;
+  function setCenter() {
+    map.panTo(new BMap.Point(n_lng, n_lat), { noAnimation: false }); // 设置中心点坐标
+    console.log("触发");
+    map.removeEventListener("tilesloaded", setCenter);
+  }
+  //地图加载完毕(地图稍微有改动就会触发) 当地图所有图块完成加载时触发此事件
+  map.addEventListener("tilesloaded", setCenter);
+};
+
+/* 列表 */
+let DeviceTotalPage = ref(0);
+let deviceList = ref([]);
+let deviceParam = ref({
+  id: 20230914133302,
+  content: {
+    pageNumber: 1,
+    pageSize: 15,
+  },
+});
+
+let deviceLoad = () => {
+  if (deviceParam.value.content.pageNumber == DeviceTotalPage.value) return;
+  deviceParam.value.content.pageNumber += 1;
+  console.log(deviceParam.value);
+  getDeviceData();
+};
+
+let getDeviceData = async () => {
+  let res = await Api.requested(deviceParam.value);
+  console.log("获取列表", res);
+  deviceList.value =
+    deviceParam.value.content.pageNumber == 1
+      ? res.data
+      : deviceList.value.concat(res.data);
+
+  list.value = res.data.filter((item) => item.latitude != "");
+  console.log("list.value", list.value);
+  if (!list.value.length) {
+    latlng.value = {
+      lat: 39.9,
+      lng: 116.39,
+    };
+    zoom.value = 6;
+  }
+  DeviceTotalPage.value = res.pageTotal;
+};
+
+let deviceClick = (data) => {
+  console.log("跳转", data);
+  router.push({
+    path: "/" + (data.dashboardpath || "baseDevice"),
+    query: {
+      id: data.w_deviceid,
+    },
+  });
+};
+
+onMounted(async () => {
+  getDeviceData();
+});
+</script>
+
+<style scope>
+* {
+  box-sizing: border-box;
+  --color1: #16fff6;
+  --color2: rgba(255, 164, 6);
+}
+/* 地图 */
+.M-map {
+  width: 100%;
+  height: calc(100vh - 290rem);
+  position: relative;
+  padding: 12rem;
+}
+.M-map .map {
+  width: 100%;
+  height: 100%;
+  border-radius: 8rem;
+  overflow: hidden;
+}
+
+.M-map .but-box {
+  position: absolute;
+  top: 25rem;
+  left: 25rem;
+  z-index: 9999;
+}
+
+.info-panel {
+  width: 250rem;
+  background: rgb(90, 100, 119, 0.8) !important;
+  position: absolute;
+  top: 48%;
+  left: 4%;
+  transform: translateY(-50%);
+  z-index: 9999999999999999999;
+  padding: 10rem;
+  color: #ffffff;
+  font-size: 14rem;
+}
+.info-panel .info-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+.info-panel .map-deviced-info {
+  background: rgba(255, 255, 255, 0.2);
+  border-radius: 5rem;
+  padding: 10rem;
+  margin: 10rem 0;
+}
+.info-panel .data-info {
+  background: rgba(255, 255, 255, 0.2);
+  border-radius: 5rem;
+  padding: 10rem;
+  margin: 10rem 0;
+}
+/* 列表 */
+.device-wrapper {
+  display: flex;
+  justify-content: center;
+  overflow-y: scroll;
+  height: calc(100% - 180rem);
+  scrollbar-width: none; /* firefox */
+  -ms-overflow-style: none; /* IE 10+ */
+  margin-top: 10rem;
+}
+.device-wrapper .device-list {
+  display: flex;
+  flex-wrap: wrap;
+  padding-bottom: 50rem;
+}
+
+.device-wrapper .device-list .content_box {
+  flex: 1 !important;
+  max-width: 212rem;
+  margin: 0 18rem;
+}
+
+.device-wrapper .device-list .used {
+  display: inline-block;
+  width: 10rem;
+  height: 10rem;
+  border-radius: 10rem;
+  background: var(--icon);
+  margin-right: 10rem;
+}
+.device-wrapper .device-list .device-title {
+  display: flex;
+  align-items: center;
+  height: 44rem;
+  font-size: 14rem;
+}
+.device-wrapper .device-list .device-title,
+img,
+.status {
+  margin-bottom: 10rem;
+  font-size: 14rem;
+}
+.device-wrapper .device-list .device-title span {
+  display: inline-block;
+  width: 140rem;
+  text-overflow: ellipsis;
+  overflow: hidden;
+  display: -webkit-box;
+  -webkit-line-clamp: 2;
+  -webkit-box-orient: vertical;
+  word-break: break-all;
+}
+.device-wrapper .device-list .content_box {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  align-content: center;
+  margin-bottom: 15rem;
+  cursor: pointer;
+  padding: 0rem 25rem;
+  width: auto !important;
+  flex: 1;
+}
+.device-wrapper .device-list .content_box:hover {
+  --color: red !important;
+}
+.device-wrapper .device-list .content_box:hover img {
+  transition: all 0.2s;
+  transform: scale(1.2);
+}
+.device-wrapper .device-list .i {
+  border-radius: 20rem;
+  background: red;
+}
+.device-wrapper .device-list img {
+  width: 100%;
+  max-height: 70rem;
+}
+.device-wrapper .device-list .status {
+  color: var(--color2);
+}
+
+.siteinfo {
+  position: absolute;
+  left: 0;
+  top: 0;
+  width: 100%;
+}
+.siteinfo .siteinfo-wrapper {
+  display: flex;
+  align-items: center;
+  align-self: flex-start;
+  width: 100%;
+  background: #40a9ff;
+}
+.siteinfo span {
+  margin-left: 10px;
+  white-space: nowrap;
+  text-overflow: ellipsis;
+  overflow: hidden;
+  font-size: 14rem;
+}
+</style>

Some files were not shown because too many files changed in this diff