vue监控视频,wvp-GB28181-pro实现

先下载wvp-GB28181-pro项目

git clone https://gitee.com/pan648540858/wvp-GB28181-pro.git

多了解的话可以看以下该项目的giteehttps://gitee.com/pan648540858/wvp-GB28181-pro

后端有很多难点,具体要做的事情访问,连接https://www.cnblogs.com/linjiaxin/p/17664391.html

将项目下载下来后,从项目中找到 jessibuca 文件夹,将其拷贝并复制到自己项目的 public 文件夹中,然后在index.html 文件中引入,看图 1、2、3

图1

图2

图3

当环境准备好后,就可以将封装好的 jessibuca 组件拷贝到自己的项目了

至于如何使用就看具体的需求了,如果按照 wvp-GB28181-pro 项目里的 live.vue 文件使用,展现出的效果如图2所示

图1

图2

但我做这个项目要求的样式不一样,如下图所示

代码

<template>
    <div class="app-container fixed-full-size">
        <div-backtop ref="pagescrollpart" style="padding:20px;flex:auto;width:100%">
            <!-- <div style="position: fixed;width: 100vw;height: 100vh;background-color: red;top: 1px;left: 1px;z-index: 999999;"></div> -->
            <div class="fu">
                <div class="monitor">
                    <div class="title">沈阳高华液化石油气有限公司</div>
                    <div class="layout-btn">
                        <svg-icon icon-class="split1" :class="['icon-img',selectIcon == 0?'icon-active':'']" @click="iconChange(0)"/>
                        <svg-icon icon-class="split4" :class="['icon-img',selectIcon == 1?'icon-active':'']" @click="iconChange(1)"/>
                        <svg-icon icon-class="split9" :class="['icon-img',selectIcon == 2?'icon-active':'']" @click="iconChange(2)"/>
                        <svg-icon icon-class="fs" class="icon-img hs" @click="iconChange(3)"/>
                        <!-- <img class="icon-img" v-for="(item,index) in icons" :key="index" :src="selectIcon == index?item.active:item.noActive" @click="iconChange(index)"/> -->
                    </div>
                    <div :class="['monitor-layout',fullScreen?'full-screen':'monitor-content']" ref="screen">
                        <!-- <div style="width: 99%;height: 85vh;display: flex;flex-wrap: wrap;background-color: #000;"> -->
                            <div v-for="i in spilt" :key="i" class="play-box":style="liveStyle" @click="openAdd(i)">
                                <div v-if="!videoUrl[i-1]" class="play-title" >点击添加视频监控画面</div>
                                <div v-else class="play-item">
                                    <player class="player" ref="player" :videoUrl="videoUrl[i-1]" fluent autoplay @screenshot="shot" @destroy="destroy"/>
                                    <div class="btn-list">
                                        <div class="icon-list">
                                            <div class="node">
                                                <img :src="qiye" />
                                                <span>沈阳市高华液化石油气有限公司</span>
                                            </div>
                                            <div class="node">
                                                <img :src="sxt" />
                                                <span>库房工作区001</span>
                                            </div>
                                        </div>
                                        <div class="function-list">
                                            <svg-icon v-show="soundState[i-1] == 'play'" icon-class="sound" @click="soundFun(i,'stop')"/>
                                            <svg-icon v-show="soundState[i-1] == 'stop'" icon-class="sound2" @click="soundFun(i,'play')"/>
                                            <svg-icon  icon-class="camera" @click="screenshot(i)"/>
                                            <svg-icon v-show="playState[i-1] == 'play'" icon-class="split1" @click="playChange(i,'stop')"/>
                                            <svg-icon v-show="playState[i-1] == 'stop'" icon-class="play" @click="playChange(i,'play')"/>
                                            <svg-icon icon-class="clos" @click.stop="closeFun(i)"/>
                                            <svg-icon icon-class="fs" @click="fullscreenSwich(i)"/>
                                        </div>
                                    </div>
                                </div>
                            </div>
                        <!-- </div> -->
                        <!-- <player ref="player" :videoUrl="videoUrl[i-1]" fluent autoplay @screenshot="shot"
                            @destroy="destroy"/> -->
                    </div>
                </div>
                <div class="warning-div">
                    <div class="real-time common">
                        <div class="row-one">
                            <div class="title real-time-title">实时警告</div>
                            <div class="jump">更多>></div>
                        </div>
                        <div class="for-item">
                            <div class="item-row-title">
                                <div class="title-element">
                                    <div class="number number-real-time">
                                        1
                                    </div>
                                    <div class="enterprise">
                                        沈阳高华液化石油气有限公司
                                    </div>
                                </div>
                                <div class="place">
                                    <img />
                                    <div>库房工作区</div>
                                </div>
                            </div>
                            <div class="item-row-info">
                                <div class=" frame frame-real-time">
                                    <img />
                                </div>
                                <div class="default">
                                    <div>
                                        警告时间:2023-12-12 13:00:00
                                    </div>
                                    <div>
                                        警告类型:二级警告
                                    </div>
                                </div>
                            </div>
                            <div class="warning-content">
                                告警内容:有车辆停留在库房工作区
                            </div>
                        </div>
                    </div>
                    <div class="history common">
                        <div class="row-one">
                            <div class="title title-history">历史警告</div>
                            <div class="jump">更多>></div>
                        </div>
                        <div class="for-item">
                            <div class="item-row-title">
                                <div class="title-element">
                                    <div class="number number-history">
                                        1
                                    </div>
                                    <div class="enterprise">
                                        沈阳高华液化石油气有限公司
                                    </div>
                                </div>
                                <div class="place">
                                    <img />
                                    <div>库房工作区</div>
                                </div>
                            </div>
                            <div class="item-row-info">
                                <div class="frame frame-history">
                                    <img />
                                </div>
                                <div class="default">
                                    <div>
                                        警告时间:2023-12-12 13:00:00
                                    </div>
                                    <div>
                                        警告类型:二级警告
                                    </div>
                                </div>
                            </div>
                            <div class="warning-content">
                                告警内容:有车辆停留在库房工作区
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div-backtop>
        <el-dialog v-dialogDrag title="添加监控画面" :visible.sync="isShow" :close-on-click-modal="false" width="800px" class="padding-col" append-to-body>
            <el-form :model="queryParams" ref="queryForm" size="small" :inline="true">
                <el-form-item label="视频通道" prop="videoChannel">
                    <el-input @keyup.enter.native="getList" v-model="queryParams.videoChannel" placeholder="请输入视频通道" clearable />
                </el-form-item>
                <el-form-item>
                    <el-button type="primary" icon="el-icon-search" size="mini" @click="getList">搜索</el-button>
                    <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
                </el-form-item>
            </el-form>
            <el-table v-loading="loading" :data="tableDataList" >
                <el-table-column type="index" width="55" />
                <el-table-column label="视频通道" align="center" prop="videoChannel" />
                <el-table-column label="操作" align="center" class-name="table-button" width="200">
                    <template slot-scope="scope" >
                        <el-button size="mini" icon="el-icon-edit" type="success" @click="selectFun(scope.row.url)"">选择</el-button>
                    </template>
                </el-table-column>
            </el-table>
            <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList" />
                <div slot="footer" class="dialog-footer">
                <el-button @click="isShow=false">取 消</el-button>
            </div>
        </el-dialog>
    </div>
</template>
<script>
import player from '.././components/jessibuca.vue'
const fs = require('@/assets/images/monitor/fs.png');
const qiye = require('@/assets/images/monitor/qiye.png');
const sxt = require('@/assets/images/monitor/sxt.png');
export default{
    name:'realTimeMonitoring',
    components: {
        player
    },
    data(){
        return {
            //请求监控参数
            queryParams:{
                videoChannel:'',
                pageNum: 1,
                pageSize: 10,
            },
            //加载动画
            loading:false,
            //表格数据
            tableDataList:[
                {
                    videoChannel:'通道一',
                    url:"ws://192.168.2.142:80/rtp/34020000001320000002_34020000001320000002.live.flv", 
                },
                {
                    videoChannel:'通道二',
                    url:"ws://192.168.2.142:80/rtp/34020000001320000001_34020000001320000001.live.flv", 
                },
                {
                    videoChannel:'通道三',
                    url:"ws://192.168.2.142:80/rtp/34020000001320000003_34020000001320000003.live.flv", 
                },
                {
                    videoChannel:'通道一',
                    url:"ws://192.168.2.142:80/rtp/34020000001320000002_34020000001320000002.live.flv", 
                },
                {
                    videoChannel:'通道一',
                    url:"ws://192.168.2.142:80/rtp/34020000001320000002_34020000001320000002.live.flv", 
                },{
                    videoChannel:'通道一',
                    url:"ws://192.168.2.142:80/rtp/34020000001320000002_34020000001320000002.live.flv", 
                },{
                    videoChannel:'通道一',
                    url:"ws://192.168.2.142:80/rtp/34020000001320000002_34020000001320000002.live.flv", 
                },{
                    videoChannel:'通道一',
                    url:"ws://192.168.2.142:80/rtp/34020000001320000002_34020000001320000002.live.flv", 
                },{
                    videoChannel:'通道一',
                    url:"ws://192.168.2.142:80/rtp/34020000001320000002_34020000001320000002.live.flv", 
                },
                ,{
                    videoChannel:'通道一',
                    url:"ws://192.168.2.142:80/rtp/34020000001320000002_34020000001320000002.live.flv", 
                },
            ],
            //分页条数
            total:10,
            //弹框显示
            isShow:false,
            //视频地址
            videoUrl:[ 
                ''
                // "ws://192.168.2.136:80/rtp/34020000001320000002_34020000001320000002.live.flv"
            ],
            //被点击的视频索引
            clickIndex:null,
            // videoUrl:[],
            //企业和摄像头图标
            qiye:qiye,
            sxt:sxt,
            fs:fs,
            //是否全屏展示
            fullScreen:false,
            // 被点击的图标
            selectIcon:0,
            //显示多少屏幕
            spilt:1,
            playerIdx: 0,//激活播放器
            resizeObserver:null,
            //记录播放状态的数组
            playState:['play'],
            soundState:['stop'],
        }
    },
    mounted(){
        //监听屏幕变化
        this.resizeObserver = new ResizeObserver(entries => {
            //判断是否全屏
            if(
                document.fullscreenElement ||
                document.mozFullScreenElement ||
                document.webkitFullscreenElement ||
                document.msFullscreenElement
            ){
                //全屏
                // console.log('全屏了')
            }else{
                //全屏
                this.fullScreen=false;
            }
        });
        this.resizeObserver.observe(this.$el);
    },
    computed: {
        //显示屏数量改变的时候改变监控视频大小
        liveStyle() {
            let style = {width: '100%', height: '100%'}
            switch (this.spilt) {
                case 4:
                    style = {width: '49.7%', height: '49.7%'}
                break
                case 9:
                    style = {width: '32.9%', height: '32.9%'}
                break
            }
            this.$nextTick(() => {
                for (let i = 0; i < this.spilt; i++) {
                    const player = this.$refs.player
                    player && player[i] && player[i].updatePlayerDomSize()
                }
            })
            return style
        }
    },
    methods:{
        //请求列表
        getList(){
            this.loading=true
            docList(this.queryParams)
            .then(res=>{
                if(res.code == 200){
                    this.tableDataList = res.rows;
                    this.total=res.total;
                }
            })
            .catch(err=>{})
            .finally(()=>{this.loading=false;})
        },
        //重置
        resetQuery(){
            this.value=''
            this.queryParams={
                videoChannel:'',
                pageNum: 1,
                pageSize: 10,
            }
            this.getList();
        },
        //选择监控视频
        selectFun(url){
            this.videoUrl[this.clickIndex]=url;
            this.isShow=false;
        },
        //添加监控视频
        openAdd(i){
            console.log(i);
            if(this.videoUrl[i-1] == ''||this.videoUrl[i-1] == undefined){
                this.isShow=true;
                this.clickIndex=i-1;
            }
            
        },
        //布局图标点击
        iconChange(index){
            if(this.selectIcon == index)return
            switch(index){
                case 0:
                    this.spilt = 1;
                    this.selectIcon = index;
                    this.videoUrl=['']
                    this.playState=['play']
                    this.soundState=['stop']
                break;
                case 1:
                    this.spilt = 4;
                    this.selectIcon = index;
                    this.videoUrl=['','','','']
                    this.playState=['play','play','play','play']
                    this.soundState=['stop','stop','stop','stop']
                break;
                case 2:
                    this.spilt = 9;
                    this.selectIcon = index;
                    this.videoUrl=['','','','','','','','','']
                    this.playState=['play','play','play','play','play','play','play','play','play']
                    this.soundState=['stop','stop','stop','stop','stop','stop','stop','stop','stop']
                break;
                case 3:
                    //全屏时放大
                    var el = document.documentElement;
                    var rfs = el.requestFullScreen || el.webkitRequestFullScreen || el.mozRequestFullScreen || el.msRequestFullscreen;      
                        if(typeof rfs != "undefined" && rfs) {
                            rfs.call(el);
                        };
                    this.fullScreen=true;
                    // return;
                break;
            }
        },
        //截图
        screenshot(i){
            this.$refs.player[i-1].screenshot()
        },
        //放大/缩放
        fullscreenSwich(i){
            this.$refs.player[i-1].fullscreenSwich()
        },
        //播放按钮点击事件
        playChange(i,v){
            let playState = JSON.parse(JSON.stringify(this.playState))
            playState[i-1]=v
            this.playState=JSON.parse(JSON.stringify(playState))
            v=='play'?this.$refs.player[i-1].playBtnClick():this.$refs.player[i-1].destroy()
        },
        //声音
        soundFun(i,v){
            console.log('vvv',v)
            let soundState = JSON.parse(JSON.stringify(this.soundState))
            soundState[i-1]=v
            this.soundState=JSON.parse(JSON.stringify(soundState))
            v=='stop'?this.$refs.player[i-1].mute():this.$refs.player[i-1].cancelMute()
        },
        //关闭
        closeFun(i){
            let videoUrl = JSON.parse(JSON.stringify(this.videoUrl))
            videoUrl[i-1]=''
            this.videoUrl = JSON.parse(JSON.stringify(videoUrl))
        },
        destroy(idx) {
            console.log(idx);
            this.clear(idx.substring(idx.length - 1))
        },
        clear(idx) {
            let dataStr = window.localStorage.getItem('playData') || '[]'
            let data = JSON.parse(dataStr);
            data[idx - 1] = null;
            console.log(data);
            window.localStorage.setItem('playData', JSON.stringify(data))
        },
        shot(e) {
            // console.log(e)
            // send({code:'image',data:e})
            var base64ToBlob = function (code) {
                let parts = code.split(';base64,');
                let contentType = parts[0].split(':')[1];
                let raw = window.atob(parts[1]);
                let rawLength = raw.length;
                let uInt8Array = new Uint8Array(rawLength);
                for (let i = 0; i < rawLength; ++i) {
                    uInt8Array[i] = raw.charCodeAt(i);
                }
                return new Blob([uInt8Array], {
                type: contentType
                });
            };
            let aLink = document.createElement('a');
            let blob = base64ToBlob(e); //new Blob([content]);
            let evt = document.createEvent("HTMLEvents");
            evt.initEvent("click", true, true); //initEvent 不加后两个参数在FF下会报错  事件类型,是否冒泡,是否阻止浏览器的默认行为
            aLink.download = '截图';
            aLink.href = URL.createObjectURL(blob);
            aLink.click();
        },
    },
    watch: {
        spilt(newValue) {
            console.log("切换画幅;" + newValue)
            let that = this
            for (let i = 1; i <= newValue; i++) {
                console.log(!that.$refs['player' + i])
                if (!that.$refs['player' + i]) {
                    continue
                }
                this.$nextTick(() => {
                    if (that.$refs['player' + i] instanceof Array) {
                        that.$refs['player' + i][0].resize()
                    } else {
                        that.$refs['player' + i].resize()
                    }
                })

            }
            // window.localStorage.setItem('split', newValue)
        },
        
    }
}
</script>
<style lang='scss' scoped>
.fu{
    display: flex;
    flex-wrap: nowrap;
    flex-direction: row;
    .monitor{
        width: 72%;
        display: flex;
        flex-direction: column;
        align-items: center;
        .title{
            color: #409EFF;
            font-size: 23px;
        }
        .layout-btn{
            margin-top:10px;
            width: 100%;
            height: 40px;
            padding: 5px 10px;
            display: flex;
            justify-content: end;
            background-color: #F2F2F2;
            
            
            .icon-img{
                cursor:pointer;
                width: 30px;
                height: 30px;
                margin-left: 10px;
                color:#6B6B6B;
            }
            .icon-active{
                color:#409EFF;
            }
            .hs:hover {
                color:#409EFF; /* 鼠标移入时的背景颜色 */
            }
        }
        .monitor-content{
            margin-top:10px;
            width: 100%;
            height: 500px;
        }
        .full-screen{
            position: fixed;
            width: 100vw;
            height: 100vh;
            background-color: #fff;
            top: 0px;
            left: 0px;
            z-index: 2010;
        }
        .monitor-layout{
            // margin-top:10px;
            // width: 100%;
            // min-height: 500px;
            display: flex;
            flex-wrap: wrap;
            justify-content: space-between;
            .play-title{
                color: #FFFFFF;
                font-size: 1rem;
                // font-weight: bold;
            }
            .play-box {
                cursor: pointer;
                background-color: #858585;
                border: 2px solid #505050;
                display: flex;
                align-items: center;
                justify-content: center;
                .play-item{
                    width: 100%;
                    height: 100%;
                    display: flex;
                    flex-direction: column;
                    .player{
                        height: 90% !important;
                    }
                    .btn-list{
                        // flex: 1;
                        height:7vh;
                        width: 100%;
                        padding: 5px 10px;
                        background-color: #F2F2F2;
                        display: flex;
                        justify-content: space-between;
                        .icon-list{
                            display: flex;
                            flex-direction: column;
                            justify-content: space-between;
                            width: 41%;
                            height: 100%;
                            .node{
                                display: flex;
                                align-items: center;
                                // height: 50%;
                                
                                img{
                                    width: 12px;
                                    height: 12px;
                                }
                                span{
                                    margin-left: 5px;
                                    font-size: 14px;
                                    // color: #409EFF;
                                    overflow: hidden;
                                    white-space:nowrap;/*默认normal 自动换行*/
                                    text-overflow:ellipsis; /*默认是clip 超出部分直接切除*/
                                }
                            }
                            
                        }
                        .function-list{
                            flex: 1;
                            display: flex;
                            justify-content: end;
                            align-items: center;
                            .svg-icon:hover{
                                color: #409EFF;
                            }
                            .svg-icon{
                                width: 1.5rem;
                                height: 1.5rem;
                                margin-left: 10px;
                                cursor:pointer;
                            }
                            // img{
                            //     width: 1.5rem;
                            //     height: 1.5rem;
                            //     margin-left: 10px;
                            //     cursor:pointer;
                            // }
                        }
                    }
                }
            }
        }
    }
    .warning-div{
        flex: 1;
        background-color: #F2F2F2;
        padding: 10px;
        margin-left: 5px;
        .common{
            border-radius: 10px;
            padding: 10px;
            margin-bottom: 10px;
            background-color: #fff;
            .row-one{
                display: flex;
                justify-content: space-between;
                height: 18px;
                width: 100%;
                .title{
                    height: 18px;
                    line-height: 18px;
                    padding-left: 5px;
                }
                .real-time-title{
                    border-left: 5px solid red;
                }
                .title-history{
                    border-left: 5px solid #02A7F0;
                }
                .jump{
                    height: 18px;
                    line-height: 18px;
                    cursor:pointer;
                }
            }
            .for-item{
                // padding: 5px 0px;
                margin-top: 5px;
                border-bottom: 2px solid #D7D7D7;
                .item-row-title{
                    display: flex;
                    justify-content: space-between;
                    margin-top: 10px;
                    .title-element{
                        display: flex;
                        align-items: center;
                        .number{
                            height: 14px;
                            width: 14px;
                            line-height: 14px;
                            font-size: 14px;
                            font-weight: 600;
                            text-align: center;
                            color: #fff;
                        }
                        .number-real-time{background-color: red;}
                        .number-history{background-color: #02A7F0;}
                        .enterprise{
                            font-size: 14px;
                            margin-left: 5px;
                        }
                    }
                    .place{
                        font-size: 14px;
                        color: #02A7F0;
                        display: flex;
                        align-items: center;
                        img{
                            width: 14px;
                            height: 14px;
                            margin-right: 5px;
                        }
                    }
                }
                .item-row-info{
                    margin-top: 10px;
                    padding: 5px;
                    display: flex;
                    font-size: 14px;
                    justify-content: space-between;
                    .frame{
                        width: 90px;
                        height: 60px;
                        img{
                            width: 100%;
                            height: 100%;
                        }
                    }
                    .frame-history{
                        border: 1px solid #02A7F0;
                        box-shadow: 1px 1px 5px 0 #02A7F0;
                    }
                    .frame-real-time{
                        border: 1px solid red;
                        box-shadow: 1px 1px 5px 0 #f60e0e;
                    }
                    .default{
                        padding: 5px;
                        display: flex;
                        flex-direction: column;
                        justify-content: space-between;
                    }
                }
                .warning-content{
                    margin:10px 0px;
                    font-size: 14px;
                }
            }
        }
        .real-time{

        }
        .history{
            
        }
    }
    
}
</style>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值