ZZJ
2021-12-03 1706494087a9f8fd22f691d279e9ef7756cd316d
地图
4个文件已添加
12个文件已修改
1138 ■■■■ 已修改文件
public/images/map/Group 594.png 补丁 | 查看 | 原始文档 | blame | 历史
public/images/map/video_20210924_101628.mp4 补丁 | 查看 | 原始文档 | blame | 历史
public/images/map/安全帽-红.png 补丁 | 查看 | 原始文档 | blame | 历史
public/images/map/安全帽-绿.png 补丁 | 查看 | 原始文档 | blame | 历史
public/images/map/监控.png 补丁 | 查看 | 原始文档 | blame | 历史
src/api/helemt.ts 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/internetData/views/helemtTable.vue 197 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/internetEquipment/components/headCard.vue 114 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/internetEquipment/components/helemetEchart.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/internetEquipment/components/helemetHead.vue 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/internetEquipment/components/telephoneBox.vue 122 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/internetEquipment/module/elecModule.vue 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/internetEquipment/module/historyModule.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/internetEquipment/module/mapIndex.vue 626 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/internetEquipment/module/realTimeModule.vue 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/internetEquipment/views/helemetEquipment.vue 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
public/images/map/Group 594.png
public/images/map/video_20210924_101628.mp4
Binary files differ
public/images/map/°²È«Ã±-ºì.png

public/images/map/°²È«Ã±-ÂÌ.png

public/images/map/¼à¿Ø.png
src/api/helemt.ts
@@ -73,4 +73,12 @@
        method: "post",
        data
    })
}
export const delZones = (data) => {
    return request({
        url: `/iotdata/del-zone`,
        method: "post",
        data
    })
}
src/pages/internetData/views/helemtTable.vue
@@ -110,25 +110,25 @@
              src="/images/InternetData/视频.png"
              alt=""
              v-if="!scope.row.isSend"
              @click="sendVoice(scope.row)"
              @click="sendVoice(scope.row, scope.$index)"
            />
            <img
              src="/images/InternetData/视频_点击.png"
              alt=""
              v-else
              @click="sendVoice(scope.row)"
              @click="sendVoice(scope.row, scope.$index)"
            />
            <img
              src="/images/InternetData/语音.png"
              alt=""
              v-if="!scope.row.istele"
              @click="telephone(scope.row)"
              @click="telephone(scope.row, scope.$index)"
            />
            <img
              src="/images/InternetData/语音_点击.png"
              alt=""
              v-else
              @click="telephone(scope.row)"
              @click="telephone(scope.row, scope.$index)"
            />
          </div>
        </template>
@@ -166,141 +166,10 @@
      currentPage: 1,
      page_size: 10,
      total: 10,
      tableData: [
        {
          code: "A123123123123",
          elec: 79.1,
          ip: "192.168.1.2",
          mac: "ec:da:da:da:ed:98",
          longitude: 120.123123,
          latitude: 120.123123,
          height: "11.21",
          time: "0.23.45",
          positon: "单向定位",
          isSend: false,
          istele: false,
        },
        {
          code: "A123123123123",
          elec: 29.1,
          ip: "192.168.1.2",
          mac: "ec:da:da:da:ed:98",
          longitude: 120.123123,
          latitude: 120.123123,
          height: "11.21",
          time: "0.23.45",
          positon: "单向定位",
          isSend: false,
          istele: false,
        },
        {
          code: "A123123123123",
          elec: 0,
          ip: "192.168.1.2",
          mac: "ec:da:da:da:ed:98",
          longitude: 120.123123,
          latitude: 120.123123,
          height: "11.21",
          time: "0.23.45",
          positon: "单向定位",
          isSend: false,
          istele: false,
        },
        {
          code: "A123123123123",
          elec: 79.1,
          ip: "192.168.1.2",
          mac: "ec:da:da:da:ed:98",
          longitude: 120.123123,
          latitude: 120.123123,
          height: "11.21",
          time: "0.23.45",
          positon: "单向定位",
          isSend: false,
          istele: false,
        },
        {
          code: "A123123123123",
          elec: 79.1,
          ip: "192.168.1.2",
          mac: "ec:da:da:da:ed:98",
          longitude: 120.123123,
          latitude: 120.123123,
          height: "11.21",
          time: "0.23.45",
          positon: "单向定位",
          isSend: false,
          istele: false,
        },
        {
          code: "A123123123123",
          elec: 79.1,
          ip: "192.168.1.2",
          mac: "ec:da:da:da:ed:98",
          longitude: 120.123123,
          latitude: 120.123123,
          height: "11.21",
          time: "0.23.45",
          positon: "单向定位",
          isSend: false,
          istele: false,
        },
        {
          code: "A123123123123",
          elec: 79.1,
          ip: "192.168.1.2",
          mac: "ec:da:da:da:ed:98",
          longitude: 120.123123,
          latitude: 120.123123,
          height: "11.21",
          time: "0.23.45",
          positon: "单向定位",
          isSend: false,
          istele: false,
        },
        {
          code: "A123123123123",
          elec: 79.1,
          ip: "192.168.1.2",
          mac: "ec:da:da:da:ed:98",
          longitude: 120.123123,
          latitude: 120.123123,
          height: "11.21",
          time: "0.23.45",
          positon: "单向定位",
          isSend: false,
          istele: false,
        },
        {
          code: "A123123123123",
          elec: 79.1,
          ip: "192.168.1.2",
          mac: "ec:da:da:da:ed:98",
          longitude: 120.123123,
          latitude: 120.123123,
          height: "11.21",
          time: "0.23.45",
          positon: "单向定位",
          isSend: false,
          istele: false,
        },
        {
          code: "A123123123123",
          elec: 79.1,
          ip: "192.168.1.2",
          mac: "ec:da:da:da:ed:98",
          longitude: 120.123123,
          latitude: 120.123123,
          height: "11.21",
          time: "0.23.45",
          positon: "单向定位",
          isSend: false,
          istele: false,
        },
      ],
      helemtArr: [],
      commentContent: "",
      telephoneObj: null,
      targetIndex: null,
    };
  },
  created() {
@@ -312,11 +181,11 @@
  methods: {
    async getHelemtArr(data) {
      const res = await getHelemtData(data);
      console.log(res);
      this.helemtArr = res.data.items;
      this.total = res.data.total;
    },
    sendVoice(target) {
    sendVoice(target, index) {
      const _this = this;
      target.isSend = true;
      const h = this.$createElement;
@@ -381,29 +250,41 @@
          target.isSend = false;
          done();
        },
      }).then((action) => {
        if (action == "confirm") {
          if (!voiceText) {
            this.$message({
              message: "指令不能为空",
              type: "warning",
      })
        .then((action) => {
          if (action == "confirm") {
            if (!voiceText) {
              this.$message({
                message: "指令不能为空",
                type: "warning",
              });
              target.isSend = false;
              _this.$set(_this.helemtArr, index, target);
              return;
            }
            console.log(voiceText);
            sendAudio(target.device_sn, voiceText).then((res) => {
              this.$message({
                message: "指令发送成功",
                type: "success",
              });
              target.isSend = false;
              _this.$set(_this.helemtArr, index, target);
            });
            return;
            target.isSend = false;
            _this.$set(_this.helemtArr, index, target);
          } else {
            target.isSend = false;
            _this.$set(_this.helemtArr, index, target);
          }
          console.log(voiceText);
          sendAudio(target.device_sn, voiceText).then((res) => {
            this.$message({
              message: "指令发送成功",
              type: "success",
            });
          });
        })
        .catch(() => {
          target.isSend = false;
        } else {
          target.isSend = false;
        }
      });
          _this.$set(_this.helemtArr, index, target);
        });
    },
    telephone(target) {
    telephone(target, index) {
      this.targetIndex = index;
      target.istele = true;
      this.telephoneObj = target;
    },
@@ -431,7 +312,9 @@
    },
    closeTele(e) {
      e.istele = false;
      this.$set(this.helemtArr, this.targetIndex, e);
      this.telephoneObj = null;
      this.targetIndex = null;
    },
  },
  components: {
src/pages/internetEquipment/components/headCard.vue
@@ -1,77 +1,73 @@
<template>
  <div class="head-card">
      <div class="card-left">
          <div class="number" :style="colorStyle">{{number}}</div>
          <div class="info">{{info}}</div>
      </div>
      <img class="card-right" :src="src" alt="">
    <div class="card-left">
      <div class="number" :style="colorStyle">{{ number }}</div>
      <div class="info">{{ info }}</div>
    </div>
    <img class="card-right" :src="src" alt="" />
  </div>
</template>
<script>
export default {
    props: {
        number: {
            require: true
        },
        info: {
            require: true
        },
        icon: {
            require: true
        },
        color: {
            require: true
        },
        src: {
            require: true
        }
  props: {
    number: {
      require: true,
    },
    data (){
        return {
        }
    info: {
      require: true,
    },
    computed: {
        colorStyle (){
            return {
                "--color":this.color
            }
        }
    }
}
    icon: {
      require: true,
    },
    color: {
      require: true,
    },
    src: {
      require: true,
    },
  },
  data() {
    return {};
  },
  computed: {
    colorStyle() {
      return {
        "--color": this.color,
      };
    },
  },
};
</script>
<style scoped lang="scss">
.head-card {
    box-sizing: border-box;
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 20px;
    width: 187px;
    height: 90px;
    background: #FFFFFF;
    box-shadow: 0px 2px 10px rgba(141, 164, 187, 0.25);
    border-radius: 15px;
  box-sizing: border-box;
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 20px 2%;
  width: 187px;
  height: 90px;
  background: #ffffff;
  box-shadow: 0px 2px 10px rgba(141, 164, 187, 0.25);
  border-radius: 15px;
    .card-left {
        .number {
            font-size: 24px;
            font-weight: 700;
            color: var(--color);
        }
        .info {
            font-size: 12px;
            color: #4F4F4F;
;
        }
  .card-left {
    .number {
      font-size: 24px;
      font-weight: 700;
      color: var(--color);
    }
    .card-right {
        width: 58px;
        height: 58px;
    .info {
      font-size: 12px;
      color: #4f4f4f;
    }
  }
  .card-right {
    width: 58px;
    height: 58px;
  }
}
</style>
src/pages/internetEquipment/components/helemetEchart.vue
@@ -21,6 +21,9 @@
    });
    let myChart = echarts.init(document.getElementById("echart-cotainer"));
    myChart.setOption(this.option);
    window.addEventListener("resize", function () {
      myChart.resize();
    });
  },
  data() {
    return {
src/pages/internetEquipment/components/helemetHead.vue
@@ -51,10 +51,12 @@
  display: flex;
  .head-card {
    flex: 1;
    margin-right: 10px;
  }
  .helemet-echart {
    flex: 4;
    margin-left: 10px;
    width: 570px;
    height: 90px;
src/pages/internetEquipment/components/telephoneBox.vue
New file
@@ -0,0 +1,122 @@
<template>
  <div class="telephone-box">
    <div class="title">
      <span class="icon iconfont">&#xe7cc;</span>
      <span>去电</span>
    </div>
    <div class="info">
      <div class="id">1139</div>
      <div class="sip">sip:1139@47.112.193.0</div>
    </div>
    <div class="video">1</div>
    <div class="control">
      <img src="/images/InternetData/挂断.png" />
      <img src="/images/InternetData/声音.png" class="mid" />
      <img src="/images/InternetData/话筒.png" />
    </div>
    <div class="close el-icon-close" @click="close"></div>
  </div>
</template>
<script>
export default {
  props: {
    tele: {
      type: Object,
    },
  },
  data() {
    return {};
  },
  methods: {
    close() {
      this.$emit("close");
    },
  },
};
</script>
<style scoped lang="scss">
.telephone-box {
  box-sizing: border-box;
  position: fixed;
  z-index: 5;
  padding: 32px 28px 28px 55px;
  width: 420px;
  height: 382px;
  left: 50%;
  top: 50%;
  margin-top: -15%;
  margin-left: -15%;
  background: #ffffff;
  border-radius: 8px;
  color: #4f4f4f;
  .title {
    text-align: left;
    font-size: 16px;
    font-weight: 700;
    .icon {
      margin-right: 2px;
      font-size: 18px;
      font-weight: normal;
    }
  }
  .info {
    margin-top: 18px;
    font-weight: bold;
    font-size: 16px;
    .sip {
      margin-top: 2px;
      font-size: 12px;
      font-weight: normal;
    }
  }
  .video {
    margin: 0 auto;
    margin-top: 20px;
    box-sizing: border-box;
    width: 104px;
    height: 104px;
    background: #454141;
    border: 5px solid #ffaa44;
    border-radius: 50%;
    font-size: 36px;
    color: #fff;
    line-height: 94px;
  }
  .control {
    margin-top: 50px;
    img {
      width: 37px;
      height: 37px;
    }
    .mid {
      margin: 0 37px;
    }
  }
  .close {
    cursor: pointer;
    position: absolute;
    top: 12px;
    right: 12px;
    font-size: 12px;
    font-weight: 700;
  }
}
</style>
src/pages/internetEquipment/module/elecModule.vue
@@ -62,10 +62,10 @@
  .elec-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    justify-content: space-around;
    margin-bottom: 4px;
    padding: 20px 5px 20px 5px;
    width: 240px;
    padding: 20px 0;
    width: 100%;
    height: 78px;
    background: #f9fafc;
    border-radius: 10px;
src/pages/internetEquipment/module/historyModule.vue
@@ -87,11 +87,11 @@
  .history-item {
    display: flex;
    width: 240px;
    width: 100%;
    height: 74px;
    margin-bottom: 4px;
    align-items: center;
    justify-content: space-between;
    justify-content: space-around;
    background: #f9fafc;
    border-radius: 10px;
    padding: 0 10px;
src/pages/internetEquipment/module/mapIndex.vue
@@ -1,19 +1,102 @@
<template>
  <div id="map-index">
    <div class="control">
      <div class="location icon iconfont" @click="location">&#xe74e;</div>
      <div class="zoom-in icon iconfont" @click="zoomIn">&#xeb89;</div>
      <div class="zoom-out icon iconfont" @click="zoomOut">&#xe758;</div>
      <a href="#" title="定位" @click="aClick()">
        <div class="location icon iconfont" @click="location">&#xe74e;</div>
      </a>
      <a href="#" title="放大" @click="aClick()">
        <div class="zoom-in icon iconfont" @click="zoomIn">&#xeb89;</div>
      </a>
      <a href="#" title="缩小" @click="aClick()">
        <div class="zoom-out icon iconfont" @click="zoomOut">&#xe758;</div>
      </a>
    </div>
    <div class="range icon iconfont" @click="drawPolygon">&#xe773;</div>
    <a href="#" title="新增/编辑" @click="aClick()">
      <div class="range icon iconfont" @click="drawPolygon">&#xe773;</div>
    </a>
    <el-input v-model="nodeId" placeholder="请输入内容"></el-input>
    <div class="save" v-if="showBtn" @click="savePoly">保存</div>
    <div class="del" v-if="polygonInfo" @click="delPoly">删除</div>
    <div class="cancel" v-if="showBtn" @click="resetMap">取消</div>
    <span id="polygonInfo" v-show="polygonInfo">{{ polygonInfo }}</span>
    <img
      v-if="myNode && !isHidden"
      src="/images/map/Group 594.png"
      alt=""
      class="video_icon"
      @click="hiddenVideo()"
    />
    <a v-else href="#" title="实时监控" @click="aClick()">
      <img
        src="/images/map/监控.png"
        alt=""
        class="video_icon"
        @click="showVideo()"
      />
    </a>
    <div class="video_box" v-if="myNode" :class="{ hidden: isHidden }">
      <div class="title">
        <div class="left">
          <span class="ball"></span>
          <span class="left_info">实时监控</span>
        </div>
        <div class="right">设备编码: {{ myNode.values_.id }}</div>
      </div>
      <video controls="controls" loop="loop">
        <source src="/images/map/video_20210924_101628.mp4" type="video/mp4" />
      </video>
    </div>
    <div class="helmet_box" v-show="myNode">
      <div class="icon_close iconfont" @click="close">&#xe729;</div>
      <div class="sn" v-if="myNode">{{ myNode.values_.lat.id }}</div>
      <div class="location" v-if="myNode">经度: {{ myNode.values_.lat }}</div>
      <div class="location" v-if="myNode">纬度: {{ myNode.values_.lng }}</div>
      <div class="info" v-if="myNode">电量: {{ myNode.values_.battery }}</div>
      <div class="button">
        <img
          src="/images/InternetData/视频.png"
          alt=""
          v-if="!isSending"
          @click="sendVoice()"
        />
        <img src="/images/InternetData/视频_点击.png" alt="" v-if="isSending" />
        <img
          src="/images/InternetData/语音.png"
          alt=""
          v-if="isTele == false"
          @click="isTele = true"
        />
        <img
          src="/images/InternetData/语音_点击.png"
          alt=""
          v-if="isTele == true"
          @click="isTele = false"
        />
      </div>
    </div>
    <telephoneBox :tele="myNode" v-if="isTele" @close="isTele = false" />
    <div class="mask" v-if="isTele"></div>
  </div>
</template>
<script>
import { getHelemtData, getZones, createZones } from "@/api/helemt";
import {
  getHelemtData,
  getZones,
  createZones,
  delZones,
  sendAudio,
} from "@/api/helemt";
import telephoneBox from "../components/telephoneBox.vue";
import "ol/ol.css";
import Feature from "ol/Feature";
@@ -28,6 +111,9 @@
import Draw from "ol/interaction/Draw";
import { Modify, Snap } from "ol/interaction";
import Polygon from "ol/geom/Polygon";
import Select from "ol/interaction/Select";
import Overlay from "ol/Overlay";
import { pointerMove } from "ol/events/condition";
let myMap = {};
let myVectorSource = {};
@@ -41,24 +127,20 @@
});
let myDraw = {};
let myModify = {};
let myPolygon = {};
let mySelect = {};
let overlay = {};
let overlay2 = {};
let voiceText = "";
export default {
  created() {
    this.getNodeData();
  },
  data() {
    return {
      isSending: false,
      isTele: false,
      isHidden: false,
      showBtn: false,
      nodeArr: [
        { data: [116.06157, 39.66157], id: 1, color: "绿" },
        { data: [116.06247, 39.66247], id: 2, color: "绿" },
        { data: [116.06337, 39.66337], id: 3, color: "绿" },
        { data: [116.06467, 39.66437], id: 4, color: "绿" },
        { data: [116.06517, 39.66517], id: 5, color: "红" },
        { data: [116.06627, 39.66627], id: 6, color: "红" },
        { data: [116.06787, 39.66787], id: 7, color: "红" },
        { data: [116.06897, 39.66897], id: 8, color: "红" },
      ],
      nodeArr: [],
      nodeId: "",
      iconArr: [],
      rangeArr: [],
@@ -68,14 +150,21 @@
      polyFeature: [],
      drawStore: [],
      modifyStore: [],
      polygonInfo: "",
      nodeFeature: [],
      myNode: null,
      commentContent: "",
    };
  },
  mounted() {
    this.initMap();
  },
  components: {
    telephoneBox,
  },
  methods: {
    async getNodeData() {},
    async initMap() {
      const that = this;
      // èŽ·å–èŠ‚ç‚¹
      const res = await getHelemtData();
      this.nodeArr = [];
@@ -84,6 +173,7 @@
          data: [item.lng, item.lat],
          id: item.device_sn,
          color: item.is_out_bound == 0 ? "绿" : "红",
          battery: item.battery,
        });
      });
@@ -97,7 +187,6 @@
          return obj;
        });
      }
      console.log(this.polygonArr);
      // è®¾ç½®åœ°å›¾ä¸­å¿ƒ
      this.center = this.nodeArr[0].data;
@@ -131,6 +220,114 @@
        console.log(item);
      })
    }) */
      window.addEventListener("resize", function () {
        map.updateSize();
      });
      const select = new Select({
        filter: (feature, layer) => {
          if (feature.values_ && feature.values_.type == "node") {
            this.myNode = feature;
            return true;
          } else if (feature.type && feature.type == "polygon") {
            myPolygon = feature;
            this.myNode = null;
            return true;
          } else {
            this.myNode = null;
            return false;
          }
        },
        style: (feature) => {
          if (feature.values_ && feature.values_.type == "node") {
            return new Style({
              image: new Icon({
                size: [32, 32],
                src: `/images/map/安全帽-${feature.values_.color}.png`,
              }),
              zIndex: 1,
            });
          } else if (feature.type && feature.type == "polygon") {
            return new Style({
              fill: new Fill({
                color: "rgba(0, 0, 255, 0.1)",
              }),
              stroke: new Stroke({
                color: "skyblue",
                width: 3,
              }),
            });
          }
        },
      });
      const select2 = new Select({
        condition: pointerMove,
        filter: (feature, layer) => {
          if (feature.values_ && feature.values_.type == "node") {
            return true;
          } else {
            return false;
          }
        },
        style: (feature) => {
          if (feature.values_ && feature.values_.type == "node") {
            return new Style({
              image: new Icon({
                size: [32, 32],
                src: `/images/map/安全帽-${feature.values_.color}.png`,
              }),
              zIndex: 1,
            });
          }
        },
      });
      const info = document.querySelector("#polygonInfo");
      map.addInteraction(select);
      map.addInteraction(select2);
      mySelect = select;
      select.on("select", function (e) {
        e.stopPropagation();
        overlay2.setPosition(undefined);
        if (e.selected.length == 0) {
          that.polygonInfo = "";
          that.nodeId = "";
          that.myNode = null;
          return false;
        }
        if (e.selected[0].values_.type == "node") {
          that.isHidden = false;
          that.polygonInfo = "";
          that.nodeId = e.selected[0].values_.id;
          return false;
        }
        if (myPolygon.polygonName) {
          that.polygonInfo = myPolygon.polygonName;
        } else {
          that.polygonInfo = "新区域";
        }
        overlay.setPosition(e.mapBrowserEvent.coordinate);
        return false;
      });
      select2.on("select", function (e) {
        if (
          e.selected.length &&
          e.selected[0].values_.type == "node" &&
          that.myNode &&
          that.myNode.values_.id == e.selected[0].values_.id
        ) {
          overlay2.setPosition(e.mapBrowserEvent.coordinate);
        } else {
        }
      });
    },
    initNode([x, y], color) {
      const iconFeature = new Feature({
@@ -147,12 +344,19 @@
      iconFeature.setStyle(iconStyle);
      this.iconArr.push(iconFeature);
      iconFeature.set("color", `${color}`);
      iconFeature.set("lat", `${x}`);
      iconFeature.set("lng", `${y}`);
      return iconFeature;
    },
    initAllNode() {
      this.nodeArr.forEach((item) => {
        const node = this.initNode(item.data, item.color);
        node.set("id", item.id);
        node.set("type", "node");
        node.set("battery", item.battery);
        this.nodeFeature.push(node);
        myVectorSource.addFeature(node);
      });
    },
@@ -161,6 +365,8 @@
      this.polygonArr.forEach((item) => {
        const feature = new Feature({ geometry: new Polygon([item.data]) });
        feature.id = item.id;
        feature.type = "polygon";
        feature.polygonName = item.name;
        this.polyFeature.push(feature);
      });
    },
@@ -179,6 +385,19 @@
      });
    },
    initBottomMap(vectorLayer) {
      const info = document.querySelector("#polygonInfo");
      const helmet_box = document.querySelector(".helmet_box");
      overlay2 = new Overlay({
        element: helmet_box,
        autoPan: true,
        autoPanAnimation: {
          duration: 250,
        },
      });
      overlay = new Overlay({
        element: info,
      });
      return new Map({
        target: "map-index",
        layers: [baseLayer, vectorLayer],
@@ -186,6 +405,7 @@
          center: transform(this.center, "EPSG:4326", "EPSG:3857"),
          zoom: this.zoom,
        }),
        overlays: [overlay, overlay2],
      });
    },
    zoomIn() {
@@ -204,6 +424,8 @@
      view.setCenter(transform(this.center, "EPSG:4326", "EPSG:3857"));
    },
    drawPolygon() {
      this.resetMap();
      mySelect.setActive(false);
      this.showBtn = true;
      const draw = new Draw({
        source: myVectorSource,
@@ -232,6 +454,7 @@
        }
        event.feature.id = id;
        event.feature.type = "polygon";
        this.drawStore.push({
          id,
          data: event.feature.getGeometry().getCoordinates()[0],
@@ -240,7 +463,6 @@
      const modify = new Modify({ source: myVectorSource });
      modify.addEventListener("modifyend", (event) => {
        console.log(event.features);
        const id = event.features.array_[0].id;
        const data = event.features.array_[0].getGeometry().getCoordinates()[0];
        this.modifyStore.push({ id, data });
@@ -250,14 +472,14 @@
      myMap.addInteraction(draw);
    },
    resetMap() {
      this.polygonInfo = "";
      mySelect.setActive(true);
      this.initPolygonArr();
      console.log(this.polyFeature);
      const vectorSource = new VectorSource({
        features: this.polyFeature,
      });
      /* if(this.polygonArr.length>0){
      this.initPolygonArr()
      console.log(this.polyFeature);
      vectorSource.addFeature(this.polyFeature[0])
      } */
      myVectorSource = vectorSource;
@@ -272,6 +494,7 @@
      this.modifyStore = [];
    },
    async savePoly() {
      mySelect.setActive(true);
      myMap.removeInteraction(myDraw);
      myMap.removeInteraction(myModify);
      this.showBtn = false;
@@ -291,7 +514,6 @@
      }
      const arrData = this.polygonArr.map((item) => {
        let name = item.name ? item.name : "";
        console.log(item);
        let data = item.data.map((arr) => {
          arr = transform([arr[0], arr[1]], "EPSG:3857", "EPSG:4326");
          return arr.join(",");
@@ -303,8 +525,181 @@
          id: +item.id,
        };
      });
      const res = await createZones({ dots_arr: arrData });
      console.log(res);
      await createZones({ dots_arr: arrData });
      const res = await getHelemtData();
      this.nodeArr = [];
      res.data.items.forEach((item) => {
        this.nodeArr.push({
          data: [item.lng, item.lat],
          id: item.device_sn,
          color: item.is_out_bound == 0 ? "绿" : "红",
        });
      });
      this.nodeFeature.forEach((item) => {
        myVectorSource.removeFeature(item);
      });
      this.initNode();
      this.initAllNode();
    },
    delPoly() {
      this.$confirm("此操作将删除该区域, æ˜¯å¦ç»§ç»­?", "提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
      })
        .then(async () => {
          myVectorSource.removeFeature(myPolygon);
          const res = await delZones({ id: myPolygon.id });
          if (res.status == 200) {
            this.$message({
              type: "success",
              message: "删除成功!",
            });
            this.polygonInfo = "";
            const res2 = await getZones();
            if (res2.data && res2.data.items && res2.data.items.length > 0) {
              this.polygonArr = res2.data.items.map((obj) => {
                obj.data = obj.dots.map((item) => {
                  return transform(
                    [item[0], item[1]],
                    "EPSG:4326",
                    "EPSG:3857"
                  );
                });
                return obj;
              });
            }
          } else {
            this.$message({
              type: "info",
              message: "删除失败",
            });
          }
        })
        .catch(() => {
          this.$message({
            type: "info",
            message: "已取消删除",
          });
        });
    },
    showVideo() {
      if (!this.myNode) {
        return false;
      }
      this.isHidden = false;
    },
    hiddenVideo() {
      document.querySelector("video").pause();
      this.isHidden = true;
    },
    close() {
      overlay2.setPosition(undefined);
    },
    onCommentInputChange() {
      let value = document.querySelector("#commentContent").value;
      voiceText = value;
      let cont = 20 - value.length;
      document.querySelector(
        "#comment_info"
      ).innerHTML = `还可输入${cont}个字符`;
    },
    sendVoice() {
      const _this = this;
      this.isSending = true;
      const h = this.$createElement;
      this.$msgbox({
        message: h(
          "div",
          {
            attrs: {
              class: "el-textarea",
            },
          },
          [
            h(
              "div",
              {
                attrs: {
                  class: "el-title",
                },
              },
              [
                h(
                  "span",
                  {
                    attrs: {
                      class: "icon iconfont",
                    },
                  },
                  "\ue7cc"
                ),
                h("span", null, "发送语音"),
              ]
            ),
            h("textarea", {
              attrs: {
                placeholder: "请输入语音命令",
                maxlength: "20",
                class: "el-textarea__inner",
                autocomplete: "off",
                rows: 3,
                id: "commentContent",
              },
              value: this.commentContent,
              on: { input: this.onCommentInputChange },
            }),
            h(
              "div",
              { attrs: { class: "info", id: "comment_info" } },
              "还可输入20个字符"
            ),
          ]
        ),
        showCancelButton: true,
        confirmButtonText: "确定",
        confirmButtonClass: "hele_btn_save",
        cancelButtonClass: "hele_btn_cancel",
        cancelButtonText: "取消",
        beforeClose: (action, instance, done) => {
          document.querySelector("#commentContent").value = "";
          document.querySelector(
            "#comment_info"
          ).innerHTML = `还可输入20个字符`;
          _this.isSending = false;
          done();
        },
      })
        .then((action) => {
          if (action == "confirm") {
            if (!voiceText) {
              this.$message({
                message: "指令不能为空",
                type: "warning",
              });
              _this.isSending = false;
              return;
            }
            sendAudio(_this.myNode.values_.id, voiceText).then((res) => {
              this.$message({
                message: "指令发送成功",
                type: "success",
              });
              _this.isSending = false;
            });
            _this.isSending = false;
          } else {
            _this.isSending = false;
          }
        })
        .catch(() => {
          _this.isSending = false;
        });
    },
    aClick() {
      return false;
    },
  },
  watch: {
@@ -326,14 +721,12 @@
        if (res.data.items && res.data.items.length > 0) {
          res.data.items.forEach((obj) => {
            this.nodeArr.forEach((item) => {
              if ((item.id = obj.device_sn)) {
              if (item.id == obj.device_sn) {
                arr.push(item);
              }
            });
          });
        }
        console.log(this.rangeArr);
        if (this.rangeArr.length > 0) {
          this.rangeArr.forEach((item) => {
@@ -362,6 +755,7 @@
            rangeFeature.setStyle(iconStyle);
            myVectorSource.addFeature(rangeFeature);
            rangeFeature.set("type", "range");
            this.rangeArr.push(rangeFeature);
          });
        }
@@ -372,12 +766,106 @@
</script>
<style scoped lang="scss">
a {
  background-color: transparent;
  color: #337ab7;
  text-decoration: none;
}
a:active a:hover {
  outline: 0;
}
#map-index {
  position: relative;
  margin: 20px 0;
  width: 1170px;
  width: 100%;
  height: 396px;
  border-radius: 15px;
  .helmet_box {
    width: 205px;
    height: 172px;
    padding: 10px 10px 20px 15px;
    font-size: 12px;
    background: rgba(255, 255, 255, 0.7);
    backdrop-filter: blur(4px);
    border-radius: 15px;
    text-align: left;
    .icon_close {
      text-align: right;
      cursor: pointer;
    }
    .sn {
      color: #f54336;
    }
    .location {
      margin: 10px 0;
    }
    .button {
      margin-top: 10px;
      text-align: center;
      img {
        cursor: pointer;
        width: 22px;
        &:first-child {
          margin-right: 48px;
        }
      }
    }
  }
  .video_box {
    box-sizing: border-box;
    overflow: hidden;
    position: absolute;
    z-index: 2;
    top: 45px;
    right: 25px;
    width: 483px;
    height: 306px;
    background: rgba(241, 250, 246, 0.6);
    backdrop-filter: blur(4px);
    /* Note: backdrop-filter has minimal browser support */
    border-radius: 15px;
    border: 1px solid rgb(17, 170, 102);
    transition: all linear 0.5s;
    &.hidden {
      width: 0;
      border: none;
    }
    .title {
      margin: 15px 40px 0 20px;
      width: 420px;
      display: flex;
      justify-content: space-between;
      align-items: center;
      color: #4f4f4f;
      font-size: 12px;
      .left {
        .ball {
          display: inline-block;
          width: 0;
          height: 0;
          border: 4px solid #f54336;
          border-radius: 2px;
          margin-right: 10px;
        }
      }
    }
    video {
      margin: 8px 40px 0 20px;
      width: 424px;
      height: 246px;
      object-fit: fill;
    }
  }
  .control {
    position: absolute;
    display: flex;
@@ -464,6 +952,84 @@
    line-height: 36px;
    cursor: pointer;
  }
  .del {
    position: absolute;
    z-index: 3;
    top: 15px;
    right: 113px;
    width: 87px;
    height: 35px;
    background: rgb(245, 108, 108);
    border: 1px solid rgb(245, 108, 108);
    border-radius: 8px;
    color: #fff;
    font-size: 12px;
    line-height: 36px;
    cursor: pointer;
  }
  .video_icon {
    position: absolute;
    z-index: 3;
    top: 179px;
    right: 10px;
    width: 37px;
  }
  #polygonInfo {
    padding: 10px;
    border: 1px solid;
    color: black;
    background-color: #fff;
    z-index: 3;
    width: 100px;
  }
  .mask {
    position: fixed;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    text-align: center;
    z-index: 4;
    background-color: black;
    opacity: 0.5;
  }
}
.el-textarea {
  height: 150px;
  padding: 0 15px;
  .el-title {
    margin-top: 20px;
    margin-bottom: 15px;
    color: #4f4f4f;
    font-size: 16px;
    font-weight: 700;
    .icon {
      font-weight: normal;
      font-size: 19px;
    }
  }
  .el-textarea__inner {
    width: 357px;
    &:focus {
      border: 1px solid #11aa66;
    }
  }
  .info {
    font-size: 12px;
    color: #828282;
    text-align: right;
    padding-right: 38px;
  }
}
</style>
src/pages/internetEquipment/module/realTimeModule.vue
@@ -1,17 +1,23 @@
<template>
  <div class="real-time-module">
    <div class="title">实时抓拍预警</div>
    <div class="real-time-item" v-for="(item, index) in boundArr" :key="index">
      <img :src="item.snap_shot" alt="" class="warnArea" />
      <warnDescription
        :warnDes="{
          code: item.device_sn,
          time: item.updated_at,
          longitude: item.lng,
          latitude: item.lat,
          warn: '未在电子围栏区域',
        }"
      />
    <div class="real-time-list">
      <div
        class="real-time-item"
        v-for="(item, index) in boundArr"
        :key="index"
      >
        <img :src="item.snap_shot" alt="" class="warnArea" />
        <warnDescription
          :warnDes="{
            code: item.device_sn,
            time: item.updated_at,
            longitude: item.lng,
            latitude: item.lat,
            warn: '未在电子围栏区域',
          }"
        />
      </div>
    </div>
  </div>
</template>
@@ -32,10 +38,7 @@
<style scoped lang="scss">
.real-time-module {
  display: flex;
  flex-wrap: wrap;
  padding: 20px;
  padding-right: 0px;
  width: 570px;
  height: 292px;
  background-color: #fff;
@@ -43,17 +46,29 @@
  border-radius: 15px;
  overflow-y: scroll;
  .real-time-list {
    display: grid;
    justify-content: space-between;
    grid-template-columns: repeat(auto-fill, 170px);
    grid-gap: 10px;
  }
  .title {
    margin-bottom: 10px;
    font-size: 14px;
    font-weight: 700;
    width: 530px;
    width: 100%;
    text-align: left;
  }
  .real-time-item {
    margin-right: 13px;
    margin-right: 10px;
  }
  .real-time-item:last-child {
    margin-right: auto;
  }
  .warnArea {
    width: 167px;
    height: 104px;
src/pages/internetEquipment/views/helemetEquipment.vue
@@ -67,10 +67,17 @@
    display: flex;
    justify-content: start;
    color: #4f4f4f;
    .real-time-module {
      flex: 2.35;
    }
    .elec-module {
      flex: 1;
      margin: 0 20px;
    }
    .history-module {
      flex: 1;
    }
  }
}
</style>