Browse Source

updata map

sanqi73 3 weeks ago
parent
commit
3edcb51ba2

BIN
src/assets/images/box.png


BIN
src/assets/images/desk.png


BIN
src/assets/images/picture.png


BIN
src/assets/images/uwb.png


+ 142 - 0
src/enums/mapData.js

@@ -0,0 +1,142 @@
+export const images = [
+  {
+    src: require("@/assets/images/desk.png"),
+    alt: "desk 1",
+    centerX: 130,
+    centerY: 150,
+    width: "350px",
+    height: "250px",
+    transform: "rotate(90deg)"
+  },
+  {
+    src: require("@/assets/images/desk.png"),
+    alt: "desk 2",
+    centerX: 130,
+    centerY: 450,
+    width: "350px",
+    height: "250px",
+    transform: "rotate(90deg)"
+  },
+  {
+    src: require("@/assets/images/desk.png"),
+    alt: "desk 3",
+    centerX: 250,
+    centerY: 150,
+    width: "350px",
+    height: "250px",
+    transform: "rotate(90deg)"
+  },
+  {
+    src: require("@/assets/images/desk.png"),
+    alt: "desk 4",
+    centerX: 250,
+    centerY: 450,
+    width: "350px",
+    height: "250px",
+    transform: "rotate(90deg)"
+  },
+  {
+    src: require("@/assets/images/desk.png"),
+    alt: "desk 5",
+    centerX: 420,
+    centerY: 150,
+    width: "350px",
+    height: "250px",
+    transform: "rotate(90deg)"
+  },
+  {
+    src: require("@/assets/images/desk.png"),
+    alt: "desk 6",
+    centerX: 420,
+    centerY: 450,
+    width: "350px",
+    height: "250px",
+    transform: "rotate(90deg)"
+  },
+  {
+    src: require("@/assets/images/desk.png"),
+    alt: "desk 5",
+    centerX: 540,
+    centerY: 150,
+    width: "350px",
+    height: "250px",
+    transform: "rotate(90deg)"
+  },
+  {
+    src: require("@/assets/images/desk.png"),
+    alt: "desk 6",
+    centerX: 540,
+    centerY: 450,
+    width: "350px",
+    height: "250px",
+    transform: "rotate(90deg)"
+  },
+  {
+    src: require("@/assets/images/uwb.png"),
+    alt: "position",
+    centerX: 0,
+    centerY: 50,
+    width: "50px",
+    height: "50px",
+    transform: "rotate(-90deg)"
+  },
+  {
+    src: require("@/assets/images/uwb.png"),
+    alt: "position",
+    centerX: 0,
+    centerY: 550,
+    width: "50px",
+    height: "50px",
+    transform: "rotate(-90deg)"
+  },
+  {
+    src: require("@/assets/images/uwb.png"),
+    alt: "position",
+    centerX: 700,
+    centerY: 550,
+    width: "50px",
+    height: "50px",
+    transform: "rotate(90deg)"
+  },
+  {
+    src: require("@/assets/images/uwb.png"),
+    alt: "position",
+    centerX: 700,
+    centerY: 50,
+    width: "50px",
+    height: "50px",
+    transform: "rotate(90deg)",
+  },
+  {
+    src: require("@/assets/images/picture.png"),
+    alt: "position",
+    centerX: 40,
+    centerY: 500,
+    width: "250px",
+    height: "300px",
+    transform: "rotate(0)",
+  },
+  {
+    src: require("@/assets/images/picture.png"),
+    alt: "position",
+    centerX: 660,
+    centerY: 500,
+    width: "250px",
+    height: "300px",
+    transform: "rotate(0)",
+  },
+];
+
+
+export const doors = [
+  {
+    centerX: 35,
+    centerY: 0,
+    radius: 50
+  },
+  {
+    centerX: 650,
+    centerY: 0,
+    radius: 50
+  }
+];

+ 1 - 1
src/router/index.js

@@ -79,7 +79,7 @@ export const constantRoutes = [
     children: [
       {
         path: "outdoor",
-        component: () => import("@/views/item/echart"),
+        component: () => import("@/views/item/text"),
         name: "outdoor",
         meta: {
           title: "室内定位",

+ 318 - 0
src/views/item/text.vue

@@ -0,0 +1,318 @@
+<template>
+  <div class="body">
+    <el-card class="head_card"
+      shadow="always">
+      <el-row class="head_card_row">
+        <el-col :span="6"
+          class="head_card_item">
+          <span class="button_title">当前设备:</span>
+          <el-select v-model="value"
+            placeholder="请选择"
+            @change="selectDevice">
+            <el-option v-for="item in options"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value">
+            </el-option>
+          </el-select>
+        </el-col>
+
+        <el-col :span="6"
+          class="head_card_item">
+          <span class="button_title">当前设备状态:</span>
+
+          <el-tag type="success"
+            v-if="device.statue === 1">设备在线</el-tag>
+
+          <el-tag type="danger"
+            v-else-if="device.statue === 0">设备离线</el-tag>
+          <el-tag v-else>无设备</el-tag>
+        </el-col>
+
+        <el-col :span="4"
+          class="head_card_item">
+          <span class="button_title">当前设备X坐标:</span>
+          <span style="font-size: 17px;font-weight: bold;">{{ device.x }}</span>
+        </el-col>
+        <el-col :span="4"
+          class="head_card_item">
+          <span class="button_title">当前设备Y坐标:</span>
+          <span style="font-size: 17px;font-weight: bold;">{{ device.y }}</span>
+        </el-col>
+        <el-col :span="4"
+          class="head_card_item">
+          <span class="button_title">当前设备Z坐标:</span>
+          <span style="font-size: 17px;font-weight: bold;">{{ device.z }}</span>
+        </el-col>
+      </el-row>
+
+    </el-card>
+
+    <el-card style="padding: 25px">
+      <div ref="map"
+        class="map">
+
+        <p style="position:absolute;left: -20px;top: -20px;font-size: 20px;">0</p>
+        <p style="position:absolute;left: 5px;top: -45px;font-size: 20px;">0</p>
+        <p style="position:absolute;left: -20px;bottom: -45px;font-size: 20px;">600</p>
+        <p style="position:absolute;right: -20px;top: -45px;font-size: 20px;">700</p>
+
+        <img v-for="(image, index) in images"
+          :key="index"
+          :src="image.src"
+          :alt="image.alt"
+          :style="{
+            left: `${image.x}px`,
+            top: `${image.y}px`,
+            height: image.height,
+            width: image.width,
+            transform: image.transform,
+          }"
+          class="positioned-image" />
+
+        <img v-for="(box, index) in boxs"
+          :src="box.src"
+          :alt="box.alt"
+          :style="{
+            left: `${box.x}px`,
+            top: `${box.y}px`,
+            height: box.height,
+            width: box.width,
+            transform: box.transform,
+          }"
+          :class="box.class" />
+
+        <svg :width="mapWidth"
+          :height="mapHeight"
+          class="positioned-svg">
+          <path :d="doorPath"
+            stroke="#BDBDBD"
+            stroke-width="2"
+            fill="none" />
+        </svg>
+      </div>
+    </el-card>
+
+  </div>
+</template>
+
+<script>
+import api from "@/api/item/device";
+import { images, doors } from "@/enums/mapData";
+export default {
+  data() {
+    return {
+
+      device: {},
+      options: [],
+      value: '',
+      images: images,
+      doors: doors,
+      boxs: [],
+      mapWidth: 0,
+      mapHeight: 0
+    };
+  },
+  mounted() {
+    window.addEventListener('resize', this.handleResize);
+    this.handleResize();
+    this.getOptions()
+    this.getCoordinateData()
+    setInterval(() => {
+      if (this.value != null && this.value != '') {
+        this.selectDevice(this.value); // 定时刷新当前设备数据
+      }
+      this.getCoordinateData(); // 定时刷新坐标数据
+
+    }, 1000)
+
+  },
+  beforeUnmount() {
+    window.removeEventListener('resize', this.handleResize);
+  },
+  computed: {
+    // 设备门坐标路径
+    doorPath() {
+      const scaleX = this.mapWidth / 700;
+      const scaleY = this.mapHeight / 600;
+      let pathData = '';
+      this.doors.forEach((door) => {
+        const centerX = door.centerX * scaleX;
+        const centerY = door.centerY * scaleY;
+        const radius = door.radius * Math.min(scaleX, scaleY);
+        // 绘制四分之一圆(从 90 度到 180 度)
+        const doorPathSegment = `M ${centerX} ${centerY} A ${radius} ${radius} 0 0 1 ${centerX + radius} ${centerY} L ${centerX} ${centerY + radius} A ${radius} ${radius} 0 0 0 ${centerX - radius} ${centerY} Z `;
+        pathData += doorPathSegment;
+      });
+      return pathData;
+    }
+  },
+  methods: {
+    // 获取设备选项
+    getOptions() {
+      api.getDeviceOptions().then(res => {
+
+        this.options = res.data;
+      })
+    },
+
+    // 选择设备
+    selectDevice(id) {
+      api.getDeviceData(id).then(res => {
+        this.device = res.data;
+        this.deviceId = res.data.deviceid;  // 获取选中的设备ID
+      })
+    },
+
+    // 获取坐标数据
+    getCoordinateData() {
+      api.getCoordinateData().then(res => {
+        const filterData = res.data.filter(item => item.statue === 1);
+        for (let i = 0; i < filterData.length; i++) {
+          const item = filterData[i];
+          const existingBoxIndex = this.boxs.findIndex(box => box.alt === item.deviceid);
+
+          if (existingBoxIndex !== -1) {
+            // 如果设备已经存在,更新其属性
+            const existingBox = this.boxs[existingBoxIndex];
+            existingBox.centerX = item.coordinate[0] * 100;
+            existingBox.centerY = item.coordinate[1] * 100;
+            const classes = ['positioned-image'];
+            if (item.deviceid === this.device.deviceid) {
+              classes.push('boxs');
+            }
+            existingBox.class = classes.join(' ');
+          } else {
+            // 如果设备不存在,添加新的 box
+            const classes = ['positioned-image'];
+            if (item.deviceid === this.device.deviceid) {
+              classes.push('boxs');
+            }
+            this.boxs.push({
+              src: require("@/assets/images/box.png"),
+              alt: item.deviceid,
+              centerX: item.coordinate[0] * 100,
+              centerY: item.coordinate[1] * 100,
+              width: "50px",
+              height: "50px",
+              transform: "rotate(0)",
+              class: classes.join(' ')
+            });
+          }
+        }
+        // 调用封装的方法
+        this.boxs = this.updatePositionAndSize(this.boxs);
+      });
+    },
+
+    // 监听窗口大小变化
+    handleResize() {
+      this.images = this.updatePositionAndSize(this.images);
+    },
+
+    // 更新图片的位置和大小
+    updatePositionAndSize(arr) {
+      const rect = this.$refs.map && this.$refs.map.getBoundingClientRect();
+      if (rect) {
+        this.mapWidth = rect.width;
+        this.mapHeight = rect.height;
+        const scaleX = rect.width / 700;
+        const scaleY = rect.height / 600;
+        return arr.map(item => {
+          const width = parseInt(item.width, 10);
+          const height = parseInt(item.height, 10);
+          return {
+            ...item,
+            x: item.centerX * scaleX - width / 2,
+            y: item.centerY * scaleY - height / 2
+          };
+        });
+      }
+      return arr;
+    },
+    // getClick(event) {
+    //   const rect = this.$refs.map.getBoundingClientRect();
+    //   const scaleX = rect.width / 700;
+    //   const scaleY = rect.height / 600;
+    //   const clickX = (event.clientX - rect.left) / scaleX;
+    //   const clickY = (event.clientY - rect.top) / scaleY;
+    //   this.x = Math.round(clickX);
+    //   this.y = Math.round(clickY);
+    // },
+
+  }
+};
+</script>
+
+<style lang="scss" scoped>
+.body {
+  width: 100%;
+  height: 100%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  flex-direction: column;
+  overflow: hidden;
+}
+
+.head_card {
+  margin-bottom: 5px;
+  height: 55px;
+  width: calc(80vw + 95px);
+
+  &_row {
+    display: flex;
+    align-items: center;
+    /* 垂直居中所有列 */
+  }
+
+  &_item {
+    display: flex;
+    align-items: center;
+    /* 垂直居中 */
+    justify-content: flex-start;
+    /* 水平居中,视需要而定 */
+    height: 100%;
+    /* 确保有足够的高度 */
+  }
+}
+
+.map {
+  height: 75vh;
+  width: 80vw;
+  border: 1px solid #cccccc;
+  position: relative;
+}
+
+.positioned-image {
+  position: absolute;
+}
+
+.boxs {
+  opacity: .5;
+  animation: fadeInOut 1s infinite ease-in-out;
+}
+
+
+@keyframes fadeInOut {
+
+  0%,
+  100% {
+    opacity: .4;
+  }
+
+  25% {
+    opacity: .6;
+  }
+
+  50% {
+    opacity: 1;
+  }
+}
+
+.positioned-svg {
+  position: absolute;
+  top: 0;
+  left: 0;
+}
+</style>