巴林闲侠
2 years ago
20 changed files with 601 additions and 251 deletions
@ -1,244 +0,0 @@ |
|||||
import React, { useState, useEffect, useRef } from "react"; |
|
||||
import { connect } from "react-redux"; |
|
||||
import moment from 'moment' |
|
||||
import { Button, Modal, Col, Row, Space } from "@douyinfe/semi-ui"; |
|
||||
import TextScroll from './textScroll' |
|
||||
import './videoPlay.less'; |
|
||||
|
|
||||
const VideoPlay = ({ height, width }) => { |
|
||||
const [jessibuca, setjessibuca] = useState(null) |
|
||||
const [playUrl, setPlayUrl] = useState('http://flv.bdplay.nodemedia.cn/live/bbb.flv') |
|
||||
const [isPlaying, setIsPlaying] = useState(false) |
|
||||
const [operationState, setoperationState] = useState() |
|
||||
|
|
||||
const changeSelectState = (key) => { |
|
||||
const nextOperationState = JSON.parse(JSON.stringify(operationState)) |
|
||||
for (let k in nextOperationState) { |
|
||||
if (k == key) { |
|
||||
nextOperationState[k].select = !nextOperationState[k].select |
|
||||
} else if (key !== 'fullScreen') { |
|
||||
nextOperationState[k].select = false |
|
||||
} |
|
||||
} |
|
||||
return nextOperationState |
|
||||
} |
|
||||
|
|
||||
const operation = [{ |
|
||||
key: 'control', |
|
||||
click: () => { |
|
||||
let nextOperationState = changeSelectState('control') |
|
||||
setoperationState(nextOperationState) |
|
||||
} |
|
||||
}, { |
|
||||
key: 'talk', |
|
||||
click: () => { |
|
||||
let nextOperationState = changeSelectState('talk') |
|
||||
setoperationState(nextOperationState) |
|
||||
} |
|
||||
}, { |
|
||||
key: 'fullScreen', |
|
||||
click: () => { |
|
||||
let nextOperationState = changeSelectState('fullScreen') |
|
||||
setoperationState(nextOperationState) |
|
||||
} |
|
||||
}, { |
|
||||
key: 'histroy', |
|
||||
click: () => { |
|
||||
|
|
||||
} |
|
||||
},] |
|
||||
useEffect(() => { |
|
||||
create() |
|
||||
let nextOperationState = {} |
|
||||
for (let p of operation) { |
|
||||
nextOperationState[p.key] = { |
|
||||
select: false |
|
||||
} |
|
||||
} |
|
||||
setoperationState(nextOperationState) |
|
||||
}, []) |
|
||||
|
|
||||
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) |
|
||||
} |
|
||||
|
|
||||
useEffect(() => { |
|
||||
play() |
|
||||
}, [jessibuca]) |
|
||||
|
|
||||
const play = () => { |
|
||||
if (jessibuca && playUrl) { |
|
||||
jessibuca.play(playUrl); |
|
||||
setIsPlaying(true) |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
const pause = () => { |
|
||||
if (jessibuca) { |
|
||||
jessibuca.pause(); |
|
||||
setIsPlaying(false) |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
const butStyle = { |
|
||||
border: '1px solid #fff', display: 'inline-block', color: '#fff', padding: '0 10px', |
|
||||
display: 'flex', alignItems: 'center', height: '64%', marginLeft: 12 |
|
||||
} |
|
||||
|
|
||||
return ( |
|
||||
<> |
|
||||
<div style={{ height: height || '100%', width: width || '100%' }}> |
|
||||
|
|
||||
<div style={{ position: 'relative', display: 'flex' }}> |
|
||||
{/* 顶部信息 */} |
|
||||
<div style={{ |
|
||||
height: 42, lineHeight: '42px', background: '#00000026', |
|
||||
position: 'absolute', width: '100%', zIndex: 99, |
|
||||
color: '#fff' |
|
||||
}}> |
|
||||
<Row > |
|
||||
<Col span={9} style={{ |
|
||||
backgroundImage: 'url(/assets/images/background/videoPlayBg.png)', |
|
||||
backgroundSize: '100% 100%', |
|
||||
backgroundRepeat: 'no-repeat', |
|
||||
textAlign: 'center' |
|
||||
}}>123</Col> |
|
||||
<Col span={15} style={{}}> |
|
||||
<div style={{ paddingRight: 12 }}> |
|
||||
<TextScroll content={['asdadasdasdasdasdasd', '123123']} duration={6} /> |
|
||||
</div> |
|
||||
</Col> |
|
||||
</Row> |
|
||||
</div> |
|
||||
{/* 视频内容 */} |
|
||||
<div id="container" style={{ height: height || '100%', width: width || '100%' }}></div> |
|
||||
{/* 云控 对讲 对应操作内容 */} |
|
||||
{ |
|
||||
operationState ? |
|
||||
operationState.control.select ? |
|
||||
<div style={{ |
|
||||
position: 'absolute', top: 'calc(50% - 105px)', left: 'calc(50% - 125px)', |
|
||||
width: 210, height: 250, backgroundColor: '#00000014', borderRadius: 68 |
|
||||
}}> |
|
||||
<div style={{ |
|
||||
height: 148, width: 148, borderRadius: '100%', backgroundColor: '#2F53EA72', margin: '12px auto 18px', |
|
||||
position: 'relative', |
|
||||
}}> |
|
||||
{ |
|
||||
[{ |
|
||||
style: { top: 12, left: (148 - 24) / 2, } |
|
||||
}, { |
|
||||
style: { right: 12, top: (148 - 24) / 2, } |
|
||||
}, { |
|
||||
style: { bottom: 12, left: (148 - 24) / 2, } |
|
||||
}, { |
|
||||
style: { left: 12, top: (148 - 24) / 2, } |
|
||||
}].map((s, i) => { |
|
||||
return ( |
|
||||
<img |
|
||||
src="/assets/images/background/up.png" |
|
||||
style={Object.assign({ |
|
||||
height: 24, width: 24, display: 'inline-block', transform: `rotate(${i * 90}deg)`, |
|
||||
position: 'absolute' |
|
||||
}, s.style)} |
|
||||
/> |
|
||||
) |
|
||||
}) |
|
||||
} |
|
||||
<div style={{ |
|
||||
height: 32, width: 32, border: '2px solid #ffffff24', borderRadius: '100%', |
|
||||
position: 'absolute', top: (148 - 34) / 2, left: (148 - 34) / 2 |
|
||||
}} /> |
|
||||
</div> |
|
||||
{ |
|
||||
[ |
|
||||
[{ n: '+' }, { n: '焦距' }, { n: '-' }], |
|
||||
[{ n: '+' }, { n: '缩放' }, { n: '-' }] |
|
||||
].map(s => { |
|
||||
return ( |
|
||||
<div style={{ |
|
||||
width: 110, height: 22, margin: '0 auto 6px', display: 'flex', alignContent: 'center', justifyContent: 'space-around', |
|
||||
backgroundColor: '#2F53EA72', color: '#fff' |
|
||||
}}> |
|
||||
{ |
|
||||
s.map((m, mi) => { |
|
||||
return ( |
|
||||
<div style={{ textAlign: 'center', display: 'inline-block', cursor: mi != 1 ? 'pointer' : 'auto' }}>{m.n}</div> |
|
||||
) |
|
||||
}) |
|
||||
} |
|
||||
</div> |
|
||||
) |
|
||||
}) |
|
||||
} |
|
||||
</div> : |
|
||||
operationState.talk.select ? |
|
||||
<div style={{ |
|
||||
position: 'absolute', top: 'calc(50% - 88px)', left: 'calc(50% - 156px)', |
|
||||
width: 312, height: 176, backgroundColor: '#000000A5', |
|
||||
}}> |
|
||||
<img src="/assets/images/background/talking.png" style={{ display: 'block', margin: '12px auto' }} /> |
|
||||
<div style={{ |
|
||||
height: 32, width: 88, textAlign: 'center', margin: 'auto', color: '#fff', backgroundColor: '#1859C1', |
|
||||
lineHeight: '32px' |
|
||||
}}>开始讲话</div> |
|
||||
</div> : |
|
||||
'' : '' |
|
||||
} |
|
||||
{/* 下方操作 */} |
|
||||
<div style={{ |
|
||||
height: 42, lineHeight: '42px', background: 'linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.8) 100%)', padding: '0 12px', |
|
||||
display: 'flex', justifyContent: 'space-between', |
|
||||
position: 'absolute', bottom: 0, width: '100%', zIndex: 99 |
|
||||
}}> |
|
||||
<div style={{ display: 'flex', alignItems: 'center' }}> |
|
||||
{ |
|
||||
operationState ? |
|
||||
operation.map(p => { |
|
||||
return <img |
|
||||
src={`/assets/images/background/video-icon-${p.key}-${operationState[p.key].select ? 'select' : 'unselect'}.png`} |
|
||||
height={26} |
|
||||
style={{ marginRight: 24 }} |
|
||||
onClick={p.click} |
|
||||
/> |
|
||||
}) : '' |
|
||||
} |
|
||||
</div> |
|
||||
<div style={{ display: 'flex', alignItems: 'center' }}> |
|
||||
<div style={butStyle}>标清</div> |
|
||||
<div style={butStyle}>高清</div> |
|
||||
</div> |
|
||||
</div> |
|
||||
</div> |
|
||||
|
|
||||
</div> |
|
||||
</> |
|
||||
) |
|
||||
} |
|
||||
|
|
||||
function mapStateToProps (state) { |
|
||||
const { auth } = state; |
|
||||
return { |
|
||||
user: auth.user, |
|
||||
}; |
|
||||
} |
|
||||
|
|
||||
export default connect(mapStateToProps)(VideoPlay); |
|
@ -0,0 +1,83 @@ |
|||||
|
import React, { useState, useEffect, useRef } from "react"; |
||||
|
import { connect } from "react-redux"; |
||||
|
import moment from 'moment' |
||||
|
import VideoOperationCloudControl from './videoOperationCloudControl' |
||||
|
import VideoOperationTalk from './VideoOperationTalk' |
||||
|
import VideoOperationSpeed from './videoOperationSpeed' |
||||
|
import VideoOperationVoice from './VideoOperationVoice' |
||||
|
import { IconPause, IconPlay } from '@douyinfe/semi-icons'; |
||||
|
import './videoPlay.less'; |
||||
|
|
||||
|
const VideoOperation = ({ operationState, operation, voiceDisY, setVoiceDisY }) => { |
||||
|
|
||||
|
const butStyle = { |
||||
|
border: '1px solid #fff', display: 'inline-block', color: '#fff', padding: '0 10px', |
||||
|
display: 'flex', alignItems: 'center', height: '64%', marginLeft: 12, cursor: 'pointer', |
||||
|
position: 'relative' |
||||
|
} |
||||
|
|
||||
|
return ( |
||||
|
<> |
||||
|
{ |
||||
|
operationState ? |
||||
|
operationState.control.select ? |
||||
|
<VideoOperationCloudControl /> : |
||||
|
operationState.talk.select ? |
||||
|
<VideoOperationTalk /> : |
||||
|
'' : '' |
||||
|
} |
||||
|
{/* 下方操作 */} |
||||
|
<div style={{ |
||||
|
height: 42, lineHeight: '42px', background: 'linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.8) 100%)', padding: '0 12px', |
||||
|
display: 'flex', justifyContent: 'space-between', |
||||
|
position: 'absolute', bottom: 0, width: '100%', zIndex: 99, color: '#fff' |
||||
|
}}> |
||||
|
{ |
||||
|
operationState ? |
||||
|
operationState.histroy.select ? |
||||
|
<> |
||||
|
<div style={{ display: 'flex', alignItems: 'center' }}> |
||||
|
<IconPause style={{ cursor: 'pointer' }} /> |
||||
|
{/* <IconPlay style={{ cursor: 'pointer' }} /> */} |
||||
|
<span style={{ marginLeft: 12 }}>{moment().format('YYYY-MM-DD HH:mm:ss')}/{moment().format('YYYY-MM-DD HH:mm:ss')}</span> |
||||
|
</div> |
||||
|
<div style={{ display: 'flex', alignItems: 'center' }}> |
||||
|
<VideoOperationVoice voiceDisY={voiceDisY} setVoiceDisY={setVoiceDisY} /> |
||||
|
<VideoOperationSpeed butStyle={butStyle} /> |
||||
|
<div style={butStyle}>时间设置</div> |
||||
|
</div> |
||||
|
</> |
||||
|
: |
||||
|
<> |
||||
|
<div style={{ display: 'flex', alignItems: 'center' }}> |
||||
|
{ |
||||
|
operationState ? |
||||
|
operation.map(p => { |
||||
|
return <img |
||||
|
src={`/assets/images/background/video-icon-${p.key}-${operationState[p.key].select ? 'select' : 'unselect'}.png`} |
||||
|
height={26} |
||||
|
style={{ marginRight: 24, cursor: 'pointer' }} |
||||
|
onClick={p.click} |
||||
|
/> |
||||
|
}) : '' |
||||
|
} |
||||
|
</div> |
||||
|
<div style={{ display: 'flex', alignItems: 'center' }}> |
||||
|
<div style={butStyle}>标清</div> |
||||
|
<div style={butStyle}>高清</div> |
||||
|
</div> |
||||
|
</> : '' |
||||
|
} |
||||
|
</div> |
||||
|
</> |
||||
|
) |
||||
|
} |
||||
|
|
||||
|
function mapStateToProps (state) { |
||||
|
const { auth } = state; |
||||
|
return { |
||||
|
user: auth.user, |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
export default connect(mapStateToProps)(VideoOperation); |
@ -0,0 +1,74 @@ |
|||||
|
import React, { useState, useEffect, useRef } from "react"; |
||||
|
import { connect } from "react-redux"; |
||||
|
import './videoPlay.less'; |
||||
|
|
||||
|
const VideoOperationCloudControl = ({ }) => { |
||||
|
|
||||
|
return ( |
||||
|
<div style={{ |
||||
|
position: 'absolute', top: 'calc(50% - 105px)', left: 'calc(50% - 125px)', |
||||
|
width: 210, height: 250, backgroundColor: '#00000014', borderRadius: 68 |
||||
|
}}> |
||||
|
<div style={{ |
||||
|
height: 148, width: 148, borderRadius: '100%', backgroundColor: '#2F53EA72', margin: '12px auto 18px', |
||||
|
position: 'relative', |
||||
|
}}> |
||||
|
{ |
||||
|
[{ |
||||
|
style: { top: 12, left: (148 - 24) / 2, } |
||||
|
}, { |
||||
|
style: { right: 12, top: (148 - 24) / 2, } |
||||
|
}, { |
||||
|
style: { bottom: 12, left: (148 - 24) / 2, } |
||||
|
}, { |
||||
|
style: { left: 12, top: (148 - 24) / 2, } |
||||
|
}].map((s, i) => { |
||||
|
return ( |
||||
|
<img |
||||
|
src="/assets/images/background/up.png" |
||||
|
style={Object.assign({ |
||||
|
height: 24, width: 24, display: 'inline-block', transform: `rotate(${i * 90}deg)`, |
||||
|
position: 'absolute' |
||||
|
}, s.style)} |
||||
|
/> |
||||
|
) |
||||
|
}) |
||||
|
} |
||||
|
<div style={{ |
||||
|
height: 32, width: 32, border: '2px solid #ffffff24', borderRadius: '100%', |
||||
|
position: 'absolute', top: (148 - 34) / 2, left: (148 - 34) / 2 |
||||
|
}} /> |
||||
|
</div> |
||||
|
{ |
||||
|
[ |
||||
|
[{ n: '+' }, { n: '焦距' }, { n: '-' }], |
||||
|
[{ n: '+' }, { n: '缩放' }, { n: '-' }] |
||||
|
].map(s => { |
||||
|
return ( |
||||
|
<div style={{ |
||||
|
width: 110, height: 22, margin: '0 auto 6px', display: 'flex', alignContent: 'center', justifyContent: 'space-around', |
||||
|
backgroundColor: '#2F53EA72', color: '#fff' |
||||
|
}}> |
||||
|
{ |
||||
|
s.map((m, mi) => { |
||||
|
return ( |
||||
|
<div style={{ textAlign: 'center', display: 'inline-block', cursor: mi != 1 ? 'pointer' : 'auto' }}>{m.n}</div> |
||||
|
) |
||||
|
}) |
||||
|
} |
||||
|
</div> |
||||
|
) |
||||
|
}) |
||||
|
} |
||||
|
</div> |
||||
|
) |
||||
|
} |
||||
|
|
||||
|
function mapStateToProps (state) { |
||||
|
const { auth } = state; |
||||
|
return { |
||||
|
user: auth.user, |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
export default connect(mapStateToProps)(VideoOperationCloudControl); |
@ -0,0 +1,33 @@ |
|||||
|
import React, { useState, useEffect, useRef } from "react"; |
||||
|
import { connect } from "react-redux"; |
||||
|
import './videoPlay.less'; |
||||
|
|
||||
|
const VideoOperationSpeed = ({ butStyle }) => { |
||||
|
|
||||
|
return ( |
||||
|
<div style={butStyle} className="video_speed_but"> |
||||
|
<div className="video_speed_options" style={{ |
||||
|
position: 'absolute', top: -24 * 3 - 24, backgroundColor: '#00000099', width: 60, |
||||
|
left: -6, padding: '8px 0' |
||||
|
}}> |
||||
|
{ |
||||
|
[1, 2, 3].map((s) => { |
||||
|
return ( |
||||
|
<div className="video_speed_option" style={{ textAlign: 'center', height: 24, lineHeight: '24px' }}>{s}.0 x</div> |
||||
|
) |
||||
|
}) |
||||
|
} |
||||
|
</div> |
||||
|
倍速 |
||||
|
</div> |
||||
|
) |
||||
|
} |
||||
|
|
||||
|
function mapStateToProps (state) { |
||||
|
const { auth } = state; |
||||
|
return { |
||||
|
user: auth.user, |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
export default connect(mapStateToProps)(VideoOperationSpeed); |
@ -0,0 +1,33 @@ |
|||||
|
import React, { useState, useEffect, useRef } from "react"; |
||||
|
import { connect } from "react-redux"; |
||||
|
import './videoPlay.less'; |
||||
|
|
||||
|
const VideoOperationTalk = ({ butStyle }) => { |
||||
|
|
||||
|
return ( |
||||
|
<div style={butStyle} className="video_speed_but"> |
||||
|
<div className="video_speed_options" style={{ |
||||
|
position: 'absolute', top: -24 * 3 - 24, backgroundColor: '#00000099', width: 60, |
||||
|
left: -6, padding: '8px 0' |
||||
|
}}> |
||||
|
{ |
||||
|
[1, 2, 3].map((s) => { |
||||
|
return ( |
||||
|
<div className="video_speed_option" style={{ textAlign: 'center', height: 24, lineHeight: '24px' }}>{s}.0 x</div> |
||||
|
) |
||||
|
}) |
||||
|
} |
||||
|
</div> |
||||
|
倍速 |
||||
|
</div> |
||||
|
) |
||||
|
} |
||||
|
|
||||
|
function mapStateToProps (state) { |
||||
|
const { auth } = state; |
||||
|
return { |
||||
|
user: auth.user, |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
export default connect(mapStateToProps)(VideoOperationTalk); |
@ -0,0 +1,74 @@ |
|||||
|
import React, { useState, useEffect, useRef } from "react"; |
||||
|
import { connect } from "react-redux"; |
||||
|
import { IconVolume2, } from '@douyinfe/semi-icons'; |
||||
|
import './videoPlay.less'; |
||||
|
|
||||
|
const VideoOperationVoice = ({ voiceDisY, setVoiceDisY }) => { |
||||
|
|
||||
|
return ( |
||||
|
<div className="video_voice_but" style={{ display: 'flex', alignItems: 'center', position: 'relative', height: '100%', }}> |
||||
|
<div className="video_voice_options"> |
||||
|
<div style={{ |
||||
|
position: 'absolute', top: -100 - 32 - 16, backgroundColor: '#00000099', width: 32, |
||||
|
left: -9, padding: '4px 0 12px', |
||||
|
display: 'flex', justifyContent: 'center', flexDirection: 'column', alignItems: 'center', |
||||
|
}}> |
||||
|
<span style={{ height: 32, lineHeight: '32px', }}>{Math.abs(voiceDisY)}</span> |
||||
|
<div style={{ |
||||
|
width: 2, height: 100, backgroundColor: '#ffffffa0', position: 'relative', |
||||
|
}} onMouseDown={(ev) => { console.log('object'); }}> |
||||
|
<div |
||||
|
style={{ |
||||
|
height: 12, width: 12, borderRadius: '100%', backgroundColor: '#fff', |
||||
|
position: 'relative', left: -5, cursor: 'pointer', |
||||
|
bottom: -94 |
||||
|
}} |
||||
|
id='voice_point' |
||||
|
onMouseDown={(ev) => { |
||||
|
ev.stopPropagation(); |
||||
|
ev.preventDefault(); |
||||
|
|
||||
|
let oevent = ev; |
||||
|
let distanceY = oevent.clientY |
||||
|
let prev = Date.now(); |
||||
|
const point = document.getElementById('voice_point') |
||||
|
document.onmousemove = function (ev) { |
||||
|
ev.stopPropagation(); |
||||
|
ev.preventDefault(); |
||||
|
// 节流 |
||||
|
let now = Date.now(); |
||||
|
if (now - prev >= 0) { |
||||
|
let oevent = ev; |
||||
|
let y = voiceDisY + oevent.clientY - distanceY |
||||
|
if (y < -100) { |
||||
|
y = -100 |
||||
|
} else if (y > 0) { |
||||
|
y = 0 |
||||
|
} |
||||
|
setVoiceDisY(y) |
||||
|
point.style.bottom = -94 - y + 'px'; |
||||
|
prev = Date.now(); |
||||
|
} |
||||
|
}; |
||||
|
document.onmouseup = function () { |
||||
|
document.onmousemove = null; |
||||
|
document.onmouseup = null; |
||||
|
}; |
||||
|
}} |
||||
|
/> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<IconVolume2 style={{ cursor: 'pointer' }} /> |
||||
|
</div> |
||||
|
) |
||||
|
} |
||||
|
|
||||
|
function mapStateToProps (state) { |
||||
|
const { auth } = state; |
||||
|
return { |
||||
|
user: auth.user, |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
export default connect(mapStateToProps)(VideoOperationVoice); |
@ -0,0 +1,140 @@ |
|||||
|
import React, { useState, useEffect, useRef } from "react"; |
||||
|
import { connect } from "react-redux"; |
||||
|
import screenfull from 'screenfull'; |
||||
|
import VideoHeader from './voiceHeader' |
||||
|
import VideoOperation from './videoOperation' |
||||
|
import './videoPlay.less'; |
||||
|
|
||||
|
const VideoPlay = ({ height, width }) => { |
||||
|
const [jessibuca, setjessibuca] = useState(null) |
||||
|
const [playUrl, setPlayUrl] = useState('http://flv.bdplay.nodemedia.cn/live/bbb.flv') |
||||
|
const [isPlaying, setIsPlaying] = useState(false) |
||||
|
const [operationState, setoperationState] = useState() |
||||
|
const [voiceDisY, setVoiceDisY] = useState(0) |
||||
|
|
||||
|
const changeSelectState = (key) => { |
||||
|
const nextOperationState = JSON.parse(JSON.stringify(operationState)) |
||||
|
for (let k in nextOperationState) { |
||||
|
if (k == key) { |
||||
|
nextOperationState[k].select = !nextOperationState[k].select |
||||
|
} else if (k !== 'fullScreen') { |
||||
|
nextOperationState[k].select = false |
||||
|
} |
||||
|
} |
||||
|
return nextOperationState |
||||
|
} |
||||
|
|
||||
|
const operation = [{ |
||||
|
key: 'control', |
||||
|
click: () => { |
||||
|
let nextOperationState = changeSelectState('control') |
||||
|
setoperationState(nextOperationState) |
||||
|
} |
||||
|
}, { |
||||
|
key: 'talk', |
||||
|
click: () => { |
||||
|
let nextOperationState = changeSelectState('talk') |
||||
|
setoperationState(nextOperationState) |
||||
|
} |
||||
|
}, { |
||||
|
key: 'fullScreen', |
||||
|
click: () => { |
||||
|
let nextOperationState = changeSelectState('fullScreen') |
||||
|
setoperationState(nextOperationState) |
||||
|
let player = document.getElementById('vcmp_videoplay') |
||||
|
if (screenfull.isEnabled) { |
||||
|
screenfull.toggle(player); |
||||
|
} |
||||
|
} |
||||
|
}, { |
||||
|
key: 'histroy', |
||||
|
click: () => { |
||||
|
let nextOperationState = changeSelectState('histroy') |
||||
|
setoperationState(nextOperationState) |
||||
|
} |
||||
|
},] |
||||
|
useEffect(() => { |
||||
|
create() |
||||
|
let nextOperationState = {} |
||||
|
for (let p of operation) { |
||||
|
nextOperationState[p.key] = { |
||||
|
select: false |
||||
|
} |
||||
|
} |
||||
|
setoperationState(nextOperationState) |
||||
|
}, []) |
||||
|
|
||||
|
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() |
||||
|
} |
||||
|
|
||||
|
useEffect(() => { |
||||
|
play() |
||||
|
}, [jessibuca]) |
||||
|
|
||||
|
const play = () => { |
||||
|
if (jessibuca && playUrl) { |
||||
|
jessibuca.play(playUrl); |
||||
|
setIsPlaying(true) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
const pause = () => { |
||||
|
if (jessibuca) { |
||||
|
jessibuca.pause(); |
||||
|
setIsPlaying(false) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return ( |
||||
|
<> |
||||
|
<div style={{ height: height || '100%', width: width || '100%' }}> |
||||
|
<div id="vcmp_videoplay" style={{ position: 'relative', display: 'flex', height: '100%', width: '100%' }}> |
||||
|
{/* 顶部信息 */} |
||||
|
<VideoHeader operationState={operationState} changeSelectState={changeSelectState} setoperationState={setoperationState} /> |
||||
|
{/* 视频内容 */} |
||||
|
<div id="container" |
||||
|
style={{ |
||||
|
height: '100%', width: '100%' |
||||
|
}}> |
||||
|
|
||||
|
</div> |
||||
|
{/* 云控 对讲 对应操作内容 */} |
||||
|
<VideoOperation |
||||
|
operationState={operationState} operation={operation} |
||||
|
voiceDisY={voiceDisY} setVoiceDisY={setVoiceDisY} |
||||
|
/> |
||||
|
</div> |
||||
|
|
||||
|
</div> |
||||
|
</> |
||||
|
) |
||||
|
} |
||||
|
|
||||
|
function mapStateToProps (state) { |
||||
|
const { auth } = state; |
||||
|
return { |
||||
|
user: auth.user, |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
export default connect(mapStateToProps)(VideoPlay); |
@ -0,0 +1,23 @@ |
|||||
|
.video_speed_but:hover { |
||||
|
.video_speed_options { |
||||
|
display: block; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.video_speed_options { |
||||
|
display: none; |
||||
|
} |
||||
|
|
||||
|
.video_speed_option:hover { |
||||
|
color: #A3B5FF; |
||||
|
} |
||||
|
|
||||
|
.video_voice_but:hover { |
||||
|
.video_voice_options { |
||||
|
display: block; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.video_voice_options { |
||||
|
display: none; |
||||
|
} |
@ -0,0 +1,53 @@ |
|||||
|
import React, { useState, useEffect, useRef } from "react"; |
||||
|
import { connect } from "react-redux"; |
||||
|
import moment from 'moment' |
||||
|
import { Col, Row, } from "@douyinfe/semi-ui"; |
||||
|
import { IconReply } from '@douyinfe/semi-icons'; |
||||
|
import TextScroll from '../textScroll' |
||||
|
import './videoPlay.less'; |
||||
|
|
||||
|
const VideoHeader = ({ operationState, changeSelectState, setoperationState }) => { |
||||
|
|
||||
|
return ( |
||||
|
<div style={{ |
||||
|
height: 42, lineHeight: '42px', background: '#00000026', |
||||
|
position: 'absolute', width: '100%', zIndex: 99, |
||||
|
color: '#fff' |
||||
|
}}> |
||||
|
<Row> |
||||
|
<Col span={9} style={{ |
||||
|
backgroundImage: 'url(/assets/images/background/videoPlayBg.png)', |
||||
|
backgroundSize: '100% 100%', |
||||
|
backgroundRepeat: 'no-repeat', |
||||
|
// textAlign: 'center', |
||||
|
padding: '0 12px' |
||||
|
}}> |
||||
|
{ |
||||
|
operationState && operationState.histroy.select ? |
||||
|
<> |
||||
|
<IconReply style={{ marginRight: 12, cursor: 'pointer' }} onClick={() => { |
||||
|
let nextOperationState = changeSelectState('histroy') |
||||
|
setoperationState(nextOperationState) |
||||
|
}} /> |
||||
|
</> : '' |
||||
|
} |
||||
|
{moment().format('YYYY-MM-DD HH:mm:ss')} xxxxxxx |
||||
|
</Col> |
||||
|
<Col span={15} style={{}}> |
||||
|
<div style={{ paddingRight: 12 }}> |
||||
|
<TextScroll content={['asdadasdasdasdasdasd', '123123']} duration={6} /> |
||||
|
</div> |
||||
|
</Col> |
||||
|
</Row> |
||||
|
</div> |
||||
|
) |
||||
|
} |
||||
|
|
||||
|
function mapStateToProps (state) { |
||||
|
const { auth } = state; |
||||
|
return { |
||||
|
user: auth.user, |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
export default connect(mapStateToProps)(VideoHeader); |
Loading…
Reference in new issue