国标GB28181流媒体服务器支持多分屏操作

2020-05-20 23:07:51 浏览数 (1)

最近感觉使用国标协议的开发者有很多,我们国标GB28181流媒体服务器提供流转发服务,负责将GB28181设备/平台推送的PS流转成ES流,然后提供RTSP、RTMP、FLV、HLS多种格式进行分发,实现web浏览器、手机浏览器、微信等各种终端无插件播放。

之前有开发者说我们国标GB28181的流媒体服务器需要查看视频的时候,只能单独查看一路视频,想同时查看多路视频的时候,就不是很方便操作。

原本的界面如下:

我们的研发人员也对这个多分屏的问题进行了研究,在前几天实现了国标GB28181流媒体服务器的多分屏操作(我由衷觉得我的研发部同事们都很厉害啊!),界面如下图:

以下是实现代码,大家可以参考一下:

代码语言:javascript复制
<template>
  <div>
    <div class="screen-main">
      <el-row>
        <el-col :xs="24" :sm="24" :md="24" :lg="4" :xl="4">
          <div class="screen-tree" @scroll="scrollEvent">
            <span class="screen-tree-title">设备列表</span>
            <el-tree
              v-loading="loading"
              :data="terrData"
              node-key="ID"
              default-expand-all
              :props="{children: 'Children', label: 'Name'}"
            >
              <span slot-scope="{ node, data }" class="custom-tree-node">
                <div :class="['custom-tree-node', {'private-info': !data.Online&&data.Type===1}, {'private-info': data.ChannelCount===0} ]" :title="data.ID" @click="onSelection(data)">
                  <i :class="['fa', {'private-success': data.Online&&data.Type===1}, { 'fa-video-camera': data.Type===2},{'fa-desktop':data.Type===1} ]" />
                  {{ data.Name?data.Name:data.ID }}
                </div>
              </span>
            </el-tree>
          </div>
        </el-col>
        <el-col :xs="24" :sm="24" :md="24" :lg="16" :xl="16">  
        
          <div style="padding-top: 50px;">
            <el-row class="screen-main-player" v-if="isShow">
              <el-col :xs="24" :sm="colNum[3]" :md="colNum[2]" :lg="colNum[1]" :xl="colNum[0]" v-for="(item, index) in PlayerData" :key="index" :class="[{'active-shadow': indexType===index}]" >  
                <div class="screen-main-item" @click.stop="indexType=index">
                  <SereenPlayer :DeviceID="item.DeviceID" :ID="item.ID" :Index="index" @index="onIndex" :Radio="radio"/>
                </div>
              </el-col>
            </el-row>
          </div>
          <div class="screen-radio">
            <el-radio-group v-model="radio" size="small" @change="getList()"> 
              <el-radio-button :label="item.type" v-for="(item, index) in radioData" :key="index">{{item.name}}</el-radio-button>
              <el-radio-button :label="radio"><i class="fa fa-arrows-alt" @click.prevent="fullscreen"></i></el-radio-button>
            </el-radio-group>
          </div>
        </el-col>
      </el-row>
    </div>
  </div>
</template>
<script>
import SereenPlayer from './SereenPlayer'
export default {
  components: { SereenPlayer },
  data() {
    return {
      indexType: 0,
      terrData: [],
      isShow: true,
      loading: true,
      queryDev: undefined,
      DeviceCount: 0,
      radio: 4,
      PlayerData: [],
      PlayerDataName: '',
      radioData: [
        { type: 1, name: '单屏' },
        { type: 4, name: '四分屏' },
        { type: 9, name: '九分屏' },
        { type: 16, name: '十六分屏' },
        { type: 36, name: '三十六分屏' },
        { type: 64, name: '六十四分屏' },
      ]
    }
  },
  computed: {
    colNum(){
      if (this.radio === 1) {
        return [24,24,24,24]
      } else if (this.radio === 4) {
        return [12,12,12,12]
      }else if (this.radio === 9) {
        return [8,8,12,12]
      }else if (this.radio === 16) {
        return [6,6,12,12]
      }else if (this.radio === 36) {
        return [4,4,12,12]
      }else if (this.radio === 64) {
        return [3,3,12,12]
      }
    }
  },
  created() {
    this.getDeviceList()
  },
  mounted() {
    this.getList()
  },
  methods: {
    scrollEvent(e){
      if(e.currentTarget.scrollTop e.currentTarget.clientHeight>=e.currentTarget.scrollHeight){
        console.log('t!');
      }
    },
    fullscreen() {
      this.$fullscreen.enter(this.$el.querySelector(`.screen-main-player`), {
          wrap: false
      })
    },
    onIndex(index) {
      this.PlayerData[index].DeviceID = ''
      this.PlayerData[index].ID = ''
    },
    getList() {
      this.isShow = false
      this.indexType = 0
      this.PlayerData = []
      for (let index = 0; index < this.radio; index  ) {
        this.PlayerData.push({
          ID: '',
          DeviceID: ''
        })  
      }
      this.isShow = true
    },
    onSelection(data) {
      if (data.Type===1&&data.Online===false) {
        this.$message({
          message: '设备已离线!',
          type: 'warning'
        })
        return
      } 
      if (data.Type===2) {
        if (this.indexType<this.radio) {
          this.PlayerData[this.indexType].DeviceID = data.DeviceID
          this.PlayerData[this.indexType].ID = data.ID
          if ((this.indexType 1)<this.radio) {
            this.indexType  
          }
        } 
        return
      } else {
        if (!data.Online) {
          return
        }
        if (data.Children.length!==0) return
        this.getChannels(data.ID, data)
      }
    },
    getDeviceList() {
      this.loading = true;
      let _this = this;
      $.get("/api/v1/device/list", {
        q: this.queryDev      
      })
      .then(res => {
        _this.DeviceCount = res.DeviceCount
        res.DeviceList.forEach(item => {
          _this.terrData.push({
            Name:item.Name,
            ChannelCount:item.ChannelCount,
            ID:item.ID,
            Online:item.Online,
            Children: [],
            Type: 1,
            Loading: false
          })
        })
      })
      .always(() => {
        this.loading = false;
      })
    },
    getChannels(ID, data) {
      this.loading = true;
      let _this = this
      $.get("/api/v1/device/info", {
        serial: ID
      })
      .then(res => {
        if(res.ChannelCount == 0) {
          _this.$message({
            message: '设备下无通道!',
            type: 'warning'
          })
        }else {
          res.ChannelList.forEach(item => {
           data.Children .push({
              Name:item.Name,
              DeviceID:item.DeviceID,
              SnapURL:item.SnapURL,
              ID:item.ID,
              Online: true,
              Children: [],
              Type: 2,
              Loading: false
            })
          })
        }
        this.loading = false;
      })
      .always(() => {
        this.loading = false;
      })
    }
  }
}
</script>
<style lang="less" scoped>
  .screen-radio {
    padding: 20px 15px;
    padding-left: 0;
    padding-bottom: 5px; 
  }
  .screen-tree {
    padding-right: 30px;
    padding-top: 40px;
    min-height: e("calc(100vh - 131px)");
    max-height: e("calc(100vh - 131px)");
    overflow:auto;
    .el-tree {
      background: transparent;
    }
    .screen-tree-title {
      display: block;
      font-size: 16px;
      padding-bottom: 5px;
      padding-left: 22px;
    }
  }
  .screen-main {
    .screen-main-item {
      border: 1px solid #ccc;
    }
  }
  .active-shadow{
    .screen-main-item {
      border: 1px solid red;
    }
  }
</style>
<style lang="less">
 .screen-main {
    >.el-row>.el-col {
      padding: 0 !important;
    }
  }
.fullscreen {
  position: fixed;
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
}
.screen-radio .el-radio-button:last-child .el-radio-button__inner{
  border-color: #dcdfe6;
  border-left: 0px;
  box-shadow: none !important;
  background-color: #ffffff;
  color: #606266;
  &:hover {
    color: #00a65a;
  }
}
</style>

0 人点赞