Parcourir la source

fix: camera perfect and bind camera

hulinfei il y a 3 ans
Parent
commit
3d1f6e6289

+ 11 - 0
src/api/camera.js

@@ -99,3 +99,14 @@ export function detail (stream) {
     method: 'get'
   })
 }
+//
+export function getBindCamera (query) {
+  const { deviceId, ...params } = query
+  return request({
+    url: `device/bind/thirdPartyCamera/${deviceId}`,
+    method: 'get',
+    params: {
+      ...params
+    }
+  })
+}

+ 5 - 2
src/views/device/detail/index.vue

@@ -69,6 +69,7 @@ import LinkState from './components/LinkState'
 import Sensors from './components/external/Sensors'
 import Transmitter from './components/external/Transmitter'
 import ReceivingCard from './components/external/ReceivingCard'
+import camera from './../../external/camera'
 
 export default {
   name: 'DeviceDetail',
@@ -80,7 +81,8 @@ export default {
     LinkState,
     Sensors,
     Transmitter,
-    ReceivingCard
+    ReceivingCard,
+    camera
   },
   data () {
     return {
@@ -97,7 +99,8 @@ export default {
         this.accessSet.has(Access.VIEW_SENSORS) ? { key: 'Sensors', label: '传感器' } : null,
         __STAGING__ ? { key: 'Transmitter', label: '发送控制设备' } : null,
         __STAGING__ ? { key: 'ReceivingCard', label: '接收卡' } : null,
-        __STAGING__ ? { key: 'LinkState', label: '全链路监测状态' } : null
+        __STAGING__ ? { key: 'LinkState', label: '全链路监测状态' } : null,
+        __STAGING__ ? { key: 'camera', label: '摄像头' } : null
       ].filter(val => val)
     }
   },

+ 4 - 4
src/views/external/camera/components/Detail.vue

@@ -7,7 +7,7 @@
       class="el-icon-close closeDetail"
       @click="close"
     />
-    <div class="detail-top">
+    <div v-if="detailobj.cameraType===2" class="detail-top">
       <div class="detail_text">
         {{ detailobj.name }}人流量监测
       </div>
@@ -19,9 +19,9 @@
       class="video"
       muted
       autoplay
-      :poster="require('@/assets//video-post.png')"
+      :poster="require('@/assets/video-post.png')"
     />
-    <div class="detail-buttom">
+    <div v-if="detailobj.cameraType===2" class="detail-buttom">
       <el-row :gutter="16">
         <el-col :span="24">
           <div class="video-controls l-flex--row">
@@ -525,7 +525,7 @@ export default {
     cursor: pointer;
     z-index: 3;
     font-size: 42px;
-    color: #fff;
+    color: #000;
   }
   .video {
     width: 100%;

+ 302 - 0
src/views/external/camera/components/Fullscreen.vue

@@ -0,0 +1,302 @@
+<template>
+  <div class="fullscreen">
+    <!-- <i
+      class="el-icon-close closeDetail"
+      @click="close"
+    /> -->
+    <div>
+      <el-row v-if="videoOption.list.length" :gutter="16" class="rowheight">
+        <el-col
+          v-for="(video, index) in videoOption.list"
+          :key="index"
+          :span="8"
+          class="cameraRow"
+        >
+          <div
+            ref="videoC"
+            class="o-video bg-purple"
+            :style="{ height: videoheight }"
+          >
+            <video
+              :ref="video.identifier"
+              style="width: 100%"
+              class="video"
+              muted
+              autoplay
+              controls
+              :poster="require('@/assets/video-post.png')"
+            />
+            <div v-show="!video.onlineStatus" class="offLine">设备离线</div>
+          </div>
+        </el-col>
+      </el-row>
+      <div v-if="!videoOption.list.length && !videoOption.error" class="empty">
+        无摄像头数据
+      </div>
+      <el-result v-if="videoOption.error" icon="warning">
+        <template #extra>
+          <el-link
+            class="u-pointer"
+            type="warning"
+            @click="getCamera(cameraType)"
+          >
+            出错了,点击重试
+          </el-link>
+        </template>
+      </el-result>
+    </div>
+  </div>
+</template>
+
+<script>
+import flvjs from 'flv.js'
+
+const CAMERA_URL = `${location.protocol === 'https:' ? 'wss' : 'ws'}://${
+  process.env.VUE_APP_GATEWAY || location.host
+}${process.env.VUE_APP_CAMERA_PROXY}`
+import {
+  getCamera,
+  getBindCamera
+} from '@/api/camera'
+
+import { createListOptions } from '@/utils'
+export default {
+  // name: "CameraFullscreen",
+  props: {
+    device: {
+      type: Object,
+      default () {
+        return {}
+      }
+    },
+    cameraType: {
+      type: Number,
+      default () {
+        return 1
+      }
+    },
+    totalCount: {
+      type: Number,
+      default () {
+        return 1
+      }
+    }
+    // ['']
+  },
+  data () {
+    return {
+      videoOption: createListOptions({ pageSize: this.totalCount }),
+      videoheight: 0,
+      playerList: {},
+      fullscreen: false
+    }
+  },
+  // watch: {
+  //   fullscreen (value, oldvalue) {
+  //     console.log(value, oldvalue)
+  //     if (!value && oldvalue) {
+  //       this.close()
+  //     }
+  //   }
+  // },
+  created () {
+    this.initScreen()
+    this.getCamera(this.cameraType)
+  },
+  mounted () {},
+  beforeDestroy () {
+    this.destroyPlayer()
+  },
+  methods: {
+    destroyPlayer () {
+      for (const key in this.playerList) {
+        if (Object.hasOwnProperty.call(this.playerList, key)) {
+          if (this.playerList[key]) {
+            this.playerList[key].pause()
+            this.playerList[key].unload()
+            this.playerList[key].detachMediaElement()
+            this.playerList[key].destroy()
+            this.playerList[key] = null
+          }
+        }
+      }
+    },
+    close () {
+      this.destroyPlayer()
+      this.$emit('closeDetail')
+    },
+    getCamera (cameraType) {
+      var type
+      const options = this.videoOption
+      options.error = false
+      options.loading = true
+      options.params.name = this.searchname
+      options.params.cameraType = cameraType || ''
+      if (JSON.stringify(this.device) === '{}') {
+        type = getCamera
+      } else {
+        type = getBindCamera
+        options.params.deviceId = this.device.id
+      }
+      type(options.params)
+        .then(
+          ({ data, totalCount }) => {
+            options.totalCount = totalCount || 0
+            options.list = data
+            this.$nextTick(() => {
+              this.videoheight = this.$refs.videoC[0].clientWidth * 9 / 16 + 'px'
+              this.destroyPlayer()
+              for (let i = 0; i < options.list.length; i++) {
+                var item = JSON.stringify(this.device) === '{}' ? options.list[i] : options.list[i].thirdPartyDevice
+                if (item.onlineStatus) {
+                  this.getflv(item.identifier)
+                }
+              }
+            })
+          },
+          () => {
+            options.error = true
+            options.list = []
+          }
+        )
+        .finally(() => {
+          options.loading = false
+        })
+    },
+    getflv (identifier) {
+      if (flvjs.isSupported()) {
+        // 创建一个flvjs实例
+        this.playerList[identifier] = flvjs.createPlayer({
+          type: 'flv',
+          isLive: true,
+          hasAudio: false,
+          url: `${CAMERA_URL}/${identifier}?authorization=${this.$keycloak.token}`
+        })
+        this.playerList[identifier].on('error', (e) => {
+          // console.log(e)
+          this.$message({
+            type: 'warning',
+            message: e
+          })
+        })
+        // 将实例挂载到video元素上面
+        this.playerList[identifier].attachMediaElement(this.$refs[identifier][0])
+        // player.currentTime = parseFloat(document.getElementsByName('seekpoint')[0].value);
+        try {
+          // 开始运行加载 只要流地址正常 就可以在h5页面中播放出画面了
+          this.playerList[identifier].load()
+          this.playerList[identifier].play()
+        } catch (error) {
+          console.log('连接websocker异常:' + error)
+          console.log(error)
+        }
+      }
+    },
+    initScreen () {
+      this.handleFullScreen()
+      // window.addEventListener('keydown', function (event) {
+      //   const e = event || window.event
+      //   if (e && e.keyCode === 122) {
+      //     e.preventDefault()
+      //   }
+      // })
+      window.addEventListener('fullscreenchange', v => {
+        if (this.fullscreen === true) {
+          this.fullscreen = false
+        } else {
+          this.fullscreen = true
+          this.close()
+        }
+      })
+    },
+    handleFullScreen () {
+      const element = document.documentElement
+      if (this.fullscreen) {
+        if (document.exitFullscreen) {
+          document.exitFullscreen()
+        } else if (document.webkitCancelFullScreen) {
+          document.webkitCancelFullScreen()
+        } else if (document.mozCancelFullScreen) {
+          document.mozCancelFullScreen()
+        } else if (document.msExitFullscreen) {
+          document.msExitFullscreen()
+        }
+        console.log('已还原!')
+      } else {
+        if (element.requestFullscreen) {
+          element.requestFullscreen()
+        } else if (element.webkitRequestFullScreen) {
+          element.webkitRequestFullScreen()
+        } else if (element.mozRequestFullScreen) {
+          element.mozRequestFullScreen()
+        } else if (element.msRequestFullscreen) {
+          // IE11
+          element.msRequestFullscreen()
+        }
+        console.log('已全屏!')
+      }
+      // 改变当前全屏状态
+      this.fullscreen = !this.fullscreen
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.fullscreen{
+  padding: 16px;
+}
+.closeDetail {
+  position: absolute;
+  right: 20px;
+  top: 5px;
+  cursor: pointer;
+  z-index: 3;
+  font-size: 42px;
+  color: #000;
+}
+.empty {
+  color: #aaa;
+  text-align: center;
+}
+.o-video{
+  background-color: #edf0f6;
+  position: relative;
+  overflow: hidden;
+  &_buttom {
+    position: absolute;
+    bottom: 0px;
+    width: 100%;
+    height: 58px;
+    background-image: linear-gradient(0deg, rgba(6, 11, 18, 0.9), transparent);
+    border-radius: 0px 0px 4px 4px;
+    color: #fff;
+    padding: 0 16px;
+  }
+  img {
+    cursor: pointer;
+  }
+  &_edit {
+    margin-right: 16px;
+  }
+}
+.offLine {
+  position: absolute;
+  left: 50%;
+  top: 50%;
+  color: #ff0000;
+  text-align: center;
+  transform: translate(-50%, -50%);
+}
+.cameraRow {
+  margin-bottom: 16px;
+}
+video::-webkit-media-controls-fullscreen-button {
+  display: none;
+}
+//所有控件
+video::-webkit-media-controls-enclosure {
+  display: none;
+}
+</style>
+<style lang="scss"></style>

+ 155 - 45
src/views/external/camera/index.vue

@@ -15,17 +15,25 @@
         label="人流量监测"
         name="first"
       >
-        <div class="has-top-padding">
+        <div v-loading="videoOption.loading" class="has-top-padding maxheight">
           <div class="l-flex--row c-table__header">
-            <div class="l-flex__auto c-sibling-item">
+            <div class="l-flex__none c-sibling-item">
               <button
-                v-if="isSuperAdmin"
+                v-if="isSuperAdmin && bind"
                 class="o-button"
                 @click="onAdd"
               >
                 <i class="o-button__icon el-icon-circle-plus-outline" />新增
               </button>
             </div>
+            <div class="l-flex__auto c-sibling-item">
+              <button
+                class="o-button o-botton_white"
+                @click="onFull"
+              >
+                <i class="o-button__icon el-icon-full-screen" />全部
+              </button>
+            </div>
             <search-input
               v-model.trim="searchname"
               class="l-flex__none c-sibling-item"
@@ -62,6 +70,7 @@
                   class="video"
                   muted
                   autoplay
+                  controls
                   :poster="require('@/assets//video-post.png')"
                 />
                 <div
@@ -72,7 +81,7 @@
                 </div>
                 <div class="o-video_buttom l-flex--row">
                   <div class="l-flex__auto">{{ video.name }}</div>
-                  <template v-if="isSuperAdmin">
+                  <template v-if="isSuperAdmin && bind">
                     <img
                       class="o-video_edit"
                       :src="imgUrl.edit"
@@ -102,7 +111,7 @@
               <el-link
                 class="u-pointer"
                 type="warning"
-                @click="getCamera"
+                @click="getCamera(cameraType)"
               >
                 出错了,点击重试
               </el-link>
@@ -112,25 +121,33 @@
             :total="videoOption.totalCount"
             :page.sync="videoOption.params.pageNum"
             :limit.sync="videoOption.params.pageSize"
-            @pagination="getCamera"
+            @pagination="getCamera(cameraType)"
           />
         </div>
       </el-tab-pane>
-      <!-- <el-tab-pane
+      <el-tab-pane
         label="LED屏画面监测"
         name="second"
       >
-        <div v-loading="screenOption.loading" class="has-top-padding">
+        <div v-loading="screenOption.loading" class="has-top-padding maxheight">
           <div class="l-flex--row c-table__header">
-            <div class="l-flex__auto c-sibling-item">
+            <div class="l-flex__none c-sibling-item">
               <button
-                v-if="isSuperAdmin"
+                v-if="isSuperAdmin && bind"
                 class="o-button"
                 @click="onAdd"
               >
                 <i class="o-button__icon el-icon-circle-plus-outline" />新增
               </button>
             </div>
+            <div class="l-flex__auto c-sibling-item">
+              <button
+                class="o-button o-botton_white"
+                @click="onFull"
+              >
+                <i class="o-button__icon el-icon-full-screen" />全部
+              </button>
+            </div>
             <search-input
               v-model.trim="searchname"
               class="l-flex__none c-sibling-item"
@@ -167,6 +184,7 @@
                   class="video"
                   muted
                   autoplay
+                  controls
                   :poster="require('@/assets/video-post.png')"
                 />
                 <div
@@ -177,16 +195,16 @@
                 </div>
                 <div class="o-video_buttom l-flex--row">
                   <div class="l-flex__auto">{{ video.name }}</div>
-                  <template v-if="isSuperAdmin">
+                  <template v-if="isSuperAdmin && bind">
                     <img
                       class="o-video_edit"
                       :src="imgUrl.edit"
-                      @click.stop="editbtn(video)"
+                      @click.stop="onEdit(video)"
                     >
                     <img
                       class="o-video_delete"
                       :src="imgUrl.delete"
-                      @click.stop="deletebtn(video)"
+                      @click.stop="onDel(video)"
                     >
                   </template>
                 </div>
@@ -205,7 +223,7 @@
               <el-link
                 class="u-pointer"
                 type="warning"
-                @click="getCamera"
+                @click="getCamera(cameraType)"
               >
                 出错了,点击重试
               </el-link>
@@ -216,10 +234,10 @@
             :page-sizes="[6]"
             :page.sync="screenOption.params.pageNum"
             :limit.sync="screenOption.params.pageSize"
-            @pagination="getCamera"
+            @pagination="getCamera(cameraType)"
           />
         </div>
-      </el-tab-pane> -->
+      </el-tab-pane>
     </el-tabs>
     <el-dialog
       :title="dialogTitle"
@@ -324,6 +342,21 @@
         @closeDetail="closeDetail"
       />
     </el-dialog>
+    <el-dialog
+      title
+      :fullscreen="true"
+      :visible="fullshow"
+      :close-on-click-modal="false"
+      class="fulldialog"
+    >
+      <Fullscreen
+        v-if="fullshow"
+        :camera-type="cameraType"
+        :device="device"
+        :total-count="cameraType===2?videoOption.totalCount:screenOption.totalCount"
+        @closeDetail="closeDetail"
+      />
+    </el-dialog>
   </wrapper>
 </template>
 
@@ -334,17 +367,28 @@ import {
   getCamera,
   addCamera,
   updateCamera,
-  deleteCamera
+  deleteCamera,
+  getBindCamera
 } from '@/api/camera'
 import { createListOptions } from '@/utils'
 import Detail from './components/Detail'
+import Fullscreen from './components/Fullscreen'
 
 const CAMERA_URL = `${location.protocol === 'https:' ? 'wss' : 'ws'}://${process.env.VUE_APP_GATEWAY || location.host}${process.env.VUE_APP_CAMERA_PROXY}`
 
 export default {
   name: 'Camera',
   components: {
-    Detail
+    Detail,
+    Fullscreen
+  },
+  props: {
+    device: {
+      type: Object,
+      default () {
+        return {}
+      }
+    }
   },
   data () {
     return {
@@ -381,19 +425,20 @@ export default {
       screenOption: createListOptions({
         pageSize: 6
       }),
-      checkList: [],
-      returnList: createListOptions({
-        pageSize: 9
-      }),
-      returnheight: 0,
-      rowNum: 8
+      fullshow: false,
+      bind: JSON.stringify(this.device) === '{}'
     }
   },
   computed: {
-    ...mapGetters(['isSuperAdmin'])
+    ...mapGetters(['isSuperAdmin']),
+    cameraType () {
+      return this.activeName === 'first' ? 2 : 1
+    }
   },
   created () {
-    this.getCamera()
+    // console.log(JSON.stringify(this.device) === '{}')
+    this.getCamera(this.cameraType)
+    // this.getBindCamera()
   },
   beforeDestroy () {
     this.destroyPlayer()
@@ -412,26 +457,72 @@ export default {
         }
       }
     },
-    handleClick () {},
+    handleClick () {
+      this.getCamera(this.cameraType)
+      // if (this.cameraType === 1) {
+      //   if (this.screenOption.list.length === 0) {
+      //     this.getCamera(this.cameraType, 'no')
+      //   }
+      // } else {
+      //   if (this.videoOption.list.length === 0) {
+      //     this.getCamera(this.cameraType, 'no')
+      //   }
+      // }
+    },
     search () {
-      this.getCamera()
+      this.getCamera(this.cameraType)
     },
-    getCamera () {
-      const options = this.videoOption
+    getBindCamera () {
+      getBindCamera({
+        deviceId: this.device.id,
+        cameraType: this.cameraType
+      }).then((data) => {
+        console.log(data)
+      })
+    },
+    getCamera (cameraType, no) {
+      var type
+      var options
+      if (cameraType === 2) {
+        options = this.videoOption
+      } else {
+        options = this.screenOption
+      }
+      // const options = this.videoOption
       options.error = false
       options.loading = true
       options.params.name = this.searchname
-      getCamera(options.params)
+      options.params.cameraType = cameraType || ''
+      if (this.bind) {
+        type = getCamera
+      } else {
+        type = getBindCamera
+        options.params.deviceId = this.device.id
+      }
+      type(options.params)
         .then(
           ({ data, totalCount }) => {
-            options.totalCount = totalCount
+            options.totalCount = totalCount || 0
             options.list = data
-            options.totalCount && this.$nextTick(() => {
-              this.videoheight = (this.$refs.videoB[0].clientWidth * 9) / 16 + 'px'
+            // options.totalCount &&
+            this.$nextTick(() => {
+              try {
+                if (this.$refs.videoB) {
+                  this.videoheight = ((this.$refs.videoB[0].clientWidth || this.$refs.screenB[0].clientWidth) * 9) / 16 + 'px'
+                } else if (this.$refs.screenB) {
+                  this.videoheight = ((this.$refs.screenB[0].clientWidth || this.$refs.videoB[0].clientWidth) * 9) / 16 + 'px'
+                }
+              } catch (error) {
+                console.log(error)
+              }
               this.destroyPlayer()
-              for (let i = 0; i < data.length; i++) {
-                if (options.list[i].onlineStatus) {
-                  this.getflv(options.list[i].identifier)
+              // if (!no) {
+              //   this.destroyPlayer()
+              // }
+              for (let i = 0; i < options.list.length; i++) {
+                var item = this.bind ? options.list[i] : options.list[i].thirdPartyDevice
+                if (item.onlineStatus) {
+                  this.getflv(item.identifier)
                 }
               }
             })
@@ -451,10 +542,11 @@ export default {
         identifier: this.camera.identifier,
         username: this.camera.username,
         password: this.camera.password,
-        remark: this.camera.remark
+        remark: this.camera.remark,
+        cameraType: this.cameraType
       }).then(() => {
         this.handleCloseAddDialog('cameraForm')
-        this.getCamera()
+        this.getCamera(this.cameraType)
       })
     },
     onAdd () {
@@ -507,10 +599,11 @@ export default {
         identifier: item.identifier,
         username: this.camera.username,
         password: this.camera.password,
-        remark: this.camera.remark
+        remark: this.camera.remark,
+        cameraType: this.cameraType
       }).then(() => {
         this.handleCloseAddDialog('cameraForm')
-        this.getCamera()
+        this.getCamera(this.cameraType)
       })
     },
     onDel (item) {
@@ -519,7 +612,7 @@ export default {
         if (videoOption.list.length === 1 && videoOption.params.pageNum > 1) {
           videoOption.params.pageNum -= 1
         }
-        this.getCamera()
+        this.getCamera(this.cameraType)
       })
     },
     getflv (identifier) {
@@ -532,7 +625,11 @@ export default {
           url: `${CAMERA_URL}/${identifier}?authorization=${this.$keycloak.token}`
         })
         this.playerList[identifier].on('error', (e) => {
-          console.log(e)
+          // console.log(e)
+          this.$message({
+            type: 'warning',
+            message: e
+          })
         })
         // 将实例挂载到video元素上面
         this.playerList[identifier].attachMediaElement(this.$refs[identifier][0])
@@ -556,7 +653,12 @@ export default {
     },
     closeDetail () {
       this.detailing = false
-      this.getCamera()
+      this.fullshow = false
+      this.getCamera(this.cameraType)
+    },
+    onFull () {
+      this.destroyPlayer()
+      this.fullshow = true
     }
   }
 }
@@ -571,7 +673,7 @@ video::-webkit-media-controls-enclosure {
   height: 100%;
 }
 .rowheight {
-  // height: calc(100% - 40px);
+  max-height: calc(100% - 100px);
   overflow: auto;
 }
 .c-tabs {
@@ -625,6 +727,14 @@ video::-webkit-media-controls-enclosure {
   color: #aaa;
   text-align: center;
 }
+.maxheight{
+  height: 100%;
+}
+.o-botton_white{
+  background-color: #fff;
+  border: 1px solid #D5D9E4;
+  color: #8E929C;
+}
 </style>
 <style lang="scss">
 .fulldialog {