|
|
|
import React from 'react';
|
|
|
|
import { connect } from 'react-redux';
|
|
|
|
import PropTypes from 'prop-types';
|
|
|
|
import ReactTooltip from 'react-tooltip';
|
|
|
|
import classnames from 'classnames';
|
|
|
|
import clipboardCopy from 'clipboard-copy';
|
|
|
|
import * as appPropTypes from './appPropTypes';
|
|
|
|
import { withRoomContext } from '../RoomContext';
|
|
|
|
import * as requestActions from '../redux/requestActions';
|
|
|
|
import { Appear } from './transitions';
|
|
|
|
import Me from './Me';
|
|
|
|
import ChatInput from './ChatInput';
|
|
|
|
import Peers from './Peers';
|
|
|
|
import Stats from './Stats';
|
|
|
|
import Notifications from './Notifications';
|
|
|
|
import NetworkThrottle from './NetworkThrottle';
|
|
|
|
import { log } from 'gulp-util';
|
|
|
|
import UrlParse from 'url-parse';
|
|
|
|
|
|
|
|
class Room extends React.Component {
|
|
|
|
render() {
|
|
|
|
const {
|
|
|
|
roomClient,
|
|
|
|
room,
|
|
|
|
me,
|
|
|
|
amActiveSpeaker,
|
|
|
|
onRoomLinkCopy
|
|
|
|
} = this.props;
|
|
|
|
|
|
|
|
const mediasoupClientVersion = room.mediasoupClientVersion === '__MEDIASOUP_CLIENT_VERSION__'
|
|
|
|
? 'dev'
|
|
|
|
: room.mediasoupClientVersion;
|
|
|
|
|
|
|
|
|
|
|
|
const urlParser = new UrlParse(window.location.href, true);
|
|
|
|
// 将字符串按 & 分隔
|
|
|
|
const parts = urlParser.href.split('&');
|
|
|
|
// 提取并解析每个部分
|
|
|
|
const params = parts.slice(1).reduce((acc, part) => {
|
|
|
|
const [key, value] = part.split('=');
|
|
|
|
if (key && value) acc[key] = value;
|
|
|
|
return acc;
|
|
|
|
}, {});
|
|
|
|
|
|
|
|
let roomId = params['roomId'];
|
|
|
|
|
|
|
|
return (
|
|
|
|
<Appear duration={300}>
|
|
|
|
<div data-component='Room'>
|
|
|
|
<div className='crumbs'>
|
|
|
|
<span className='goback' onClick={() => {
|
|
|
|
// 向主页面发送消息请求返回主页面
|
|
|
|
window.parent.postMessage('goBack', '*');
|
|
|
|
}}>
|
|
|
|
值班专家<span style={{ margin: '0 4px' }}>{`>`}</span>
|
|
|
|
</span>
|
|
|
|
<span style={{ color: '#5F6368' }}>在线聊天</span>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<Notifications />
|
|
|
|
|
|
|
|
{/* 当前房间状态信息 */}
|
|
|
|
{/* <div className='state'>
|
|
|
|
<div className={classnames('icon', room.state)} />
|
|
|
|
<p className={classnames('text', room.state)}>{room.state}</p>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div className='info'>
|
|
|
|
<p className='text'><span className='label'>server: </span>{room.mediasoupVersion}</p>
|
|
|
|
<p className='text'><span className='label'>client: </span>{mediasoupClientVersion}</p>
|
|
|
|
<p className='text'><span className='label'>handler: </span>{room.mediasoupClientHandler}</p>
|
|
|
|
</div> */}
|
|
|
|
|
|
|
|
{/* 复制当前房间链接 */}
|
|
|
|
{/* <div className='room-link-wrapper'>
|
|
|
|
<div className='room-link'>
|
|
|
|
<a
|
|
|
|
className='link'
|
|
|
|
href={room.url}
|
|
|
|
target='_blank'
|
|
|
|
rel='noopener noreferrer'
|
|
|
|
onClick={(event) =>
|
|
|
|
{
|
|
|
|
// If this is a 'Open in new window/tab' don't prevent
|
|
|
|
// click default action.
|
|
|
|
if (
|
|
|
|
event.ctrlKey || event.shiftKey || event.metaKey ||
|
|
|
|
// Middle click (IE > 9 and everyone else).
|
|
|
|
(event.button && event.button === 1)
|
|
|
|
)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
event.preventDefault();
|
|
|
|
|
|
|
|
clipboardCopy(room.url)
|
|
|
|
.then(onRoomLinkCopy);
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
invitation link
|
|
|
|
</a>
|
|
|
|
</div>
|
|
|
|
</div> */}
|
|
|
|
|
|
|
|
<Peers />
|
|
|
|
|
|
|
|
<div
|
|
|
|
className={classnames('me-container', {
|
|
|
|
'active-speaker': amActiveSpeaker
|
|
|
|
})}
|
|
|
|
>
|
|
|
|
<Me />
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div className='chat-input-container'>
|
|
|
|
<ChatInput />
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div className='sidebar'>
|
|
|
|
<div
|
|
|
|
className={classnames('button', 'hide-videos', {
|
|
|
|
on: me.audioOnly,
|
|
|
|
disabled: me.audioOnlyInProgress
|
|
|
|
})}
|
|
|
|
data-tip={'将参与者的视频 显示/隐藏'}
|
|
|
|
onClick={() => {
|
|
|
|
me.audioOnly
|
|
|
|
? roomClient.disableAudioOnly()
|
|
|
|
: roomClient.enableAudioOnly();
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
|
|
|
|
<div
|
|
|
|
className={classnames('button', 'mute-audio', {
|
|
|
|
on: me.audioMuted
|
|
|
|
})}
|
|
|
|
data-tip={'将参与者的音频 静音/取消静音'}
|
|
|
|
onClick={() => {
|
|
|
|
me.audioMuted
|
|
|
|
? roomClient.unmuteAudio()
|
|
|
|
: roomClient.muteAudio();
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
|
|
|
|
<div
|
|
|
|
className={classnames('button', 'restart-ice', {
|
|
|
|
disabled: me.restartIceInProgress
|
|
|
|
})}
|
|
|
|
data-tip='重新启动 ICE'
|
|
|
|
onClick={() => roomClient.restartIce()}
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
{/* 当前房间状态信息 */}
|
|
|
|
{/* <Stats /> */}
|
|
|
|
|
|
|
|
<If condition={window.NETWORK_THROTTLE_SECRET}>
|
|
|
|
<NetworkThrottle
|
|
|
|
secret={window.NETWORK_THROTTLE_SECRET}
|
|
|
|
/>
|
|
|
|
</If>
|
|
|
|
|
|
|
|
<ReactTooltip
|
|
|
|
place='right'
|
|
|
|
effect='solid'
|
|
|
|
delayShow={100}
|
|
|
|
delayHide={100}
|
|
|
|
delayUpdate={50}
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
</Appear>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
componentDidMount() {
|
|
|
|
const { roomClient } = this.props;
|
|
|
|
|
|
|
|
roomClient.join();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Room.propTypes =
|
|
|
|
{
|
|
|
|
roomClient: PropTypes.any.isRequired,
|
|
|
|
room: appPropTypes.Room.isRequired,
|
|
|
|
me: appPropTypes.Me.isRequired,
|
|
|
|
amActiveSpeaker: PropTypes.bool.isRequired,
|
|
|
|
onRoomLinkCopy: PropTypes.func.isRequired
|
|
|
|
};
|
|
|
|
|
|
|
|
const mapStateToProps = (state) => {
|
|
|
|
return {
|
|
|
|
room: state.room,
|
|
|
|
me: state.me,
|
|
|
|
amActiveSpeaker: state.me.id === state.room.activeSpeakerId
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
const mapDispatchToProps = (dispatch) => {
|
|
|
|
return {
|
|
|
|
onRoomLinkCopy: () => {
|
|
|
|
dispatch(requestActions.notify(
|
|
|
|
{
|
|
|
|
text: '房间链接已复制到剪贴板'
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
const RoomContainer = withRoomContext(connect(
|
|
|
|
mapStateToProps,
|
|
|
|
mapDispatchToProps
|
|
|
|
)(Room));
|
|
|
|
|
|
|
|
export default RoomContainer;
|