Переглянути джерело

优化模型隐藏和右键卡死bug;驾驶舱人员增加手动删除在场信息;周界、火灾、激光云台报警弹窗与消除调整;周界撤防布防调整;激光云台扫描动画增加;增加报警闪烁光效;增加语音通话弹窗;

fan 1 місяць тому
батько
коміт
9f91a439e4

+ 1 - 1
public/js/config.js

@@ -9,7 +9,7 @@ const BASE_URL = '/yapi' //开发接口代理
  */
 const HOME_DATA = {
   startDate: '2024-11-27',
-  group: '国家管网集团北京管道公司',
+  group: '国家管网集团北京管道有限公司',
   company: '内蒙古输油气分公司',
   curStation: '托克托压气站',
 }

+ 4 - 4
public/js/station.js

@@ -266,10 +266,10 @@ const STATION_CONFIG_2 = [
         picPath: '/imgs/yx_hhht.JPG',
         preTag: '',
         data: [
-          { name: '管道里程', value: '0', unit: '', tmag: '' },
-          { name: '经度', value: '0', unit: '', tag: '' },
-          { name: '纬度', value: '0', unit: '', tag: '' },
-          { name: '高程', value: '0', unit: '', tmag: '' },
+          { name: '管道里程', value: '531237.0', unit: '', tmag: '' },
+          { name: '经度', value: '111.641454172,', unit: '', tag: '' },
+          { name: '纬度', value: '40.620619066', unit: '', tag: '' },
+          { name: '高程', value: '1025.135', unit: '', tmag: '' },
         ],
       },
       {

+ 8 - 0
src/API/accessControl.js

@@ -31,4 +31,12 @@ export const getAreaPersonList = data =>
     url: '/AccessControl/Log/GetAreaPersonList',
     data,
     notShowLoading: true,
+  })
+// 删除指定门禁区域人员信息
+export const setAreaPersonOut = data =>
+  $http({
+    method: 'POST',
+    url: '/AccessControl/Log/SetAreaPersonOut',
+    data,
+    notShowLoading: true,
   })

+ 9 - 0
src/API/custom.js

@@ -64,3 +64,12 @@ export const getCameraList = data =>
     data,
     notShowLoading: true,
   })
+
+  //获取人员信息
+export const getPersonList = data =>
+  $http({
+    method: 'post',
+    url: '/System/Person/GetPageListJson',
+    data,
+    notShowLoading: true,
+  })

+ 8 - 0
src/API/perimeter.js

@@ -28,3 +28,11 @@ export const getPerimeterListJson = data =>
     data,
     notShowLoading: true,
   })
+// 获取周界撤防)
+export const setWithdrawn = data =>
+  $http({
+    method: 'POST',
+    url: `/Perimeter/Config/Withdrawn`,
+    data,
+    notShowLoading: true,
+  })

+ 2 - 0
src/store/getters.js

@@ -10,7 +10,9 @@ const getters = {
   alarmDataCount: (state) => state.globalConfig.alarmDataCount,
   alarmAudio: (state) => state.globalConfig.alarmAudio,//全局报警声音
   oneKey110: (state) => state.globalConfig.oneKey110,//一键110
+  animationEnable: (state) => state.globalConfig.animationEnable,//报警光效
   soundDialog: (state) => state.globalConfig.soundDialog,//防爆扩音
+  voiceCallDialog: (state) => state.globalConfig.voiceCallDialog,//语音通话
   soundElementDialog: (state) => state.globalConfig.soundElementDialog,//防爆扩音图层元素弹窗
   accessControlDialog: (state) => state.globalConfig.accessControlDialog,//门禁控制
   jgytControlDialog: (state) => state.globalConfig.jgytControlDialog,//激光云台

+ 15 - 1
src/store/modules/globalConfig.js

@@ -6,9 +6,11 @@ const state = {
   switchConfigShow: false,
   alarmDataObj: {}, //所有报警信息的集合,用以实时更新lebel标签的数据,以及初次报警标签的显示
   alarmDataCount: 0,
-  alarmAudio: { show: false, alarmType: "all" },
+  alarmAudio: { show: false, alarmMsg: '', alarmType: "all" },
   oneKey110: { show: false, dialogMsg: {}, type: "all" },
+  animationEnable: { show: false, dialogMsg: {}, type: "all" },
   soundDialog: { show: false, dialogMsg: {}, type: "all" },
+  voiceCallDialog: { show: false, dialogMsg: {}, type: "all" },
   soundElementDialog: { show: false, dialogMsg: {}, type: "all" },
   accessControlDialog: { show: false, dialogMsg: {}, type: "all" },
   jgytControlDialog: { show: false, dialogMsg: {}, type: "all" },
@@ -52,9 +54,15 @@ const mutations = {
   SET_ONEKEY110(state, data) {
     state.oneKey110 = data;
   },
+  SET_ANIMATIONENABLE(state, data) {
+    state.animationEnable = data;
+  },
   SET_SOUNDDIALOG(state, data) {
     state.soundDialog = data;
   },
+  SET_VOICECALLDIALOG(state, data) {
+    state.voiceCallDialog = data;
+  },
   SET_SOUNDELEMENTDIALOG(state, data) {
     state.soundElementDialog = data;
   },
@@ -173,9 +181,15 @@ const actions = {
   setOneKey110({ commit }, data) {
     commit("SET_ONEKEY110", data);
   },
+  setAnimationEnable({ commit }, data) {
+    commit("SET_ANIMATIONENABLE", data);
+  },
   setSoundDialog({ commit }, data) {
     commit("SET_SOUNDDIALOG", data);
   },
+  setVoiceCallDialog({ commit }, data) {
+    commit("SET_VOICECALLDIALOG", data);
+  },
   setSoundElementDialog({ commit }, data) {
     commit("SET_SOUNDELEMENTDIALOG", data);
   },

+ 136 - 25
src/views/Home.vue

@@ -2,9 +2,14 @@
   <div class="home-container">
     <!-- 头部菜单 -->
     <base-header
+      id="drag"
       @openLayer="handleOpenLayer"
       v-show="hasToken && !fullScreen"
     />
+    <div id="animation-top" class="top"></div>
+    <div id="animation-bottom" class="bottom"></div>
+    <div id="animation-left" class="left"></div>
+    <div id="animation-right" class="right"></div>
     <router-view ref="routerView" />
     <!-- 底部背景 -->
     <div class="footer" v-show="hasToken && !fullScreen"></div>
@@ -23,6 +28,8 @@
     <onekey-110-dialog />
     <!-- 防爆扩音弹窗 由vuex控制 -->
     <sound-dialog />
+    <!-- 语音通话弹窗 由vuex控制 -->
+    <voice-call-dialog />
     <!-- 门禁弹窗 由vuex控制 -->
     <access-control-dialog />
     <!-- 激光云台 由vuex控制 -->
@@ -66,6 +73,7 @@ import ContactInfoDialog from "@/views/components/emergency/ContactInfoDialog";
 import PersonListDialog from "@/views/components/dialog/PersonListDialog";
 import Onekey110Dialog from "@/views/components/dialog/Onekey110Dialog";
 import SoundDialog from "@/views/components/dialog/SoundDialog";
+import VoiceCallDialog from "@/views/components/dialog/VoiceCallDialog";
 import AccessControlDialog from "@/views/components/dialog/AccessControlDialog";
 import JGYTControlDialog from "@/views/components/dialog/JGYTControlDialog";
 import AlarmDetailDialog from "@/views/components/dialog/AlarmDetailDialog";
@@ -81,6 +89,32 @@ export default {
     return {
       hasToken: false,
       fullScreen: false,
+      animationName: "yel",
+      animationStyle: `@keyframes yel{
+          0% {
+            box-shadow: 0 0 0px #ffffff;
+          }
+          50% {
+            box-shadow: #F8E71C 0px 0px 100px;
+          }
+          100% {
+            box-shadow: 0 0 0px #ffffff;
+          }
+        }`,
+      shadowColors: {
+        ["306001"]: { name: "重大级别", color: "#FF3636", anmationName: "red" },
+        ["306002"]: { name: "较大级别", color: "#FF9F00", anmationName: "ora" },
+        ["306003"]: { name: "一般级别", color: "#F8E71C", anmationName: "yel" },
+        ["306004"]: { name: "低级别", color: "#53A3FF", anmationName: "blue" },
+        ["024001"]: { name: "一级", color: "#FF3636", anmationName: "red" },
+        ["024002"]: { name: "二级", color: "#FF9F00", anmationName: "ora" },
+        ["024003"]: { name: "三级", color: "#53A3FF", anmationName: "blue" },
+        ["3"]: { name: "一级", color: "#FF3636", anmationName: "red" },
+        ["2"]: { name: "二级", color: "#FF3636", anmationName: "red" },
+        ["1"]: { name: "三级", color: "#53A3FF", anmationName: "blue" },
+        ["4"]: { name: "三级", color: "#53A3FF", anmationName: "blue" },
+        ["5"]: { name: "二级", color: "#FF9F00", anmationName: "ora" },
+      },
     };
   },
   components: {
@@ -94,6 +128,7 @@ export default {
     Onekey110Dialog,
     PersonListDialog,
     SoundDialog,
+    VoiceCallDialog,
     AccessControlDialog,
     JGYTControlDialog,
     AlarmAudioDialog,
@@ -108,6 +143,7 @@ export default {
       "alarmAudio",
       "oneKey110",
       "personListDialog",
+      "animationEnable",
     ]),
   },
   watch: {
@@ -115,6 +151,15 @@ export default {
       const token = localStorage.getItem("token");
       this.hasToken = !!token;
     },
+    "animationEnable.show": {
+      handler(newVal) {
+        setTimeout(() => {
+          this.updateShadow();
+        }, 200);
+      },
+      // deep: true,
+      immediate: true,
+    },
   },
   created() {
     this.$store.dispatch("mqtt/startMqtt");
@@ -194,6 +239,52 @@ export default {
     // }, 5000)
   },
   methods: {
+    updateShadow() {
+      if (
+        this.animationEnable.dialogMsg &&
+        this.animationEnable.dialogMsg.level
+      ) {
+        this.anmationName =
+          this.shadowColors[this.animationEnable.dialogMsg.level].anmationName;
+        this.animationStyle = `@keyframes ${this.anmationName}{
+          0% {
+            box-shadow: 0 0 0px ${
+              this.shadowColors[this.animationEnable.dialogMsg.level].color
+            };
+          }
+          50% {
+            box-shadow:${
+              this.shadowColors[this.animationEnable.dialogMsg.level].color
+            } 0px 0px 300px;
+          }
+          100% {
+            box-shadow: 0 0 0px ${
+              this.shadowColors[this.animationEnable.dialogMsg.level].color
+            };
+          }
+        }`;
+        document.styleSheets[0].insertRule(this.animationStyle, 0);
+      }
+      if (this.animationEnable.show) {
+        document.getElementById("animation-top").style.animation =
+          this.anmationName + " 2s infinite";
+        document.getElementById("animation-bottom").style.animation =
+          this.anmationName + " 2s infinite";
+        document.getElementById("animation-left").style.animation =
+          this.anmationName + " 2s infinite";
+        document.getElementById("animation-right").style.animation =
+          this.anmationName + " 2s infinite";
+      } else {
+        document.getElementById("animation-top").style.animation =
+          this.anmationName + " 0s infinite";
+        document.getElementById("animation-bottom").style.animation =
+          this.anmationName + " 0s infinite";
+        document.getElementById("animation-left").style.animation =
+          this.anmationName + " 0s infinite";
+        document.getElementById("animation-right").style.animation =
+          this.anmationName + " 0s infinite";
+      }
+    },
     /**
      * 根据图层名称打开图层,同时打开图元列表
      */
@@ -251,10 +342,10 @@ export default {
           // }
           else if (topic === "Message/New") {
             const data = JSON.parse(content);
-            console.log("系统消息:", data);
+            // console.log("系统消息:", data);
           } else if (topic === "Alarm/List") {
             const data = JSON.parse(content);
-            console.log("报警消息:", data);
+            // console.log("报警消息:", data);
             if (data[0]) {
               // setTimeout(() => {
               //   this.$store.dispatch("globalConfig/setAlarmAudio", {
@@ -283,11 +374,11 @@ export default {
             const data = JSON.parse(content);
             // console.log("门禁事件数据", data);
             this.$notify({
-              dangerouslyUseHTMLString: true,
-              customClass: "notify-info",
               title: "智能门禁",
+              duration: 1500, //自动关闭时间1.5s
               message: data.Content,
-              duration: 1500,//自动关闭时间1.5s
+              offset: 70,
+              type: "warning",
             });
             // if (this.$refs.routerView.$options.name === "basePage") {
             //   this.$refs.routerView.pushZnmjStatus(data);
@@ -296,13 +387,17 @@ export default {
             const data = JSON.parse(content);
             // console.log("周界报警数据", data);
             if (this.$refs.routerView.$options.name === "basePage") {
-              this.$refs.routerView.pushPerimeterStatus(data);
+              setTimeout(() => {
+                this.$refs.routerView.pushPerimeterStatus(data);
+              }, 200);
             }
           } else if (topic.startsWith("Fire/")) {
             const data = JSON.parse(content);
             // console.log("火灾报警数据", data);
             if (this.$refs.routerView.$options.name === "basePage") {
-              this.$refs.routerView.pushFireStatus(data);
+              setTimeout(() => {
+                this.$refs.routerView.pushFireStatus(data);
+              }, 200);
             }
           } else if (topic.startsWith("LaserPtz/")) {
             const data = JSON.parse(content);
@@ -310,8 +405,7 @@ export default {
             if (this.$refs.routerView.$options.name === "basePage") {
               setTimeout(() => {
                 this.$refs.routerView.pushJGYTStatus(data);
-                // this.$refs.routerView.pushPerimeterStatus(data)
-              }, 2000);
+              }, 200);
             }
           }
         },
@@ -323,22 +417,6 @@ export default {
   },
 };
 </script>
-<style>
-.notify-info {
-  top: 0.4rem !important;
-  right: 0.1rem !important;
-  width: 2rem !important;
-  background: rgba(24, 45, 77, 0.8) !important;
-  border-radius: 0.04rem 0px 0px 0.04rem !important;
-  border-color: #64bbff !important;
-}
-.el-notification__title {
-  color: white !important;
-}
-.el-notification__content {
-  color: white !important;
-}
-</style>
 <style lang="less" scoped>
 .home-container {
   pointer-events: none;
@@ -349,6 +427,39 @@ export default {
   background-image: url(~@/assets/imgs/mask.png);
   background-repeat: no-repeat;
   background-size: 100% 100%;
+  .top {
+    position: absolute;
+    left: 0;
+    top: -98px;
+    right: 0;
+    z-index: 10000;
+    height: 100px;
+  }
+  .bottom {
+    position: absolute;
+    left: 0;
+    right: 0;
+    bottom: -98px;
+    z-index: 10000;
+    height: 100px;
+  }
+  .left {
+    position: absolute;
+    left: -98px;
+    top: 0;
+    bottom: 0;
+    z-index: 10000;
+    width: 100px;
+  }
+  .right {
+    position: absolute;
+    right: -98px;
+    top: 0;
+    bottom: 0;
+    z-index: 10000;
+    width: 100px;
+    height: 100%;
+  }
   .footer {
     position: absolute;
     left: 50%;

+ 168 - 50
src/views/basePage/components/dialog/AlarmMapDialog.vue

@@ -6,10 +6,11 @@
       <div class="dialog_header_box">
         <div class="dialog_header_close" @click="handleClose"></div>
       </div>
-      <div class="dialog_content_box">
+      <div class="dialog_content_box" :key="refreshKey">
         <template v-if="alarmType === 'perimeter'">
           <div class="warn-title">
-            {{ dialogConfig.dialogMsg.data.name }}
+            {{ dialogConfig.dialogMsg.data.code }}
+            <!-- {{ dialogConfig.dialogMsg.data.segmentName }} -->
           </div>
           <div>
             当前状态:<span
@@ -37,14 +38,21 @@
           </div>
           <div class="perimeter-btn">
             <el-button class="handle-btn" @click="handleChangeDefense">
-              {{ dialogConfig.dialogMsg.data.defense ? "撤防" : "布防" }}
+              {{ dialogConfig.dialogMsg.data.withdrawn ? "布防" : "撤防" }}
             </el-button>
-            <el-button class="handle-btn" @click="handleCancelPerimeterAlarm">
+            <el-button
+              class="handle-btn"
+              @click="handleCancelPerimeterAlarm"
+              v-if="dialogConfig.dialogMsg.data.alarmStatus"
+            >
               报警消除
             </el-button>
           </div>
         </template>
         <template v-if="alarmType === 'fire'">
+          <div class="warn-title">
+            编号:{{ dialogConfig.dialogMsg.data.code }}
+          </div>
           <div class="warn-title">
             {{ dialogConfig.dialogMsg.data.name }}
           </div>
@@ -55,7 +63,7 @@
                 color: perimeterAlarmTypeColor,
               }"
             >
-              {{ perimeterAlarmType }}
+              {{ fireAlarmType }}
             </span>
           </div>
           <div>
@@ -69,7 +77,10 @@
           </div>
           <div
             class="perimeter-btn"
-            v-if="dialogConfig.dialogMsg.data.alarmType > 0"
+            v-if="
+              dialogConfig.dialogMsg.data.alarmType > 0 &&
+              dialogConfig.dialogMsg.data.alarmType !== 4
+            "
           >
             <el-button class="handle-btn" @click="handleCancelFireAlarm">
               报警消除
@@ -77,8 +88,18 @@
           </div>
         </template>
         <template v-if="alarmType === 'jgyt'">
-          <div class="warn-title">激光云台气体泄漏检测</div>
+          <div class="warn-title">{{ dialogConfig.dialogMsg.data.name }}</div>
           <div>
+            当前状态:<span
+              class="warn-type"
+              :style="{
+                color: perimeterAlarmTypeColor,
+              }"
+            >
+              {{ jgytAlarmType }}
+            </span>
+          </div>
+          <!-- <div>
             <span class="warn-label">当前状态:</span>
             <span
               class="warn-type"
@@ -93,31 +114,32 @@
                 dialogConfig.dialogMsg.data.alarmState === 1 ? "异常" : "正常"
               }}
             </span>
-          </div>
+          </div> -->
           <div v-if="dialogConfig.dialogMsg.data.alarmState === 1">
             <span class="warn-label">报警时间:</span>
             <span class="warn-time">
               {{ dialogConfig.dialogMsg.data.alarmTime }}
             </span>
           </div>
-          <div>
+          <div v-else>
             <span class="warn-label">时间:</span>
             <span class="warn-time">
               {{ dialogConfig.dialogMsg.data.dateTime }}
             </span>
           </div>
           <el-row class="jgyt-row-box">
-            <el-col
-              v-for="item in dialogConfig.dialogMsg.data.JGYTData"
-              :key="item.dataTag"
-              :span="12"
-            >
+            <el-col v-for="item in tags" :key="item.dataTag" :span="12">
               <span class="warn-label">{{ item.name }}:</span>
               <span class="warn-type">
-                {{ `${item.value} ${item.unit}` }}
+                {{ getTagsValue(item.dataTag) }}{{ item.unit }}
               </span>
             </el-col>
           </el-row>
+          <div class="jgyt-btn" v-if="dialogConfig.dialogMsg.data.alarmStatus">
+            <el-button class="handle-btn" @click="handleCancelJGYTAlarm">
+              报警消除
+            </el-button>
+          </div>
         </template>
         <template v-if="alarmType === 'rail'">
           <div class="warn-title">
@@ -152,7 +174,7 @@
           </div>
         </template>
       </div>
-      <div
+      <!-- <div
         class="handle-btn-box"
         v-if="
           dialogConfig.dialogMsg.data.alarmState === 1 ||
@@ -160,7 +182,7 @@
         "
       >
         <el-button class="handle-btn" @click="handleAlarm">立即处理</el-button>
-      </div>
+      </div> -->
     </div>
     <!-- <audio id="mapAlarmAudio" src="/audio/onekeyalarm.mp3" loop></audio> -->
   </div>
@@ -168,6 +190,7 @@
 
 <script>
 import { dealAlarm } from "@/API/common";
+import { setWithdrawn } from "@/API/perimeter";
 import Dayjs from "dayjs";
 import { mapGetters } from "vuex";
 export default {
@@ -190,32 +213,38 @@ export default {
     },
   },
   data() {
-    return {};
+    return {
+      refreshKey: 0,
+      tags: [
+        { name: "浓度值", dataTag: "ndTag", value: "0", unit: "ppm·m" },
+        { name: "光强度", dataTag: "gqTag", value: "0", unit: "" },
+        { name: "垂直角度", dataTag: "czTag", value: "0", unit: "" },
+        { name: "水平角度", dataTag: "spTag", value: "0", unit: "" },
+      ],
+    };
   },
   watch: {
     alarmType: {
       handler(val) {
-        if (val !== "jgyt") return;
-        let tags = [
-          { name: "浓度值", dataTag: "ndTag", value: "0", unit: "ppm·m" },
-          { name: "光强度", dataTag: "gqTag", value: "0", unit: "" },
-          { name: "垂直角度", dataTag: "czTag", value: "0", unit: "" },
-          { name: "水平角度", dataTag: "spTag", value: "0", unit: "" },
-        ];
-        for (let i = 0; i < tags.length; i++) {
-          let tag = tags[i];
-          let keys = Object.keys(this.rtData);
-          let tagValue = this.dialogConfig.dialogMsg.data.tags[tag.dataTag];
-          if (!!keys.length && !!tagValue) {
-            for (let j = 0; j < keys.length; j++) {
-              let key = keys[j];
-              if (tagValue === key) {
-                tag.value = this.rtData[key].Value;
+        console.log("页面数据:", this.dialogConfig);
+        this.refresh();
+        if (val == "jgyt") {
+          for (let i = 0; i < this.tags.length; i++) {
+            let tag = this.tags[i];
+            let keys = Object.keys(this.rtData);
+            let tagValue = this.dialogConfig.dialogMsg.data.tags[tag.dataTag];
+            if (!!keys.length && !!tagValue) {
+              for (let j = 0; j < keys.length; j++) {
+                let key = keys[j];
+                if (tagValue === key) {
+                  tag.value = this.rtData[key].Value;
+                }
               }
             }
           }
+          this.dialogConfig.dialogMsg.data["JGYTData"] = this.tags;
+          this.refresh();
         }
-        this.dialogConfig.dialogMsg.data["JGYTData"] = tags;
       },
       immediate: true,
     },
@@ -231,6 +260,44 @@ export default {
           return "警告";
         case 3:
           return "报警";
+        case 4:
+          return "撤防";
+        case 5:
+          return "故障";
+        default:
+          return "正常";
+      }
+    },
+    fireAlarmType() {
+      let alarmType = this.dialogConfig.dialogMsg.data.alarmType;
+      switch (alarmType) {
+        case 1:
+          return "离线";
+        case 2:
+          return "警告";
+        case 3:
+          return "报警";
+        case 4:
+          return "屏蔽";
+        case 5:
+          return "故障";
+        default:
+          return "正常";
+      }
+    },
+    jgytAlarmType() {
+      let alarmType = this.dialogConfig.dialogMsg.data.alarmType;
+      switch (alarmType) {
+        case 1:
+          return "离线";
+        case 2:
+          return "警告";
+        case 3:
+          return "报警";
+        case 4:
+          return "屏蔽";
+        case 5:
+          return "故障";
         default:
           return "正常";
       }
@@ -244,6 +311,10 @@ export default {
           return "#FFA500";
         case 3:
           return "#FF0000";
+        case 4:
+          return "#DCDCDC";
+        case 5:
+          return "#FFF100";
         default:
           return "#00FF00";
       }
@@ -252,23 +323,27 @@ export default {
   mounted() {
     // this.alarmType === "perimeter" &&
     //   document.getElementById("mapAlarmAudio").play();
-    // console.log(this.dialogConfig);
   },
   methods: {
+    refresh() {
+      this.refreshKey++;
+    },
     Dayjs,
     handleClose() {
       this.$emit("handleClose");
     },
     handleAlarm() {
-      this.handleClose();
       const id = this.dialogConfig.dialogMsg.data.alarmId;
-      console.log("立即处理事件信息", this.dialogConfig.dialogMsg);
-      dealAlarm({ id }).then(res => {
+      console.log("立即处理事件信息", this.dialogConfig);
+      dealAlarm({ id }).then((res) => {
         // 关闭摄像头弹窗,后续再优化
         if (!!this.dialogConfig.dialogMsg.data.cameraId) {
-          this.$store.dispatch('dialog/closeVideoDialog', this.dialogConfig.dialogMsg.data.cameraId)
+          this.$store.dispatch(
+            "dialog/closeVideoDialog",
+            this.dialogConfig.dialogMsg.data.cameraId
+          );
         }
-      })
+      });
       if (!!this.dialogConfig.dialogMsg.data.cameraId) {
         this.$store.dispatch(
           "dialog/closeVideoDialog",
@@ -288,14 +363,37 @@ export default {
         this.handleCancelFireAlarm();
         console.log("Fire");
       }
+      this.handleClose();
     },
     handleChangeDefense() {
-      this.dialogConfig.dialogMsg.data.defense =
-        !this.dialogConfig.dialogMsg.data.defense;
+      //按钮切换
+      this.dialogConfig.dialogMsg.data.withdrawn =
+        !this.dialogConfig.dialogMsg.data.withdrawn;
+      if (this.dialogConfig.dialogMsg.data.withdrawn) {
+        console.log("即将撤防完成");
+      } else {
+        console.log("即将布防完成");
+      }
+      const p = {
+        perimeterId: this.dialogConfig.dialogMsg.data.perimeterId,
+        segmentId: this.dialogConfig.dialogMsg.data.id,
+        withdrawn: this.dialogConfig.dialogMsg.data.withdrawn,
+        // perimeterId: this.dialogConfig.dialogMsg.data.id,
+        // segmentId: this.dialogConfig.dialogMsg.data.segmentId,
+        // withdrawn: this.dialogConfig.dialogMsg.data.withdrawn,
+      };
+      //布防撤防
+      setWithdrawn(p).then((res) => {
+        if (res.code === 20000) {
+          console.log("操作完成");
+        }
+      });
+      this.refresh();
+      // this.$emit("handleClose");
     },
     handleCancelPerimeterAlarm() {
-      console.log(this.dialogConfig.dialogMsg.data);
-      console.log(this.$parent.perimeterTagsData);
+      // console.log(this.dialogConfig.dialogMsg.data);
+      // console.log(this.$parent.perimeterTagsData);
       this.$emit("handleClose");
       this.$parent.pushPerimeterStatus({
         alarmPoint: null,
@@ -303,12 +401,14 @@ export default {
         buildId: this.buildInfo.positioningBuildId,
         camera: null,
         floorNo: 2,
-        segmentId: this.dialogConfig.dialogMsg.data.segmentId,
+        segmentId: this.dialogConfig.dialogMsg.data.id,
+        // segmentId: this.dialogConfig.dialogMsg.data.segmentId,
       });
+      this.refresh();
     },
     handleCancelFireAlarm() {
-      console.log(this.dialogConfig.dialogMsg.data);
-      console.log(this.$parent.fireTagsData);
+      // console.log(this.dialogConfig.dialogMsg.data);
+      // console.log(this.$parent.fireTagsData);
       this.$emit("handleClose");
       this.$parent.pushFireStatus({
         alarmPoint: null,
@@ -318,10 +418,12 @@ export default {
         floorNo: 2,
         id: this.dialogConfig.dialogMsg.data.id,
       });
+      this.refresh();
     },
     handleCancelJGYTAlarm() {
-      console.log(this.dialogConfig.dialogMsg.data);
-      console.log(this.$parent.jgytTagsData);
+      // console.log(this.dialogConfig.dialogMsg.data);
+      // console.log(this.$parent.jgytTagsData);
+      this.$emit("handleClose");
       this.$parent.pushJGYTStatus({
         alarmPoint: null,
         alarmType: -1,
@@ -330,6 +432,17 @@ export default {
         buildId: this.buildInfo.positioningBuildId,
         id: this.dialogConfig.dialogMsg.data.id,
       });
+      this.refresh();
+    },
+    getTagsValue(tag) {
+      if (this.dialogConfig.dialogMsg) {
+        let tagValue = this.dialogConfig.dialogMsg.data.tags[tag];
+        return this.rtData[tagValue] && this.rtData[tagValue].Value
+          ? this.rtData[tagValue].Value
+          : "";
+      } else {
+        return 0;
+      }
     },
   },
 };
@@ -417,6 +530,11 @@ export default {
     .perimeter-btn {
       margin-top: 10px;
     }
+    .jgyt-btn {
+      margin-top: 10px;
+      text-align: right;
+      padding-right: 10px;
+    }
     .handle-btn-box {
       // width: calc(100% - ) ;
       position: absolute;

+ 1 - 1
src/views/basePage/components/layerControl/index.vue

@@ -358,7 +358,7 @@ export default {
       const dataSource = viewer.dataSources.getByName("layer_" + id);
       if (dataSource.length) {
         const entities = dataSource[0].entities.values;
-        console.log("选中的所有实体", entities);
+        // console.log("选中的所有实体", entities);
         entities.forEach((item) => {
           item.show = state;
         });

+ 12 - 7
src/views/basePage/index.vue

@@ -13,7 +13,7 @@
       @showPersonLayer="showPersonLayer"
       @openBuilding="openBuilding"
     />
-    <footer-navigation/>
+    <footer-navigation />
     <!-- <footer-navigation v-show="mapMode.value === 'home'" /> -->
 
     <!-- 楼层控制 -->
@@ -283,7 +283,7 @@ export default {
   watch: {
     alarmDataObj: {
       handler(newVal) {
-        console.log("报警对象信息", newVal);
+        // console.log("报警对象信息", newVal);
         for (const key in newVal) {
           if (["perimeter", "jgyt", "fire"].includes(key)) {
             // 当前显示的弹窗
@@ -303,16 +303,20 @@ export default {
                 if (val.alarmState === 1 || val.alarmStatus === true) {
                   let position = [];
                   if (key === "jgyt") {
+                    // console.log("JGYT弹窗数据信息", this.mapDialogConfig[key]);
                     position = [+val.longitude, +val.latitude, +val.height];
                   } else if (key === "fire") {
-                    console.log("火灾弹窗数据信息", this.mapDialogConfig[key]);
+                    // console.log("火灾弹窗数据信息", this.mapDialogConfig[key]);
                     position = val.alarmPosition;
                   } else if (key === "perimeter") {
-                    console.log("周界弹窗数据信息", this.mapDialogConfig[key]);
+                    // console.log("周界弹窗数据信息", this.mapDialogConfig[key]);
                     position = [...val.alarmPosition, 4];
-                    if (val.segmentName) {
-                      val.name = val.name + val.segmentName;
+                    if (val.code) {
+                      val.name = val.name + val.code;
                     }
+                    // if (val.segmentName) {
+                    //   val.name = val.name + val.segmentName;
+                    // }
                   }
                   this.mapDialogConfig[key].push({
                     show: false,
@@ -320,6 +324,7 @@ export default {
                   });
                   let p1 = 132,
                     p2 = 236;
+                  key === "perimeter" && ((p1 = 140), (p2 = 236));
                   key === "jgyt" && ((p1 = 200), (p2 = 210));
                   key === "fire" && ((p1 = 150), (p2 = 236));
                   for (let data of this.mapDialogConfig[key]) {
@@ -367,7 +372,7 @@ export default {
     },
     openDialog,
     setMapMode(newValue) {
-      console.log("模式参数信息:",newValue.value);
+      console.log("模式参数信息:", newValue.value);
       const mode = MAP_MODE_LIST[newValue.value];
       if (!!mode) {
         console.log("模式切换");

+ 60 - 34
src/views/basePage/mixins/LoadLayer/JGYT.js

@@ -111,28 +111,27 @@ export default {
           !pre.hasOwnProperty(cur) && (pre[cur] = `DataCommunication/TagData/${jgytData[cur]}`)
           return pre
         }, {})
-        console.log(topics)
-        if (show) {
-          this.$store.dispatch('mqtt/subscribe', {
-            topic: Object.values(topics),
-            onMessage: (topic, message, packet) => {
-              // console.log(topic);
-              const content = message.toString()
-              if (topic === 'Online') {
-                // console.log(new Date(), content);
-              } else if (topic.startsWith('DataCommunication/TagData/')) {
-                //订阅的实时数据
-                //存储到vuex中
-                //console.log(content)
-                let data = JSON.parse(content)
-                let arr = new Array(1).fill(data)
-                this.$store.dispatch('globalConfig/updateRTData', arr)
-              }
-            },
-          })
-        } else {
-          this.$store.dispatch('mqtt/unsubscribe', Object.values(topics))
-        }
+        // if (show) {
+        this.$store.dispatch('mqtt/subscribe', {
+          topic: Object.values(topics),
+          onMessage: (topic, message, packet) => {
+            // console.log(topic);
+            const content = message.toString()
+            if (topic === 'Online') {
+              // console.log(new Date(), content);
+            } else if (topic.startsWith('DataCommunication/TagData/')) {
+              //订阅的实时数据
+              //存储到vuex中
+              //console.log(content)
+              let data = JSON.parse(content)
+              let arr = new Array(1).fill(data)
+              this.$store.dispatch('globalConfig/updateRTData', arr)
+            }
+          },
+        })
+        // } else {
+        //   this.$store.dispatch('mqtt/unsubscribe', Object.values(topics))
+        // }
       }
     },
     async getJGYTTagsData() {
@@ -168,6 +167,7 @@ export default {
           }
           // 新接口返回参数
           return {
+            panTag: +n.panTag,
             longitude: +n.longitude,
             latitude: +n.latitude,
             height: +n.height,
@@ -212,33 +212,39 @@ export default {
           }, 3000)
         }
       } else {
-        // this.animationJGYT(data)
+        this.animationJGYT(data)
       }
     },
     animationJGYT(data) {
       const viewer = getViewer()
       const dataSource = viewer.dataSources.getByName('layer_jgyt')[0]
-      console.log('激光云台报警', dataSource)
+      console.log('激光云台报警', data, dataSource)
       const entity1 = dataSource?.entities.getById(data.id)
       const entity2 = dataSource?.entities.getById('pt_' + data.id)
       if (!entity1 || !entity2) return
       const curJGYT = this.jgytTagsData.find(e => e.id === data.id)
       const cameraId = curJGYT?.cameraId
       if (data.alarmType > 0) {
+        //报警声音
         this.$store.dispatch("globalConfig/setAlarmAudio", {
           show: true,
           alarmType: data.alarmType,
         });
+        //报警联动
         setTimeout(() => {
           entity1.show = true
           entity2.show = true
+          //漂移
           flyToByViewer(entity2)
+          //摄像头联动
           if (cameraId) {
             this.$store.dispatch('dialog/openVideoDialog', cameraId)
           }
+          //报警弹窗消息
           this.$store.dispatch('globalConfig/updateAlarmDataObj', {
             jgyt: this.jgytTagsData.map(tag => {
               if (tag.id === data.id) {
+                tag.alarmId = data.alarmId
                 tag.alarmState = 1
                 tag.alarmType = data.alarmType
                 tag.alarmStatus = true
@@ -246,27 +252,44 @@ export default {
               return tag
             }),
           })
+          //报警光效
+          this.$store.dispatch("globalConfig/setAnimationEnable", {
+            show: true,
+            dialogMsg: {
+              level: data.alarmType,
+            },
+            type: "All",
+          });
         }, 1000)
       } else {
         this.$store.dispatch("globalConfig/setAlarmAudio", {
           show: false,
           alarmType: data.alarmType,
         });
-        entity1.show = false
-        entity2.show = false
+        entity1.show = true
+        entity2.show = true
         this.$store.dispatch('globalConfig/updateAlarmDataObj', {
-          jgyt: this.jgytTagsData.map(tag => {
+          jgyt: [this.jgytTagsData.map(tag => {
             if (tag.id === data.id) {
+              tag.alarmId = 0
               tag.alarmState = 0
               tag.alarmType = 0
               tag.alarmStatus = false
             }
             return tag
-          }),
+          })],
         })
         if (cameraId) {
           this.$store.dispatch('dialog/closeVideoDialog', cameraId)
         }
+        //报警光效
+        this.$store.dispatch("globalConfig/setAnimationEnable", {
+          show: false,
+          dialogMsg: {
+            level: data.alarmType,
+          },
+          type: "All",
+        });
         // setTimeout(() => {
         flyToPerspective(this.buildInfo?.perspective)
         // }, 1000)
@@ -276,6 +299,8 @@ export default {
       let dataSource = addNewDatasource('layer_jgyt')
       this.jgytTagsData.forEach((data, index) => {
         const jgytConfig = this.jgytConfig[index]
+        console.log("激光云台动画参数:", jgytConfig);
+
         dataSource.entities.add(
           new Entity({
             id: data.id,
@@ -334,31 +359,32 @@ export default {
     getPositionArr() {
       this.jgytConfig.forEach((data, index) => {
         if (data.scanType) {
-          // 实时扫描角度
-          // data.curHeading = 360 - this.rtData?.XLJCYT_PanPos?.Value + 90 || 0;
-        } else {
+
           // 模拟扫描角度
           // 通过最小最大角度的判断,使扫描可以来回重复
           if (data.boundaryType) {
             //到边界返回
             if (data.flog) {
-              data.curHeading += data.speed
+              data.curHeading += data.speed / 10
               if (data.curHeading >= data.maxHeading) {
                 data.flog = false
               }
             } else {
-              data.curHeading -= data.speed
+              data.curHeading -= data.speed / 10
               if (data.curHeading <= data.mixHeading) {
                 data.flog = true
               }
             }
           } else {
             //到边界从头开始
-            data.curHeading += data.speed
+            data.curHeading += data.speed / 10
             if (data.curHeading >= data.maxHeading) {
               data.curHeading = data.mixHeading
             }
           }
+        } else {
+          // 实时扫描角度
+          // data.curHeading = 360 - this.rtData?.XLJCYT_PanPos?.Value + 90 || 0;
         }
         data.positionArr = this.calcPoints(data.longitude, data.latitude, data.shortwaveRange, data.curHeading)
       })

+ 2 - 2
src/views/basePage/mixins/LoadLayer/accessControl.js

@@ -68,7 +68,7 @@ export default {
     },
     addZnmjTags() {
       let dataSource = addNewDatasource('layer_' + this.znmjDataSourceName)
-      console.log("智能门禁基础信息", this.znmjTagsData);
+      // console.log("智能门禁基础信息", this.znmjTagsData);
       this.znmjTagsData.forEach(d => {
         d.GPSPoints = this.transPosition([{ x: d.location.x, y: d.location.y, z: d.height }])
         dataSource.entities.add(
@@ -129,7 +129,7 @@ export default {
       const dataSource = viewer.dataSources.getByName('layer_znmj')
       if (dataSource.length > 0) {
         let item = dataSource[0].entities.getById(data.accessControl.id)
-        console.log(item, "地图实体数据", item.properties.details._value, '接收参数', data);
+        // console.log(item, "地图实体数据", item.properties.details._value, '接收参数', data);
         if (!!item) {
           const { longitude, latitude } = this.buildInfo.gpsCoordinate0
           const gpsAlarmPoint = _locate(item.properties.details._value.location.x, item.properties.details._value.location.y, { x: longitude, y: latitude })

+ 32 - 5
src/views/basePage/mixins/LoadLayer/fire.js

@@ -144,12 +144,21 @@ export default {
         if (!!item) {
           const { longitude, latitude } = this.buildInfo.gpsCoordinate0
           const gpsAlarmPoint = _locate(item.properties.details._value.location.x, item.properties.details._value.location.y, { x: longitude, y: latitude })
-          if (data.alarmType > 0) {
+          if (data.alarmType > 0 && data.alarmType !== 4) {
+            //报警声音
             this.$store.dispatch("globalConfig/setAlarmAudio", {
               show: true,
               alarmType: data.alarmType,
               data: data
             });
+            //报警光效
+            this.$store.dispatch("globalConfig/setAnimationEnable", {
+              show: true,
+              dialogMsg: {
+                level: data.alarmType,
+              },
+              type: "All",
+            });
             //报警点标记
             if (data.alarmPoint) {
               //地图元素
@@ -175,6 +184,7 @@ export default {
                   duration: 1.5,
                 })
                 //增加属性
+                item.properties.details._value.alarmId = data.alarmId
                 item.properties.details._value.alarmPoint = data.alarmPoint
                 item.properties.details._value.alarmType = data.alarmType
                 item.properties.details._value.camera = data.camera
@@ -204,13 +214,19 @@ export default {
               }, 200)
             }
           } else {
+            //报警声音
             this.$store.dispatch("globalConfig/setAlarmAudio", {
               show: false,
               alarmType: data.alarmType,
             });
-            // this.$store.dispatch('globalConfig/updateAlarmDataObj', {
-            //   fire: this.fireTagsData,
-            // })
+            //报警光效
+            this.$store.dispatch("globalConfig/setAnimationEnable", {
+              show: false,
+              dialogMsg: {
+                level: data.alarmType,
+              },
+              type: "All",
+            });
             item.show = true
             setTimeout(() => {
               item.billboard = {
@@ -221,8 +237,19 @@ export default {
               }
               item.position = Cartesian3.fromDegrees(gpsAlarmPoint.x, gpsAlarmPoint.y, item.properties.details._value.height)
             }, 200)
-            // console.log('c测试', gpsAlarmPoint, item);
 
+            //增加属性
+            item.properties.details._value.alarmId = 0
+            item.properties.details._value.alarmPoint = data.alarmPoint
+            item.properties.details._value.alarmType = data.alarmType
+            item.properties.details._value.camera = data.camera
+            item.properties.details._value.alarmState = 0
+            item.properties.details._value.alarmStatus = false
+            item.properties.details._value.alarmPosition = [gpsAlarmPoint.x, gpsAlarmPoint.y, item.properties.details._value.height]
+            this.$store.dispatch('globalConfig/updateAlarmDataObj', {
+              fire: [item.properties.details._value],
+            })
+            // console.log('火灾信息测试', gpsAlarmPoint, item.properties.details._value, this.fireTagsData);
           }
         }
       }

+ 45 - 8
src/views/basePage/mixins/LoadLayer/perimeter.js

@@ -161,7 +161,7 @@ export default {
           dataSource.entities.add(
             new Entity({
               id: seg.id,
-              name: perimeter.name + '分段' + seg.code,
+              name: perimeter.name + seg.code,
               show: false,
               wall: {
                 positions: Cartesian3.fromDegreesArrayHeights(positions),
@@ -199,7 +199,7 @@ export default {
           }, 3000)
         }
       } else {
-        // this.animationPerimeter(data)
+        this.animationPerimeter(data)
       }
     },
     animationPerimeter(data) {
@@ -223,16 +223,29 @@ export default {
           case 3:
             color = '#FF0000'
             break
+          case 5:
+            color = '#FFF100'
+            break
           default:
             break
         }
         let item = dataSource[0].entities.getById(data.segmentId)
         if (!!item) {
-          if (data.alarmType > 0 || data.alarmType < 4) {
+          if (data.alarmType > 0 && data.alarmType !== 4) {
+            //报警声音
             this.$store.dispatch("globalConfig/setAlarmAudio", {
               show: true,
+              // alarmMsg: '周界触发报警!',
               alarmType: data.alarmType,
             });
+            //报警光效
+            this.$store.dispatch("globalConfig/setAnimationEnable", {
+              show: true,
+              dialogMsg: {
+                level: data.alarmType,
+              },
+              type: "All",
+            });
             if (data.alarmPoint) {
               //地图元素
               let x = 1
@@ -279,11 +292,19 @@ export default {
                   },
                   duration: 1.5,
                 })
-
                 //报警分段标记
+                let perimeterSegmentData = {}
                 this.perimeterTagsData.forEach(tag => {
                   tag.segments.forEach(seg => {
                     if (seg.id === data.segmentId) {
+                      perimeterSegmentData = seg
+                      perimeterSegmentData.alarmId = data.alarmId//报警id
+                      perimeterSegmentData.alarmState = 1
+                      perimeterSegmentData.alarmType = data.alarmType
+                      perimeterSegmentData.alarmStatus = true
+                      perimeterSegmentData.alarmPosition = [gpsAlarmPoint.x, gpsAlarmPoint.y]
+
+                      tag.alarmId = data.alarmId//报警id
                       tag.alarmState = 1
                       tag.alarmType = data.alarmType
                       tag.alarmStatus = true
@@ -295,12 +316,12 @@ export default {
                       if (!!data.cameras?.length) {
                         tag.cameraId = data.cameras[0].cameraId
                       }
-                      //console.log("周界报警位置:" + seg);
+                      console.log("周界报警位置:" + seg, this.perimeterTagsData, perimeterSegmentData);
                     }
                   })
                 })
                 this.$store.dispatch('globalConfig/updateAlarmDataObj', {
-                  perimeter: this.perimeterTagsData,
+                  perimeter: [perimeterSegmentData],
                 })
                 if (!!data?.camera?.id) {
                   this.$store.dispatch('dialog/openVideoDialog', data.camera.id)
@@ -312,23 +333,39 @@ export default {
               item.position = null
             }
           } else {
+            let perimeterSegmentData = {}
             this.perimeterTagsData.forEach(tag => {
               tag.segments.forEach(seg => {
                 if (seg.id === data.segmentId) {
+                  perimeterSegmentData = seg
+                  perimeterSegmentData.alarmId = 0//报警id
+                  perimeterSegmentData.alarmState = 0
+                  perimeterSegmentData.alarmType = data.alarmType
+                  perimeterSegmentData.alarmStatus = false
+                  perimeterSegmentData.alarmPosition = [0, 0]
+
                   tag.alarmState = 0
-                  tag.alarmType = 0 //data.alarmType;
+                  tag.alarmType = data.alarmType //data.alarmType;
                   tag.alarmStatus = false
                   tag.alarmPosition = [0, 0]
                 }
               })
             })
             this.$store.dispatch('globalConfig/updateAlarmDataObj', {
-              perimeter: this.perimeterTagsData,
+              perimeter: [perimeterSegmentData],
             })
             this.$store.dispatch("globalConfig/setAlarmAudio", {
               show: false,
               alarmType: data.alarmType,
             });
+            //报警光效
+            this.$store.dispatch("globalConfig/setAnimationEnable", {
+              show: false,
+              dialogMsg: {
+                level: data.alarmType,
+              },
+              type: "All",
+            });
             item.wall.material = Color.fromCssColorString(color).withAlpha(0.8)
             item.show = this.perimeterTagsShow
             item.billboard = null

+ 49 - 7
src/views/basePage/mixins/MapEvent.js

@@ -24,6 +24,7 @@ export default {
   name: 'mapEvent',
   data() {
     return {
+      modelShow: false,
       tooltipDialogArr: [],
       alwaysShowDialogArr: [],
       overlapCamera: {
@@ -228,11 +229,13 @@ export default {
               this.showModelToolTip(pickObj.id.code, pickObj.id.name, pickObj, obj)
             } else if (type === 'layer_perimeter') {
               const data = pickObj.id.properties ? pickObj.id.properties.segment._value : ''
+              data.alarmStatus = false
               if (this.mapDialogConfig.perimeter.some(item => item.dialogMsg?.data?.id == data.id)) {
                 this.mapDialogConfig.perimeter = this.mapDialogConfig.perimeter.filter(
                   item => item.dialogMsg?.data?.id != data.id
                 )
               }
+              console.log("点击获取周界信息:", data);
               this.mapDialogConfig.perimeter.push({
                 show: false,
                 dialogMsg: { data, position: [longitude, latitude, height] },
@@ -257,6 +260,39 @@ export default {
                 })()
               }
 
+
+              // const perimeterData = pickObj.id.properties ? pickObj.id.properties.perimeter._value : ''
+              // const segmentData = pickObj.id.properties ? pickObj.id.properties.segment._value : ''
+              // console.log("点击获取周界信息:", perimeterData, segmentData, this.mapDialogConfig.perimeter);
+              // perimeterData.alarmStatus = false
+              // perimeterData.segmentName = '分段' + segmentData.code
+              // perimeterData.segmentId = segmentData.id
+              // perimeterData.withdrawn = segmentData.withdrawn
+              // perimeterData.cameras = segmentData.cameras
+              // this.mapDialogConfig.perimeter = [{
+              //   show: false,
+              //   dialogMsg: { data: perimeterData, position: [longitude, latitude, height] },
+              // }]
+              // console.log("周界信息", this.mapDialogConfig.perimeter)
+              // for (let d of this.mapDialogConfig.perimeter) {
+              //   ; (() => {
+              //     setTimeout(() => {
+              //       d.show = true
+              //       if (d.dialogMsg.data.cameras?.length) {
+              //         this.$store.dispatch('dialog/openVideoDialog', d.dialogMsg.data.cameras[0].cameraId)
+              //       }
+              //       this.$store.dispatch('home/setMapPopupConfig', {
+              //         isShow: true,
+              //         type: 'point',
+              //         position: d.dialogMsg?.position,
+              //         dialogid: 'perimeter_' + d.dialogMsg?.data?.id,
+              //         p1: 140,
+              //         p2: 236,
+              //       })
+              //     }, 0)
+              //   })()
+              // }
+
             } else if (type === 'layer_fire') {
               // if (this.mapDialogConfig.fire.some(item => item.dialogMsg?.data?.id == data.id)) {
               //   this.mapDialogConfig.fire = this.mapDialogConfig.fire.filter(
@@ -266,7 +302,7 @@ export default {
               const fireInfo = pickObj.id.properties._details._value
               const gpsAlarmPoint = this.transPosition([{ x: fireInfo.location.x, y: fireInfo.location.y, z: fireInfo.height }])
               console.log('坐标点转化', gpsAlarmPoint);
-              fireInfo.alarmType = -1
+              // fireInfo.alarmType = -1//强制报警类型调整
               this.mapDialogConfig.fire = []
               console.log("无报警", this.mapDialogConfig.fire);
               this.mapDialogConfig.fire.push({
@@ -357,6 +393,7 @@ export default {
             }
             //模型点击隐藏
             if (featureName.startsWith("综合楼")) {
+              this.modelShow = true
               setModelShow(//tkt
                 {
                   model: "tkt_yu0j1s",
@@ -367,6 +404,7 @@ export default {
                 false
               );
             } else if (featureName.startsWith("110KV变电所")) {
+              this.modelShow = true
               setModelShow(//tkt
                 {
                   model: "tkt_yu0j1s",
@@ -377,6 +415,7 @@ export default {
                 false
               );
             } else {
+              this.modelShow = false
               this.showModelToolTip(
                 feature.tileset.code,
                 feature.getProperty("id"),
@@ -397,7 +436,7 @@ export default {
             // } else {
             //   this.showModelToolTip(feature.tileset.code, feature.getProperty('id'), pickObj, obj)
             // }
-            //feature.show = false;
+            // feature.show = false;
           }
 
           if (feature instanceof Cesium3DTileFeature && feature.getProperty('name') !== '000000') {
@@ -468,9 +507,11 @@ export default {
       const handler = new ScreenSpaceEventHandler(scene.canvas)
       viewer.screenSpaceEventHandler.removeInputAction(ScreenSpaceEventType.RIGHT_CLICK)
       //鼠标右键点击人员,列出重叠人员,只有一个时不列出
-      
+
       handler.setInputAction(movement => {
-        setModelShow({ model: "tkt_yu0j1s" }, true);
+        if (this.modelShow) {
+          setModelShow({ model: "tkt_yu0j1s" }, true);
+        }
         //输入一些位置信息,调试用
         // 从笛卡尔坐标获取经纬度
         let position = viewer.scene.pickPosition(movement.position)
@@ -499,7 +540,7 @@ export default {
 
         if (cDefined(pickObj)) {
           if (pickObj.id && pickObj.id instanceof Entity) {
-            // console.log("鼠标位置信息", pickObj)
+            console.log("鼠标位置信息", pickObj)
             const type = pickObj.id.properties ? pickObj.id.properties._type._value : ''
             if (type === 'person') {
               this.overlapWindow.overlapPersons = [] //先清空
@@ -539,7 +580,7 @@ export default {
                   }
                 }
               })
-              console.log(this.overlapCamera.overlapCameras)
+              console.log("测试", multiObjs, this.overlapCamera.overlapCameras)
               if (this.overlapCamera.overlapCameras.length > 1) {
                 //说明有人员重叠,需要打开提示窗口
                 this.overlapCamera.show = true
@@ -558,10 +599,11 @@ export default {
                 if (v.id && v.id instanceof Entity) {
                   const vtype = v.id.properties ? v.id.properties._type._value : ''
                   if (vtype === 'layer_fire') {
-                    //console.log(v.id);
+                    console.log(v.id);
                     const fire = v.id.properties.details._value
                     this.overlapFire.overlapFires.push({
                       id: v.id.id,
+                      code: fire.code,
                       name: v.id.properties.details._value.name,
                       fire,
                     })

+ 1 - 1
src/views/basePage/panels/Overview.vue

@@ -224,7 +224,7 @@ export default {
     async getAlarmDataList() {
       try {
         const params = {
-          pageSize: 1000,
+          pageSize: 10000,
           pageIndex: 1,
           dealStatus: "", //0
           confirmStatus: "",

+ 68 - 17
src/views/basePage/panels/PersonStatistics.vue

@@ -15,7 +15,7 @@
           <div v-if="personList.length">
             <div class="item" v-for="item of personList" :key="item.id">
               <div class="left">
-                <img :src="item.imgUrl" @click="openPersonInfo" />
+                <img :src="item.imgUrl" @click="delInfo(item)" />
               </div>
               <div class="divider"></div>
               <div class="right">
@@ -186,7 +186,7 @@
 import BaseTitle from "./BaseTitle.vue";
 import VueSeamless from "vue-seamless-scroll";
 import { getPersonTypeList, getAccessInfo } from "@/API/positioning";
-import { getAreaPersonList, getAccessLogList } from "@/API/accessControl";
+import { setAreaPersonOut,getAreaPersonList, getAccessLogList } from "@/API/accessControl";
 import Dayjs from "dayjs";
 
 export default {
@@ -403,31 +403,49 @@ export default {
       try {
         let res = await getAreaPersonList({ id: "791707314364096512" });
         if (res.code === 20000) {
-          console.log(res);
+          // console.log(res);
           if (res.data.content != null && res.data.content != undefined) {
             let localList = [];
             let workList = [];
             let visitList = [];
             let personInfoList = [];
             res.data.content.forEach((i) => {
-              personInfoList.push({
-                id: i.workNo,
-                name: i.name,
-                pic: "",
-                type: i.positionName,
-                posi: i.positionName,
-                personType: i.typeName,
-                comp: i.companyName == null ? "" : i.companyName,
-                phone: i.telephone,
-                imgUrl:
-                  i.photoPath == null
-                    ? this.defaultPhoto
-                    : "/yapi" + i.photoPath,
-              });
+              if (i.typeBelong == 1) {
+                personInfoList.push({
+                  id: i.workNo,
+                  name: i.name,
+                  pic: "",
+                  type: i.positionName,
+                  posi: i.positionName,
+                  personType: i.typeName,
+                  comp: i.departmentName == null ? "" : i.departmentName,
+                  phone: i.telephone,
+                  imgUrl:
+                    i.photoPath == null
+                      ? this.defaultPhoto
+                      : "/yapi" + i.photoPath,
+                });
+              } else {
+                personInfoList.push({
+                  id: i.workNo,
+                  name: i.name,
+                  pic: "",
+                  type: i.positionName,
+                  posi: i.positionName,
+                  personType: i.typeName,
+                  comp: i.companyName == null ? "" : i.companyName,
+                  phone: i.telephone,
+                  imgUrl:
+                    i.photoPath == null
+                      ? this.defaultPhoto
+                      : "/yapi" + i.photoPath,
+                });
+              }
               switch (i.type) {
                 //访客
                 case "546093319541760000":
                   visitList.push({
+                    id:i.id,
                     workNo: i.workNo,
                     name: i.name,
                   });
@@ -435,6 +453,7 @@ export default {
                 //施工
                 case "403245878963347456":
                   workList.push({
+                    id:i.id,
                     workNo: i.workNo,
                     name: i.name,
                   });
@@ -442,6 +461,7 @@ export default {
                 //员工
                 case "255022541838691649":
                   localList.push({
+                    id:i.id,
                     workNo: i.workNo,
                     name: i.name,
                   });
@@ -468,6 +488,37 @@ export default {
         console.log(error);
       }
     },
+    async delPersonMessage(item) {
+      try {
+        let res = await setAreaPersonOut({ areaId: '791707314364096512', personId: item.id });
+      } catch (error) {
+        console.log(error);
+      }
+    },
+    delInfo(item) {
+      this.$confirm("是否将" + item.name + "从入场列表中删除,?", "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning",
+      })
+        .then(() => {
+          console.log("删除" + item.name + "人员已入场信息!");
+          this.delPersonMessage(item)//删除接口
+          this.$message({
+            type: "success",
+            message: "删除成功!",
+          });
+          setTimeout(() => {
+            this.getMessage();
+          }, 500);
+        })
+        .catch(() => {
+          this.$message({
+            type: "info",
+            message: "已取消删除",
+          });
+        });
+    },
   },
 };
 </script>

+ 1 - 1
src/views/basePage/panels/RiskHint.vue

@@ -156,7 +156,7 @@ export default {
       } catch (err) {}
     },
     openRiskDialog(data) {
-      console.log(data);
+      console.log("风险报警数据", data);
       let dialogConfig = {
         dialogId: "risk_" + data.id,
         show: true, //是否显示

+ 8 - 0
src/views/components/baseFooter/FooterNavigation.vue

@@ -225,6 +225,14 @@ export default {
               type: "All",
             });
             break;
+          case "yyth":
+            console.log("语音通话");
+            this.$store.dispatch("globalConfig/setVoiceCallDialog", {
+              show: true,
+              dialogMsg: {},
+              type: "All",
+            });
+            break;
 
           default:
             break;

+ 22 - 17
src/views/components/baseHeader/left.vue

@@ -74,6 +74,9 @@
             <el-dropdown-item @click.native="test2">
               <span style="display: block">110一键报警</span>
             </el-dropdown-item>
+            <!-- <el-dropdown-item @click.native="test5">
+              <span style="display: block">报警动画</span>
+            </el-dropdown-item> -->
             <!-- <el-dropdown-item @click.native="messageInfo">
               <span style="display: block">弹窗</span>
             </el-dropdown-item> -->
@@ -303,6 +306,25 @@ export default {
         type: "All",
       });
     },
+    test5() {
+      console.log("报警动画");
+      this.$store.dispatch("globalConfig/setAnimationEnable", {
+        show: true,
+        dialogMsg: {
+          level: "024003",
+        },
+        type: "All",
+      });
+      setTimeout(() => {
+        this.$store.dispatch("globalConfig/setAnimationEnable", {
+          show: false,
+          dialogMsg: {
+            level: "024003",
+          },
+          type: "All",
+        });
+      }, 5000);
+    },
     test1() {
       this.setShouldAnimation(true);
       setTimeout(() => {
@@ -348,7 +370,6 @@ export default {
       this.$notify({
         //样式style块
         dangerouslyUseHTMLString: true,
-        customClass: "notify-info",
         title: "智能门禁",
         message:
           "【郝波】在门禁【托克托出站门禁】人脸认证通过,离开【托克托压气站】",
@@ -660,22 +681,6 @@ export default {
   },
 };
 </script>
-<style>
-.notify-info {
-  top: 0.4rem !important;
-  right: 0.1rem !important;
-  width: 2rem !important;
-  background: rgba(24, 45, 77, 0.8) !important;
-  border-radius: 0.04rem 0px 0px 0.04rem !important;
-  border-color: #64bbff !important;
-}
-.el-notification__title {
-  color: white !important;
-}
-.el-notification__content {
-  color: white !important;
-}
-</style>
 <style lang="less" scoped>
 .base-header-container {
   // width: 1920px;

+ 31 - 24
src/views/components/dialog/AccessControlDialog.vue

@@ -95,6 +95,7 @@
             <div class="select_video">
               <div class="select_video_main">
                 <video-image-window
+                  :key="refreshKey"
                   :cameraData="cameraFaceInfo1.camera"
                   :cameraId="cameraFaceInfo1.camera.id"
                 />
@@ -126,6 +127,7 @@
             <div class="select_video">
               <div class="select_video_main">
                 <video-image-window
+                  :key="refreshKey"
                   :cameraData="cameraFaceInfo2.camera"
                   :cameraId="cameraFaceInfo2.camera.id"
                 />
@@ -213,12 +215,17 @@ import Dayjs from "dayjs";
 import { mapGetters } from "vuex";
 export default {
   name: "accessControlDialog",
-  components: { BaseDragBgDialog, BaseTableList, VideoImageWindow },
+  components: {
+    BaseDragBgDialog,
+    BaseTableList,
+    VideoImageWindow,
+  },
   watch: {
     "accessControlDialog.show": {
       handler(newVal) {
         this.baseDialogConfig.show = newVal;
         if (newVal) {
+          this.getCameraList();
           this.initAccessControlList("");
           this.initAccessLogList();
         }
@@ -230,8 +237,10 @@ export default {
       handler(newValue, oldValue) {
         // this.filterKey = "";
         this.tableConfig.tableData = newValue;
+        console.log("门禁列表-摄像头列表", newValue, this.cameraList);
         if (newValue && newValue.length > 0) {
-          this.getCameraList();
+          this.getAccessCameraList();
+          this.filterInfo();
         }
         this.refresh();
       },
@@ -304,7 +313,7 @@ export default {
         { id: "3", name: "摄像头3" },
       ],
       cameraFaceInfo1: { id: "1", name: "摄像头1", camera: { id: "1" } },
-      cameraFaceInfo2: { id: "1", name: "摄像头1", camera: { id: "1" } },
+      cameraFaceInfo2: { id: "2", name: "摄像头2", camera: { id: "2" } },
       cameraCarInfo1: { id: "2", name: "摄像头2", camera: { id: "1" } },
       cameraCarInfo2: { id: "3", name: "摄像头3", camera: { id: "1" } },
       departmentOptions: [],
@@ -322,6 +331,7 @@ export default {
     // this.initAccessControlList("");
     // this.initAccessLogList();
     // this.getDepartmentByPid();
+    // this.getCameraList();
     this.departmentOptions = GY_STATIONS.filter((e) => e.id !== "");
   },
   computed: {
@@ -342,7 +352,7 @@ export default {
         };
         const res = await getAccessInfoList(params);
         this.dataList = res.data.content;
-        // console.log("门禁列表", this.dataList);
+        console.log("门禁列表", this.dataList);
       } catch (err) {
         console.log(err);
       }
@@ -359,7 +369,7 @@ export default {
         };
         const res = await getAccessLogList(params);
         this.recordList = res.data.content;
-        // console.log("门禁事件列表", params, this.recordList);
+        console.log("门禁事件列表", params, this.recordList);
       } catch (err) {
         console.log(err);
       }
@@ -372,28 +382,25 @@ export default {
         };
         const res = await getCameraList(params);
         this.cameraList = res.data.content;
-        // console.log("摄像头列表", this.cameraList);
-        if (this.dataList && this.dataList.length > 1) {
-          this.cameraFaceList = [];
-          this.cameraCarList = [];
-          for (let i = 0; i < this.dataList.length; i++) {
-            const e = this.dataList[i];
-            if (e.faceRecognition) {
-              this.cameraFaceList.push(e);
-            } else {
-              this.cameraCarList.push(e);
-            }
-          }
-        }
-        // //人脸识别列表
-        // this.cameraFaceList = this.dataList.filter((e) => e.faceRecognition);
-        // //车辆识别列表
-        // this.cameraCarList = this.dataList.filter((e) => !e.faceRecognition);
-        this.filterInfo();
+        console.log("摄像头列表", this.cameraList);
       } catch (err) {
         console.log(err);
       }
     },
+    getAccessCameraList() {
+      if (this.dataList && this.dataList.length > 1) {
+        this.cameraFaceList = [];
+        this.cameraCarList = [];
+        for (let i = 0; i < this.dataList.length; i++) {
+          const e = this.dataList[i];
+          if (e.faceRecognition) {
+            this.cameraFaceList.push(e);
+          } else {
+            this.cameraCarList.push(e);
+          }
+        }
+      }
+    },
     filterCamera(c) {
       if (this.cameraList && this.cameraList.length > 0) {
         var a = c;
@@ -495,7 +502,7 @@ export default {
             this.cameraCarList[this.cameraCarList.length - 1]
           );
         }
-      }, 300);
+      }, 1000);
       // console.log(
       //   "门禁摄像头",
       //   this.cameraFaceInfo,

+ 13 - 8
src/views/components/dialog/AlarmAudioDialog.vue

@@ -18,9 +18,7 @@ export default {
       default() {
         return {
           show: false,
-          dialogMsg: {
-            data: {},
-          },
+          alarmMsg: "",
           alarmType: "",
         };
       },
@@ -44,7 +42,7 @@ export default {
         //关闭声音
         document.getElementById("mapAlarmAudio").pause();
         document.getElementById("mapAlarmAudio").load();
-        console.log("报警声音是否启动:", val);
+        // console.log("报警声音是否启动:", val);
         if (val.show && document.getElementById("mapAlarmAudio")) {
           if (val.alarmType) {
             //报警类型匹配报警声音
@@ -65,6 +63,12 @@ export default {
                 this.alarmURL = "/audio/longalarm.mp3";
                 break;
               case "2":
+                this.alarmURL = "/audio/inoutalarm.mp3";
+                break;
+              case "4":
+                this.alarmURL = "/audio/onekeyalarm.mp3";
+                break;
+              case "5":
                 this.alarmURL = "/audio/onekeyalarm.mp3";
                 break;
               case "3":
@@ -85,15 +89,16 @@ export default {
           }
           setTimeout(() => {
             document.getElementById("mapAlarmAudio").play();
-            console.log("报警声音", document.getElementById("mapAlarmAudio"));
+            // console.log("报警声音", document.getElementById("mapAlarmAudio"));
           }, 200);
           setTimeout(() => {
             document.getElementById("mapAlarmAudio").pause();
             document.getElementById("mapAlarmAudio").load();
-            if (this.alarmMsg) {
-              // this.speak(); //语音播报报警
-            }
           }, 10000);
+          // this.alarmMsg = val.alarmMsg?.length > 0 ? val.alarmMsg : "";
+          // if (this.alarmMsg) {
+          //   this.speak(); //语音播报报警
+          // }
         } else {
           document.getElementById("mapAlarmAudio").pause();
           document.getElementById("mapAlarmAudio").load();

+ 12 - 78
src/views/components/dialog/JGYTControlDialog/index.vue

@@ -45,7 +45,6 @@
                   size="mini"
                   clearable
                   placeholder="请选择摄像头"
-                  @change="exchangeVideo()"
                 >
                   <el-option
                     v-for="item in cameraList"
@@ -92,7 +91,6 @@
                   size="mini"
                   clearable
                   placeholder="请选择摄像头"
-                  @change="exchangeVideo()"
                 >
                   <el-option
                     v-for="item in cameraList"
@@ -263,7 +261,7 @@ export default {
           },
         ],
       },
-      cameraList: [{ id: "1", name: "摄像头1" }],
+      cameraList: [{ id: "1", name: "" }],
       jgyt1: {},
       jgyt2: {},
       cameraInfo1: {
@@ -277,8 +275,6 @@ export default {
         id: "",
         positioningBuildId: "",
       },
-      tagList: [],
-      tagDataList: [],
     };
   },
   created() {
@@ -290,7 +286,7 @@ export default {
     this.departmentOptions = GY_STATIONS.filter((e) => e.id !== "");
   },
   computed: {
-    ...mapGetters(["jgytControlDialog"]),
+    ...mapGetters(["rtData", "jgytControlDialog"]),
   },
   mounted() {},
   methods: {
@@ -307,15 +303,16 @@ export default {
         const res = await getJGYTList(params);
         this.dataList = res.data.content;
         // console.log("激光云台列表", this.dataList);
-        this.startMqtt();
         if (this.dataList && this.dataList.length > 0) {
           this.jgyt1 = this.dataList[0];
           this.jgyt2 = this.dataList[this.dataList.length - 1];
         }
         this.cameraList = this.dataList.map((e) => e.camera);
         if (this.cameraList && this.cameraList.length > 0) {
-          this.cameraInfo1 = this.cameraList[0];
-          this.cameraInfo2 = this.cameraList[this.cameraList.length - 1];
+          setTimeout(() => {
+            this.cameraInfo1 = this.cameraList[0];
+            this.cameraInfo2 = this.cameraList[this.cameraList.length - 1];
+          }, 300);
         }
         // console.log("激光云台摄像头列表",this.cameraList,this.cameraInfo1,this.cameraInfo2);
       } catch (err) {
@@ -417,78 +414,15 @@ export default {
         }
       }
     },
-    startMqtt() {
-      const topics = this.tagList;
-      const _this = this;
-      this.$store.dispatch("mqtt/subscribe", {
-        topic: ["DataCommunication/TagData/#"],
-        onMessage: (topic, message, packet) => {
-          const content = message.toString();
-          if (topic.startsWith("DataCommunication/TagData/")) {
-            let data = JSON.parse(content);
-            Vue.set(this.tagDataList, data.Tag, data);
-          }
-        },
-      });
-      setTimeout(() => {
-        this.refreshSubscribe();
-        // console.log("激光云台弹窗实时数据:", this.tagDataList);
-      }, 1000);
-      this.$once("hook:beforeDestroy", () => {
-        this.$store.dispatch("mqtt/unsubscribe", topics);
-      });
-    },
-    refreshSubscribe() {
-      // this.tagDataList = {};
-      // console.log(this.mqttClient.connected);
-      if (this.mqttClient && this.mqttClient.connected) {
-        let tags = [];
-        if (this.dataList) {
-          //激光云台设备列表
-          if (this.tagList.length == 0) {
-            this.dataList.forEach((e) => {
-              if (e.type === 1) {
-                tags.push(`DataCommunication/TagData/` + e.concentrationTag);
-                tags.push(`DataCommunication/TagData/` + e.lightIntensityTag);
-                tags.push(`DataCommunication/TagData/` + e.panTag);
-                tags.push(`DataCommunication/TagData/` + e.tileTag);
-              } else {
-                tags.push(
-                  `DataCommunication/TagData/` + e.dahua_ConcentrationLelTag
-                );
-                tags.push(
-                  `DataCommunication/TagData/` + e.dahua_ConcentrationTag
-                );
-                tags.push(
-                  `DataCommunication/TagData/` + e.dahua_PresetIndexTag
-                );
-                tags.push(`DataCommunication/TagData/` + e.dahua_PresetNameTag);
-              }
-            });
-            this.tagList = tags;
-          }
-        }
-        // console.log("newTopic", tags);
-        let unsubscribeTopicArray = lodash.difference(this.tagList, tags);
-        if (unsubscribeTopicArray.length > 0) {
-          //console.log('解除订阅', unsubscribeTopicArray)
-          this.mqttClient.unsubscribe(unsubscribeTopicArray);
-        }
-        let subscribeTopicArray = lodash.difference(tags, this.tagList);
-        if (subscribeTopicArray.length > 0) {
-          //console.log('订阅', subscribeTopicArray)
-          this.mqttClient.subscribe(subscribeTopicArray);
-        }
-        this.tagList = tags;
+    getTagsValue(tagValue) {
+      if (tagValue) {
+        return this.rtData[tagValue] && this.rtData[tagValue].Value
+          ? this.rtData[tagValue].Value
+          : "";
       } else {
-        setTimeout(() => {
-          this.refreshSubscribe();
-        }, 1000);
+        return 0;
       }
     },
-    getTagsValue(tag) {
-      return this.tagDataList[tag]&&this.tagDataList[tag].Value?this.tagDataList[tag].Value:"";
-    },
   },
 };
 </script>

+ 7 - 8
src/views/components/dialog/RiskTipDialog.vue

@@ -141,7 +141,7 @@
               >取消</el-button
             >
             <el-button class="btn-handle" size="mini" @click="handleDeal"
-              >解除</el-button
+              >确认</el-button
             >
           </div>
         </div>
@@ -153,9 +153,8 @@
 <script>
 import { mapGetters } from "vuex";
 import { eliminateRisk } from "@/API/risk.js";
+import { dealAlarm } from "@/API/alarm";
 import Dayjs from "dayjs";
-import { update } from "lodash-es";
-import { animation } from "maptalks";
 export default {
   name: "RiskTipDialog",
   props: {
@@ -226,7 +225,7 @@ export default {
     window.addEventListener("resize", this.pxToRem);
   },
   computed: {
-    ...mapGetters(["riskDialogs","alarmAudio"]),
+    ...mapGetters(["riskDialogs", "alarmAudio"]),
     zIndex() {
       const config = this.riskDialogs.find(
         (e) => e.dialogId === this.dialogConfig?.dialogId
@@ -287,10 +286,10 @@ export default {
     async handleDeal() {
       try {
         const { code, msg } = await eliminateRisk([this.dialogConfig.data.id]);
-        this.$message({
-          type: code == 20000 ? "success" : "danger",
-          message: msg,
-        });
+        // this.$message({
+        //   type: code == 20000 ? "success" : "danger",
+        //   message: msg,
+        // });
         this.$store.dispatch("globalConfig/setDrawRiskTime", Dayjs(new Date()));
         this.handleClose();
       } catch (error) {

+ 111 - 0
src/views/components/dialog/VoiceCallDialog/Dialer.vue

@@ -0,0 +1,111 @@
+<template>
+  <div class="dialer-container">
+    <!-- 显示输入的电话号码 -->
+    <el-input type="text" v-model="currentPhoneNumber" readonly />
+    <div class="dialer-buttons">
+      <!-- 循环生成数字按钮 -->
+      <el-button
+        v-for="number in numbers"
+        type="primary"
+        :key="number"
+        :class="{ 'special-number': number === '1' }"
+        @click="appendNumber(number)"
+      >
+        {{ number }}
+      </el-button>
+    </div>
+    <!-- 语音输入按钮 -->
+    <el-button type="info" @click="startVoiceInput"> 语音输入 </el-button>
+    <!-- 清除输入的电话号码 -->
+    <el-button type="warning" @click="clearNumber">清除</el-button>
+    <!-- 模拟拨号操作 -->
+    <el-button type="success" @click="callNumber">拨号</el-button>
+    <!-- 模拟拨号操作 -->
+    <el-button type="danger" @click="downNumber">挂断</el-button>
+  </div>
+</template>
+  
+  <script>
+export default {
+  props: {
+    phoneNumber: {
+      type: String,
+      default: "",
+    },
+  },
+  data() {
+    return {
+      // 拨号盘上的数字和符号
+      numbers: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "*", "0", "#"],
+    };
+  },
+  computed: {
+    currentPhoneNumber: {
+      get() {
+        return this.phoneNumber;
+      },
+      set(value) {
+        // 当输入框的值改变时,通过自定义事件将新值传递给父组件
+        this.$emit("update:phoneNumber", value);
+      },
+    },
+  },
+  methods: {
+    appendNumber(number) {
+      this.currentPhoneNumber += number;
+    },
+    clearNumber() {
+      this.currentPhoneNumber = "";
+    },
+    callNumber() {
+      if (this.currentPhoneNumber) {
+        alert(`正在拨打号码: ${this.currentPhoneNumber}`);
+      } else {
+        alert("请输入电话号码");
+      }
+    },
+    startVoiceInput() {
+      const recognition = new (window.SpeechRecognition ||
+        window.webkitSpeechRecognition)();
+      recognition.lang = "zh-CN";
+
+      recognition.onresult = (event) => {
+        const transcript = event.results[0][0].transcript;
+        this.currentPhoneNumber = transcript.replace(/[^0-9*#]/g, "");
+      };
+      recognition.start();
+    },
+  },
+};
+</script>
+  
+  <style scoped>
+.dialer-container {
+  margin: 20px auto;
+  width: 300px;
+  text-align: center;
+  font-weight: bold; /* 文字加粗 */
+}
+.dialer-buttons {
+  margin: 10px auto;
+  display: grid;
+  grid-template-columns: repeat(3, 3fr);
+  gap: 4px;
+}
+
+.dialer-buttons button {
+  padding: 10px;
+  font-size: 20px;
+}
+
+button {
+  font-size: 20px;
+  margin: 5px;
+}
+
+/* 定义数字 1 的特殊样式 */
+.special-number {
+  margin-left: 10px;
+  color: #ffffff; /* 文字颜色为白色 */
+}
+</style>

+ 153 - 0
src/views/components/dialog/VoiceCallDialog/index.vue

@@ -0,0 +1,153 @@
+<template>
+  <base-drag-bg-dialog
+    :dialogConfig="baseDialogConfig"
+    @handleClose="closeDialog"
+    @onActivated="onActivated"
+  >
+    <!-- 弹窗内容 -->
+    <div class="dialog_box">
+      <!-- 内容 -->
+      <div class="dialog_content_box">
+        <el-row>
+          <el-col :span="11">
+            <div class="content">
+              <div class="title">拨号盘</div>
+              <div class="voice">
+                <Dialer
+                  :phoneNumber="parentPhoneNumber"
+                  @update:phoneNumber="parentPhoneNumber = $event"
+                />
+              </div>
+            </div>
+          </el-col>
+          <el-col :span="13">
+            <div class="content">
+              <div class="title">通讯录</div>
+              <div class="table">
+                <base-table-list
+                  :tableConfig="tableConfig"
+                  @handleClick="handleTableClick"
+                />
+              </div>
+            </div>
+          </el-col>
+        </el-row>
+      </div>
+    </div>
+  </base-drag-bg-dialog>
+</template>
+<script>
+import BaseDragBgDialog from "@/views/components/base/BaseDragBgDialog.vue";
+import BaseTableList from "@/views/components/base/BaseTableList";
+import Dialer from "./Dialer.vue";
+import { getPersonList } from "@/API/custom";
+
+import { mapGetters } from "vuex";
+export default {
+  name: "VoiceCallDialog",
+  components: { BaseDragBgDialog, BaseTableList, Dialer },
+  watch: {
+    "voiceCallDialog.show": {
+      handler(newVal) {
+        this.baseDialogConfig.show = newVal;
+        this.init();
+      },
+      // deep: true,
+      immediate: true,
+    },
+  },
+  data() {
+    return {
+      BASE_URL,
+      parentPhoneNumber: "",
+      baseDialogConfig: {
+        dialogId: "VoiceCall",
+        show: false,
+        title: "语音通话",
+        width: 800,
+        height: 510,
+        center: true,
+        zIndex: 10,
+      },
+      tableConfig: {
+        needIndex: false,
+        height: 380,
+        header: [
+          { title: "姓名", prop: "name", width: "" },
+          { title: "号码", prop: "telephone", width: "" },
+          {
+            title: "操作",
+            prop: "operation",
+            width: "",
+            btns: [{ btnName: "拨号", btnType: "open" }],
+          },
+        ],
+        tableData: [],
+        rowClick: this.location,
+      },
+    };
+  },
+  computed: {
+    ...mapGetters(["voiceCallDialog"]),
+  },
+  mounted() {},
+  methods: {
+    async init() {
+      try {
+        const res = await getPersonList({});
+        if (res.code === 20000) {
+          this.tableConfig.tableData = res.data.content.filter((item) => {
+            return item.telephone && item.telephone.length > 0;
+          });
+          console.log("人员列表:", res, this.tableConfig.tableData);
+        }
+      } catch (err) {
+        console.log(err);
+      }
+    },
+    closeDialog() {
+      this.$store.dispatch("globalConfig/setVoiceCallDialog", {
+        show: false,
+        dialogMsg: {},
+        type: "All",
+      });
+    },
+    onActivated() {
+      this.$nextTick(() => {
+        this.$refs.dealContent.focus();
+      });
+    },
+    handleTableClick(data, btnType) {
+      if (btnType === "open") {
+        console.log("拨号", data);
+        this.parentPhoneNumber = data.telephone;
+      }
+    },
+  },
+};
+</script>
+<style lang="less" scoped>
+.dialog_box {
+  width: 100%;
+  height: 100%;
+  box-sizing: border-box;
+  position: absolute;
+  z-index: 4000;
+  .dialog_content_box {
+    color: #fff;
+    font-size: large;
+    .content {
+      .title {
+      }
+      .voice {
+      }
+      .table {
+        width: 94%;
+        text-align: left;
+        margin-top: 20px;
+        margin-left: -10px;
+      }
+    }
+  }
+}
+</style>