yusheng 2 هفته پیش
والد
کامیت
89b4c14d2a
2فایلهای تغییر یافته به همراه94 افزوده شده و 490 حذف شده
  1. 62 213
      src/views/components/video.vue
  2. 32 277
      src/views/monitor/index.vue

+ 62 - 213
src/views/components/video.vue

@@ -1,30 +1,17 @@
 <template>
-  <!-- <div v-loading="loading">
-
-  </div> -->
-  <video
-    :id="'video' + index"
-    style="background-color: #333"
-    class="video"
-    muted
-    playsinline
-  ></video>
+  <div style="height: 100%; width: 100%">
+    <div id="video-player" ref="videoPlayer" class="video-player"></div>
+  </div>
 </template>
 
 <script>
-  import mpegts from 'mpegts.js';
+  import Player from 'xgplayer';
+  import FlvPlugin from 'xgplayer-flv';
+  import 'xgplayer/dist/index.min.css'; // 引入播放器默认样式
 
   export default {
     name: 'VideoPlayer',
     props: {
-      videoUrl: {
-        type: String,
-        default: ''
-      },
-      index: {
-        type: Number,
-        default: 0
-      },
       playDelaySeconds: {
         type: Number,
         default: 5 // 延迟2秒播放
@@ -33,214 +20,76 @@
     data() {
       return {
         player: null,
-        reconnectAttempts: 0,
-        maxReconnectAttempts: 5,
-        reconnectTimer: null,
-        isManualDestroy: false,
-        isPageUnloading: false, // 页面刷新/关闭标志
-        hasStarted: false, // 防止重复播放
-        config: {
-          liveBufferLatencyChasing: true,
-          liveBufferLatencyMinRemain: 0.5,
-          liveBufferLatencyMaxLatency: 1.5,
-          enableStashBuffer: false,
-          stashInitialSize: 128,
-          enableWorker: true,
-          lazyLoadMaxDuration: 3 * 60
-        }
+        url: ''
       };
     },
-    watch: {
-      videoUrl: {
-        handler(newUrl, oldUrl) {
-          if (newUrl && newUrl !== oldUrl) {
-            this.reconnectPlayer();
-          }
-        },
-        immediate: false
-      }
-    },
+    watch: {},
     mounted() {
-      window.addEventListener('beforeunload', this.handleBeforeUnload);
-      this.startPlay();
-    },
-    beforeDestroy() {
-      this.isPageUnloading = true;
-      this.isManualDestroy = true;
-      window.removeEventListener('beforeunload', this.handleBeforeUnload);
-      this.cleanReconnectTimer();
-      this.destroyPlayer();
+      // this.startPlay();
     },
+    beforeDestroy() {},
     methods: {
-      handleBeforeUnload() {
-        // 页面刷新/关闭时立即标记,阻止任何后续异步操作
-        this.isPageUnloading = true;
-        this.isManualDestroy = true;
-        this.cleanReconnectTimer();
-        this.destroyPlayer();
-      },
-
-      startPlay() {
-        if (this.isPageUnloading || this.isManualDestroy) return;
-        if (!mpegts.getFeatureList().mseLivePlayback) {
-          console.warn('当前浏览器不支持 mpegts.js 直播回放');
-          return;
-        }
-        const videoElement = document.getElementById('video' + this.index);
-        if (!videoElement) {
-          console.warn('video 元素未找到,延迟重试');
-          this.scheduleReconnect();
-          return;
-        }
-
-        try {
-          this.player = mpegts.createPlayer(
-            {
-              type: 'flv',
-              isLive: true,
-              hasAudio: false,
-              url: this.videoUrl,
-              cors: true
-            },
-            this.config
-          );
-
-          this.player.attachMediaElement(videoElement);
-          this.player.load();
-
-          // 媒体信息就绪后,延迟播放
-          this.player.on(mpegts.Events.MEDIA_INFO, () => {
-            if (this.isPageUnloading || this.isManualDestroy) return;
-            if (this.hasStarted) return;
-            this.hasStarted = true;
-            this.$emit('setLoading', true);
-
-            setTimeout(() => {
-              this.$emit('setLoading', false);
-
-              if (this.isPageUnloading || this.isManualDestroy || !this.player)
-                return;
-              this.player.play().catch((err) => {
-                if (err.name !== 'NotAllowedError') {
-                  this.scheduleReconnect();
-                }
-              });
-            }, this.playDelaySeconds * 1000);
-          });
-
-          // 兜底:如果 MEDIA_INFO 未触发,LOADING_COMPLETE 时也尝试延迟播放
-          this.player.on(mpegts.Events.LOADING_COMPLETE, () => {
-            if (this.isPageUnloading || this.isManualDestroy) return;
-            if (!this.hasStarted) {
-              console.warn('未收到 MEDIA_INFO,但仍尝试延迟播放');
-              this.hasStarted = true;
-              setTimeout(() => {
-                if (
-                  this.isPageUnloading ||
-                  this.isManualDestroy ||
-                  !this.player
-                )
-                  return;
-                this.player.play().catch((e) => console.warn);
-              }, this.playDelaySeconds * 1000);
-            }
-          });
+      handleBeforeUnload() {},
 
-          // 错误处理
-          this.player.on(mpegts.Events.ERROR, (errorType, errorDetail) => {
-            if (this.isPageUnloading || this.isManualDestroy) return;
-            console.error('mpegts 错误:', errorType, errorDetail);
-            if (errorType === mpegts.ErrorTypes.NETWORK_ERROR) {
-              this.scheduleReconnect();
-            } else if (
-              errorType === mpegts.ErrorTypes.MEDIA_ERROR &&
-              this.reconnectAttempts === 0
-            ) {
-              this.scheduleReconnect(true);
-            }
-          });
-
-          // 缓冲统计,重置重连计数
-          this.player.on(mpegts.Events.STATISTICS_INFO, (stats) => {
-            if (this.isPageUnloading || this.isManualDestroy) return;
-            if (stats && stats.bufferLength > 0.5) {
-              this.reconnectAttempts = 0;
-            }
-          });
-        } catch (err) {
-          console.error('创建播放器异常:', err);
-          this.scheduleReconnect();
+      startPlay(url) {
+        if (url) {
+          this.url = url;
         }
-      },
 
-      destroyPlayer() {
-        if (this.player) {
-          try {
-            this.player.pause();
-            this.player.unload();
-            this.player.detachMediaElement();
-            this.player.destroy();
-          } catch (e) {
-            // 刷新时可能已经销毁,静默处理
-          }
-          this.player = null;
-        }
-        // 手动清理 video 元素,彻底释放资源
-        const videoElement = document.getElementById('video' + this.index);
-        if (videoElement) {
-          videoElement.pause();
-          videoElement.src = '';
-          videoElement.load();
-          if (videoElement.srcObject) {
-            videoElement.srcObject = null;
+        if (this.player) this.player.destroy();
+
+        // this.videoUrl = this.url.split(',');
+        this.flag = 0;
+        var config = {
+          id: 'video-player',
+          url: this.url,
+          autoplay: true,
+          autoplayMuted: true,
+          closeVideoClick: true,
+          // controls: false,
+          closeInactive: true,
+          fitVideoSize: 'auto',
+          plugins: [FlvPlugin], // 关键:引入 FLV 插件
+          errorTips: '<span style="color:red">请选择需要播放的摄像头</span>',
+          /**倍速播放 */
+          playbackRate: [1],
+          defaultPlaybackRate: 1,
+          flv: {
+            retryCount: 3, // 网络错误时重试次数[reference:8]
+            retryDelay: 1000, // 重试间隔(ms)[reference:9]
+            loadTimeout: 10000, // 加载超时时间(ms)[reference:10]
+            preloadTime: 5 // 抗抖动缓冲区大小(秒)[reference:11]
           }
-        }
-        this.hasStarted = false;
-      },
-
-      scheduleReconnect(onlyOnce = false) {
-        if (this.isPageUnloading || this.isManualDestroy) return;
-        if (this.reconnectAttempts >= this.maxReconnectAttempts) {
-          console.error('已达最大重连次数,停止尝试');
-          return;
-        }
-        if (onlyOnce && this.reconnectAttempts > 0) return;
-
-        this.cleanReconnectTimer();
-        const delay = Math.min(
-          1000 * Math.pow(1.5, this.reconnectAttempts),
-          10000
-        );
-        console.log(
-          `${delay}ms 后尝试重连... (第${this.reconnectAttempts + 1}次)`
-        );
-        this.reconnectTimer = setTimeout(() => {
-          this.reconnectPlayer();
-        }, delay);
-      },
-
-      reconnectPlayer() {
-        if (this.isPageUnloading || this.isManualDestroy) return;
-        this.reconnectAttempts++;
-        console.log(`重连播放器,第${this.reconnectAttempts}次尝试`);
-        this.destroyPlayer();
-        this.startPlay();
-      },
-
-      cleanReconnectTimer() {
-        if (this.reconnectTimer) {
-          clearTimeout(this.reconnectTimer);
-          this.reconnectTimer = null;
-        }
+        };
+        var player = new Player(config);
+        player.once('ready', () => {});
       }
     }
   };
 </script>
 
 <style scoped lang="scss">
-  .video {
-    height: 100%;
-    width: 100%;
-    background-color: #333;
+  :deep(.el-loading-mask) {
+    background-color: #000;
+  }
+  :deep(.xgplayer-skin-default.xgplayer-pause) {
+    .xgplayer-start {
+      display: none !important;
+    }
+  }
+  :deep(.xgplayer-progress) {
+    display: none !important;
+  }
+
+  .video-player {
+    width: 100% !important;
+    height: 100% !important;
+  }
+  .video-playerrr {
+    position: absolute !important;
+    height: 300px !important;
+    top: 50px;
+    /* display: none; */
+    z-index: -100 !important;
   }
 </style>

+ 32 - 277
src/views/monitor/index.vue

@@ -11,223 +11,14 @@
 
     <div class="center">
       <div class="monitor">
-        <el-carousel
-          ref="carouselRef"
-          indicator-position="outside"
-          style="height: calc(100% - 42px)"
-          :autoplay="false"
-          trigger="click"
-          @change="carouselChange"
-        >
-          <el-carousel-item
-            v-for="(page, pageIndex) in pageNum"
-            :key="pageIndex"
-          >
-            <div class="page" v-loading="loading">
-              <div
-                :style="itemStyle"
-                v-for="(video, videoIndex) in itemNum(pageIndex)"
-                :key="videoIndex"
-              >
-                <div
-                  v-if="pageIndex == carouselIndex"
-                  style="width: 100%; height: 100%"
-                  @click="
-                    deviceCode =
-                      videoList[pageIndex * layout * layout + videoIndex][
-                        'cameraCode'
-                      ]
-                  "
-                  :class="{
-                    active:
-                      deviceCode ==
-                      videoList[pageIndex * layout * layout + videoIndex][
-                        'cameraCode'
-                      ]
-                  }"
-                  class="box-border videoItem"
-                >
-                  <!-- <myVideo
-                    :video-url="
-                      videoList[pageIndex * layout * layout + videoIndex]['url']
-                    "
-                    :index="pageIndex * layout * layout + videoIndex"
-                  /> -->
-                  <myVideo
-                    :autoplay="true"
-                    :muted="true"
-                    :width="960"
-                    :height="540"
-                    :isLive="true"
-                    show-reload-btn
-                    @setLoading="setLoading"
-                    :video-url="
-                      videoList[pageIndex * layout * layout + videoIndex]['url']
-                    "
-                  />
-                  <div class="mask1">
-                    <img
-                      @click.stop="
-                        handleScreenshot(
-                          pageIndex * layout * layout + videoIndex,
-                          $event
-                        )
-                      "
-                      :src="
-                        require('@/assets/svgs/centerctl/videoSur/camera.svg')
-                      "
-                    />
-                  </div>
-                  <div
-                    class="mask2"
-                    v-if="
-                      stopList.includes(
-                        pageIndex * layout * layout + videoIndex
-                      )
-                    "
-                  >
-                    <img
-                      class="play"
-                      @click.stop="
-                        play(pageIndex * layout * layout + videoIndex)
-                      "
-                      :src="
-                        require('@/assets/svgs/centerctl/videoSur/play.svg')
-                      "
-                      alt=""
-                    />
-                  </div>
-                </div>
-              </div>
-            </div>
-          </el-carousel-item>
-        </el-carousel>
-
-        <div class="center-handle">
-          <div
-            class="layout-type"
-            id="layout"
-            @click="getFocus"
-            @blur="blur"
-            tabindex="0"
-          >
-            <div style="width: 100%; height: 100%" @click="toggle" tabindex="0">
-              <div class="layout">
-                <div
-                  v-for="(item, index) in layout * layout"
-                  :key="index"
-                  :style="{
-                    width: `calc((100% - 1px * (${layout} - 1)) / ${layout})`,
-                    height: `calc((100% - 1px * (${layout} - 1)) / ${layout})`,
-                    backgroundColor: '#404446'
-                  }"
-                ></div>
-              </div>
-              <i class="el-icon-caret-bottom"></i>
-            </div>
-
-            <div class="group" v-show="isShow">
-              <div
-                class="layout"
-                v-show="index + 1 != layout"
-                v-for="(item, index) in maxLayout"
-                :key="index"
-              >
-                <div
-                  @click="choose(index)"
-                  v-for="n in (index + 1) * (index + 1)"
-                  :key="n"
-                  :style="{
-                    width: `calc((100% - 1px * (${index + 1} - 1)) / ${
-                      index + 1
-                    })`,
-                    height: `calc((100% - 1px * (${index + 1} - 1)) / ${
-                      index + 1
-                    })`,
-                    backgroundColor: '#404446'
-                  }"
-                ></div>
-              </div>
-            </div>
-          </div>
-          <div class="play">
-            <el-tooltip
-              class="item"
-              effect="dark"
-              content="第一个"
-              placement="top"
-            >
-              <img
-                @click="home"
-                :src="require('@/assets/svgs/centerctl/videoSur/last.svg')"
-                alt=""
-              />
-            </el-tooltip>
-            <el-tooltip
-              class="item"
-              effect="dark"
-              content="上一个"
-              placement="top"
-            >
-              <img
-                @click="last"
-                :src="
-                  require('@/assets/svgs/centerctl/videoSur/fast-backward.svg')
-                "
-                alt=""
-              />
-            </el-tooltip>
-            <el-tooltip
-              class="item"
-              effect="dark"
-              content="播放/暂停"
-              placement="top"
-            >
-              <img
-                @click="playStop"
-                :src="require('@/assets/svgs/centerctl/videoSur/play-stop.svg')"
-                alt=""
-              />
-            </el-tooltip>
-            <el-tooltip
-              class="item"
-              effect="dark"
-              content="下一个"
-              placement="top"
-            >
-              <img
-                @click="next"
-                :src="
-                  require('@/assets/svgs/centerctl/videoSur/fast-forward.svg')
-                "
-                alt=""
-              />
-            </el-tooltip>
-            <el-tooltip
-              class="item"
-              effect="dark"
-              content="最后一个"
-              placement="top"
-            >
-              <img
-                @click="end"
-                :src="require('@/assets/svgs/centerctl/videoSur/next.svg')"
-                alt=""
-              />
-            </el-tooltip>
-          </div>
+        <myVideo
+          :width="960"
+          :height="540"
+          show-reload-btn
+          @setLoading="setLoading"
+          ref="myVideoRef"
+        />
 
-          <div class="video-handle">
-            <img
-              :src="require('@/assets/svgs/centerctl/videoSur/volume-x.svg')"
-              alt=""
-            />
-            <img
-              :src="require('@/assets/svgs/centerctl/videoSur/big.svg')"
-              alt=""
-            />
-          </div>
-        </div>
       </div>
     </div>
     <div style="height: 100%; padding: 0">
@@ -557,25 +348,28 @@
         }
       },
       playStop() {
-        let index = Math.floor(
-          this.videoList.findIndex(
-            (item) => item.cameraCode == this.deviceCode
-          ) /
-            (this.layout * this.layout)
-        );
-        let videoElement = document.getElementById('video' + index);
-        if (videoElement && videoElement.paused) {
-          videoElement.play();
-          this.stopList = this.stopList.filter((item) => item != index);
-        } else {
-          if (videoElement) videoElement.pause();
-          this.stopList.push(index);
-        }
+        this.$refs.myVideoRef.playStop();
+        // let index = Math.floor(
+        //   this.videoList.findIndex(
+        //     (item) => item.cameraCode == this.deviceCode
+        //   ) /
+        //     (this.layout * this.layout)
+        // );
+        // let videoElement = document.getElementById('video' + index);
+        // if (videoElement && videoElement.paused) {
+        //   videoElement.play();
+        //   this.stopList = this.stopList.filter((item) => item != index);
+        // } else {
+        //   if (videoElement) videoElement.pause();
+        //   this.stopList.push(index);
+        // }
       },
       play(index) {
-        let videoElement = document.getElementById('video' + index);
-        if (videoElement) videoElement.play();
-        this.stopList = this.stopList.filter((item) => item != index);
+        this.$refs.myVideoRef.play();
+
+        // let videoElement = document.getElementById('video' + index);
+        // if (videoElement) videoElement.play();
+        // this.stopList = this.stopList.filter((item) => item != index);
       },
       async getCameraList(list) {
         this.monitorData = list;
@@ -606,7 +400,8 @@
       async getCameraUrl() {
         await realTime.delStreamProxy(this.deviceCode);
         const res = await realTime.getCameraUrl([this.deviceCode]);
-        this.videoList = res;
+        this.$refs.myVideoRef.startPlay(res[0].url);
+        // this.videoList = res;
         console.log(this.videoList);
       }
     }
@@ -754,49 +549,7 @@
       height: calc(100% - 27px);
     }
   }
-  .page {
-    display: flex;
-    align-content: space-between;
-    flex-wrap: wrap;
-    gap: 5px;
-    height: 100%;
-    .videoItem {
-      border: 4px solid transparent;
-      position: relative;
-      .mask1 {
-        position: absolute;
-        top: 0;
-        left: 0;
-        width: 50px;
-        height: 20px;
-        z-index: 111;
-      }
-      .mask2 {
-        position: absolute;
-        top: 50%;
-        left: 50%;
-        transform: translate(-50%, -50%);
-        width: 50px;
-        height: 50px;
-        z-index: 111;
-        background-color: #000000d3;
-        border-radius: 50%;
-        display: flex;
-        justify-content: center;
-        align-items: center;
-        .play {
-          width: 70%;
-          transform: translateX(3px);
-        }
-      }
-    }
-    .active {
-      border: 4px solid #2c8ae0;
-    }
-    img {
-      vertical-align: middle;
-    }
-  }
+
 
   .deviceInfo,
   .deviceInfo * {
@@ -954,6 +707,8 @@
 
     .play {
       display: flex;
+      justify-content: center;
+      width: 100%;
       align-items: flex-start;
       gap: 24px;
     }