,其中的视频文件路径 可以使用湖南卫视在线播放地址,如果能正常播放时可自行换成自己的播放地址
海康视频时时在线预览
npm i videojs
videojs-contrib-hls
在main.js文件中引入并挂载原型上
import VideoJs from 'video.js'
import 'video.js/dist/video-js.min.css'
import 'videojs-contrib-hls' // 如果播放 rtmp文件不用引入
Vue.prototype.$video = VideoJs
湖南卫视接口可用于测试
rtmp://58.200.131.2:1935/livetv/hunantv
<template>
<j-modal
:title="title"
:width="width"
:visible="visible"
:fullscreen="false"
switchFullscreen
:maskClosable="false"
:confirmLoading="confirmLoading"
@cancel="handleCancel"
:footer="null"
>
<a-spin :spinning="confirmLoading">
<a-alert message="设备有 11 个警告尚未处理" type="warning" show-icon closable />
<div class="monitorin-info">
<div class="monitorin">
<!-- x-vlc-plugin application/x-mpegURL rtmp/flv-->
<video
id="myVideoInfo"
class="video-js vjs-default-skin"
autoplay="autoplay"
controls
preload="auto"
>
<source :src="videoSrc" type="application/x-mpegURL" />
</video>
<div class="control">
<div class="fl cap-voice-btns">
<a-button type="primary" @click="captureReport">抓拍上传</a-button>
<a-button
type="primary"
@mouseup="voiceIntercom('up')"
@mousedown="voiceIntercom('down')"
>语音对讲</a-button>
</div>
<div class="direction">
<div class="top">
<a-icon
type="caret-up"
@mouseup="controlDirection(1,'UP')"
@mousedown="controlDirection(0,'UP')"
title="上移"
/>
</div>
<div class="center">
<a-icon
type="caret-left"
@mouseup="controlDirection(1,'LEFT')"
@mousedown="controlDirection(0,'LEFT')"
title="左移"
/>
<span @click="controlDirection(0,'GOTO_PRESET')" title="复位">
<a-icon type="poweroff" />
</span>
<a-icon
type="caret-right"
@mouseup="controlDirection(1,'RIGHT')"
@mousedown="controlDirection(0,'RIGHT')"
title="右移"
/>
</div>
<div class="bottom">
<a-icon
type="caret-down"
@mouseup="controlDirection(1,'DOWN')"
@mousedown="controlDirection(0,'DOWN')"
title="下移"
/>
</div>
</div>
<!-- 焦距调节 -->
<div class="fl">
<a-button
shape="circle"
icon="minus"
@mouseup="controlDirection(1,'ZOOM_OUT')"
@mousedown="controlDirection(0,'ZOOM_OUT')"
/>
<a-button
shape="circle"
icon="plus"
@mouseup="controlDirection(1,'OOM_IN')"
@mousedown="controlDirection(0,'OOM_IN')"
/>
</div>
</div>
</div>
</div>
<VoiceIntercom :urls="voiceIntercomUrl" />
</a-spin>
</j-modal>
</template>
<script>
import { postAction, getAction, httpAction } from '@/api/manage.js'
import { validateDuplicateValue } from '@/utils/util'
import Monitoring from './model/Monitoring'
import CaptureReport from './CaptureReport'
import VoiceIntercom from './VoiceIntercom'
export default {
name: 'WorksiteMonitoringInfo',
components: {
Monitoring,
CaptureReport,
VoiceIntercom
},
inject: ['reload'],
props: {
passData: {
type: String,
default: ''
}
},
data() {
return {
voiceIntercomUrl: '', // 语音对讲流连接地址
flag: true, // 節流开关
title: '',
width: 800,
visible: false,
confirmLoading: false,
videoSrc: '', // 视频地址
player: null, // videoJs 实例对象
cameraIndexCode: '',
dataSource: [],
ws: null,
ipagination: {
current: 1,
pageSize: 10,
pageSizeOptions: ['10', '20', '30'],
showTotal: (total, range) => {
return range[0] + '-' + range[1] + ' 共' + total + '条'
},
showQuickJumper: true,
showSizeChanger: true,
total: 0
},
loading: false,
url: {
previewurls: '/safety/admin/cameramanager/previewurls', // 流连接
manualcapture: '/safety/admin/cameramanager/manualcapture', // 摄像头-抓图
talkurls: '/safety/admin/cameramanager/talkurls', // 摄像头-获取对话流连接
controlling: '/safety/admin/cameramanager/controlling' // 摄像头-云台控制
}
}
},
watch: {
visible(newVal, oldVal) {
// 销毁video实例,阻止关闭标签之后继续请求
if (!newVal) {
this.player && this.player.pause()
this.player = null
this.reload()
this.player && this.player.dispose()
this.player && this.player.tech_.dispose()
} else {
this.getVideo(this.cameraIndexCode)
}
}
},
methods: {
// 开启弹窗
openModal(title, id) {
this.visible = true
this.title = title
this.cameraIndexCode = 'c56495c3f368494a8eff6052028e61ea' // id'e8695d5733064450a2c0e3704e5bcdd0' // 'c56495c3f368494a8eff6052028e61ea' // id
},
// 获取视频流、
getVideo() {
let parmas = {}
let data = this.$qs.stringify({
cameraIndexCode: this.cameraIndexCode,
protocol: 'hls', // hls
expand: 'transcode=0',
streamTyp: 1, // 0
transmode: 1
// streamform: 'ps'
})
postAction(this.url.previewurls, data)
.then(({ message }) => {
console.log('-----文件详情res----', message)
this.videoSrc = message
// this.videoSrc = 'rtmp://58.200.131.2:1935/livetv/hunantv'
})
.then(() => {
let that = this
this.$nextTick(() => {
that.getPlayVideo()
})
})
},
getPlayVideo() {
let _this = this
_this.player = _this.$video(document.getElementById('myVideoInfo'), {
controls: true,
autoplay: true,
preload: 'auto',
controlBar: {
playToggle: true
}
})
},
// 方向控制 ()
async controlDirection(action, command = '') {
let parmas = {
action, // 0 操作动作(1 开始 0 停止)
cameraIndexCode: this.cameraIndexCode, //
command, // 操作动作(LEFT 左转 RIGHT 右转 UP 上转 DOWN 下转 FOCUS_NEAR 焦点前移 FOCUS_FAR 焦点后移 )
presetIndex: 20,
speed: 1
}
let timer = null
if (true) {
this.flag = false
timer = setTimeout(() => {
this.flag = true
clearTimeout(timer)
}, 2000)
let { success } = await postAction(this.url.controlling, parmas)
if (!success) this.$message.error('该设备不支持')
else {
if (!action) {
this.$message.success('操作成功,请稍候')
}
}
}
},
// 打开抓拍上传弹窗
async captureReport() {
let data = this.$qs.stringify({
cameraIndexCode: this.cameraIndexCode
})
let { success, message } = await postAction(this.url.manualcapture, data)
if (success) {
let data = {
passData: this.passData,
cameraIndexCode: this.cameraIndexCode,
url: message
// cameraName:this.cameraName, // 摄像机名称
// project:this.projectTree // 工程树 警告位置
}
await this.$refs.CaptureReport.showModal(data)
}
},
// 语音对讲
async voiceIntercom(eventType) {
let parmas = {
cameraIndexCode: this.cameraIndexCode,
expand: 'streamform=ps',
transmode: 1,
eurlExpand: ''
}
let { success, message } = await postAction(this.url.talkurls, parmas)
if (!success) {
this.$message.error('操作失败,请稍后重试')
return false
}
this.voiceIntercomUrl = message
console.log(message)
console.log('戍邊不能', eventType) // down up
return false
this.ws = new WebSocket(message)
console.log(this.ws)
this.ws.onopen = function(evt) {
console.log('Connection open ...', evt)
this.ws.send('Hello WebSockets!')
}
},
handleCancel() {
this.visible = false
},
// 查看
infoView(name, id) {}
}
}
</script>
<style lang="less" scoped>
@import '~@assets/less/common.less';
.fl {
display: flex;
justify-content: space-between;
margin-top: 15px;
}
.info {
display: flex;
flex-wrap: wrap;
margin: 15px 0;
p {
width: 45%;
}
}
.monitorin-info {
margin-bottom: 30px;
.monitorin {
width: 100%;
position: relative;
#myVideoInfo {
width: 100%;
min-height: 550px;
margin-top: 25px;
}
.control {
position: absolute;
z-index: 2;
bottom: 85px;
right: 20px;
width: 300px;
text-align: center;
padding: 15px 30px 0 30px;
/* 抓拍上传,语音对讲按钮 */
.cap-voice-btns {
display: flex;
justify-content: space-between;
margin-bottom: 200px;
}
/* 方向按钮 */
.direction {
text-align: center;
i {
font-size: 35px;
cursor: pointer;
color: #fff;
}
.top {
font-weight: bold;
cursor: pointer;
}
.center {
span {
display: inline-block;
width: 100px;
height: 80px;
border-radius: 50%;
text-align: center;
line-height: 80px;
font-size: 25px;
cursor: pointer;
}
}
.bottom {
cursor: pointer;
}
}
}
}
}
.near {
margin-top: 30px;
font-weight: bold;
}
</style>