Parcourir la source

无人机调整

Hwf il y a 2 mois
Parent
commit
679ea7d21c

+ 20 - 0
package-lock.json

@@ -30,6 +30,7 @@
         "element-plus": "2.7.5",
         "element-resize-detector": "^1.2.4",
         "file-saver": "^2.0.5",
+        "flv.js": "^1.6.2",
         "fuse.js": "7.0.0",
         "gcoord": "^1.0.7",
         "highlight.js": "11.9.0",
@@ -7384,6 +7385,11 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/es6-promise": {
+      "version": "4.2.8",
+      "resolved": "https://registry.npmmirror.com/es6-promise/-/es6-promise-4.2.8.tgz",
+      "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w=="
+    },
     "node_modules/esbuild": {
       "version": "0.20.2",
       "resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.20.2.tgz",
@@ -8226,6 +8232,15 @@
       "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==",
       "dev": true
     },
+    "node_modules/flv.js": {
+      "version": "1.6.2",
+      "resolved": "https://registry.npmmirror.com/flv.js/-/flv.js-1.6.2.tgz",
+      "integrity": "sha512-xre4gUbX1MPtgQRKj2pxJENp/RnaHaxYvy3YToVVCrSmAWUu85b9mug6pTXF6zakUjNP2lFWZ1rkSX7gxhB/2A==",
+      "dependencies": {
+        "es6-promise": "^4.2.8",
+        "webworkify-webpack": "^2.1.5"
+      }
+    },
     "node_modules/follow-redirects": {
       "version": "1.15.6",
       "resolved": "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.6.tgz",
@@ -13909,6 +13924,11 @@
       "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==",
       "dev": true
     },
+    "node_modules/webworkify-webpack": {
+      "version": "2.1.5",
+      "resolved": "https://registry.npmmirror.com/webworkify-webpack/-/webworkify-webpack-2.1.5.tgz",
+      "integrity": "sha512-2akF8FIyUvbiBBdD+RoHpoTbHMQF2HwjcxfDvgztAX5YwbZNyrtfUMgvfgFVsgDhDPVTlkbb5vyasqDHfIDPQw=="
+    },
     "node_modules/which": {
       "version": "2.0.2",
       "resolved": "https://registry.npmmirror.com/which/-/which-2.0.2.tgz",

+ 1 - 0
package.json

@@ -38,6 +38,7 @@
     "element-plus": "2.7.5",
     "element-resize-detector": "^1.2.4",
     "file-saver": "^2.0.5",
+    "flv.js": "^1.6.2",
     "fuse.js": "7.0.0",
     "gcoord": "^1.0.7",
     "highlight.js": "11.9.0",

+ 77 - 0
src/components/FlvVideo/index.vue

@@ -0,0 +1,77 @@
+<template>
+  <video ref="videoRef" :autoplay="autoPlay" :controls="controls" :muted="muted" />
+</template>
+
+<script lang="ts" setup name="FlvVideo">
+import flvjs from 'flv.js';
+
+const props = defineProps({
+  videoUrl: {
+    require: true,
+    default: () => ''
+  },
+  autoPlay: {
+    type: Boolean,
+    default: false
+  },
+  muted: {
+    type: Boolean,
+    default: false
+  },
+  controls: {
+    type: Boolean,
+    default: false
+  }
+});
+const videoRef = ref();
+let flvPlayer = ref();
+
+// 播放视频
+const handleVideoPlay = () => {
+  if (flvjs.isSupported()) {
+    if (flvPlayer.value) {
+      flvPlayer.value.pause();
+      flvPlayer.value.unload();
+      flvPlayer.value.detachMediaElement();
+      flvPlayer.value.destroy();
+    }
+    flvPlayer.value = flvjs.createPlayer(
+      {
+        type: 'flv',
+        url: props.videoUrl
+      },
+      {
+        cors: true, //是否跨域
+        enableWorker: true, //是否多线程工作
+        anableStashBuffer: false, //是否启用缓存
+        autoCleanupSourceBuffer: true //是否自动缓存
+      }
+    );
+    flvPlayer.value.attachMediaElement(videoRef.value);
+    flvPlayer.value.load();
+    flvPlayer.value.play();
+    //报错重连
+    flvPlayer.value.on(flvjs.Events.ERROR, (errType, errDetail) => {
+      if (flvPlayer.value) {
+        destoryVideo();
+      }
+    });
+  }
+};
+
+const destoryVideo = () => {
+  if (flvPlayer.value) {
+    flvPlayer.value.pause();
+    flvPlayer.value.unload();
+    flvPlayer.value.detachMediaElement();
+    flvPlayer.value.destroy();
+    flvPlayer.value = null;
+  }
+};
+
+onMounted(() => {
+  handleVideoPlay();
+});
+</script>
+
+<style lang="scss" scoped></style>

+ 4 - 2
src/components/HKVideo/index.vue

@@ -2,12 +2,13 @@
   <div class="dot-box" :style="{ width: width ? width + 'px' : '100%', height: height ? height + 'px' : '100%' }">
     <div class="video-box" @click="play_now">
       <HikvisionPlayer
-        v-if="!reload && (isPlaying || autoplay)"
+        v-if="!reload && (isPlaying || autoplay) && !isNoLive"
         ref="videoPlayer"
         style="width: 100%; height: 100%; object-fit: fill"
         @on-playing="onHkPlaying"
         @on-play-error="onHKPlayError"
       />
+      <FlvVideo v-if="isPlaying && isNoLive" ref="FlvVideoRef" :videoUrl="dot_data.video_code"style="width: 100%; height: 100%; object-fit: fill" />
       <img v-if="posterVisible" class="video-play" src="@/assets/images/video/play.png" alt="" />
       <img v-if="posterVisible && dot_data.poster" class="video-poster" :src="dot_data.poster" />
       <div v-if="errBKVisible" class="err_bk">
@@ -31,7 +32,8 @@ const props = defineProps({
   dot_data: Object,
   width: Number,
   height: Number,
-  autoplay: Boolean
+  autoplay: Boolean,
+  isNoLive: Boolean
 });
 const play = () => {
   play_now();

+ 22 - 14
src/components/HKVideo/index2.vue

@@ -2,13 +2,14 @@
   <div class="dot-box" :style="{ width: width ? width + 'px' : '100%', height: height ? height + 'px' : '100%' }">
     <div class="video-box" @click="play_now">
       <HikvisionPlayer
-        v-if="isPlaying"
+        v-if="isPlaying && !isNoLive"
         ref="videoPlayer"
         hideEnlarge
         style="width: 100%; height: 100%; object-fit: fill"
         @on-playing="onHkPlaying"
         @on-play-error="onHKPlayError"
       />
+      <FlvVideo v-if="isPlaying && isNoLive" ref="FlvVideoRef" :videoUrl="dot_data.video_code" style="width: 100%; height: 100%; object-fit: fill" />
       <div class="video-header">
         <div class="label" :title="dot_data.name">{{ dot_data.name }}</div>
         <div class="video-header-right">
@@ -39,14 +40,20 @@
     <!--收藏弹窗-->
     <VideoTagEdit v-if="showCollectDialog" :id="dot_data.id" v-model="showCollectDialog" :tags="tags" @update-video-tag="getData2" />
     <!--点击全屏弹窗-->
-    <video-dialog v-if="showFullScreenDialog" v-model="showFullScreenDialog" :videoMonitorData="dot_data" @changeTagsData="getData" />
+    <video-dialog
+      v-if="showFullScreenDialog"
+      v-model="showFullScreenDialog"
+      :videoMonitorData="dot_data"
+      :isNoLive="isNoLive"
+      @changeTagsData="getData"
+    />
   </div>
 </template>
 
 <script setup lang="ts" name="HKVideo2">
 import HikvisionPlayer from './hikvision-h5player.vue';
 import VideoDialog from '@/components/HKVideo/video-dialog.vue';
-import { getVideoById, getVideoTagInfo, getVideoUrlById } from '@/api/videoMonitor';
+import { getVideoTagInfo, getVideoUrlById } from '@/api/videoMonitor';
 
 interface Tag {
   dict_label: string;
@@ -68,6 +75,7 @@ interface Props {
   autoplay?: boolean;
   isIndex?: boolean;
   hiddenCollect: boolean;
+  isNoLive?: boolean;
 }
 
 const props = withDefaults(defineProps<Props>(), {});
@@ -78,6 +86,7 @@ const isPlaying = ref(false);
 const errBKVisible = ref(false);
 const posterVisible = ref(true);
 let videoPlayer = ref(null);
+let FlvVideoRef = ref(null);
 const tags = ref([]);
 
 watch(
@@ -133,18 +142,17 @@ const play_now = async (check?: boolean) => {
   posterVisible.value = false;
   errBKVisible.value = false;
   isPlaying.value = true;
-  // 视频监控数据
-  // getVideoById(props.dot_data.video_code).then((res) => {
-  //   if (res.data.status === 0) {
-  //     errBKVisible.value = true;
-  //     isPlaying.value = false;
-  //   } else {
-  getVideoUrlById(props.dot_data.video_code).then((res) => {
-    wsUrl.value = res.data;
-    videoPlayer.value.play(wsUrl.value);
+  nextTick(() => {
+    if (props.isNoLive) {
+      // FlvVideoRef.value.handleVideoPlay(props.dot_data.video_code);
+    } else {
+      // 视频监控数据
+      getVideoUrlById(props.dot_data.video_code).then((res) => {
+        wsUrl.value = res.data;
+        videoPlayer.value.play(wsUrl.value);
+      });
+    }
   });
-  //   }
-  // });
 };
 // 停止播放
 const stop_now = async () => {

+ 3 - 2
src/components/HKVideo/video-dialog.vue

@@ -4,13 +4,13 @@
     type="lg"
     header-type="header2"
     :title="videoMonitorData.name ? videoMonitorData.name : '视频'"
-    :get-tag-id="videoMonitorData.video_code"
+    :get-tag-id="isNoLive ? '' : videoMonitorData.video_code"
     hide-footer
     draggable
     @changeTagsData="changeTagsData"
   >
     <div class="video-box">
-      <HKVideo :dot_data="videoMonitorData" autoplay />
+      <HKVideo :dot_data="videoMonitorData" :isNoLive="isNoLive" autoplay />
     </div>
   </Dialog>
 </template>
@@ -18,6 +18,7 @@
 <script lang="ts" setup>
 interface Props {
   modelValue: boolean;
+  isNoLive: boolean;
   videoMonitorData: any;
 }
 

+ 1 - 0
src/types/components.d.ts

@@ -56,6 +56,7 @@ declare module 'vue' {
     ElTree: typeof import('element-plus/es')['ElTree']
     ElUpload: typeof import('element-plus/es')['ElUpload']
     FileUpload: typeof import('./../components/FileUpload/index.vue')['default']
+    FlvVideo: typeof import('./../components/FlvVideo/index.vue')['default']
     FooterSection: typeof import('./../components/FooterSection/index.vue')['default']
     Hamburger: typeof import('./../components/Hamburger/index.vue')['default']
     HeaderSearch: typeof import('./../components/HeaderSearch/index.vue')['default']

+ 20 - 4
src/views/globalMap/RightMenu/UAV/DroneDetail.vue

@@ -6,7 +6,7 @@
     </div>
     <div class="dialog-content">
       <div class="video-box">
-        <HKVideo ref="videoRef" :dot_data="detailsData" autoplay />
+        <HKVideo v-if="detailsData.video_code" ref="videoRef" :dot_data="detailsData" :isNoLive="isFlyVideo" autoplay />
       </div>
       <div class="title-box">{{ detailsData.name }}</div>
       <div class="btn-box">
@@ -20,7 +20,7 @@
         </div>
         <div class="btn3" @click="handleSwitchFlyVideo">
           <i class="icon-switch" />
-          <div>切换飞行视频</div>
+          <div>{{ isFlyVideo ? '切换监控视频' : '切换飞行视频' }}</div>
         </div>
       </div>
       <div class="title-box2">
@@ -101,6 +101,8 @@ const emits = defineEmits(['update:modelValue']);
 const containerScale = inject('containerScale');
 const detailsData = ref({
   video_code: '',
+  video_url: '',
+  fly_video: '',
   name: '',
   hangarInfo: {
     internetSpeed: '',
@@ -113,10 +115,14 @@ const detailsData = ref({
     windSpeed: ''
   }
 });
+let isFlyVideo = ref(false);
+
 const initData = () => {
   const data = {
     name: '曹江无人机机库',
-    video_code: '44090000001320004507',
+    video_code: '',
+    video_url: '44090000001320004507',
+    fly_video: 'https://mm.tjpapp.com/flv/yingyu-2019-11-01_1.flv',
     hangarInfo: {
       internetSpeed: '472',
       temperature: '32',
@@ -128,6 +134,8 @@ const initData = () => {
       windSpeed: '0.2'
     }
   };
+  isFlyVideo.value = false;
+  data.video_code = data.video_url;
   detailsData.value = data;
 };
 let videoRef = ref();
@@ -143,7 +151,15 @@ const handleVideoRefresh = () => {
 };
 
 // 切换飞行视频
-const handleSwitchFlyVideo = () => {};
+const handleSwitchFlyVideo = () => {
+  isFlyVideo.value = !isFlyVideo.value;
+  if (isFlyVideo.value) {
+    detailsData.value.video_code = detailsData.value.fly_video;
+  } else {
+    detailsData.value.video_code = detailsData.value.video_url;
+  }
+  handleVideoRefresh();
+};
 
 const handleClose = () => {
   emits('update:modelValue', false);

+ 9 - 9
src/views/globalMap/RightMenu/UAV/index.vue

@@ -7,11 +7,11 @@
       </div>
     </div>
     <div class="flex-box">
-     <RegionalSelect @confirm="handleRegionalChange" />
+      <RegionalSelect @confirm="handleRegionalChange" />
     </div>
     <div class="flex-box" style="align-items: center; margin-top: 40px">
-      <el-input v-model="queryParams.keyword" class="custom-input" placeholder="请输入" @confirm="initData" />
-      <div class="common-btn-primary2" style="margin-left: 20px" @onclick="initData" >搜索</div>
+      <el-input v-model="queryParams.keyword" class="custom-input" placeholder="请输入" @keydown.enter="initData" />
+      <div class="common-btn-primary2" style="margin-left: 20px" @click="initData">搜索</div>
     </div>
     <div class="flex-box" style="margin-top: 40px; margin-bottom: 40px; position: relative">
       <div class="flex-title1">
@@ -38,7 +38,7 @@
       <div class="table-content">
         <div v-for="(item, index) in droneResourcesData.listData" :key="index" class="tr" @click="handleItem(item.id)">
           <div class="td">{{ item.drone_name }}</div>
-          <div class="td" style="width: 150px; flex: unset; text-align: center">{{item.status_text}}</div>
+          <div class="td" style="width: 150px; flex: unset; text-align: center">{{ item.status_text }}</div>
         </div>
       </div>
     </div>
@@ -47,10 +47,10 @@
 </template>
 
 <script setup lang="ts" name="UAV">
-import { getDroneResourcesList, getRoughTimeStatusList } from '@/api/globalMap/UAV';
-import DroneTags from '@/views/globalMap/RightMenu/UAV/DroneTags.vue';
-import RegionalSelect from '@/views/globalMap/RightMenu/UAV/RegionalSelect.vue';
-import DroneDetail from '@/views/globalMap/RightMenu/UAV/DroneDetail.vue';
+import { getRoughTimeStatusList } from '@/api/globalMap/UAV';
+import DroneTags from './DroneTags.vue';
+import RegionalSelect from './RegionalSelect.vue';
+import DroneDetail from './DroneDetail.vue';
 
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 const { drone_status } = toRefs<any>(proxy?.useDict('drone_status'));
@@ -95,7 +95,7 @@ const handleStatusChange = (data) => {
 
 // 获取数据
 const initData = async () => {
-  const params = {...queryParams, status: queryParams.status_list.join(",")};
+  const params = { ...queryParams, status: queryParams.status_list.join(",") };
   delete params['status_list'];
   console.log(params);
   getRoughTimeStatusList(params).then((res) => {