main
鲁誉程 2 months ago
parent af403afb01
commit 05fb19c521

@ -269,7 +269,7 @@ export default class RoomClient
store.dispatch(requestActions.notify( store.dispatch(requestActions.notify(
{ {
type : 'error', type : 'error',
text : 'WebSocket connection failed' text : 'WebSocket连接失败'
})); }));
}); });
@ -278,7 +278,7 @@ export default class RoomClient
store.dispatch(requestActions.notify( store.dispatch(requestActions.notify(
{ {
type : 'error', type : 'error',
text : 'WebSocket disconnected' text : 'WebSocket已断开连接'
})); }));
// Close mediasoup Transports. // Close mediasoup Transports.
@ -399,7 +399,7 @@ export default class RoomClient
store.dispatch(requestActions.notify( store.dispatch(requestActions.notify(
{ {
type : 'error', type : 'error',
text : `Error creating a Consumer: ${error}` text : `创建用户时出错: ${error}`
})); }));
throw error; throw error;
@ -468,7 +468,7 @@ export default class RoomClient
store.dispatch(requestActions.notify( store.dispatch(requestActions.notify(
{ {
type : 'error', type : 'error',
text : 'DataConsumer closed' text : 'DataConsumer 已关闭'
})); }));
}); });
@ -479,7 +479,7 @@ export default class RoomClient
store.dispatch(requestActions.notify( store.dispatch(requestActions.notify(
{ {
type : 'error', type : 'error',
text : `DataConsumer error: ${error}` text : `DataConsumer 错误: ${error}`
})); }));
}); });
@ -543,6 +543,7 @@ export default class RoomClient
store.dispatch(requestActions.notify( store.dispatch(requestActions.notify(
{ {
type : 'userMessage',
title : `${sendingPeer.displayName} says:`, title : `${sendingPeer.displayName} says:`,
text : message, text : message,
timeout : 5000 timeout : 5000
@ -587,7 +588,7 @@ export default class RoomClient
store.dispatch(requestActions.notify( store.dispatch(requestActions.notify(
{ {
type : 'error', type : 'error',
text : `Error creating a DataConsumer: ${error}` text : `创建DataConsumer时出错: ${error}`
})); }));
throw error; throw error;
@ -636,7 +637,7 @@ export default class RoomClient
store.dispatch(requestActions.notify( store.dispatch(requestActions.notify(
{ {
text : `${peer.displayName} has joined the room` text : `${peer.displayName} 加入房间`
})); }));
break; break;
@ -859,7 +860,7 @@ export default class RoomClient
store.dispatch(requestActions.notify( store.dispatch(requestActions.notify(
{ {
type : 'error', type : 'error',
text : 'Microphone disconnected!' text : '麦克风断开!'
})); }));
this.disableMic() this.disableMic()
@ -873,7 +874,7 @@ export default class RoomClient
store.dispatch(requestActions.notify( store.dispatch(requestActions.notify(
{ {
type : 'error', type : 'error',
text : `Error enabling microphone: ${error}` text : `启用麦克风时出错: ${error}`
})); }));
if (track) if (track)
@ -903,7 +904,7 @@ export default class RoomClient
store.dispatch(requestActions.notify( store.dispatch(requestActions.notify(
{ {
type : 'error', type : 'error',
text : `Error closing server-side mic Producer: ${error}` text : `关闭服务器端麦克风生成器时出错: ${error}`
})); }));
} }
@ -931,7 +932,7 @@ export default class RoomClient
store.dispatch(requestActions.notify( store.dispatch(requestActions.notify(
{ {
type : 'error', type : 'error',
text : `Error pausing server-side mic Producer: ${error}` text : `暂停服务器端麦克风生成器时出错: ${error}`
})); }));
} }
} }
@ -957,7 +958,7 @@ export default class RoomClient
store.dispatch(requestActions.notify( store.dispatch(requestActions.notify(
{ {
type : 'error', type : 'error',
text : `Error resuming server-side mic Producer: ${error}` text : `恢复服务器端麦克风生成器时出错: ${error}`
})); }));
} }
} }
@ -1148,7 +1149,7 @@ export default class RoomClient
store.dispatch(requestActions.notify( store.dispatch(requestActions.notify(
{ {
type : 'error', type : 'error',
text : 'Webcam disconnected!' text : '网络摄像头已断开连接!'
})); }));
this.disableWebcam() this.disableWebcam()
@ -1162,7 +1163,7 @@ export default class RoomClient
store.dispatch(requestActions.notify( store.dispatch(requestActions.notify(
{ {
type : 'error', type : 'error',
text : `Error enabling webcam: ${error}` text : `启用网络摄像头时出错: ${error}`
})); }));
if (track) if (track)
@ -1195,7 +1196,7 @@ export default class RoomClient
store.dispatch(requestActions.notify( store.dispatch(requestActions.notify(
{ {
type : 'error', type : 'error',
text : `Error closing server-side webcam Producer: ${error}` text : `关闭服务器端网络摄像头生成器时出错: ${error}`
})); }));
} }
@ -1265,7 +1266,7 @@ export default class RoomClient
store.dispatch(requestActions.notify( store.dispatch(requestActions.notify(
{ {
type : 'error', type : 'error',
text : `Could not change webcam: ${error}` text : `无法更改网络摄像头: ${error}`
})); }));
} }
@ -1322,7 +1323,7 @@ export default class RoomClient
store.dispatch(requestActions.notify( store.dispatch(requestActions.notify(
{ {
type : 'error', type : 'error',
text : `Could not change webcam resolution: ${error}` text : `无法更改网络摄像头分辨率: ${error}`
})); }));
} }
@ -1517,7 +1518,7 @@ export default class RoomClient
store.dispatch(requestActions.notify( store.dispatch(requestActions.notify(
{ {
type : 'error', type : 'error',
text : 'Share disconnected!' text : '共享已断开连接!'
})); }));
this.disableShare() this.disableShare()
@ -1533,7 +1534,7 @@ export default class RoomClient
store.dispatch(requestActions.notify( store.dispatch(requestActions.notify(
{ {
type : 'error', type : 'error',
text : `Error sharing: ${error}` text : `共享错误: ${error}`
})); }));
} }
@ -1567,7 +1568,7 @@ export default class RoomClient
store.dispatch(requestActions.notify( store.dispatch(requestActions.notify(
{ {
type : 'error', type : 'error',
text : `Error closing server-side share Producer: ${error}` text : `关闭服务器端共享生成器时出错: ${error}`
})); }));
} }
@ -1674,7 +1675,7 @@ export default class RoomClient
store.dispatch(requestActions.notify( store.dispatch(requestActions.notify(
{ {
text : 'ICE restarted' text : 'ICE 重新启动'
})); }));
} }
catch (error) catch (error)
@ -1684,7 +1685,7 @@ export default class RoomClient
store.dispatch(requestActions.notify( store.dispatch(requestActions.notify(
{ {
type : 'error', type : 'error',
text : `ICE restart failed: ${error}` text : `ICE 重启失败: ${error}`
})); }));
} }
@ -1710,7 +1711,7 @@ export default class RoomClient
store.dispatch(requestActions.notify( store.dispatch(requestActions.notify(
{ {
type : 'error', type : 'error',
text : `Error setting max sending video spatial layer: ${error}` text : `设置最大发送视频空间层时出错: ${error}`
})); }));
} }
} }
@ -1736,7 +1737,7 @@ export default class RoomClient
store.dispatch(requestActions.notify( store.dispatch(requestActions.notify(
{ {
type : 'error', type : 'error',
text : `Error setting Consumer preferred layers: ${error}` text : `设置用户首选图层时出错: ${error}`
})); }));
} }
} }
@ -1760,7 +1761,7 @@ export default class RoomClient
store.dispatch(requestActions.notify( store.dispatch(requestActions.notify(
{ {
type : 'error', type : 'error',
text : `Error setting Consumer priority: ${error}` text : `设置用户优先级时出错: ${error}`
})); }));
} }
} }
@ -1775,7 +1776,7 @@ export default class RoomClient
store.dispatch(requestActions.notify( store.dispatch(requestActions.notify(
{ {
text : 'Keyframe requested for video consumer' text : '为视频用户请求关键帧'
})); }));
} }
catch (error) catch (error)
@ -1785,7 +1786,7 @@ export default class RoomClient
store.dispatch(requestActions.notify( store.dispatch(requestActions.notify(
{ {
type : 'error', type : 'error',
text : `Error requesting key frame for Consumer: ${error}` text : `为用户请求关键帧时出错: ${error}`
})); }));
} }
} }
@ -1840,7 +1841,7 @@ export default class RoomClient
store.dispatch(requestActions.notify( store.dispatch(requestActions.notify(
{ {
type : 'error', type : 'error',
text : 'Chat DataProducer closed' text : '聊天数据生成器已关闭'
})); }));
}); });
@ -1851,7 +1852,7 @@ export default class RoomClient
store.dispatch(requestActions.notify( store.dispatch(requestActions.notify(
{ {
type : 'error', type : 'error',
text : `Chat DataProducer error: ${error}` text : `聊天数据生成器错误: ${error}`
})); }));
}); });
@ -1867,7 +1868,7 @@ export default class RoomClient
store.dispatch(requestActions.notify( store.dispatch(requestActions.notify(
{ {
type : 'error', type : 'error',
text : `Error enabling chat DataProducer: ${error}` text : `启用聊天数据生成器时出错: ${error}`
})); }));
throw error; throw error;
@ -1924,7 +1925,7 @@ export default class RoomClient
store.dispatch(requestActions.notify( store.dispatch(requestActions.notify(
{ {
type : 'error', type : 'error',
text : 'Bot DataProducer closed' text : 'Bot DataProducer 已关闭'
})); }));
}); });
@ -1935,7 +1936,7 @@ export default class RoomClient
store.dispatch(requestActions.notify( store.dispatch(requestActions.notify(
{ {
type : 'error', type : 'error',
text : `Bot DataProducer error: ${error}` text : `Bot DataProducer 错误: ${error}`
})); }));
}); });
@ -1951,7 +1952,7 @@ export default class RoomClient
store.dispatch(requestActions.notify( store.dispatch(requestActions.notify(
{ {
type : 'error', type : 'error',
text : `Error enabling bot DataProducer: ${error}` text : `启用bot DataProducter时出错: ${error}`
})); }));
throw error; throw error;
@ -1967,7 +1968,7 @@ export default class RoomClient
store.dispatch(requestActions.notify( store.dispatch(requestActions.notify(
{ {
type : 'error', type : 'error',
text : 'No chat DataProducer' text : '无聊天 DataProducter'
})); }));
return; return;
@ -1984,7 +1985,7 @@ export default class RoomClient
store.dispatch(requestActions.notify( store.dispatch(requestActions.notify(
{ {
type : 'error', type : 'error',
text : `chat DataProducer.send() failed: ${error}` text : `聊天DataProducter.send()失败: ${error}`
})); }));
} }
} }
@ -2038,7 +2039,7 @@ export default class RoomClient
store.dispatch(requestActions.notify( store.dispatch(requestActions.notify(
{ {
text : 'Display name changed' text : '显示名称已更改'
})); }));
} }
catch (error) catch (error)
@ -2048,7 +2049,7 @@ export default class RoomClient
store.dispatch(requestActions.notify( store.dispatch(requestActions.notify(
{ {
type : 'error', type : 'error',
text : `Could not change display name: ${error}` text : `无法更改显示名称: ${error}`
})); }));
// We need to refresh the component for it to render the previous // We need to refresh the component for it to render the previous
@ -2225,7 +2226,7 @@ export default class RoomClient
store.dispatch(requestActions.notify( store.dispatch(requestActions.notify(
{ {
type : 'error', type : 'error',
text : `Error applying network throttle: ${error}` text : `应用网络节流时出错: ${error}`
})); }));
} }
} }
@ -2247,7 +2248,7 @@ export default class RoomClient
store.dispatch(requestActions.notify( store.dispatch(requestActions.notify(
{ {
type : 'error', type : 'error',
text : `Error resetting network throttle: ${error}` text : `重置网络节流阀时出错: ${error}`
})); }));
} }
} }
@ -2479,11 +2480,12 @@ export default class RoomClient
store.dispatch( store.dispatch(
stateActions.removeAllNotifications()); stateActions.removeAllNotifications());
store.dispatch(requestActions.notify( // store.dispatch(requestActions.notify(
{ // {
text : 'You are in the room!', // isMe : true,
timeout : 3000 // text : '你已成功加入房间',
})); // timeout : 3000
// }));
for (const peer of peers) for (const peer of peers)
{ {
@ -2535,7 +2537,7 @@ export default class RoomClient
store.dispatch(requestActions.notify( store.dispatch(requestActions.notify(
{ {
type : 'error', type : 'error',
text : `Could not join the room: ${error}` text : `无法加入房间: ${error}`
})); }));
this.close(); this.close();
@ -2614,7 +2616,7 @@ export default class RoomClient
store.dispatch(requestActions.notify( store.dispatch(requestActions.notify(
{ {
type : 'error', type : 'error',
text : `Error pausing Consumer: ${error}` text : `暂停用户时出错: ${error}`
})); }));
} }
} }
@ -2640,7 +2642,7 @@ export default class RoomClient
store.dispatch(requestActions.notify( store.dispatch(requestActions.notify(
{ {
type : 'error', type : 'error',
text : `Error resuming Consumer: ${error}` text : `恢复用户时出错: ${error}`
})); }));
} }
} }

@ -2,18 +2,17 @@ import React from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { withRoomContext } from '../RoomContext'; import { withRoomContext } from '../RoomContext';
import * as requestActions from '../redux/requestActions';
const BotMessageRegex = new RegExp('^@bot (.*)'); const BotMessageRegex = new RegExp('^@bot (.*)');
class ChatInput extends React.Component class ChatInput extends React.Component {
{ constructor(props) {
constructor(props)
{
super(props); super(props);
this.state = this.state =
{ {
text : '' text: ''
}; };
// TextArea element got via React ref. // TextArea element got via React ref.
@ -21,12 +20,12 @@ class ChatInput extends React.Component
this._textareaElem = null; this._textareaElem = null;
} }
render() render() {
{
const { const {
connected, connected,
chatDataProducer, chatDataProducer,
botDataProducer botDataProducer,
sendUserInfo
} = this.props; } = this.props;
const { text } = this.state; const { text } = this.state;
@ -37,27 +36,29 @@ class ChatInput extends React.Component
<div data-component='ChatInput'> <div data-component='ChatInput'>
<textarea <textarea
ref={(elem) => { this._textareaElem = elem; }} ref={(elem) => { this._textareaElem = elem; }}
placeholder={disabled ? 'Chat unavailable' : 'Write here...'} placeholder={disabled ? '当前聊天不可用' : '请输入聊天内容'}
dir='auto' dir='auto'
autoComplete='off' autoComplete='off'
disabled={disabled} disabled={disabled}
value={text} value={text || ''}
onChange={this.handleChange.bind(this)} onChange={this.handleChange.bind(this)}
onKeyPress={this.handleKeyPress.bind(this)} onKeyPress={this.handleKeyPress.bind(this, sendUserInfo)}
/> />
<div className='sendOut' onClick={() => {
this.sendOut(sendUserInfo);
}}>发送</div>
</div> </div>
); );
} }
handleChange(event) handleChange(event) {
{
const text = event.target.value; const text = event.target.value;
this.setState({ text }); this.setState({ text });
} }
handleKeyPress(event) handleKeyPress(sendUserInfo, event) {
{
// If Shift + Enter do nothing. // If Shift + Enter do nothing.
if (event.key !== 'Enter' || (event.shiftKey || event.ctrlKey)) if (event.key !== 'Enter' || (event.shiftKey || event.ctrlKey))
return; return;
@ -65,25 +66,26 @@ class ChatInput extends React.Component
// Don't add the sending Enter into the value. // Don't add the sending Enter into the value.
event.preventDefault(); event.preventDefault();
this.sendOut(sendUserInfo)
}
sendOut(sendUserInfo) {
let text = this.state.text.trim(); let text = this.state.text.trim();
this.setState({ text: '' }); this.setState({ text: '' });
if (text) if (text) {
{
const { roomClient } = this.props; const { roomClient } = this.props;
const match = BotMessageRegex.exec(text); const match = BotMessageRegex.exec(text);
// Chat message. // Chat message.
if (!match) if (!match) {
{
text = text.trim(); text = text.trim();
roomClient.sendChatMessage(text); roomClient.sendChatMessage(text);
sendUserInfo(text);
} }
// Message to the bot. // Message to the bot.
else else {
{
text = match[1].trim(); text = match[1].trim();
roomClient.sendBotMessage(text); roomClient.sendBotMessage(text);
@ -94,14 +96,13 @@ class ChatInput extends React.Component
ChatInput.propTypes = ChatInput.propTypes =
{ {
roomClient : PropTypes.any.isRequired, roomClient: PropTypes.any.isRequired,
connected : PropTypes.bool.isRequired, connected: PropTypes.bool.isRequired,
chatDataProducer : PropTypes.any, chatDataProducer: PropTypes.any,
botDataProducer : PropTypes.any botDataProducer: PropTypes.any
}; };
const mapStateToProps = (state) => const mapStateToProps = (state) => {
{
const dataProducersArray = Object.values(state.dataProducers); const dataProducersArray = Object.values(state.dataProducers);
const chatDataProducer = dataProducersArray const chatDataProducer = dataProducersArray
.find((dataProducer) => dataProducer.label === 'chat'); .find((dataProducer) => dataProducer.label === 'chat');
@ -109,15 +110,27 @@ const mapStateToProps = (state) =>
.find((dataProducer) => dataProducer.label === 'bot'); .find((dataProducer) => dataProducer.label === 'bot');
return { return {
connected : state.room.state === 'connected', connected: state.room.state === 'connected',
chatDataProducer, chatDataProducer,
botDataProducer botDataProducer
}; };
}; };
const mapDispatchToProps = (dispatch) => {
return {
sendUserInfo: (text) => {
dispatch(requestActions.notify({
type: 'userMessage',
isMe: true,
text: text,
}));
}
};
};
const ChatInputContainer = withRoomContext(connect( const ChatInputContainer = withRoomContext(connect(
mapStateToProps, mapStateToProps,
undefined mapDispatchToProps,
)(ChatInput)); )(ChatInput));
export default ChatInputContainer; export default ChatInputContainer;

@ -159,7 +159,7 @@ class Me extends React.Component
/> />
<ReactTooltip <ReactTooltip
type='light' place='right'
effect='solid' effect='solid'
delayShow={100} delayShow={100}
delayHide={100} delayHide={100}

@ -6,55 +6,91 @@ import * as appPropTypes from './appPropTypes';
import * as stateActions from '../redux/stateActions'; import * as stateActions from '../redux/stateActions';
import { Appear } from './transitions'; import { Appear } from './transitions';
const Notifications = ({ notifications, onClick }) => const Notifications = ({ notifications, onClick }) => {
{ console.log("notifications", notifications);
return ( return (
<div data-component='Notifications'> <div data-component='Notifications' style={{
{ width: '383px',
notifications.map((notification) => background: '#F6F7F9',
{ borderRadius: '8px',
return ( margin: '48px 30px 19px 0px'
<Appear key={notification.id} duration={250}> }}>
<div <div className='chatTitle'>聊天</div>
className={classnames('notification', notification.type)}
onClick={() => onClick(notification.id)}
>
<div className='icon' />
<div className='body'> <div className='chatwarp'>
<If condition={notification.title}> {
<p className='title'>{notification.title}</p> notifications.map((notification) => {
</If> return (
<div key={notification.id} style={{ padding: '0 20px', fontSize: '14px' }}>
{
//
notification.type == 'userMessage' ?
<div style={{marginTop: 36}}>
{
notification.isMe ?
<div style={{ display: 'flex', flexDirection: 'row-reverse', flexWrap: 'wrap' }}>
<div style={{ color: '#232B40', marginBottom: 10, width: '100%', textAlign: 'right' }}></div>
<div style={{ width: 'max-content', padding: '10px 20px', color: '#434D6C', lineHeight: '26px', background: '#CDD8F1', borderRadius: '8px 0px 8px 8px' }}>
{notification.text}
</div>
</div> :
<>
<div style={{ color: '#232B40', marginBottom: 10 }}>用户-{notification.id}</div>
<div style={{ width: 'max-content', padding: '10px 20px', color: '#434D6C', lineHeight: '26px', background: '#fff', borderRadius: '0px 8px 8px 8px' }}>
{notification.text}
</div>
</>
}
</div> :
<div style={{width: '100%', margin: '20px 0', textAlign: 'center'}}>
{notification.text}
</div>
}
<p className='text'>{notification.text}</p>
</div>
</div> </div>
</Appear>
);
}) //
} // <Appear key={notification.id} duration={250}>
// <div
// className={classnames('notification', notification.type)}
// onClick={() => onClick(notification.id)}
// >
// <div className='icon' />
// <div className='body'>
// <If condition={notification.title}>
// <p className='title'>{notification.title}</p>
// </If>
// <p className='text'>{notification.text}</p>
// </div>
// </div>
// </Appear>
);
})
}
</div>
</div> </div>
); );
}; };
Notifications.propTypes = Notifications.propTypes =
{ {
notifications : PropTypes.arrayOf(appPropTypes.Notification).isRequired, notifications: PropTypes.arrayOf(appPropTypes.Notification).isRequired,
onClick : PropTypes.func.isRequired onClick: PropTypes.func.isRequired
}; };
const mapStateToProps = (state) => const mapStateToProps = (state) => {
{
const { notifications } = state; const { notifications } = state;
return { notifications }; return { notifications };
}; };
const mapDispatchToProps = (dispatch) => const mapDispatchToProps = (dispatch) => {
{
return { return {
onClick : (notificationId) => onClick: (notificationId) => {
{
dispatch(stateActions.removeNotification(notificationId)); dispatch(stateActions.removeNotification(notificationId));
} }
}; };

@ -99,7 +99,7 @@ export default class PeerView extends React.Component
return ( return (
<div data-component='PeerView'> <div data-component='PeerView'>
<div className='info'> <div className='info'>
<div className='icons'> {/* <div className='icons'>
<div <div
className={classnames('icon', 'info', { on: showInfo })} className={classnames('icon', 'info', { on: showInfo })}
onClick={() => this.setState({ showInfo: !showInfo })} onClick={() => this.setState({ showInfo: !showInfo })}
@ -395,12 +395,14 @@ export default class PeerView extends React.Component
{this._printConsumerScore(videoConsumerId, videoScore)} {this._printConsumerScore(videoConsumerId, videoScore)}
</If> </If>
</If> </If>
</div> </div> */}
<div className={classnames('peer', { 'is-me': isMe })}> <div className={classnames('peer', { 'is-me': isMe })} style={{position: 'absolute', bottom: 0}}>
<Choose> <Choose>
<When condition={isMe}> <When condition={isMe}>
<EditableInput <span className='display-name'>{peer.displayName}</span>
{/* 可自行修改名称 */}
{/* <EditableInput
value={peer.displayName} value={peer.displayName}
propName='displayName' propName='displayName'
className='display-name editable' className='display-name editable'
@ -413,7 +415,7 @@ export default class PeerView extends React.Component
spellCheck : 'false' spellCheck : 'false'
}} }}
onChange={({ displayName }) => onChangeDisplayName(displayName)} onChange={({ displayName }) => onChangeDisplayName(displayName)}
/> /> */}
</When> </When>
<Otherwise> <Otherwise>

@ -34,9 +34,17 @@ class Room extends React.Component
return ( return (
<Appear duration={300}> <Appear duration={300}>
<div data-component='Room'> <div data-component='Room'>
<div className='crumbs'>
<span className='goback' onClick={() => {history.push('/counselling/expertList')}}>
值班专家<span style={{margin: '0 4px'}}>{`>`}</span>
</span>
<span style={{color: '#5F6368'}}>在线聊天</span>
</div>
<Notifications /> <Notifications />
<div className='state'> {/* 当前房间状态信息 */}
{/* <div className='state'>
<div className={classnames('icon', room.state)} /> <div className={classnames('icon', room.state)} />
<p className={classnames('text', room.state)}>{room.state}</p> <p className={classnames('text', room.state)}>{room.state}</p>
</div> </div>
@ -45,9 +53,10 @@ class Room extends React.Component
<p className='text'><span className='label'>server:&nbsp;&nbsp;</span>{room.mediasoupVersion}</p> <p className='text'><span className='label'>server:&nbsp;&nbsp;</span>{room.mediasoupVersion}</p>
<p className='text'><span className='label'>client:&nbsp;&nbsp;</span>{mediasoupClientVersion}</p> <p className='text'><span className='label'>client:&nbsp;&nbsp;</span>{mediasoupClientVersion}</p>
<p className='text'><span className='label'>handler:&nbsp;&nbsp;</span>{room.mediasoupClientHandler}</p> <p className='text'><span className='label'>handler:&nbsp;&nbsp;</span>{room.mediasoupClientHandler}</p>
</div> </div> */}
<div className='room-link-wrapper'> {/* 复制当前房间链接 */}
{/* <div className='room-link-wrapper'>
<div className='room-link'> <div className='room-link'>
<a <a
className='link' className='link'
@ -76,7 +85,7 @@ class Room extends React.Component
invitation link invitation link
</a> </a>
</div> </div>
</div> </div> */}
<Peers /> <Peers />
@ -98,7 +107,7 @@ class Room extends React.Component
on : me.audioOnly, on : me.audioOnly,
disabled : me.audioOnlyInProgress disabled : me.audioOnlyInProgress
})} })}
data-tip={'Show/hide participants\' video'} data-tip={'将参与者的视频 显示/隐藏'}
onClick={() => onClick={() =>
{ {
me.audioOnly me.audioOnly
@ -111,7 +120,7 @@ class Room extends React.Component
className={classnames('button', 'mute-audio', { className={classnames('button', 'mute-audio', {
on : me.audioMuted on : me.audioMuted
})} })}
data-tip={'Mute/unmute participants\' audio'} data-tip={'将参与者的音频 静音/取消静音'}
onClick={() => onClick={() =>
{ {
me.audioMuted me.audioMuted
@ -124,12 +133,13 @@ class Room extends React.Component
className={classnames('button', 'restart-ice', { className={classnames('button', 'restart-ice', {
disabled : me.restartIceInProgress disabled : me.restartIceInProgress
})} })}
data-tip='Restart ICE' data-tip='重新启动 ICE'
onClick={() => roomClient.restartIce()} onClick={() => roomClient.restartIce()}
/> />
</div> </div>
<Stats /> {/* 当前房间状态信息 */}
{/* <Stats /> */}
<If condition={window.NETWORK_THROTTLE_SECRET}> <If condition={window.NETWORK_THROTTLE_SECRET}>
<NetworkThrottle <NetworkThrottle
@ -138,7 +148,7 @@ class Room extends React.Component
</If> </If>
<ReactTooltip <ReactTooltip
type='light' place='right'
effect='solid' effect='solid'
delayShow={100} delayShow={100}
delayHide={100} delayHide={100}
@ -182,7 +192,7 @@ const mapDispatchToProps = (dispatch) =>
{ {
dispatch(requestActions.notify( dispatch(requestActions.notify(
{ {
text : 'Room link copied to the clipboard' text : '房间链接已复制到剪贴板'
})); }));
} }
}; };

@ -2,7 +2,7 @@ import randomString from 'random-string';
import * as stateActions from './stateActions'; import * as stateActions from './stateActions';
// This returns a redux-thunk action (a function). // This returns a redux-thunk action (a function).
export const notify = ({ type = 'info', text, title, timeout }) => export const notify = ({ type = 'info', isMe = false, text, title, timeout }) =>
{ {
if (!timeout) if (!timeout)
{ {
@ -23,16 +23,16 @@ export const notify = ({ type = 'info', text, title, timeout }) =>
type, type,
title, title,
text, text,
timeout timeout,
isMe,
}; };
return (dispatch) => return (dispatch) =>
{ {
dispatch(stateActions.addNotification(notification)); dispatch(stateActions.addNotification(notification));
// setTimeout(() =>
setTimeout(() => // {
{ // dispatch(stateActions.removeNotification(notification.id));
dispatch(stateActions.removeNotification(notification.id)); // }, timeout);
}, timeout);
}; };
}; };

@ -2,19 +2,35 @@
position: relative; position: relative;
height: 100%; height: 100%;
width: 100%; width: 100%;
display: flex;
align-items: center;
> .sendOut {
width: 80px;
height: 34px;
background: linear-gradient( 139deg, #5C64FF 0%, #6988F8 100%);
border-radius: 17px;
color: #fff;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
font-size: 12px;
margin: 0 12px;
}
> textarea { > textarea {
height: 100%; // height: 100%;
width: 100%; width: 100%;
padding: 4px 8px; padding: 4px 8px;
resize: none; resize: none;
outline: none; outline: none;
background-color: rgba(#243B55, 1); background-color: rgba(#fff, 1);
color: #fff; color: #000;
font-family: inherit; font-family: inherit;
font-size: 13px; font-size: 13px;
font-weight: 400; font-weight: 400;
line-height: 22px; line-height: 23px;
border: none; border: none;
+placeholder() { +placeholder() {

@ -6,7 +6,7 @@
padding: 0 20px; padding: 0 20px;
background: rgba(#fff, 0.95); background: rgba(#fff, 0.95);
border-radius: 4px; border-radius: 4px;
box-shadow: 0px 5px 12px 2px rgba(#111, 0.5); // box-shadow: 0px 5px 12px 2px rgba(#111, 0.5);
font-family: 'Roboto'; font-family: 'Roboto';
> h1.draggable { > h1.draggable {

@ -1,19 +1,18 @@
[data-component='Notifications'] { [data-component='Notifications'] {
position: fixed; position: fixed;
z-index: 9999; z-index: 9999;
pointer-events: none; // pointer-events: none;
top: 0; top: 0;
right: 0; right: 0;
bottom: 0; bottom: 0;
padding: 20px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: flex-end; //justify-content: flex-end;
align-items: flex-end; //align-items: flex-end;
+desktop() { +desktop() {
padding: 10px; // padding: 10px;
width: 300px; // width: 300px;
} }
+mobile() { +mobile() {
@ -22,6 +21,23 @@
max-width: 220px; max-width: 220px;
} }
> .chatTitle {
color: #000;
font-size: 16px;
height: 54px;
line-height: 54px;
padding-left: 20px;
border-bottom: 1px solid #EBEBEB;
font-weight: 500;
}
> .chatwarp {
overflow: hidden;
overflow-y: auto;
height: calc(100% - 50px - 85px);
}
> .notification { > .notification {
pointer-events: auto; pointer-events: auto;
margin-top: 4px; margin-top: 4px;

@ -165,7 +165,7 @@
} }
&:not(.is-me) { &:not(.is-me) {
padding: 20px; padding: 10px;
align-items: flex-start; align-items: flex-start;
pointer-events: none; pointer-events: none;
} }

@ -3,8 +3,9 @@
width: 100%; width: 100%;
+desktop() { +desktop() {
width: 100%; width: calc(100% - 423px);
padding: 40px 0 220px 0; background: #fff;
padding: 40px 0 220px 50px;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
flex-wrap: wrap; flex-wrap: wrap;
@ -29,11 +30,12 @@
+desktop() { +desktop() {
flex: 0 0 auto; flex: 0 0 auto;
height: 382px; border-radius: 8px;
width: 450px; height: 202px;
margin: 6px; width: 264px;
margin: 10px;
border: 1px solid rgba(#fff, 0.15); border: 1px solid rgba(#fff, 0.15);
box-shadow: 0px 5px 12px 2px rgba(#111, 0.5); // box-shadow: 0px 5px 12px 2px rgba(#111, 0.5);
transition-property: border-color; transition-property: border-color;
transition-duration: 0.35s; transition-duration: 0.35s;

@ -5,6 +5,21 @@
AppearFadeIn(300ms); AppearFadeIn(300ms);
> .crumbs {
position: absolute;
margin: 16px 30px;
font-size: 14px;
> .goback {
cursor: pointer;
color: #C5C5C5;
&:hover {
color: #5F6368;
}
}
}
> .state { > .state {
position: fixed; position: fixed;
z-index: 100; z-index: 100;
@ -189,7 +204,7 @@
position: fixed; position: fixed;
z-index: 100; z-index: 100;
overflow: hidden; overflow: hidden;
box-shadow: 0px 5px 12px 2px rgba(#111, 0.5); // box-shadow: 0px 5px 12px 2px rgba(#111, 0.5);
transition-property: border-color; transition-property: border-color;
transition-duration: 0.2s; transition-duration: 0.2s;
@ -198,10 +213,11 @@
} }
+desktop() { +desktop() {
height: 250px; height: 202px;
width: 294px; width: 264px;
bottom: 60px; bottom: 20px;
left: 20px; left: 20px;
border-radius: 8px;
border: 1px solid rgba(#fff, 0.15); border: 1px solid rgba(#fff, 0.15);
} }
@ -216,16 +232,19 @@
> .chat-input-container { > .chat-input-container {
position: fixed; position: fixed;
z-index: 100; z-index: 9999;
overflow: hidden; overflow: hidden;
box-shadow: 0px 5px 12px 2px rgba(#111, 0.5); box-shadow: 0px 5px 12px 2px rgba(#111, 0.5);
+desktop() { +desktop() {
height: 30px; bottom: 30px;
width: 294px; right: 45px;
bottom: 20px; width: 350px;
left: 20px; height: 60px;
border: 1px solid rgba(#fff, 0.15); height: 60px;
background: #FFFFFF;
box-shadow: 0px 0px 10px 0px rgba(226,226,226,0.5);
border-radius: 8px;
} }
+mobile() { +mobile() {
@ -265,7 +284,7 @@
background-position: center; background-position: center;
background-size: 75%; background-size: 75%;
background-repeat: no-repeat; background-repeat: no-repeat;
background-color: $COLOR_BG_1; background-color: rgba(#000, 0.3);
cursor: pointer; cursor: pointer;
transition-property: opacity, background-color; transition-property: opacity, background-color;
transition-duration: 0.2s; transition-duration: 0.2s;

@ -16,7 +16,7 @@ html {
// background-size: cover; // background-size: cover;
// background-repeat: no-repeat; // background-repeat: no-repeat;
background: #141E30; background: #141E30;
background: linear-gradient(to top, #243B55, #141E30); background: #fff;
font-family: 'Roboto'; font-family: 'Roboto';
font-weight: 300; font-weight: 300;
@ -36,6 +36,7 @@ body {
#mediasoup-demo-app-container { #mediasoup-demo-app-container {
height: 100%; height: 100%;
width: 100%; width: 100%;
background: #fff;
// Components // Components
@import './components/Room'; @import './components/Room';
@ -67,3 +68,23 @@ body {
position: fixed; // Required for old IE position: fixed; // Required for old IE
} }
} }
::-webkit-scrollbar {
height: 6px;
width: 6px;
background: rgba(0, 0, 0, 0.1) !important;
}
::-webkit-scrollbar-thumb {
background: rgba(0, 0, 0, 0.1) !important;
border-radius: 3px;
&:hover {
background: rgba(0, 0, 0, 0.20) !important;
}
}
::-webkit-scrollbar-track {
background-color: #f6f7f94d !important;
box-shadow: initial !important;
}

@ -17,7 +17,7 @@ module.exports =
// Signaling settings (protoo WebSocket server and HTTP API server). // Signaling settings (protoo WebSocket server and HTTP API server).
https : https :
{ {
listenIp : '192.168.0.167', // 换成你的IP地址 listenIp : '0.0.0.0', // 换成你的IP地址
// NOTE: Don't change listenPort (client app assumes 4443). // NOTE: Don't change listenPort (client app assumes 4443).
listenPort : process.env.PROTOO_LISTEN_PORT || 4443, listenPort : process.env.PROTOO_LISTEN_PORT || 4443,
// NOTE: Set your own valid certificate files. // NOTE: Set your own valid certificate files.

Loading…
Cancel
Save