dedsudiyu il y a 1 mois
Parent
commit
ebf477d0a3
2 fichiers modifiés avec 607 ajouts et 500 suppressions
  1. 602 0
      src/components/voiceBroadcast/voiceBroadcast.vue
  2. 5 500
      src/views/alarmPage/index.vue

+ 602 - 0
src/components/voiceBroadcast/voiceBroadcast.vue

@@ -0,0 +1,602 @@
+<template>
+  <div class="voiceBroadcast">
+    <div class="null-box" @click="offButton()"></div>
+    <p class="get-button"
+       v-if="showPermissionButton"
+       @click="handlePermissionCheck"
+    >点击获取麦克风权限</p>
+    <div class="broadcast" v-if="!showPermissionButton">
+      <p class="broadcast_t">语音广播<span>选择喇叭位置</span></p>
+      <!-- 按钮部分 -->
+      <div class="trumpet-max-box">
+        <div @click="trumpetClick(index)" class="trumpet-for-box"
+             :class="item.type?'trumpet-color-a':'trumpet-color-b'" v-for="(item,index) in trumpetList" :key="index">
+          <img :src="imagesUrl('commonality/icon_sskz_zc.png')" v-if="!item.type">
+          <img :src="imagesUrl('commonality/icon_sskz_xz.png')" v-if="item.type">
+          {{item.deviceName}}
+        </div>
+      </div>
+      <div class="broadcast_m no-long-press">
+        <div class="broadcast_m_t no-long-press"
+             :class="liveType?'broadcast_m_t_back_a':'broadcast_m_t_back_b'"
+             @touchstart="handleTouchStart"
+             @touchmove="handleTouchMove"
+             @touchend="handleTouchEnd"
+             @touchcancel="handleTouchEnd"
+             @contextmenu.prevent="handleContextMenu">
+        </div>
+        <p class="broadcast_m_b no-long-press" v-if="!liveType">按住说话,录入广播内容</p>
+        <p class="broadcast_m_b no-long-press" v-if="liveType">松开发送,向上滑动取消发送</p>
+      </div>
+    </div>
+  </div>
+</template>
+<script>
+  import { Toast,Dialog } from 'vant';
+  import Recorder from 'recorder-core';
+  import 'recorder-core/src/engine/mp3';
+  import 'recorder-core/src/engine/mp3-engine';
+  import { systemFileUpload,iotAppSpeakerPlayVoice } from "@/api/index";
+  export default {
+    name: 'voiceBroadcast',
+    props: {
+      trumpetList:[],
+    },
+    data () {
+      return {
+        //广播相关
+        voiceType:false,
+        liveType: false,
+        sendLock: true, //发送锁,当为true时上锁,false时解锁发送
+        isEvacuate: true, //疏散按钮控制,当为true时候执行疏散
+        //H5
+        recording: false,
+        isInitializing: false, // 新增:防止重复初始化
+        recorder: null,
+        audioBlob: null,
+        audioPath: null,
+        //H5 拖拽
+        touchStartY: 0,
+        isLongPress: false,
+        hasMoved: false,
+        longPressTimer: null,
+        moveDirection: null,
+        hasTriggeredMethod3: false, // 确保方法3只触发一次
+        //麦克风权限相关
+        showPermissionButton: true, // 控制按钮显示
+        permissionStatus: null,     // 保存权限状态
+        stream:null,
+      }
+    },
+    created(){
+
+    },
+    mounted(){
+
+    },
+    methods:{
+      offButton(){
+        this.$parent.voiceButton();
+      },
+      trumpetClick(index) {
+        this.trumpetList[index].type = !this.trumpetList[index].type;
+      },
+      // 触摸开始
+      handleTouchStart(event) {
+        // 彻底阻止所有默认行为
+        event.preventDefault();
+        event.stopPropagation();
+        this.touchStartY = event.touches[0].clientY;
+        this.hasMoved = false;
+        this.moveDirection = null;
+        this.hasTriggeredMethod3 = false;
+        // 提前预初始化录音器
+        if (!this.recorder && !this.isInitializing) {
+          this.preInitRecorder();
+        }
+        // 设置长按定时器
+        this.longPressTimer = setTimeout(() => {
+          this.isLongPress = true;
+          this.startRecord(); // 执行方法1
+        }, 300); // 300ms触发长按
+      },
+      // 预初始化录音器(不开始录音)
+      async preInitRecorder() {
+        if (this.isInitializing || this.recorder) return;
+
+        this.isInitializing = true;
+        try {
+          this.recorder = new Recorder({
+            type: "mp3",
+            bitRate: 128,
+            sampleRate: 44100
+          });
+
+          await new Promise((resolve, reject) => {
+            this.recorder.open(() => {
+              console.log("录音器预初始化成功");
+              this.isInitializing = false;
+              resolve();
+            }, (error) => {
+              console.error("录音器预初始化失败:", error);
+              this.isInitializing = false;
+              this.recorder = null;
+              reject(error);
+            });
+          });
+        } catch (error) {
+          console.error("预初始化失败:", error);
+          Toast.fail('麦克风权限获取失败,请允许麦克风权限');
+        }
+      },
+      // 触摸移动
+      handleTouchMove(event) {
+        // 彻底阻止所有默认行为
+        event.preventDefault();
+        event.stopPropagation();
+        if (!this.isLongPress) return;
+        const currentY = event.touches[0].clientY;
+        const deltaY = currentY - this.touchStartY;
+        // 检测滑动方向(向上滑动为负值)
+        if (Math.abs(deltaY) > 75) { // 增加阈值避免误触
+          this.hasMoved = true;
+          this.moveDirection = deltaY < 0 ? 'up' : 'down';
+          // 向上滑动执行方法3(确保只触发一次)
+          if (this.moveDirection === 'up' && !this.hasTriggeredMethod3) {
+            this.hasTriggeredMethod3 = true;
+            this.delRecord();
+          }
+        }
+      },
+      // 触摸结束
+      handleTouchEnd() {
+        // 清除长按定时器
+        clearTimeout(this.longPressTimer);
+        if (this.isLongPress) {
+          this.stopRecord(); // 执行方法2
+        }
+        // 重置状态
+        this.isLongPress = false;
+        this.hasMoved = false;
+        this.moveDirection = null;
+      },
+      async initRecorder() {
+        this.recorder = new Recorder({
+          type: "mp3", // 输出格式
+          bitRate: 128, // 比特率
+          sampleRate: 44100 // 采样率
+        });
+        this.recorder.open(() => {
+          console.log("录音器初始化成功");
+          this.recorder.start(); // 初始化后立即开始录音
+        }, (error) => {
+          console.error("录音器初始化失败:", error);
+          Toast.fail('麦克风权限获取失败,请允许麦克风权限');
+        });
+        // try {
+        //   // 获取麦克风权限
+        //   this.stream = await navigator.mediaDevices.getUserMedia({ audio: true });
+        //   this.recorder = new Recorder({
+        //     type: "mp3", // 输出格式
+        //     bitRate: 128, // 比特率
+        //     sampleRate: 44100 // 采样率
+        //   });
+        //
+        //   this.recorder.open(() => {
+        //     // console.log("录音器初始化成功");
+        //     this.recorder.start(); // 初始化后立即开始录音
+        //   }, (error) => {
+        //     console.error("录音器初始化失败:", error);
+        //     Toast.fail('麦克风权限获取失败,请允许麦克风权限');
+        //   });
+        // } catch (err) {
+        //   console.error("获取麦克风失败:", err);
+        //   Toast.fail('请允许麦克风权限');
+        // }
+      },
+      // 开始录音
+      async startRecord() {
+        let self = this;
+        if (!this.recorder) {
+          await this.initRecorder();
+          // this.startRecord()
+          return;
+        }
+        let num = 0;
+        for (let i = 0; i < self.trumpetList.length; i++) {
+          if (self.trumpetList[i].type) {
+            num++
+          }
+        }
+        if (num == 0) {
+          Toast.fail('请选择喇叭');
+          return
+        }
+        // 如果录音器不存在或未初始化完成,先初始化
+        if (!this.recorder) {
+          try {
+            await this.preInitRecorder();
+          } catch (error) {
+            Toast.fail('录音器初始化失败');
+            return;
+          }
+        }
+        // 确保录音器已经打开
+        if (this.recorder) {
+          this.recorder.start();
+          this.recording = true;
+          this.liveType = true;
+          Toast('录音开始');
+        }
+        // this.recorder.start();
+        // this.recording = true;
+        // this.liveType = true;
+        // Toast('录音开始');
+      },
+      // 停止录音
+      stopRecord() {
+        // 清除长按定时器
+        clearTimeout(this.longPressTimer);
+        if (this.isLongPress && this.recorder && this.recording) {
+          this.recorder.stop((blob, duration) => {
+            this.recording = false;
+            this.liveType = false;
+            this.audioBlob = blob;
+            this.audioPath = URL.createObjectURL(blob);
+            this.uploadAudio();
+          }, (error) => {
+            console.error("录音失败:", error);
+            Toast('录音失败');
+            this.recording = false;
+            this.liveType = false;
+          });
+        }
+        // if (!this.recorder || !this.recording) return;
+        // this.recorder.stop((blob, duration) => {
+        //   this.recording = false;
+        //   this.liveType = false;
+        //   this.audioBlob = blob;
+        //   // 生成临时文件路径
+        //   this.audioPath = URL.createObjectURL(blob);
+        //   this.uploadAudio();
+        // }, (error) => {
+        //   console.error("录音失败:", error);
+        //   Toast('录音失败');
+        // });
+      },
+      delRecord(){
+        if (this.recorder && this.recording) {
+          this.recorder.stop(() => {
+            this.recording = false;
+            this.liveType = false;
+            this.audioBlob = null;
+            this.audioPath = null;
+            Toast('已取消发送');
+          });
+        }
+        this.isLongPress = false;
+        // this.recorder.stop((blob, duration) => {
+        //   this.recording = false;
+        //   this.liveType = false;
+        //   this.audioBlob = null;
+        //   this.audioPath = null;
+        // })
+      },
+      // 上传录音文件
+      uploadAudio() {
+        let self = this;
+        if (!this.audioBlob) return;
+        // 1. 通过fetch获取Blob数据
+        fetch(this.audioPath)
+          .then(response => response.blob())
+          .then(blob => {
+            // 2. 将Blob转换为File对象
+            const file = new File([blob], 'audio.mp3', { type: 'audio/mp3' });
+            let formData = new FormData();
+            formData.append("file", file);
+            systemFileUpload(formData).then(response => {
+              console.log('response',response)
+              let url = localStorage.getItem('fileBrowseEnvironmentExtranet') + '/' + response.data.url;
+              self.iotAppSpeakerPlayVoice(url);
+            });
+          })
+          .catch(error => {
+            console.error('获取Blob数据失败', error);
+          });
+      },
+      iotAppSpeakerPlayVoice(text){
+        let self = this;
+        let list = [];
+        for (let i = 0; i < self.trumpetList.length; i++) {
+          if (self.trumpetList[i].type) {
+            list.push(self.trumpetList[i].deviceNo)
+          }
+        }
+        let obj = {
+          deviceNo: list.join(','),
+          voiceUrls: text,
+          cycle: 1,
+          level: 1000,
+        };
+        iotAppSpeakerPlayVoice(obj).then(response => {
+          Toast.success('发送成功');
+        });
+      },
+      //麦克风权限相关
+      async checkPermission() {
+        // 检查浏览器支持性[citation:4][citation:7]
+        if (!navigator.permissions || !navigator.permissions.query) {
+          console.warn("浏览器不支持 Permissions API");
+          return 'unsupported';
+        }
+
+        try {
+          // 查询麦克风权限状态[citation:2][citation:4][citation:7]
+          const permissionStatus = await navigator.permissions.query({ name: 'microphone' });
+          return permissionStatus.state;
+        } catch (error) {
+          console.error("查询麦克风权限时发生错误:", error);
+          return 'error';
+        }
+      },
+
+      async handlePermissionCheck() {
+        this.preInitRecorder();
+        // let userAgent = navigator.userAgent; //取得浏览器的userAgent字符串
+        // if (userAgent.indexOf("Android") > -1 || userAgent.indexOf("Windows") > -1) {
+        //   this.recorder = new Recorder({
+        //     type: "mp3", // 输出格式
+        //     bitRate: 128, // 比特率
+        //     sampleRate: 44100 // 采样率
+        //   });
+        //   this.recorder.open(() => {
+        //     console.log("111111111录音器初始化成功");
+        //     this.recorder.start(); // 初始化后立即开始录音
+        //   }, (error) => {
+        //     console.error("1111111录音器初始化失败:", error);
+        //   });
+        // }
+        const status = await this.checkPermission();
+        this.permissionStatus = status;
+
+        switch (status) {
+          case 'granted':
+            // 已授权,隐藏按钮[citation:7]
+            this.showPermissionButton = false;
+            // 这里可以触发后续的录音操作
+            break;
+
+          case 'denied':
+            // 已拒绝,显示按钮但需要特殊处理[citation:7]
+            this.showPermissionButton = true;
+            // 可以在这里显示引导用户去设置页面开启权限的提示
+            this.showSettingsGuide();
+            break;
+
+          case 'prompt':
+            // 尝试请求权限[citation:1][citation:2]
+            try {
+              await this.requestMicrophonePermission();
+            } catch (error) {
+            }
+            break;
+
+          default:
+            this.showPermissionButton = true;
+        }
+      },
+
+      async requestMicrophonePermission() {
+        try {
+          // 请求麦克风权限[citation:1][citation:2][citation:5]
+          this.stream = await navigator.mediaDevices.getUserMedia({ audio: true });
+          // 权限获取成功,隐藏按钮
+          this.showPermissionButton = false;
+          this.permissionStatus = 'granted';
+          // 立即停止流,避免占用麦克风[citation:2]
+          this.stream.getTracks().forEach(track => track.stop());
+        } catch (error) {
+          this.permissionStatus = 'denied';
+          this.showPermissionButton = true;
+
+          // 处理不同的错误类型[citation:2]
+          if (error.name === 'NotAllowedError') {
+            Toast.fail('用户拒绝授予麦克风权限');
+          } else if (error.name === 'NotFoundError') {
+            Toast.fail('未找到麦克风设备');
+          } else if (error.name === 'NotReadableError') {
+            Toast.fail('麦克风被其他应用占用');
+          } else {
+            Toast.fail('获取麦克风权限失败');
+          }
+        }
+      },
+      showSettingsGuide() {
+        Toast.fail('请允许麦克风访问权限');
+      }
+    },
+  }
+</script>
+<style scoped lang="scss">
+  .voiceBroadcast{
+    height: 100%;
+    width: 100%;
+    position: fixed;
+    top: 0;
+    display: flex;
+    flex-direction: column;
+    z-index: 10;
+    background: rgba(0, 0, 0, 0.4);
+    .null-box {
+      flex: 1;
+    }
+    .get-button{
+      width:500px;
+      height:80px;
+      line-height:80px;
+      font-size:32px;
+      color:#fff;
+      background-color: #0183FA;
+      border-radius:6px;
+      margin:300px 125px;
+    }
+    .broadcast {
+      width: 100%;
+      background: #FFFFFF;
+      border-top-left-radius: 20px;
+      border-top-right-radius: 20px;
+      padding: 22px 30px 30px;
+      box-sizing: border-box;
+      margin-top: 20px;
+      position: absolute;
+      bottom: 0;
+
+      .broadcast_t {
+        font-size: 30px;
+        font-family: PingFang SC;
+        font-weight: 500;
+        color: #333333;
+        line-height: 30px;
+
+        >label {
+          font-size: 24px;
+          font-family: PingFang SC;
+          font-weight: 500;
+          color: #999999;
+          line-height: 30px;
+          margin-left: 16px;
+        }
+      }
+
+      .trumpet-max-box {
+        display: flex;
+        justify-content: flex-start;
+        margin-top: 22px;
+        flex-wrap: wrap;
+
+        .trumpet-for-box {
+          display: inline-block;
+          width: auto;
+          height: 60px;
+          line-height: 60px;
+          font-size: 24px;
+          text-align: center;
+          cursor: pointer;
+          overflow: hidden;
+          border: 1px solid #E0E0E0;
+          border-radius: 10px;
+          color: #E0E0E0;
+          display: flex;
+          justify-content: center;
+          margin-right: 20px;
+          margin-bottom: 10px;
+          padding: 0 12px;
+          box-sizing: border-box;
+
+          >img {
+            width: 36px;
+            height: 34px;
+            margin: 12px 20px 0 25px;
+          }
+        }
+
+        .trumpet-color-a {
+          border: 1px solid #0183FA;
+          color: #0183FA;
+        }
+
+        .trumpet-color-b {
+          border: 1px solid #CCCCCC;
+          color: #999;
+        }
+      }
+      .no-long-press{
+        // -webkit-touch-callout: none !important;
+        // -webkit-user-select: none !important;
+        // -khtml-user-select: none !important;
+        // -moz-user-select: none !important;
+        // -ms-user-select: none !important;
+        // user-select: none !important;
+      }
+      .broadcast_m {
+        width: 100%;
+
+        .broadcast_m_t {
+          width: 142px;
+          height: 142px;
+          margin: 30px 0 0 258px;
+          position: relative;
+          font-size: 24px;
+          font-family: PingFang SC;
+          font-weight: 500;
+          line-height: 170px;
+          text-align: center;
+
+          >img {
+            width: 142px;
+            height: 142px;
+            position: absolute;
+
+          }
+
+          >label {
+            width: 100%;
+            font-size: 24px;
+            font-family: PingFang SC;
+            font-weight: 500;
+            color: #0183FA;
+            line-height: 24px;
+            display: inline-block;
+            text-align: center;
+            position: absolute;
+            top: 76px;
+          }
+
+          /* 按下 */
+          .press_color {
+            color: #FFFFFF;
+          }
+
+          /* 松开 */
+          .slip_color {
+            color: #0183FA;
+          }
+        }
+
+        .broadcast_m_b {
+          font-size: 24px;
+          font-family: PingFang SC;
+          font-weight: 500;
+          color: #999999;
+          line-height: 24px;
+          text-align: center;
+          margin-top: 14px;
+        }
+        .broadcast_m_t_back_a {
+          background: url('https://zj-wechat.oss-cn-beijing.aliyuncs.com/xcx_images/xcx_v3/commonality/icon_sskz_skfs_1.png') no-repeat center 0px;
+          background-size: 100%;
+          color: #FFFFFF;
+        }
+
+        .broadcast_m_t_back_b {
+          background: url('https://zj-wechat.oss-cn-beijing.aliyuncs.com/xcx_images/xcx_v3/commonality/icon_sskz_azsh_1.png') no-repeat center 0px;
+          background-size: 100%;
+          color: #0183FA;
+        }
+      }
+
+      /* 疏散按钮 */
+      .evacuation-button-box {
+        width: 650px;
+        height: 100px;
+        background: #0183FA;
+        color: #fff;
+        text-align:center;
+        line-height: 100px;
+        font-size: 28px;
+        margin: 88px auto 0;
+        border-radius: 20px;
+      }
+    }
+  }
+</style>

+ 5 - 500
src/views/alarmPage/index.vue

@@ -284,37 +284,7 @@
     <div class="bottom-max-big-box" v-if="warnType == 4 && !alarmOutType">
       <p class="center-text">预案已结束</p>
     </div>
-    <div class="voiceBroadcast" v-if="voiceType">
-      <div class="null-box" @click="voiceButton()"></div>
-      <p class="get-button"
-        v-if="showPermissionButton"
-        @click="handlePermissionCheck"
-      >点击获取麦克风权限</p>
-      <div class="broadcast" v-if="!showPermissionButton">
-        <p class="broadcast_t">语音广播<span>选择喇叭位置</span></p>
-        <!-- 按钮部分 -->
-        <div class="trumpet-max-box">
-          <div @click="trumpetClick(index)" class="trumpet-for-box"
-               :class="item.type?'trumpet-color-a':'trumpet-color-b'" v-for="(item,index) in trumpetList" :key="index">
-            <img :src="imagesUrl('commonality/icon_sskz_zc.png')" v-if="!item.type">
-            <img :src="imagesUrl('commonality/icon_sskz_xz.png')" v-if="item.type">
-            {{item.deviceName}}
-          </div>
-        </div>
-        <div class="broadcast_m no-long-press">
-          <div class="broadcast_m_t no-long-press"
-               :class="liveType?'broadcast_m_t_back_a':'broadcast_m_t_back_b'"
-               @touchstart="handleTouchStart"
-               @touchmove="handleTouchMove"
-               @touchend="handleTouchEnd"
-               @touchcancel="handleTouchEnd"
-               @contextmenu.prevent="handleContextMenu">
-          </div>
-          <p class="broadcast_m_b no-long-press" v-if="!liveType">按住说话,录入广播内容</p>
-          <p class="broadcast_m_b no-long-press" v-if="liveType">松开发送,向上滑动取消发送</p>
-        </div>
-      </div>
-    </div>
+    <voiceBroadcast :trumpetList="trumpetList" v-if="voiceType"></voiceBroadcast>
     <fullH5PlayerVideo v-if="fullVideoType" :fullVideoProps="fullVideoProps"></fullH5PlayerVideo>
     <fullH5PlayerVideoTime v-if="fullVideoTypeBack" :fullVideoProps="fullVideoPropsBack"></fullH5PlayerVideoTime>
   </div>
@@ -324,20 +294,18 @@
   import fullH5PlayerVideo from '@/components/fullH5PlayerVideo.vue';
   import H5PlayerVideoTime from '@/components/H5PlayerVideoTime/H5PlayerVideoTime.vue';
   import fullH5PlayerVideoTime from '@/components/H5PlayerVideoTime/fullH5PlayerVideo.vue';
+  import voiceBroadcast from '@/components/voiceBroadcast/voiceBroadcast.vue';
   import {iotCameraFindByCondition, iotCameraGetPlaybackURLs,systemMineWarningNoticeDetail,
-    laboratoryEventFindByEventId,iotAppSpeakerFindHorn,laboratoryPlanCloseRiskPlan,
-    systemFileUpload,iotAppSpeakerPlayVoice } from "@/api/index";
+    laboratoryEventFindByEventId,iotAppSpeakerFindHorn,laboratoryPlanCloseRiskPlan } from "@/api/index";
   import { Toast,Dialog } from 'vant';
-  import Recorder from 'recorder-core';
-  import 'recorder-core/src/engine/mp3';
-  import 'recorder-core/src/engine/mp3-engine';
   export default {
     name: 'alarmPage',
     components: {
       H5PlayerVideo,
       fullH5PlayerVideo,
       H5PlayerVideoTime,
-      fullH5PlayerVideoTime
+      fullH5PlayerVideoTime,
+      voiceBroadcast
     },
     data() {
       return {
@@ -376,27 +344,7 @@
         alarmOutType:false,
         //喇叭数据
         trumpetList:[],
-        //广播相关
         voiceType:false,
-        liveType: false,
-        sendLock: true, //发送锁,当为true时上锁,false时解锁发送
-        isEvacuate: true, //疏散按钮控制,当为true时候执行疏散
-        //H5
-        recording: false,
-        recorder: null,
-        audioBlob: null,
-        audioPath: null,
-        //H5 拖拽
-        touchStartY: 0,
-        isLongPress: false,
-        hasMoved: false,
-        longPressTimer: null,
-        moveDirection: null,
-        hasTriggeredMethod3: false, // 确保方法3只触发一次
-        //麦克风权限相关
-        showPermissionButton: true, // 控制按钮显示
-        permissionStatus: null,     // 保存权限状态
-        stream:null,
       }
     },
     created() {
@@ -665,268 +613,6 @@
       imagesUrl(imgUrl) {
         return 'https://zj-wechat.oss-cn-beijing.aliyuncs.com/xcx_images/xcx_v3/' + imgUrl
       },
-
-      trumpetClick(index) {
-        this.trumpetList[index].type = !this.trumpetList[index].type;
-      },
-      // 触摸开始
-      handleTouchStart(event) {
-        // 彻底阻止所有默认行为
-        event.preventDefault();
-        event.stopPropagation();
-        this.touchStartY = event.touches[0].clientY;
-        this.hasMoved = false;
-        this.moveDirection = null;
-        this.hasTriggeredMethod3 = false;
-        // 设置长按定时器
-        this.longPressTimer = setTimeout(() => {
-          this.isLongPress = true;
-          this.startRecord(); // 执行方法1
-        }, 300); // 300ms触发长按
-      },
-
-      // 触摸移动
-      handleTouchMove(event) {
-        // 彻底阻止所有默认行为
-        event.preventDefault();
-        event.stopPropagation();
-        if (!this.isLongPress) return;
-        const currentY = event.touches[0].clientY;
-        const deltaY = currentY - this.touchStartY;
-        // 检测滑动方向(向上滑动为负值)
-        if (Math.abs(deltaY) > 75) { // 增加阈值避免误触
-          this.hasMoved = true;
-          this.moveDirection = deltaY < 0 ? 'up' : 'down';
-          // 向上滑动执行方法3(确保只触发一次)
-          if (this.moveDirection === 'up' && !this.hasTriggeredMethod3) {
-            this.hasTriggeredMethod3 = true;
-            this.delRecord();
-          }
-        }
-      },
-      // 触摸结束
-      handleTouchEnd() {
-        // 清除长按定时器
-        clearTimeout(this.longPressTimer);
-        if (this.isLongPress) {
-          this.stopRecord(); // 执行方法2
-        }
-        // 重置状态
-        this.isLongPress = false;
-        this.hasMoved = false;
-        this.moveDirection = null;
-      },
-      async initRecorder() {
-        this.recorder = new Recorder({
-          type: "mp3", // 输出格式
-          bitRate: 128, // 比特率
-          sampleRate: 44100 // 采样率
-        });
-        this.recorder.open(() => {
-          console.log("录音器初始化成功");
-          this.recorder.start(); // 初始化后立即开始录音
-        }, (error) => {
-          console.error("录音器初始化失败:", error);
-          Toast.fail('麦克风权限获取失败,请允许麦克风权限');
-        });
-        // try {
-        //   // 获取麦克风权限
-        //   this.stream = await navigator.mediaDevices.getUserMedia({ audio: true });
-        //   this.recorder = new Recorder({
-        //     type: "mp3", // 输出格式
-        //     bitRate: 128, // 比特率
-        //     sampleRate: 44100 // 采样率
-        //   });
-        //
-        //   this.recorder.open(() => {
-        //     // console.log("录音器初始化成功");
-        //     this.recorder.start(); // 初始化后立即开始录音
-        //   }, (error) => {
-        //     console.error("录音器初始化失败:", error);
-        //     Toast.fail('麦克风权限获取失败,请允许麦克风权限');
-        //   });
-        // } catch (err) {
-        //   console.error("获取麦克风失败:", err);
-        //   Toast.fail('请允许麦克风权限');
-        // }
-      },
-      // 开始录音
-      async startRecord() {
-        let self = this;
-        if (!this.recorder) {
-          await this.initRecorder();
-          // this.startRecord()
-          return;
-        }
-        let num = 0;
-        for (let i = 0; i < self.trumpetList.length; i++) {
-          if (self.trumpetList[i].type) {
-            num++
-          }
-        }
-        if (num == 0) {
-          Toast.fail('请选择喇叭');
-          return
-        }
-        this.recorder.start();
-        this.recording = true;
-        this.liveType = true;
-        Toast('录音开始');
-      },
-      // 停止录音
-      stopRecord() {
-        if (!this.recorder || !this.recording) return;
-        this.recorder.stop((blob, duration) => {
-          this.recording = false;
-          this.liveType = false;
-          this.audioBlob = blob;
-          // 生成临时文件路径
-          this.audioPath = URL.createObjectURL(blob);
-          this.uploadAudio();
-        }, (error) => {
-          console.error("录音失败:", error);
-          Toast('录音失败');
-        });
-      },
-      delRecord(){
-        this.recorder.stop((blob, duration) => {
-          this.recording = false;
-          this.liveType = false;
-          this.audioBlob = null;
-          this.audioPath = null;
-        })
-      },
-      // 上传录音文件
-      uploadAudio() {
-        let self = this;
-        if (!this.audioBlob) return;
-        // 1. 通过fetch获取Blob数据
-        fetch(this.audioPath)
-          .then(response => response.blob())
-          .then(blob => {
-            // 2. 将Blob转换为File对象
-            const file = new File([blob], 'audio.mp3', { type: 'audio/mp3' });
-            let formData = new FormData();
-            formData.append("file", file);
-            systemFileUpload(formData).then(response => {
-              console.log('response',response)
-              let url = localStorage.getItem('fileBrowseEnvironmentExtranet') + '/' + response.data.url;
-              self.iotAppSpeakerPlayVoice(url);
-            });
-          })
-          .catch(error => {
-            console.error('获取Blob数据失败', error);
-          });
-      },
-      iotAppSpeakerPlayVoice(text){
-        let self = this;
-        let list = [];
-        for (let i = 0; i < self.trumpetList.length; i++) {
-          if (self.trumpetList[i].type) {
-            list.push(self.trumpetList[i].deviceNo)
-          }
-        }
-        let obj = {
-          deviceNo: list.join(','),
-          voiceUrls: text,
-          cycle: 1,
-          level: 1000,
-        };
-        iotAppSpeakerPlayVoice(obj).then(response => {
-          Toast.success('发送成功');
-        });
-      },
-      //麦克风权限相关
-      async checkPermission() {
-        // 检查浏览器支持性[citation:4][citation:7]
-        if (!navigator.permissions || !navigator.permissions.query) {
-          console.warn("浏览器不支持 Permissions API");
-          return 'unsupported';
-        }
-
-        try {
-          // 查询麦克风权限状态[citation:2][citation:4][citation:7]
-          const permissionStatus = await navigator.permissions.query({ name: 'microphone' });
-          return permissionStatus.state;
-        } catch (error) {
-          console.error("查询麦克风权限时发生错误:", error);
-          return 'error';
-        }
-      },
-
-      async handlePermissionCheck() {
-        let userAgent = navigator.userAgent; //取得浏览器的userAgent字符串
-        if (userAgent.indexOf("Android") > -1 || userAgent.indexOf("Windows") > -1) {
-          this.recorder = new Recorder({
-            type: "mp3", // 输出格式
-            bitRate: 128, // 比特率
-            sampleRate: 44100 // 采样率
-          });
-          this.recorder.open(() => {
-            console.log("111111111录音器初始化成功");
-            this.recorder.start(); // 初始化后立即开始录音
-          }, (error) => {
-            console.error("1111111录音器初始化失败:", error);
-          });
-        }
-        const status = await this.checkPermission();
-        this.permissionStatus = status;
-
-        switch (status) {
-          case 'granted':
-            // 已授权,隐藏按钮[citation:7]
-            this.showPermissionButton = false;
-            // 这里可以触发后续的录音操作
-            break;
-
-          case 'denied':
-            // 已拒绝,显示按钮但需要特殊处理[citation:7]
-            this.showPermissionButton = true;
-            // 可以在这里显示引导用户去设置页面开启权限的提示
-            this.showSettingsGuide();
-            break;
-
-          case 'prompt':
-            // 尝试请求权限[citation:1][citation:2]
-            try {
-              await this.requestMicrophonePermission();
-            } catch (error) {
-            }
-            break;
-
-          default:
-            this.showPermissionButton = true;
-        }
-      },
-
-      async requestMicrophonePermission() {
-        try {
-          // 请求麦克风权限[citation:1][citation:2][citation:5]
-          this.stream = await navigator.mediaDevices.getUserMedia({ audio: true });
-          // 权限获取成功,隐藏按钮
-          this.showPermissionButton = false;
-          this.permissionStatus = 'granted';
-          // 立即停止流,避免占用麦克风[citation:2]
-          this.stream.getTracks().forEach(track => track.stop());
-        } catch (error) {
-          this.permissionStatus = 'denied';
-          this.showPermissionButton = true;
-
-          // 处理不同的错误类型[citation:2]
-          if (error.name === 'NotAllowedError') {
-            Toast.fail('用户拒绝授予麦克风权限');
-          } else if (error.name === 'NotFoundError') {
-            Toast.fail('未找到麦克风设备');
-          } else if (error.name === 'NotReadableError') {
-            Toast.fail('麦克风被其他应用占用');
-          } else {
-            Toast.fail('获取麦克风权限失败');
-          }
-        }
-      },
-      showSettingsGuide() {
-        Toast.fail('请允许麦克风访问权限');
-      }
     },
   }
 </script>
@@ -1377,186 +1063,5 @@
         color:#999;
       }
     }
-    .voiceBroadcast{
-      height: 100%;
-      width: 100%;
-      position: fixed;
-      top: 0;
-      display: flex;
-      flex-direction: column;
-      z-index: 10;
-      background: rgba(0, 0, 0, 0.4);
-      .null-box {
-        flex: 1;
-      }
-      .get-button{
-        width:500px;
-        height:80px;
-        line-height:80px;
-        font-size:32px;
-        color:#fff;
-        background-color: #0183FA;
-        border-radius:6px;
-        margin:300px 125px;
-      }
-      .broadcast {
-        width: 100%;
-        background: #FFFFFF;
-        border-top-left-radius: 20px;
-        border-top-right-radius: 20px;
-        padding: 22px 30px 30px;
-        box-sizing: border-box;
-        margin-top: 20px;
-        position: absolute;
-        bottom: 0;
-
-        .broadcast_t {
-          font-size: 30px;
-          font-family: PingFang SC;
-          font-weight: 500;
-          color: #333333;
-          line-height: 30px;
-
-          >label {
-            font-size: 24px;
-            font-family: PingFang SC;
-            font-weight: 500;
-            color: #999999;
-            line-height: 30px;
-            margin-left: 16px;
-          }
-        }
-
-        .trumpet-max-box {
-          display: flex;
-          justify-content: flex-start;
-          margin-top: 22px;
-          flex-wrap: wrap;
-
-          .trumpet-for-box {
-            display: inline-block;
-            width: auto;
-            height: 60px;
-            line-height: 60px;
-            font-size: 24px;
-            text-align: center;
-            cursor: pointer;
-            overflow: hidden;
-            border: 1px solid #E0E0E0;
-            border-radius: 10px;
-            color: #E0E0E0;
-            display: flex;
-            justify-content: center;
-            margin-right: 20px;
-            margin-bottom: 10px;
-            padding: 0 12px;
-            box-sizing: border-box;
-
-            >img {
-              width: 36px;
-              height: 34px;
-              margin: 12px 20px 0 25px;
-            }
-          }
-
-          .trumpet-color-a {
-            border: 1px solid #0183FA;
-            color: #0183FA;
-          }
-
-          .trumpet-color-b {
-            border: 1px solid #CCCCCC;
-            color: #999;
-          }
-        }
-        .no-long-press{
-          // -webkit-touch-callout: none !important;
-          // -webkit-user-select: none !important;
-          // -khtml-user-select: none !important;
-          // -moz-user-select: none !important;
-          // -ms-user-select: none !important;
-          // user-select: none !important;
-        }
-        .broadcast_m {
-          width: 100%;
-
-          .broadcast_m_t {
-            width: 142px;
-            height: 142px;
-            margin: 30px 0 0 258px;
-            position: relative;
-            font-size: 24px;
-            font-family: PingFang SC;
-            font-weight: 500;
-            line-height: 170px;
-            text-align: center;
-
-            >img {
-              width: 142px;
-              height: 142px;
-              position: absolute;
-
-            }
-
-            >label {
-              width: 100%;
-              font-size: 24px;
-              font-family: PingFang SC;
-              font-weight: 500;
-              color: #0183FA;
-              line-height: 24px;
-              display: inline-block;
-              text-align: center;
-              position: absolute;
-              top: 76px;
-            }
-
-            /* 按下 */
-            .press_color {
-              color: #FFFFFF;
-            }
-
-            /* 松开 */
-            .slip_color {
-              color: #0183FA;
-            }
-          }
-
-          .broadcast_m_b {
-            font-size: 24px;
-            font-family: PingFang SC;
-            font-weight: 500;
-            color: #999999;
-            line-height: 24px;
-            text-align: center;
-            margin-top: 14px;
-          }
-          .broadcast_m_t_back_a {
-            background: url('https://zj-wechat.oss-cn-beijing.aliyuncs.com/xcx_images/xcx_v3/commonality/icon_sskz_skfs_1.png') no-repeat center 0px;
-            background-size: 100%;
-            color: #FFFFFF;
-          }
-
-          .broadcast_m_t_back_b {
-            background: url('https://zj-wechat.oss-cn-beijing.aliyuncs.com/xcx_images/xcx_v3/commonality/icon_sskz_azsh_1.png') no-repeat center 0px;
-            background-size: 100%;
-            color: #0183FA;
-          }
-        }
-
-        /* 疏散按钮 */
-        .evacuation-button-box {
-          width: 650px;
-          height: 100px;
-          background: #0183FA;
-          color: #fff;
-          text-align:center;
-          line-height: 100px;
-          font-size: 28px;
-          margin: 88px auto 0;
-          border-radius: 20px;
-        }
-      }
-    }
   }
 </style>