@ -0,0 +1,22 @@ |
|||||
|
'use strict'; |
||||
|
const mqtt = require('mqtt'); |
||||
|
|
||||
|
module.exports = async function factory (app, opts) { |
||||
|
// const client = mqtt.connect(opts.mqtt.mqttVideoServer);
|
||||
|
|
||||
|
// client.on('connect', function () {
|
||||
|
// console.info(`mqtt connect success ${opts.mqtt.mqttVideoServer}`);
|
||||
|
// })
|
||||
|
// client.on('error', function (e) {
|
||||
|
// console.error(`mqtt connect failed ${opts.mqtt.mqttVideoServer}`);
|
||||
|
// app.fs.logger.error('info', '[FS-AUTH-MQTT]', `mqtt connect failed ${opts.mqtt.mqttVideoServer}`);
|
||||
|
// })
|
||||
|
|
||||
|
// client.subscribe('test', { qos: 2 });//订阅主题为test的消息
|
||||
|
|
||||
|
// client.on('message', function (top, message) {
|
||||
|
// console.log(message.toString());
|
||||
|
// });
|
||||
|
|
||||
|
// app.mqttVideoServer = client
|
||||
|
} |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 906 B |
After Width: | Height: | Size: 671 B |
After Width: | Height: | Size: 632 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 1012 B |
@ -0,0 +1,48 @@ |
|||||
|
import React, { useRef, useEffect, useState } from 'react' |
||||
|
import moment from 'moment' |
||||
|
import './textScroll.less' |
||||
|
|
||||
|
function TextScroll (props) { |
||||
|
const { content, duration } = props |
||||
|
const [showContent, setShowContent] = useState('1231231') |
||||
|
|
||||
|
useEffect(() => { |
||||
|
let repeatTime = moment() |
||||
|
let refreshTime = moment() |
||||
|
const scroll = () => { |
||||
|
let contentParent = document.getElementById('marquee_box') |
||||
|
document.getElementById('contentPMakeUp').style.width = contentParent.clientWidth + 'px' |
||||
|
// 控制频率 |
||||
|
if (moment().diff(refreshTime) > 1000 / 60) { |
||||
|
const contentP = document.getElementById('contentP') |
||||
|
// 静态等待时间 |
||||
|
if (moment().diff(repeatTime) > 1000 * 1.5) { |
||||
|
contentP.style.visibility = 'visible' |
||||
|
} |
||||
|
if (moment().diff(repeatTime) > 1000 * 3) { |
||||
|
contentParent.scrollLeft = contentParent.scrollLeft + 1 |
||||
|
} |
||||
|
if (contentParent.scrollLeft >= contentP.clientWidth + 24) { |
||||
|
contentParent.scrollLeft = 0 |
||||
|
repeatTime = moment() |
||||
|
setShowContent('asdasd' + Math.random()) |
||||
|
contentP.style.visibility = 'hidden' |
||||
|
} |
||||
|
refreshTime = moment() |
||||
|
} |
||||
|
window.requestAnimationFrame(scroll) |
||||
|
} |
||||
|
window.requestAnimationFrame(scroll) |
||||
|
}, []) |
||||
|
|
||||
|
return ( |
||||
|
<div className="marquee_box" id='marquee_box' style={{ overflow: 'hidden' }} > |
||||
|
<p style={{ position: 'relative', left: 24 }}> |
||||
|
<p id='contentP' style={{ display: 'inline-block', visibility: 'hidden' }}>{showContent}</p> |
||||
|
<p id='contentPMakeUp' style={{ width: 0, display: 'inline-block' }}></p> |
||||
|
</p> |
||||
|
</div> |
||||
|
) |
||||
|
} |
||||
|
|
||||
|
export default React.memo(TextScroll) |
@ -0,0 +1,19 @@ |
|||||
|
.marquee_box { |
||||
|
width: 100%; |
||||
|
height: 100%; |
||||
|
word-break: keep-all; |
||||
|
white-space: nowrap; |
||||
|
// display: flex; |
||||
|
// align-items: center; |
||||
|
} |
||||
|
|
||||
|
.marquee_box p { |
||||
|
// display: inline-block; |
||||
|
padding: 0; |
||||
|
margin: 0; |
||||
|
} |
||||
|
|
||||
|
.marquee_box:hover p { |
||||
|
animation-play-state: paused; |
||||
|
cursor: default; |
||||
|
} |
@ -0,0 +1,143 @@ |
|||||
|
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 operation = [{ |
||||
|
key: 'control', |
||||
|
click: () => { console.log(121212); } |
||||
|
}, { |
||||
|
key: 'talk', |
||||
|
click: () => { console.log(121212); } |
||||
|
}, { |
||||
|
key: 'fullScreen', |
||||
|
click: () => { console.log(121212); } |
||||
|
}, { |
||||
|
key: 'histroy', |
||||
|
click: () => { console.log(121212); } |
||||
|
},] |
||||
|
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', }}> |
||||
|
<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> |
||||
|
<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 }} |
||||
|
/> |
||||
|
}) : '' |
||||
|
} |
||||
|
</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,32 @@ |
|||||
|
import React, { useState, useEffect, useRef } from "react"; |
||||
|
import { connect } from "react-redux"; |
||||
|
import moment from 'moment' |
||||
|
import { Button, Modal, } from "@douyinfe/semi-ui"; |
||||
|
import VideoPlay from './videoPlay' |
||||
|
import './videoPlayModal.less'; |
||||
|
|
||||
|
const VideoPlayModal = ({ visible }) => { |
||||
|
|
||||
|
return ( |
||||
|
<Modal |
||||
|
visible={visible} |
||||
|
header={null} |
||||
|
footer={null} |
||||
|
size={'large'} |
||||
|
style={{}} |
||||
|
bodyStyle={{}} |
||||
|
className="videoModal" |
||||
|
> |
||||
|
<VideoPlay height={460} /> |
||||
|
</Modal> |
||||
|
) |
||||
|
} |
||||
|
|
||||
|
function mapStateToProps (state) { |
||||
|
const { auth } = state; |
||||
|
return { |
||||
|
user: auth.user, |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
export default connect(mapStateToProps)(VideoPlayModal); |
@ -0,0 +1,5 @@ |
|||||
|
.videoModal { |
||||
|
.semi-modal-content { |
||||
|
padding: 0; |
||||
|
} |
||||
|
} |