{
}}>
{
[{
- style: { top: 12, left: (148 - 24) / 2, }
+ style: { top: 12, left: (148 - 24) / 2, },
+ click: () => { cloudControl('up') }
}, {
- style: { right: 12, top: (148 - 24) / 2, }
+ style: { right: 12, top: (148 - 24) / 2, },
+ click: () => { cloudControl('right') },
}, {
- style: { bottom: 12, left: (148 - 24) / 2, }
+ style: { bottom: 12, left: (148 - 24) / 2, },
+ click: () => { cloudControl('down') },
}, {
- style: { left: 12, top: (148 - 24) / 2, }
+ style: { left: 12, top: (148 - 24) / 2 },
+ click: () => { cloudControl('left') },
}].map((s, i) => {
return (
{
height: 24, width: 24, display: 'inline-block', transform: `rotate(${i * 90}deg)`,
position: 'absolute'
}, s.style)}
+ onClick={s.click}
/>
)
})
@@ -41,8 +57,8 @@ const VideoOperationCloudControl = ({ }) => {
{
[
- [{ n: '+' }, { n: '焦距' }, { n: '-' }],
- [{ n: '+' }, { n: '缩放' }, { n: '-' }]
+ [{ n: '+', click: () => { cloudControl('focus_in') }, }, { n: '焦距' }, { n: '-', click: () => { cloudControl('focus_out') }, }],
+ [{ n: '+', click: () => { cloudControl('zoom_in') }, }, { n: '缩放' }, { n: '-', click: () => { cloudControl('zoom_out') }, }],
].map(s => {
return (
+
-
+
最长时间跨度不超过72小时
-
-
+ {
+ close()
+ }}
+ style={{
+ cursor: 'pointer', height: 32, width: 56, lineHeight: '32px', borderRadius: 2,
+ textAlign: 'center', background: '#fff', color: 'rgba(0, 0, 0, 0.65)'
+ }}
+ >取消
+ {
+ if (selectedTimeRange.length == 2 && selectedTimeRange.every(t => t)) {
+ if (Math.abs(moment(selectedTimeRange[0]).diff(moment(selectedTimeRange[1]), 'hours')) > 72) {
+ ToastInCustomContainer.destroyAll()
+ return ToastInCustomContainer.error('所选时间超过 72 小时')
+ }
+ setHistroyTime(selectedTimeRange)
+ setProcessDisX(0)
+ close()
+ }
+ }}
+ style={{
+ cursor: 'pointer', height: 32, width: 56, lineHeight: '32px', borderRadius: 2,
+ textAlign: 'center', background: '#1859C1', color: '#fff'
+ }}
+ >播放
diff --git a/code/VideoAccess-VCMP/web/client/src/components/videoPlayer/videoPlay.jsx b/code/VideoAccess-VCMP/web/client/src/components/videoPlayer/videoPlay.jsx
index 6035bf6..802e169 100644
--- a/code/VideoAccess-VCMP/web/client/src/components/videoPlayer/videoPlay.jsx
+++ b/code/VideoAccess-VCMP/web/client/src/components/videoPlayer/videoPlay.jsx
@@ -1,28 +1,48 @@
import React, { useState, useEffect, useRef } from "react";
import { connect } from "react-redux";
import screenfull from 'screenfull';
+import moment from "moment";
import VideoHeader from './voiceHeader'
import VideoOperation from './videoOperation'
import './videoPlay.less';
+const timeFormat = 'YYYY-MM-DD HH:mm:ss'
+const yingshiUrl = 'https://open.ys7.com/ezopen/h5/iframe'
const VideoPlay = ({
- height, width, type, containerId = 'myPlayer', yingshiToken,
+ height, width, containerId = 'myPlayer',
// playUrl,
-
+ name,
+ videoObj = {
+ type: 'yingshi',
+ audio: true,
+ yingshiToken: 'at.3j6eyqbn0g5xvcut73v0rzdu1nh0gnxx-4ua03m82o9-12u1t9g-rtzndpyds',
+ playUrlSd: 'ezopen://open.ys7.com/G75922040/1.live',
+ // playUrl: 'ws://221.230.55.27:8081/jessica/34020000001110000077/34020000001310000003',
+ playUrlHd: 'ezopen://open.ys7.com/G75922040/1.hd.live',
+ replayUrl: 'ezopen://open.ys7.com/G75922040/1.rec',
+ },
}) => {
const [jessibuca, setjessibuca] = useState(null)
- const [playUrl, setPlayUrl] = useState(
- // 'http://flv.bdplay.nodemedia.cn/live/bbb.flv' // TEST
- 'ws://221.230.55.27:8081/jessica/34020000001110000077/34020000001310000001',
- // 'ws://221.230.55.27:8081/jessica/34020000001110000077/34020000001310000003'
- )
const [isPlaying, setIsPlaying] = useState(false)
const [operationState, setoperationState] = useState()
const [voiceDisY, setVoiceDisY] = useState(0)
+ const [processDisX, setProcessDisX] = useState(0)
+ const [isAdjustProcess, setIsAdjustProcess] = useState(false)
+ const [histroyTime, setHistroyTime] = useState([])
+ const [histroyBegain, setHistroyBegain] = useState()
const [resolution, setResolution] = useState('sd') // 标清 sd 高清 hd
+ const operationRef = useRef(null)
+ const processChangeTimeoutRef = useRef(null)
+
const changeSelectState = (key) => {
- const nextOperationState = JSON.parse(JSON.stringify(operationState))
+ const nextOperationState = JSON.parse(JSON.stringify(operationRef.current))
+ if (key == 'histroy' && nextOperationState.histroy.select) {
+ // 取消历史播放
+ setProcessDisX(0)
+ setHistroyTime([])
+ }
+
for (let k in nextOperationState) {
if (k == key) {
nextOperationState[k].select = !nextOperationState[k].select
@@ -30,26 +50,29 @@ const VideoPlay = ({
nextOperationState[k].select = false
}
}
- return nextOperationState
+ operationRef.current = nextOperationState
+
+ if (operationRef.current.histroy.select && histroyTime.length == 0) {
+ setHistroyTime([moment().subtract(72, 'hours').format(timeFormat), moment().format(timeFormat)])
+ }
+ setoperationState(nextOperationState)
}
const operation = [{
key: 'control',
click: () => {
- let nextOperationState = changeSelectState('control')
- setoperationState(nextOperationState)
+ changeSelectState('control')
}
}, {
key: 'talk',
click: () => {
- let nextOperationState = changeSelectState('talk')
- setoperationState(nextOperationState)
+ changeSelectState('talk')
}
}, {
key: 'fullScreen',
click: () => {
- let nextOperationState = changeSelectState('fullScreen')
- setoperationState(nextOperationState)
+
+ changeSelectState('fullScreen')
let player = document.getElementById('vcmp_videoplay')
if (screenfull.isEnabled) {
screenfull.toggle(player);
@@ -58,10 +81,11 @@ const VideoPlay = ({
}, {
key: 'histroy',
click: () => {
- let nextOperationState = changeSelectState('histroy')
- setoperationState(nextOperationState)
+
+ changeSelectState('histroy')
}
},]
+
useEffect(() => {
create()
let nextOperationState = {}
@@ -71,44 +95,110 @@ const VideoPlay = ({
}
}
setoperationState(nextOperationState)
+ operationRef.current = nextOperationState
+
+ // 全屏状态监听
+ screenfull.on('change', () => {
+ if (screenfull.isFullscreen && operationRef.current && !operationRef.current['fullScreen'].select) {
+ changeSelectState('fullScreen')
+ }
+ if (!screenfull.isFullscreen && operationRef.current && operationRef.current['fullScreen'].select) {
+ changeSelectState('fullScreen')
+ }
+ });
+
+ // 萤石 ifream 信息监听
+ // const listenYingshiMessage = async (e) => {
+ // const { data, origin } = e
+ // console.log(e);
+ // if (origin !== 'https://open.ys7.com') return
+ // if (data.type == 'stop' && data.code == 1) {
+ // setIsPlaying(false)
+ // }
+ // if (data.type == 'stop' && data.code == 1) {
+ // setIsPlaying(false)
+ // }
+ // }
+ // if (videoObj.type == 'yingshi') {
+ // window.addEventListener('message', listenYingshiMessage);
+ // }
+ // return () => {
+ // window.removeEventListener('message', listenYingshiMessage);
+ // }
}, [])
+ useEffect(() => {
+ if (histroyTime.length) {
+ setHistroyBegain(histroyTime[0])
+ document.getElementById('process_point').style.left = 0 + 'px'; // 重置进度条的位置
+ } else {
+ setHistroyBegain(null)
+ }
+ }, [histroyTime])
+ useEffect(() => {
+ if (operationState && operationState.histroy.select) {
+ if (isAdjustProcess) {
+ if (processChangeTimeoutRef.current) {
+ clearTimeout(processChangeTimeoutRef.current)
+ }
+ processChangeTimeoutRef.current = setTimeout(() => {
+ setHistroyBegain(
+ moment(histroyTime[0])
+ .add(
+ Math.abs(moment(histroyTime[0]).diff(moment(histroyTime[1]), 'seconds')) * (processDisX / document.getElementById('process_point').parentElement.offsetWidth),
+ 'second'
+ )
+ .format(timeFormat)
+ )
+ }, 300)
+ }
+ }
+ }, [processDisX])
+
const create = () => {
- let $container = document.getElementById('container');
- const jessibuca = new window.Jessibuca({
- container: $container,
- videoBuffer: 0.2, // 缓存时长
- isResize: false,
- text: "",
- loadingText: "加载中",
- debug: true,
- showBandwidth: true, // 显示网速
- operateBtns: {
- fullscreen: true,
- screenshot: true,
- play: true,
- audio: true,
- },
- forceNoOffscreen: false,
- isNotMute: false,
- });
- setjessibuca(jessibuca)
- play()
+ if (videoObj.type != 'yingshi') {
+ let $container = document.getElementById('container');
+ const jessibuca = new window.Jessibuca({
+ container: $container,
+ videoBuffer: 0.2, // 缓存时长
+ isResize: false,
+ text: "",
+ loadingText: "加载中",
+ debug: true,
+ showBandwidth: true, // 显示网速
+ operateBtns: {
+ fullscreen: true,
+ screenshot: true,
+ play: true,
+ audio: true,
+ },
+ forceNoOffscreen: false,
+ isNotMute: false,
+ });
+ setjessibuca(jessibuca)
+ play()
+ }
}
- useEffect(() => {
- play()
- }, [jessibuca])
+ const yingshiOperation = (operation) => {
+ let a = document.getElementById(containerId).contentWindow.postMessage(operation, yingshiUrl)
+ console.log(a);
+ setIsPlaying(operation == 'play')
+ }
const play = () => {
- if (jessibuca && playUrl) {
- jessibuca.play(playUrl);
+ if (videoObj.type == 'yingshi') {
+ yingshiOperation('play')
+ } else if (jessibuca && videoObj.playUrlSd) {
+ jessibuca.play(videoObj.playUrlSd);
setIsPlaying(true)
}
}
const pause = () => {
- if (jessibuca) {
+ if (videoObj.type == 'yingshi') {
+ yingshiOperation('stop')
+ } else if (jessibuca) {
jessibuca.pause();
setIsPlaying(false)
}
@@ -119,20 +209,27 @@ const VideoPlay = ({
{/* 顶部信息 */}
-
+
{/* 视频内容 */}
{
- type == 'yingshi' ?
+ videoObj.type == 'yingshi' ?
:
}
- {/* 云控 对讲 对应操作内容 */}
+ {/* 下方操作栏 */}
diff --git a/code/VideoAccess-VCMP/web/client/src/components/videoPlayer/videoPlay.less b/code/VideoAccess-VCMP/web/client/src/components/videoPlayer/videoPlay.less
index 43e19bf..9a8a846 100644
--- a/code/VideoAccess-VCMP/web/client/src/components/videoPlayer/videoPlay.less
+++ b/code/VideoAccess-VCMP/web/client/src/components/videoPlayer/videoPlay.less
@@ -26,4 +26,14 @@
.video_voice_options {
display: none;
+}
+
+.video_process_but:hover {
+ .video_process_time {
+ display: block;
+ }
+}
+
+.video_process_time {
+ display: none;
}
\ No newline at end of file
diff --git a/code/VideoAccess-VCMP/web/client/src/components/videoPlayer/voiceHeader.jsx b/code/VideoAccess-VCMP/web/client/src/components/videoPlayer/voiceHeader.jsx
index cab4596..1867d93 100644
--- a/code/VideoAccess-VCMP/web/client/src/components/videoPlayer/voiceHeader.jsx
+++ b/code/VideoAccess-VCMP/web/client/src/components/videoPlayer/voiceHeader.jsx
@@ -6,7 +6,38 @@ import { IconReply } from '@douyinfe/semi-icons';
import TextScroll from '../textScroll'
import './videoPlay.less';
-const VideoHeader = ({ operationState, changeSelectState, setoperationState }) => {
+const timeFormat = 'YYYY-MM-DD HH:mm:ss'
+
+const VideoHeader = ({ operationState, changeSelectState, setoperationState, name, showTime }) => {
+ const time = useRef(moment(showTime || undefined))
+ const upTimeInterval = useRef(null)
+ const [showTime_, setShowTime] = useState(time.current.format(timeFormat))
+
+ const updateTime = () => {
+ time.current = moment(showTime || undefined)
+ if (upTimeInterval.current) {
+ clearInterval(upTimeInterval.current)
+ }
+ const upTime = () => {
+ time.current.add(1, 's')
+ setShowTime(time.current.format(timeFormat))
+ }
+ upTime()
+ upTimeInterval.current = setInterval(upTime, 1000)
+ }
+
+ useEffect(() => {
+ updateTime()
+ return () => {
+ if (upTimeInterval.current) {
+ clearInterval(upTimeInterval.current)
+ }
+ }
+ }, [])
+
+ useEffect(() => {
+ updateTime()
+ }, [showTime])
return (
{
operationState && operationState.histroy.select ?
<>
{
- let nextOperationState = changeSelectState('histroy')
- setoperationState(nextOperationState)
+ changeSelectState('histroy')
}} />
> : ''
}
- {moment().format('YYYY-MM-DD HH:mm:ss')} xxxxxxx
+ {showTime_} {name}
diff --git a/code/VideoAccess-VCMP/web/client/src/layout/index.jsx b/code/VideoAccess-VCMP/web/client/src/layout/index.jsx
index 36cffef..1fff8a4 100644
--- a/code/VideoAccess-VCMP/web/client/src/layout/index.jsx
+++ b/code/VideoAccess-VCMP/web/client/src/layout/index.jsx
@@ -154,6 +154,7 @@ const Root = props => {
// IOT system cross
window.addEventListener('message', async function (e) { // 监听 message 事件
const { data } = e
+ console.log(e);
if (data && data.action) {
if (data.action == 'initUser') {
await store.dispatch(actions.auth.initAuth(data.user))
diff --git a/code/VideoAccess-VCMP/web/client/src/sections/auth/actions/auth.js b/code/VideoAccess-VCMP/web/client/src/sections/auth/actions/auth.js
index d1fdf11..c60b211 100644
--- a/code/VideoAccess-VCMP/web/client/src/sections/auth/actions/auth.js
+++ b/code/VideoAccess-VCMP/web/client/src/sections/auth/actions/auth.js
@@ -64,9 +64,10 @@ export function login (username, password) {
export const LOGOUT = 'LOGOUT';
export function logout () {
const user = JSON.parse(sessionStorage.getItem('user'))
- AxyRequest.post(ApiTable.logout, {
- token: user.token
- });
+ user && user.token ?
+ AxyRequest.post(ApiTable.logout, {
+ token: user.token
+ }) : null;
sessionStorage.removeItem('user');
return {
type: LOGOUT
diff --git a/code/VideoAccess-VCMP/web/client/src/utils/index.js b/code/VideoAccess-VCMP/web/client/src/utils/index.js
index bd4b243..fa24482 100644
--- a/code/VideoAccess-VCMP/web/client/src/utils/index.js
+++ b/code/VideoAccess-VCMP/web/client/src/utils/index.js
@@ -2,14 +2,18 @@
import { isAuthorized } from './func';
import { AuthorizationCode } from './authCode';
import { ApiTable, RouteTable, AuthRequest, AxyRequest } from './webapi'
+import { YS_PTZ_DIRECTION, ysptz } from './videoCloudControl';
export {
- isAuthorized,
+ isAuthorized,
- AuthorizationCode,
+ AuthorizationCode,
- ApiTable,
- RouteTable,
- AuthRequest,
- AxyRequest,
+ ApiTable,
+ RouteTable,
+ AuthRequest,
+ AxyRequest,
+
+ YS_PTZ_DIRECTION,
+ ysptz,
}
\ No newline at end of file
diff --git a/code/VideoAccess-VCMP/web/client/src/utils/videoCloudControl.js b/code/VideoAccess-VCMP/web/client/src/utils/videoCloudControl.js
new file mode 100644
index 0000000..fa3620e
--- /dev/null
+++ b/code/VideoAccess-VCMP/web/client/src/utils/videoCloudControl.js
@@ -0,0 +1,54 @@
+'use strict';
+import superagent from "superagent"
+
+// 操作命令:0-上,1-下,2-左,3-右,4-左上,5-左下,6-右上,7-右下,8-放大,9-缩小,10-近焦距,11-远焦距
+export const YS_PTZ_DIRECTION = {
+ up: 0,
+ down: 1,
+ left: 2,
+ right: 3,
+ up_left: 4,
+ down_left: 5,
+ up_right: 6,
+ down_right: 7,
+ zoom_in: 9,
+ zoom_out: 8,
+ focus_in: 10,
+ focus_out: 11
+}
+
+export function ysptz (ac, { serialNo, yingshiToken, channelNo }) {
+ let params = {
+ accessToken: yingshiToken,
+ deviceSerial: serialNo,
+ channelNo: channelNo || 1,
+ direction: YS_PTZ_DIRECTION[ac],
+ speed: 2
+ }
+ let startReqBody = Object.assign({}, params, { speed: 1 })
+ let stopReqBody = params
+ let requestUrl = `https://open.ys7.com/api/lapp/device/ptz/`
+ superagent
+ .post(requestUrl + 'start')
+ .send(startReqBody)
+ .set('Content-Type', 'application/x-www-form-urlencoded')
+ .then((res) => {
+ let resBody = res.body
+ if (resBody.code != '200') {
+ // message.error(resBody.msg)
+ } else {
+ setTimeout(_ => {
+ superagent
+ .post(requestUrl + 'stop')
+ .send(stopReqBody)
+ .set('Content-Type', 'application/x-www-form-urlencoded')
+ .then((tRes) => {
+ let resBody2 = tRes.body
+ if (resBody2.code != '200') {
+ // message.error('操作失败!')
+ }
+ })
+ }, 500)
+ }
+ })
+}
\ No newline at end of file