Browse Source

完善荧石监控功能

caner 1 year ago
parent
commit
282a2f1a15

+ 4 - 0
src/assets/icons/capVideo.svg

@@ -0,0 +1,4 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 512 512">
+<path d="M448 256c0-106-86-192-192-192S64 150 64 256s86 192 192 192s192-86 192-192z" stroke="currentColor" stroke-width="32" fill="none"></path>
+<path d="M310.4 336H201.6a25.62 25.62 0 0 1-25.6-25.6V201.6a25.62 25.62 0 0 1 25.6-25.6h108.8a25.62 25.62 0 0 1 25.6 25.6v108.8a25.62 25.62 0 0 1-25.6 25.6z" ></path>
+</svg>

+ 1 - 0
src/assets/icons/change.svg

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 512 512"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32" d="M320 120l48 48l-48 48"></path><path d="M352 168H144a80.24 80.24 0 0 0-80 80v16" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32"></path><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32" d="M192 392l-48-48l48-48"></path><path d="M160 344h208a80.24 80.24 0 0 0 80-80v-16" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32"></path></svg>

+ 1 - 0
src/assets/icons/fullScreen.svg

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 512 512"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32" d="M432 320v112H320"></path><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32" d="M421.8 421.77L304 304"></path><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32" d="M80 192V80h112"></path><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32" d="M90.2 90.23L208 208"></path><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32" d="M320 80h112v112"></path><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32" d="M421.77 90.2L304 208"></path><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32" d="M192 432H80V320"></path><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32" d="M90.23 421.8L208 304"></path></svg>

+ 1 - 0
src/assets/icons/image.svg

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 512 512"><rect x="48" y="80" width="416" height="352" rx="48" ry="48" fill="none" stroke="currentColor" stroke-linejoin="round" stroke-width="32"></rect><circle cx="336" cy="176" r="32" fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="32"></circle><path d="M304 335.79l-90.66-90.49a32 32 0 0 0-43.87-1.3L48 352" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32"></path><path d="M224 432l123.34-123.34a32 32 0 0 1 43.11-2L464 368" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32"></path></svg>

+ 1 - 0
src/assets/icons/search.svg

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 512 512"><path d="M456.69 421.39L362.6 327.3a173.81 173.81 0 0 0 34.84-104.58C397.44 126.38 319.06 48 222.72 48S48 126.38 48 222.72s78.38 174.72 174.72 174.72A173.81 173.81 0 0 0 327.3 362.6l94.09 94.09a25 25 0 0 0 35.3-35.3zM97.92 222.72a124.8 124.8 0 1 1 124.8 124.8a124.95 124.95 0 0 1-124.8-124.8z" fill="currentColor"></path></svg>

+ 1 - 0
src/assets/icons/transh.svg

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 512 512"><rect x="32" y="48" width="448" height="80" rx="32" ry="32" fill="currentColor"></rect><path d="M74.45 160a8 8 0 0 0-8 8.83l26.31 252.56a1.5 1.5 0 0 0 0 .22A48 48 0 0 0 140.45 464h231.09a48 48 0 0 0 47.67-42.39v-.21l26.27-252.57a8 8 0 0 0-8-8.83zm248.86 180.69a16 16 0 1 1-22.63 22.62L256 318.63l-44.69 44.68a16 16 0 0 1-22.63-22.62L233.37 296l-44.69-44.69a16 16 0 0 1 22.63-22.62L256 273.37l44.68-44.68a16 16 0 0 1 22.63 22.62L278.62 296z" fill="currentColor"></path></svg>

+ 4 - 2
src/assets/native-plugin.ts

@@ -13,7 +13,8 @@ import {
   NSwitch,
   NFormItem,
   NForm,
-  NTree
+  NTree,
+  NTooltip
 } from 'naive-ui'
 
 const naive = create({
@@ -31,7 +32,8 @@ const naive = create({
     NSwitch,
     NFormItem,
     NForm,
-    NTree
+    NTree,
+    NTooltip
   ]
 })
 

+ 1 - 1
src/components/icon.vue

@@ -3,7 +3,7 @@ import { computed } from 'vue'
 
 const props = defineProps<{
   name: string,
-  size?: number,
+  size?: number|string,
   color?: string
 }>()
 const symbolId = computed(() => `#icon-${props.name}`)

+ 167 - 20
src/pages/views/video/index.vue

@@ -7,7 +7,15 @@
           clearable
           style=" width: 150px;height:28px;"
           size="tiny"
-        />
+        >
+          <template #suffix>
+            <Icon
+              name="search"
+              size="15"
+            />
+          </template>
+        </n-input>
+
         <n-select
           v-model:value="selectRow"
           :options="option"
@@ -15,11 +23,17 @@
           @update:value="onChange"
         />
         <n-button
-          secondary
           size="small"
+          icon-placement="right"
           style="margin-left: 10px;"
           @click="onChange(selectRow)"
         >
+          <template #icon>
+            <Icon
+              name="transh"
+              size="15"
+            />
+          </template>
           清空
         </n-button>
       </div>
@@ -48,6 +62,59 @@
           :style="`width:${(100 / selectRow) - 0.05}%;height:${(100 / selectRow) - 0.15}%;`"
         >
           <div :id="item.id" />
+          <div
+            v-if="item.fluentLiveUrl"
+            class="video-right-item-bar"
+          >
+            <div class="video-right-item-bar-left">
+              <n-tooltip trigger="hover">
+                <template #trigger>
+                  <Icon
+                    name="capVideo"
+                    size="25"
+                    :color="item.isCapVideo ? 'red' : 'white'"
+                    @click="item.captureVideo()"
+                  />
+                </template>
+                {{ item.isCapVideo ? '停止录屏' : '开始录屏' }}
+              </n-tooltip>
+              <n-tooltip trigger="hover">
+                <template #trigger>
+                  <Icon
+                    name="image"
+                    size="25"
+                    @click="item.capturePicture(item.cameraName)"
+                  />
+                </template>
+                截图
+              </n-tooltip>
+            </div>
+            <div class="video-right-item-bar-right">
+              <n-button
+                size="small"
+                icon-placement="right"
+                @click="item.changeCode()"
+              >
+                <template #icon>
+                  <Icon
+                    name="change"
+                    size="20"
+                  />
+                </template>
+                {{ item.isChangeCode ? '子码流' : '主码流' }}
+              </n-button>
+              <n-tooltip trigger="hover">
+                <template #trigger>
+                  <Icon
+                    name="fullScreen"
+                    size="25"
+                    @click="item.fullScreen()"
+                  />
+                </template>
+                全屏
+              </n-tooltip>
+            </div>
+          </div>
         </div>
       </template>
     </div>
@@ -56,19 +123,27 @@
 
 <script setup lang='ts'>
 import {
-  onMounted, onUnmounted, ref, watch
+  onMounted, onUnmounted, ref
 } from 'vue'
 import EzVideoService from './ezVideo.service'
 import { useNotification } from 'naive-ui'
 
 interface VideoItem {
   id: string,
-  liveUrl: string,
   accessToken: string,
-  video: undefined | any,
+  video: null | any,
+  isCapVideo: boolean,
+  isChangeCode: boolean,
+  cameraName: string,
+  fluentLiveUrl: string,
+  highLiveUrl: string,
   play: (a: number, b: number) => void,
   destory: () => void,
-  resize: (a: number, b: number) => void
+  resize: (a: number, b: number) => void,
+  fullScreen: () => void,
+  capturePicture: (a: string) => void,
+  captureVideo: () => void,
+  changeCode: () => void
 }
 
 const notification = useNotification()
@@ -92,7 +167,9 @@ const treeData = ref([
             accessToken: 'at.a82kqljj96ja8ony6e57nrqi4aigp963-7sn8ji0ji3-16njxp9-rmioevhxz',
             label: 'test',
             key: '1-2-1',
-            liveUrl: 'ezopen://aczn1688@open.ys7.com/FH2861570/2.live'
+            fluentLiveUrl: 'ezopen://aczn1688@open.ys7.com/FH2861570/2.live',
+            highLiveUrl: 'ezopen://aczn1688@open.ys7.com/FH2861570/2.live',
+            cameraName: 'test'
           }
         ]
       }
@@ -115,26 +192,50 @@ function onChange(v: number) {
     const ezVideoService = new EzVideoService()
     arr.push({
       id: `video${k}`,
-      liveUrl: '',
       accessToken: '',
-      video: undefined as any,
+      cameraName: `Test${k}`,
+      video: undefined,
+      isCapVideo: false,
+      isChangeCode: false,
+      fluentLiveUrl: '',
+      highLiveUrl: '',
       play(width: number, height: number) {
         if (this.video) this.destory()
-        if (!width || !height) return
+        if (!width || !height || !this.fluentLiveUrl) return
         this.video = ezVideoService.init({
-          id: this.id, url: this.liveUrl, accessToken: this.accessToken, width, height
+          id: this.id, url: this.fluentLiveUrl!, accessToken: this.accessToken, width, height
         })
       },
       destory() {
-        if (this.video) {
-          this.video.stop()
-          this.video = undefined
-          document.getElementById(this.id)?.remove()
-        }
+        if (!this.video) return
+        this.video.stop()
+        this.video = undefined
+        document.getElementById(this.id)?.remove()
       },
       resize(width: number, height: number) {
         if (!width || !height) return
         if (this.video) this.video.reSize(width, height)
+      },
+      fullScreen() {
+        if (!this.video) return
+        this.video.fullScreen()
+      },
+      capturePicture(name = 'test') {
+        if (!this.video) return
+        this.video.capturePicture(name)
+      },
+      captureVideo() {
+        if (!this.video) return
+        if (this.isCapVideo) { this.video.stopSave() } else {
+          this.video.startSave()
+        }
+        this.isCapVideo = !this.isCapVideo
+      },
+      changeCode() {
+        if (!this.video) return
+        const url = this.isChangeCode ? this.fluentLiveUrl : this.highLiveUrl
+        this.video.changePlayUrl({ url })
+        this.isChangeCode = !this.isChangeCode
       }
     })
   }
@@ -157,7 +258,7 @@ function onDrop(data: any) {
     return
   }
   // 查找没有播放的分屏
-  const index = videoItem.value.findIndex((el) => !el.accessToken && !el.liveUrl)
+  const index = videoItem.value.findIndex((el) => !el.accessToken && !el.fluentLiveUrl)
   console.log(7777, arr, videoItem.value, index)
   if (index < 0) return
   for (let k = 0; k < arr.length; k++) {
@@ -165,13 +266,14 @@ function onDrop(data: any) {
     const num = index + k
     if (num > (videoItem.value.length - 1)) continue
     videoItem.value[num].accessToken = el.accessToken
-    videoItem.value[num].liveUrl = el.liveUrl
+    videoItem.value[num].fluentLiveUrl = el.fluentLiveUrl!
+    videoItem.value[num].highLiveUrl = el.highLiveUrl!
+    videoItem.value[num].cameraName = el.cameraName
     setTimeout(() => {
       const dom = document.getElementById('videoBoxs')
       videoItem.value[num].play(dom?.clientWidth || 0, dom?.clientHeight || 0)
     }, 200)
   }
-  console.log(888, videoItem.value)
 }
 
 onMounted(() => onChange(selectRow.value))
@@ -247,12 +349,57 @@ onUnmounted(() => onChange(selectRow.value))
     &-item {
       background: black;
       overflow: hidden;
+      position: relative;
 
-      &>div {
+      &>div:first-child {
         overflow: hidden;
         width: 100%;
         height: 100%;
       }
+
+      &:hover &-bar {
+        display: flex;
+      }
+
+      &-bar {
+        position: absolute;
+        width: 100%;
+        height: 40px;
+        left: 0;
+        bottom: 0;
+        display: none;
+        justify-content: space-between;
+        align-items: center;
+        box-sizing: border-box;
+        padding: 0 10px;
+        background: rgba(0, 0, 0, 0.5);
+        color: white;
+
+        &-left,
+        &-right {
+          display: flex;
+          align-items: center;
+
+          &>svg {
+            outline: none;
+            cursor: pointer;
+          }
+
+          &>svg:not(:first-child) {
+            margin-left: 10px;
+          }
+        }
+
+        :deep(.n-button) {
+          --n-height: 25px;
+          --n-text-color: white;
+          --n-text-color-hover: white;
+          --n-border-hover: 1px solid rgba(196, 200, 206, 1);
+          --n-text-color-focus: white;
+          --n-text-color-pressed: white;
+          --n-border-focus: white;
+        }
+      }
     }
 
     .active {