Commit c21f5e58 authored by liujiaxin's avatar liujiaxin

version 1.2

parent bfcbbc6a
...@@ -4,10 +4,11 @@ import {Dialog, DialogContent, DialogContentText} from '@material-ui/core'; ...@@ -4,10 +4,11 @@ import {Dialog, DialogContent, DialogContentText} from '@material-ui/core';
import './dialog.scss'; import './dialog.scss';
import { useGlobalState } from '../../containers/root-container'; import { useGlobalState } from '../../containers/root-container';
import { roomStore } from '../../stores/room'; import {roomStore, windowMonitor} from '../../stores/room';
import { globalStore } from '../../stores/global'; import {globalStore} from '../../stores/global';
import { useHistory } from 'react-router-dom'; import { useHistory } from 'react-router-dom';
import { RoomMessage } from '../../utils/agora-rtm-client'; import { RoomMessage } from '../../utils/agora-rtm-client';
import {getApiServerHost} from "../../services/agora-end-points";
interface RoomProps { interface RoomProps {
onConfirm: (type: string) => void onConfirm: (type: string) => void
...@@ -84,6 +85,13 @@ const DialogContainer = () => { ...@@ -84,6 +85,13 @@ const DialogContainer = () => {
const onConfirm = (type: string) => { const onConfirm = (type: string) => {
if (type === 'exitRoom') { if (type === 'exitRoom') {
// debugger // debugger
// const data = roomStore.getUserUsage();
// const host = getApiServerHost();
// var blob = new Blob([JSON.stringify(data)], {
// type: 'application/x-www-form-urlencoded'
// });
// navigator.sendBeacon(`${host}/api/classroom/finish`, blob);
windowMonitor.leave()
globalStore.showLoading(); globalStore.showLoading();
roomStore.exitAll().then(() => { roomStore.exitAll().then(() => {
globalStore.stopLoading(); globalStore.stopLoading();
......
...@@ -26,10 +26,17 @@ export default function (props: any) { ...@@ -26,10 +26,17 @@ export default function (props: any) {
const val = evt.target.value.match(ALPHABETICAL)[0]; const val = evt.target.value.match(ALPHABETICAL)[0];
props.onChange(val ? val : ''); props.onChange(val ? val : '');
} }
const onBlur = (evt: any) => {
const val = evt.target.value.match(ALPHABETICAL)[0];
if (props.onBlur) {
props.onBlur(val ? val : '');
}
}
return ( return (
<> <>
<InputLabel>{props.Label}</InputLabel> <InputLabel>{props.Label}</InputLabel>
<Input className={classes.formInput} type={props.type} value={props.value} <Input className={classes.formInput} type={props.type} value={props.value}
onBlur={onBlur}
onChange={onChange}> onChange={onChange}>
</Input> </Input>
{props.requiredText ? <Typography className={classes.required}>{props.requiredText}</Typography> : null} {props.requiredText ? <Typography className={classes.required}>{props.requiredText}</Typography> : null}
......
...@@ -33,4 +33,4 @@ const FormSelect: React.FC<FormSelect> = ({ ...@@ -33,4 +33,4 @@ const FormSelect: React.FC<FormSelect> = ({
); );
} }
export default React.memo(FormSelect); export default React.memo(FormSelect);
\ No newline at end of file
...@@ -10,7 +10,7 @@ import { SketchPicker, RGBColor } from 'react-color'; ...@@ -10,7 +10,7 @@ import { SketchPicker, RGBColor } from 'react-color';
import { AgoraElectronClient } from '../utils/agora-electron-client'; import { AgoraElectronClient } from '../utils/agora-electron-client';
import { UploadBtn } from './whiteboard/upload/upload-btn'; import { UploadBtn } from './whiteboard/upload/upload-btn';
import { ResourcesMenu } from './whiteboard/resources-menu'; import { ResourcesMenu } from './whiteboard/resources-menu';
import ScaleController from './whiteboard/scale-controller'; // import ScaleController from './whiteboard/scale-controller';
import { PPTProgressPhase } from '../utils/upload-manager'; import { PPTProgressPhase } from '../utils/upload-manager';
import { UploadNoticeView } from '../components/whiteboard/upload/upload-notice'; import { UploadNoticeView } from '../components/whiteboard/upload/upload-notice';
import Progress from '../components/progress/progress'; import Progress from '../components/progress/progress';
...@@ -234,6 +234,7 @@ const MediaBoard: React.FC<MediaBoardProps> = ({ ...@@ -234,6 +234,7 @@ const MediaBoard: React.FC<MediaBoardProps> = ({
whiteboard.updateRoomState(); whiteboard.updateRoomState();
} }
/*
const showControl: boolean = useMemo(() => { const showControl: boolean = useMemo(() => {
if (me.role === 'teacher') return true; if (me.role === 'teacher') return true;
if (location.pathname.match(/big-class/)) { if (location.pathname.match(/big-class/)) {
...@@ -242,6 +243,10 @@ const MediaBoard: React.FC<MediaBoardProps> = ({ ...@@ -242,6 +243,10 @@ const MediaBoard: React.FC<MediaBoardProps> = ({
} }
} }
return false; return false;
}, []);*/
const showControl: boolean = useMemo(() => {
if (me.role === 'teacher') return true;
return false;
}, []); }, []);
const items = [ const items = [
...@@ -569,6 +574,8 @@ const items = [ ...@@ -569,6 +574,8 @@ const items = [
room={room} room={room}
/> />
} }
{ showControl ?
<div className="layer"> <div className="layer">
{!sharedStream ? {!sharedStream ?
<> <>
...@@ -584,7 +591,10 @@ const items = [ ...@@ -584,7 +591,10 @@ const items = [
</> : null} </> : null}
<UploadPanel /> <UploadPanel />
{children ? children : null} {children ? children : null}
</div> </div>: null}
{/*me.role === 'teacher' && room ? {/*me.role === 'teacher' && room ?
<ScaleController <ScaleController
zoomScale={scale} zoomScale={scale}
...@@ -603,6 +613,7 @@ const items = [ ...@@ -603,6 +613,7 @@ const items = [
/> />
: :
null*/} null*/}
{ showControl ? { showControl ?
<Control <Control
notice={globalState.notice} notice={globalState.notice}
...@@ -612,7 +623,9 @@ const items = [ ...@@ -612,7 +623,9 @@ const items = [
currentPage={currentPage} currentPage={currentPage}
totalPage={totalPage} totalPage={totalPage}
isHost={isHost} isHost={isHost}
onClick={handlePageTool}/> : null } onClick={handlePageTool}/> : null
}
{tool === 'folder' && whiteboardState.room ? {tool === 'folder' && whiteboardState.room ?
<ResourcesMenu <ResourcesMenu
active={whiteboardState.activeDir} active={whiteboardState.activeDir}
......
...@@ -10,6 +10,27 @@ ...@@ -10,6 +10,27 @@
flex: 1; flex: 1;
} }
} }
.hands-btn{
width: 16px!important;
height: 40px!important;
color: #dd4814;
}
@keyframes blink{
0%{opacity: 1;}
25%{opacity: .5;}
50%{opacity: .0;}
75%{opacity: .5;}
100%{opacity: 1;}
}
.blink{
color: #dd4814;
animation: blink 1s linear infinite;
-webkit-animation: blink 1s linear infinite;
-moz-animation: blink 1s linear infinite;
-ms-animation: blink 1s linear infinite;
-o-animation: blink 1s linear infinite;
}
.holder-avatar{ .holder-avatar{
width: 40px!important; width: 40px!important;
height: 40px!important; height: 40px!important;
......
...@@ -6,6 +6,8 @@ import { useRoomState } from '../containers/root-container'; ...@@ -6,6 +6,8 @@ import { useRoomState } from '../containers/root-container';
import { platform } from '../utils/platform'; import { platform } from '../utils/platform';
import AccountCircle from '@material-ui/icons/AccountCircle'; import AccountCircle from '@material-ui/icons/AccountCircle';
import Link from '@material-ui/core/Link'; import Link from '@material-ui/core/Link';
import PanToolIcon from '@material-ui/icons/PanTool';
import {roomStore} from "../stores/room";
const contentMode = 0; const contentMode = 0;
interface MemberHolderProps { interface MemberHolderProps {
...@@ -111,6 +113,11 @@ const MemberHolder: React.FC<MemberHolderProps> = ({ ...@@ -111,6 +113,11 @@ const MemberHolder: React.FC<MemberHolderProps> = ({
}, [domId, stream]); }, [domId, stream]);
*/ */
const isHandUp = useMemo(() => {
const hu = roomStore.state.handsUpStudents[streamID];
console.log(streamID, hu)
return hu
}, [roomStore.state.handsUpStudents]);
useEffect(() => { useEffect(() => {
if (stream && platform === 'web') { if (stream && platform === 'web') {
...@@ -234,6 +241,12 @@ const MemberHolder: React.FC<MemberHolderProps> = ({ ...@@ -234,6 +241,12 @@ const MemberHolder: React.FC<MemberHolderProps> = ({
{/*me.uid === id ||*/} {/*me.uid === id ||*/}
{me.role === 'teacher' ? {me.role === 'teacher' ?
<span className="media-btn"> <span className="media-btn">
{
isHandUp ?
<PanToolIcon className='hands-btn blink'></PanToolIcon>:
<div className='hands-btn'></div>
}
{/*<Link component="button" onClick={onAudioClick}>{audio ? "静音" : "开麦"}</Link>*/} {/*<Link component="button" onClick={onAudioClick}>{audio ? "静音" : "开麦"}</Link>*/}
{me.role === 'teacher' ? <Link component="button" onClick={onStageUp}>上台</Link> : null} {me.role === 'teacher' ? <Link component="button" onClick={onStageUp}>上台</Link> : null}
{/*<Icon onClick={onAudioClick} className={audio ? "icon-speaker-on" : "icon-speaker-off"} data={"audio"} />*/} {/*<Icon onClick={onAudioClick} className={audio ? "icon-speaker-on" : "icon-speaker-off"} data={"audio"} />*/}
......
...@@ -75,13 +75,14 @@ ...@@ -75,13 +75,14 @@
flex-direction: column; flex-direction: column;
justify-content: flex-end; justify-content: flex-end;
box-sizing: border-box; box-sizing: border-box;
min-width: 280px; /*min-width: 280px;
max-width: 280px; max-width: 280px;
min-height: 159px; min-height: 159px;
max-height: 159px; max-height: 159px;*/
position: relative; position: relative;
overflow: hidden; overflow: hidden;
flex: 1; flex: 1;
canvas { canvas {
z-index: 1; z-index: 1;
} }
...@@ -96,6 +97,7 @@ ...@@ -96,6 +97,7 @@
height: 100%; height: 100%;
width: 100%; width: 100%;
} }
// &.show-placeholder > div:last-child { // &.show-placeholder > div:last-child {
// display: none !important; // display: none !important;
// } // }
...@@ -104,10 +106,10 @@ ...@@ -104,10 +106,10 @@
.student-placeholder { .student-placeholder {
display: flex; display: flex;
top: 0; top: 0;
min-width: 280px; //min-width: 280px;
max-width: 280px; //max-width: 280px;
min-height: 135px; //min-height: 135px;
max-height: 135px; //max-height: 135px;
position: absolute; position: absolute;
z-index: 2; z-index: 2;
} }
......
This diff is collapsed.
...@@ -27,6 +27,10 @@ ...@@ -27,6 +27,10 @@
flex: 1; flex: 1;
position: relative; position: relative;
padding: 0 2px; padding: 0 2px;
display: grid;
> *{
grid-area: 1 / 1 / 2 / 2;
}
.agora-video-view{ .agora-video-view{
max-width: 100%; max-width: 100%;
min-width: 100%; min-width: 100%;
...@@ -135,10 +139,10 @@ ...@@ -135,10 +139,10 @@
} }
} }
.agora-video-view { .agora-video-view {
min-width: 187px; //min-width: 187px;
min-height: 106px; //min-height: 106px;
max-width: 187px; //max-width: 187px;
max-height: 106px; //max-height: 106px;
border-radius: 2px; border-radius: 2px;
box-sizing: border-box; box-sizing: border-box;
.student-placeholder, .student-placeholder,
...@@ -147,18 +151,21 @@ ...@@ -147,18 +151,21 @@
background-color: #DBE2E5; background-color: #DBE2E5;
justify-content: center; justify-content: center;
box-sizing: border-box; box-sizing: border-box;
background-size: 66px; //background-size: 66px;
min-width: 187px; //min-width: 187px;
min-height: 82px; //min-height: 82px;
max-width: 187px; //max-width: 187px;
max-height: 82px; //max-height: 82px;
width: 100%;
height: 70%;
border-radius: 2px; border-radius: 2px;
box-sizing: border-box; box-sizing: border-box;
position: absolute; position: absolute;
} }
.student-placeholder::before, .student-placeholder::before,
.teacher-placeholder::before { .teacher-placeholder::before {
background-size: 63px; //background-size: 63px;
background-size: calc( 40% );
} }
} }
} }
......
...@@ -42,6 +42,7 @@ function VideoShowList() { ...@@ -42,6 +42,7 @@ function VideoShowList() {
<div className="on-show"> <div className="on-show">
{teacher ? {teacher ?
<div className="camera"> <div className="camera">
<svg viewBox="0 0 7 5"></svg>
<VideoPlayer <VideoPlayer
role="teacher" role="teacher"
domId={`dom-${teacher.streamID}`} domId={`dom-${teacher.streamID}`}
...@@ -57,6 +58,7 @@ function VideoShowList() { ...@@ -57,6 +58,7 @@ function VideoShowList() {
</div> </div>
: :
<div className="camera"> <div className="camera">
<svg viewBox="0 0 7 5"></svg>
<VideoPlayer role="teacher" account={'teacher'} video audio streamID={0} /> <VideoPlayer role="teacher" account={'teacher'} video audio streamID={0} />
</div> </div>
} }
...@@ -68,6 +70,7 @@ function VideoShowList() { ...@@ -68,6 +70,7 @@ function VideoShowList() {
const student = students && students.slice(0,STAGE_NUM)[i]; const student = students && students.slice(0,STAGE_NUM)[i];
return <div className="camera" key={`stage_video${i}`}> return <div className="camera" key={`stage_video${i}`}>
<svg viewBox="0 0 7 5"></svg>
{student ? <VideoPlayer {student ? <VideoPlayer
role="student" role="student"
domId={`dom-${student.streamID}`} domId={`dom-${student.streamID}`}
......
import React, { useEffect, useRef } from 'react'; import React, { useEffect, useRef } from 'react';
import { GlobalState, globalStore} from '../stores/global'; import {GlobalState, globalStore} from '../stores/global';
import { RoomState, roomStore} from '../stores/room'; import { RoomState, roomStore, windowMonitor} from '../stores/room';
import { WhiteboardState, whiteboard } from '../stores/whiteboard'; import { WhiteboardState, whiteboard } from '../stores/whiteboard';
import { useHistory, useLocation } from 'react-router-dom'; import { useHistory, useLocation } from 'react-router-dom';
import { resolveMessage, resolvePeerMessage, resolveChannelAttrs, jsonParse } from '../utils/helper'; import { resolveMessage, resolvePeerMessage, resolveChannelAttrs, jsonParse } from '../utils/helper';
import GlobalStorage from '../utils/custom-storage'; import GlobalStorage from '../utils/custom-storage';
import {endPoint} from "../services/agora-end-points"; import {endPoint} from "../services/agora-end-points";
import {Map as immuMap} from "immutable";
export type IRootProvider = { export type IRootProvider = {
globalState: GlobalState globalState: GlobalState
...@@ -56,6 +57,8 @@ export const useWhiteboardState = () => { ...@@ -56,6 +57,8 @@ export const useWhiteboardState = () => {
return useStore().whiteboardState; return useStore().whiteboardState;
} }
export const RootProvider: React.FC<any> = ({children}) => { export const RootProvider: React.FC<any> = ({children}) => {
const globalState = useObserver<GlobalState>(globalStore); const globalState = useObserver<GlobalState>(globalStore);
const roomState = useObserver<RoomState>(roomStore); const roomState = useObserver<RoomState>(roomStore);
...@@ -102,6 +105,7 @@ export const RootProvider: React.FC<any> = ({children}) => { ...@@ -102,6 +105,7 @@ export const RootProvider: React.FC<any> = ({children}) => {
console.log('MessageFromPeer', text); console.log('MessageFromPeer', text);
const body = resolvePeerMessage(text); const body = resolvePeerMessage(text);
resolveMessage(peerId, body); resolveMessage(peerId, body);
body.cmd = +body.cmd
roomStore.handlePeerMessage(body.cmd, peerId) roomStore.handlePeerMessage(body.cmd, peerId)
.then(() => { .then(() => {
}).catch(console.warn); }).catch(console.warn);
...@@ -164,18 +168,23 @@ export const RootProvider: React.FC<any> = ({children}) => { ...@@ -164,18 +168,23 @@ export const RootProvider: React.FC<any> = ({children}) => {
useEffect(() => { useEffect(() => {
// console.log(11223344, location.pathname)
if (location.pathname === '/') { if (location.pathname === '/') {
// alert('clear1') // alert('clear1')
// GlobalStorage.clear('agora_room'); // GlobalStorage.clear('agora_room');
windowMonitor.removeUnloadEvent();
return; return;
} }
windowMonitor.addUnloadEvent();
const room = value.roomState; const room = value.roomState;
GlobalStorage.save('agora_room', { GlobalStorage.save('agora_room', {
me: room.me, me: room.me,
course: room.course, course: room.course,
mediaDevice: room.mediaDevice, mediaDevice: room.mediaDevice,
cwLink: endPoint.userToken, cwLink: endPoint.userToken,
studentsOrder: room.studentsOrder studentsOrder: room.studentsOrder,
userUsage: room.userUsage,
handsUpStudents: room.handsUpStudents
}); });
// WARN: DEBUG ONLY MUST REMOVED IN PRODUCTION // WARN: DEBUG ONLY MUST REMOVED IN PRODUCTION
//@ts-ignore //@ts-ignore
......
...@@ -23,7 +23,6 @@ export default function useStream () { ...@@ -23,7 +23,6 @@ export default function useStream () {
if (!course.teacherId || !me.uid) return; if (!course.teacherId || !me.uid) return;
const teacherInfo = roomStore.state.users.get(''+course.teacherId); const teacherInfo = roomStore.state.users.get(''+course.teacherId);
if (!teacherInfo) return; if (!teacherInfo) return;
if (me.uid === course.teacherId) { if (me.uid === course.teacherId) {
return { return {
...roomState.rtc.localStream, ...roomState.rtc.localStream,
...@@ -186,8 +185,8 @@ export default function useStream () { ...@@ -186,8 +185,8 @@ export default function useStream () {
} }
orderIdx++ orderIdx++
} }
console.log(222222, userAttrs.toArray()); // console.log(222222, userAttrs.toArray());
console.log(333333, sids); // console.log(333333, sids);
...@@ -493,6 +492,10 @@ export default function useStream () { ...@@ -493,6 +492,10 @@ export default function useStream () {
// } // }
return; return;
} }
if (type === 'fixUserStream') {
await roomStore.unPublishMeStream();
await roomStore.publishMeStream();
}
} }
} }
return value; return value;
......
...@@ -33,7 +33,7 @@ export default function BigClass() { ...@@ -33,7 +33,7 @@ export default function BigClass() {
const rtmLock = useRef<boolean>(false); const rtmLock = useRef<boolean>(false);
const lock = useRef<boolean>(false); const lock = useRef<boolean>(false);
useEffect(() => { useEffect(() => {
rtmLock.current = false; rtmLock.current = false;
return () => { return () => {
...@@ -49,7 +49,9 @@ export default function BigClass() { ...@@ -49,7 +49,9 @@ export default function BigClass() {
if (roomStore.state.course.teacherId) { if (roomStore.state.course.teacherId) {
rtmLock.current = true; rtmLock.current = true;
roomStore.rtmClient.sendPeerMessage(roomStore.state.course.teacherId, roomStore.rtmClient.sendPeerMessage(roomStore.state.course.teacherId,
{cmd: RoomMessage.applyCoVideo}) // {cmd: RoomMessage.applyCoVideo}
{cmd: RoomMessage.handsUp}
)
.then((result: any) => { .then((result: any) => {
console.log("peerMessage result ", result); console.log("peerMessage result ", result);
}) })
...@@ -59,7 +61,7 @@ export default function BigClass() { ...@@ -59,7 +61,7 @@ export default function BigClass() {
}) })
} }
} }
if (type === 'hands_up_end') { if (type === 'hands_up_end') {
if (roomStore.state.course.teacherId) { if (roomStore.state.course.teacherId) {
rtmLock.current = true; rtmLock.current = true;
...@@ -157,7 +159,7 @@ export default function BigClass() { ...@@ -157,7 +159,7 @@ export default function BigClass() {
handleClick={handleClick} handleClick={handleClick}
> >
<div className="video-container"> <div className="video-container">
{currentHost ? {currentHost ?
<VideoPlayer <VideoPlayer
role="teacher" role="teacher"
streamID={currentHost.streamID} streamID={currentHost.streamID}
...@@ -212,4 +214,4 @@ export default function BigClass() { ...@@ -212,4 +214,4 @@ export default function BigClass() {
</div> </div>
</div> </div>
) )
} }
\ No newline at end of file
...@@ -24,6 +24,7 @@ export function RoomPage({ children }: any) { ...@@ -24,6 +24,7 @@ export function RoomPage({ children }: any) {
const lock = useRef<boolean>(false); const lock = useRef<boolean>(false);
useEffect(() => { useEffect(() => {
const me = roomStore.state.me; const me = roomStore.state.me;
...@@ -83,6 +84,68 @@ export function RoomPage({ children }: any) { ...@@ -83,6 +84,68 @@ export function RoomPage({ children }: any) {
}); });
}, []); }, []);
/*
const loginFn = () => {
const me = roomStore.state.me;
const rid = roomStore.state.course.rid;
const roomType = roomStore.state.course.roomType;
const roomName = roomStore.state.course.roomName;
if (!rid || !me.uid) {
history.push('/');
}
const uid = me.uid;
const payload = {
uid,
rid,
role: me.role,
roomName,
roomType,
video: me.video,
audio: me.audio,
chat: me.chat,
account: me.account,
token: '',
boardId: me.boardId,
linkId: me.linkId,
sharedId: me.sharedId,
lockBoard: me.lockBoard,
grantBoard: me.grantBoard,
}
lock.current = true;
if (roomStore.state.rtm.joined) return;
globalStore.showLoading();
roomStore.loginAndJoin(payload, true).then(() => {
roomStore.updateMe(payload).then(() => {
lock.current && roomStore.updateSessionInfo(payload);
}).catch((err: any) => {
globalStore.showToast({
type: 'rtmClient',
message: 'login failure'
});
history.push('/');
console.warn(err)
}).finally(() => {
globalStore.stopLoading();
lock.current = false;
})
}).catch((err: any) => {
globalStore.showToast({
type: 'rtmClient',
message: 'login failure'
});
history.push('/');
console.warn(err)
})
.finally(() => {
lock.current = false;
});
}
*/
const roomType = roomTypes[roomStore.state.course.roomType]; const roomType = roomTypes[roomStore.state.course.roomType];
const location = useLocation(); const location = useLocation();
...@@ -160,18 +223,21 @@ export function RoomPage({ children }: any) { ...@@ -160,18 +223,21 @@ export function RoomPage({ children }: any) {
useEffect( () => { useEffect( () => {
const webClient = roomStore.rtcClient as AgoraWebClient; const webClient = roomStore.rtcClient as AgoraWebClient;
console.log('rtcJoined', rtcJoined, rtc.current);
if (!rtcJoined) { if (!rtcJoined) {
// return;
webClient.unpublishLocalStream() webClient.unpublishLocalStream()
} }
if (!rtcJoined || rtc.current) return; if (!rtcJoined || rtc.current) return;
if (platform === 'web') { if (platform === 'web') {
roomStore.rtmClient.getChannelAttributeBy(roomStore.state.course.rid).then((channelMeta: any) => { const fn = () => {
console.log('check user publish stream, channelMeta', channelMeta); // console.log('check user publish stream, channelMeta', channelMeta);
console.log('check user publish stream, user orders', roomStore.state.studentsOrder); // console.log('check user publish stream, user orders', roomStore.state.studentsOrder);
console.log('check user publish stream, user info', roomStore.state.me); // console.log('check user publish stream, user info', roomStore.state.me);
const studentsOrder = channelMeta.studentsOrder || roomStore.state.studentsOrder; // const studentsOrder = channelMeta.studentsOrder || roomStore.state.studentsOrder;
const studentsOrder = [...roomStore.state.studentsOrder];
// const webClient = roomStore.rtcClient as AgoraWebClient; // const webClient = roomStore.rtcClient as AgoraWebClient;
const uid = +roomStore.state.me.uid as number; const uid = +roomStore.state.me.uid as number;
...@@ -202,7 +268,28 @@ export function RoomPage({ children }: any) { ...@@ -202,7 +268,28 @@ export function RoomPage({ children }: any) {
publishLock.current = false; publishLock.current = false;
}) })
} }
}); }
/*
roomStore.rtmClient.getChannelAttributeBy(roomStore.state.course.rid).then((channelMeta: any) => {
}).catch(err => {
console.error(err)
globalStore.showToast({
type: 'rtmClient',
message: err.message
});
history.push('/');
});*/
try{
fn()
} catch (err) {
console.error(err)
globalStore.showToast({
type: 'rtmClient',
message: err.message
});
history.push('/');
}
} }
...@@ -232,7 +319,29 @@ export function RoomPage({ children }: any) { ...@@ -232,7 +319,29 @@ export function RoomPage({ children }: any) {
return; return;
} }
console.log("[agora-rtc] add event listener"); console.log("[agora-rtc] add event listener");
/*
webClient.rtc.on('stream-reconnect-start', (evt: any) => {
console.log('[agora-web] stream-reconnect-start', evt);
});
webClient.rtc.on('connection-state-change', (evt: any) => {
console.log('[agora-web] connection-state-change', evt);
});
webClient.rtc.on('reconnect', (evt: any) => {
console.log('[agora-web] reconnect', evt);
});
webClient.rtc.on('connected', (evt: any) => {
console.log('[agora-web] connected', evt);
});
webClient.rtc.on('stream-fallback', (evt: any) => {
console.log('[agora-web] stream-fallback', evt);
});
webClient.rtc.on('stream-updated', (evt: any) => {
console.log('[agora-web] stream-updated', evt);
});
webClient.rtc.on('exception', (evt: any) => {
console.log('[agora-web] exception', evt);
});
webClient.rtc.on('onTokenPrivilegeWillExpire', (evt: any) => { webClient.rtc.on('onTokenPrivilegeWillExpire', (evt: any) => {
// you need obtain the `newToken` token from server side // you need obtain the `newToken` token from server side
const newToken = ''; const newToken = '';
...@@ -253,10 +362,11 @@ export function RoomPage({ children }: any) { ...@@ -253,10 +362,11 @@ export function RoomPage({ children }: any) {
roomStore.addLocalStream(_stream); roomStore.addLocalStream(_stream);
}); });
webClient.rtc.on('stream-subscribed', ({ stream }: any) => { webClient.rtc.on('stream-subscribed', ({ stream }: any) => {
console.log('stream', 2, 'stream-subscribed')
const streamID = stream.getId(); const streamID = stream.getId();
console.log('stream', 2, 'stream-subscribed', streamID)
// when streamID is not share_id use switch high or low stream in dual stream mode // when streamID is not share_id use switch high or low stream in dual stream mode
if (location.pathname.match(/small-class/) && streamID !== SHARE_ID) { if (/*location.pathname.match(/small-class/) && */streamID !== SHARE_ID) {
if (roomStore.state.course.teacherId if (roomStore.state.course.teacherId
&& roomStore.state.course.teacherId === `${streamID}`) { && roomStore.state.course.teacherId === `${streamID}`) {
webClient.setRemoteVideoStreamType(stream, 0); webClient.setRemoteVideoStreamType(stream, 0);
...@@ -267,8 +377,8 @@ export function RoomPage({ children }: any) { ...@@ -267,8 +377,8 @@ export function RoomPage({ children }: any) {
console.log("[agora-web] dual stream set low for student"); console.log("[agora-web] dual stream set low for student");
} }
} }
console.log('stream', 3, 'addRemoteStream to play') console.log('stream step:', 3,'uid', streamID, 'addRemoteStream to play')
const _stream = new AgoraStream(stream, stream.getId(), false); const _stream = new AgoraStream(stream, streamID, false);
console.log("[agora-web] subscribe remote stream, id: ", stream.getId()); console.log("[agora-web] subscribe remote stream, id: ", stream.getId());
roomStore.addRemoteStream(_stream); roomStore.addRemoteStream(_stream);
}); });
...@@ -282,7 +392,7 @@ export function RoomPage({ children }: any) { ...@@ -282,7 +392,7 @@ export function RoomPage({ children }: any) {
const id = stream.getId(); const id = stream.getId();
if (id === roomStore.applyUid) { if (id === roomStore.applyUid) {
globalStore.removeNotice(); globalStore.removeNotice();
me.role === 'teacher' && roomStore.state.me.role === 'teacher' &&
roomStore.updateCourseLinkUid(0).then(() => { roomStore.updateCourseLinkUid(0).then(() => {
console.log("update teacher link_uid to 0"); console.log("update teacher link_uid to 0");
}).catch(console.warn); }).catch(console.warn);
...@@ -309,13 +419,13 @@ export function RoomPage({ children }: any) { ...@@ -309,13 +419,13 @@ export function RoomPage({ children }: any) {
const msg = attr === 0 ? 'resume to a&v mode' : 'fallback to audio mode'; const msg = attr === 0 ? 'resume to a&v mode' : 'fallback to audio mode';
console.info(`[agora-web] stream: ${uid} fallback: ${msg}`); console.info(`[agora-web] stream: ${uid} fallback: ${msg}`);
}) })
*/
rtc.current = true; rtc.current = true;
// debugger // debugger
// WARN: IF YOU ENABLED APP CERTIFICATE, PLEASE SIGN YOUR TOKEN IN YOUR SERVER SIDE AND OBTAIN IT FROM YOUR OWN TRUSTED SERVER API // WARN: IF YOU ENABLED APP CERTIFICATE, PLEASE SIGN YOUR TOKEN IN YOUR SERVER SIDE AND OBTAIN IT FROM YOUR OWN TRUSTED SERVER API
console.info(1.1, 'rtc join') console.info(1.1, 'rtc join')
// if (roomState.me.role == 'teacher') { // if (roomState.me.role == 'teacher' || roomState.studentsOrder.includes(+roomState.me.uid)) {
console.info( 'i m teacher should rtc join') // console.info( 'i m teacher should rtc join')
webClient webClient
.joinChannel({ .joinChannel({
uid: +roomState.me.uid, uid: +roomState.me.uid,
...@@ -323,8 +433,12 @@ export function RoomPage({ children }: any) { ...@@ -323,8 +433,12 @@ export function RoomPage({ children }: any) {
token: '', token: '',
dual: true dual: true
}).then(() => { }).then(() => {
console.info(2, 'rtc join ok')
roomStore.publishMeStream(); console.info(2, 'rtc join ok', roomState.me.uid, [...studentsOrder], [...roomStore.state.studentsOrder], [...roomState.studentsOrder])
if (roomState.me.role == 'teacher' || roomStore.state.studentsOrder.includes(+roomState.me.uid)) {
roomStore.publishMeStream();
}
// // 如果当前用户是教师,直接发布, // // 如果当前用户是教师,直接发布,
// if(roomStore.state.me.role == 'teacher') { // if(roomStore.state.me.role == 'teacher') {
// roomStore.publishMeStream(); // roomStore.publishMeStream();
...@@ -425,8 +539,8 @@ export function RoomPage({ children }: any) { ...@@ -425,8 +539,8 @@ export function RoomPage({ children }: any) {
}, [roomState.me.uid, roomState.course.rid]); }, [roomState.me.uid, roomState.course.rid]);
useEffect(() => { useEffect(() => {
console.log('studentsOrder changed');
const webClient = roomStore.rtcClient as AgoraWebClient; const webClient = roomStore.rtcClient as AgoraWebClient;
console.log('studentsOrder changed', webClient.joined, studentsOrder);
if (!webClient.joined) { if (!webClient.joined) {
return; return;
} }
...@@ -440,10 +554,6 @@ export function RoomPage({ children }: any) { ...@@ -440,10 +554,6 @@ export function RoomPage({ children }: any) {
} }
console.log(1.2 ,studentsOrder, 'studentsOrder changed publish stream'); console.log(1.2 ,studentsOrder, 'studentsOrder changed publish stream');
} }
}, [studentsOrder]); }, [studentsOrder]);
return ( return (
......
...@@ -10,7 +10,42 @@ ...@@ -10,7 +10,42 @@
min-width: 280px; min-width: 280px;
} }
} }
.hands_up{
position: absolute;
top: 0;
right: 0;
cursor: pointer;
display: flex;
height: 30px;
width: 30px;
margin: 2px;
border-radius: 4px;
box-sizing: border-box;
pointer-events: auto;
margin-top: 10px;
padding: 4px;
display: flex;
box-sizing: border-box;
align-items: center;
height: 42px;
width: 42px;
background: #fff;
box-shadow: 0 2px 4px 0 rgba(61,30,30,.1);
border-radius: 6px;
border: 1px solid #dbe2e5;
}
.hands_up:after{
width: 100%;
height: 100%;
background-position: 50%;
background-repeat: no-repeat;
background-size: contain;
content: " ";
background-image: url("data:image/png;base64,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");
}
.hands_up.disabled{
background: #dbe2e5;
}
.video-marquee-container { .video-marquee-container {
display: flex; display: flex;
min-width: 990px; min-width: 990px;
...@@ -119,4 +154,4 @@ ...@@ -119,4 +154,4 @@
} }
} }
} }
} }
\ No newline at end of file
...@@ -12,9 +12,12 @@ import {TOOL_TYPE} from "../../utils/types"; ...@@ -12,9 +12,12 @@ import {TOOL_TYPE} from "../../utils/types";
// import AgoraWebClient from "../../utils/agora-rtc-client"; // import AgoraWebClient from "../../utils/agora-rtc-client";
// import {AgoraElectronClient} from "../../utils/agora-electron-client"; // import {AgoraElectronClient} from "../../utils/agora-electron-client";
import {useRoomState} from "../../containers/root-container"; import {useRoomState} from "../../containers/root-container";
import {RoomMessage} from "../../utils/agora-rtm-client";
import Icon from "../../components/icon";
// import RoomToolsBar from "../../components/room-tools-bar"; // import RoomToolsBar from "../../components/room-tools-bar";
export default function SmallClass() { export default function SmallClass() {
const [tool, setTool] = useState(true); const [tool, setTool] = useState(true);
const roomState = useRoomState(); const roomState = useRoomState();
const changeTool = async () => { const changeTool = async () => {
...@@ -31,6 +34,56 @@ export default function SmallClass() { ...@@ -31,6 +34,56 @@ export default function SmallClass() {
} }
}, [roomState]); }, [roomState]);
const rtmLock = useRef<boolean>(false);
const handleClick = (evt: any) => {
if (rtmLock.current) return;
console.log('handleClick hands_up', evt.currentTarget);
const elem = evt.currentTarget;
if (elem.classList.contains('disabled')) {
return;
}
// if (type === 'hands_up') {
if (roomStore.state.course.teacherId) {
elem.classList.add('disabled');
setTimeout(() => {
console.log('remove disabled class');
elem.classList.remove('disabled');
}, 10 * 1000)
rtmLock.current = true;
roomStore.rtmClient.sendPeerMessage(roomStore.state.course.teacherId,
// {cmd: RoomMessage.applyCoVideo}
{cmd: RoomMessage.handsUp}
)
.then((result: any) => {
console.log("peerMessage result ", result);
if (!result) {
evt.currentTarget.classList.remove('disabled');
}
})
.catch(console.warn)
.finally(() => {
rtmLock.current = false;
})
}
// }
/*
if (type === 'hands_up_end') {
if (roomStore.state.course.teacherId) {
rtmLock.current = true;
roomStore.rtmClient.sendPeerMessage(roomStore.state.course.teacherId,
{cmd: RoomMessage.cancelCoVideo})
.then((result: any) => {
console.log("peerMessage result ", result);
})
.catch(console.warn)
.finally(() => {
rtmLock.current = false;
})
}
}
*/
}
useEffect(() => { useEffect(() => {
}, [roomStore.state.course.currentTool]); }, [roomStore.state.course.currentTool]);
...@@ -47,6 +100,15 @@ export default function SmallClass() { ...@@ -47,6 +100,15 @@ export default function SmallClass() {
? <MediaBoard /> ? <MediaBoard />
: <CourseWareFrame></CourseWareFrame>} : <CourseWareFrame></CourseWareFrame>}
{roomStore.state.me.role === 'student' && !roomState.studentsOrder.includes(+roomStore.state.me.uid) ?
<>
<Icon
data='hands_up'
onClick={handleClick}
className={`items hands_up ${false ? 'active' : ''}`}
/>
</>
:null}
{/*{ roomStore.state.me.role == 'teacher' ? <Roomboard currentActive={'media'} /> : null}*/} {/*{ roomStore.state.me.role == 'teacher' ? <Roomboard currentActive={'media'} /> : null}*/}
</div> </div>
......
...@@ -2,18 +2,24 @@ import React, { useState, useEffect, useRef } from 'react'; ...@@ -2,18 +2,24 @@ import React, { useState, useEffect, useRef } from 'react';
import { Theme, FormControl } from '@material-ui/core'; import { Theme, FormControl } from '@material-ui/core';
import {makeStyles} from '@material-ui/core/styles'; import {makeStyles} from '@material-ui/core/styles';
import Button from '../components/custom-button'; import Button from '../components/custom-button';
import RoleRadio from '../components/role-radio'; // import RoleRadio from '../components/role-radio';
import Icon from '../components/icon'; import Icon from '../components/icon';
import FormInput from '../components/form-input'; import FormInput from '../components/form-input';
import FormSelect from '../components/form-select'; // import FormSelect, {FormSelectItems} from '../components/form-select';
import { isElectron } from '../utils/platform'; import { isElectron } from '../utils/platform';
import { usePlatform } from '../containers/platform-container'; import { usePlatform } from '../containers/platform-container';
import {useHistory} from 'react-router-dom'; import {useHistory} from 'react-router-dom';
import { roomStore } from '../stores/room'; import { roomStore } from '../stores/room';
import { genUid } from '../utils/helper'; // import { genUid } from '../utils/helper';
import MD5 from 'js-md5'; // import MD5 from 'js-md5';
import { globalStore } from '../stores/global'; import { globalStore } from '../stores/global';
import { endPoint } from '../services/agora-end-points'; import { endPoint } from '../services/agora-end-points';
import Select from "@material-ui/core/Select";
import MenuItem from "@material-ui/core/MenuItem";
import InputLabel from "@material-ui/core/InputLabel";
import {useLocation} from "react-router-dom";
import { Base64 } from 'js-base64';
export const roomTypes = [ export const roomTypes = [
{value: 0, text: 'One-to-One', path: 'one-to-one'}, {value: 0, text: 'One-to-One', path: 'one-to-one'},
...@@ -25,6 +31,9 @@ const useStyles = makeStyles ((theme: Theme) => ({ ...@@ -25,6 +31,9 @@ const useStyles = makeStyles ((theme: Theme) => ({
formControl: { formControl: {
minWidth: '240px', minWidth: '240px',
maxWidth: '240px', maxWidth: '240px',
},
hide:{
display: 'none'
} }
})); }));
...@@ -34,6 +43,7 @@ type SessionInfo = { ...@@ -34,6 +43,7 @@ type SessionInfo = {
yourName: string yourName: string
yourPass: string yourPass: string
role: string role: string
classId: string
} }
const defaultState: SessionInfo = { const defaultState: SessionInfo = {
...@@ -41,11 +51,12 @@ const defaultState: SessionInfo = { ...@@ -41,11 +51,12 @@ const defaultState: SessionInfo = {
roomType: 1, roomType: 1,
role: '', role: '',
yourName: '', yourName: '',
yourPass: '' yourPass: '',
classId: ''
} }
function HomePage() { function HomePage() {
const classes = useStyles(); const style = useStyles();
const history = useHistory(); const history = useHistory();
...@@ -68,7 +79,134 @@ function HomePage() { ...@@ -68,7 +79,134 @@ function HomePage() {
const [session, setSessionInfo] = useState<SessionInfo>(defaultState); const [session, setSessionInfo] = useState<SessionInfo>(defaultState);
const [required, setRequired] = useState<any>({} as any); const [required, setRequired] = useState<any>({} as any);
const [classes, setClasses] = useState<any[]>([]);
const [loading, setLoading] = useState<boolean>(false);
const handleClassChange = (event: any) => {
setSessionInfo({
...session,
classId: event.target.value
});
// console.log('handleClassChange', event.target.value);
};
const fetchClasses = async (val: any) => {
console.log('fetchClasses', val, session.yourName);
if (!session.yourName) {
setSessionInfo({
...session,
classId: ''
});
setClasses([])
return
}
// setLoading(true);
globalStore.showLoading();
const data = await endPoint.fetchClasses(session.yourName);
console.log(data);
// setLoading(false);
globalStore.stopLoading();
setSessionInfo({
...session,
classId: ''
});
setClasses(data)
}
const doCheckWithToken = (userInfo: any) => {
loginLive(userInfo);
}
const doCheckWithUser = () => {
endPoint.login({username: session.yourName, password: session.yourPass, classid: session.classId}).then((userInfo: any) => {
loginLive(userInfo);
}).catch((err: any) => {
globalStore.showToast({
type: 'rtmClient',
message: err
})
});
}
const loginLive = (userInfo: any) => {
console.log(userInfo);
session.roomName = userInfo["class_id"];// userInfo["class_id"];
// session.yourName = userInfo["nick_name"];
session.role = userInfo["classRole"]==="tea"?"teacher":"student"
session.roomType = 1;
if (!roomTypes[session.roomType]) return;
const path = roomTypes[session.roomType].path
const payload = {
uid: `${userInfo["id"]}`, // userInfo["classRole"]==="tea"?"100":`${session.yourName.substr(-2)}`, // `${userInfo["id"]}`, // genUid(),
rid: `${session.roomName}`, // `${session.roomType}${MD5(session.roomName)}`,
role: session.role,
roomName: session.roomName,
roomType: session.roomType,
video: 0,
audio: 0,
chat: 1,
account: `${userInfo["nick_name"]}`,
token: '',
boardId: '',
linkId: 0,
sharedId: 0,
lockBoard: 0,
}
ref.current = true;
globalStore.showLoading();
roomStore.loginAndJoin(payload).then(() => {
roomStore.updateSessionInfo(payload);
history.push(`/classroom/${path}`);
}).catch((err: any) => {
if (err.reason) {
globalStore.showToast({
type: 'rtmClient',
message: err.reason
})
} else {
globalStore.showToast({
type: 'rtmClient',
message: 'login failure, please checkout ur network'
})
}
console.warn(err);
}).finally(() => {
ref.current = false;
globalStore.stopLoading();
})
}
const location = useLocation();
// console.log(1111111111111, location );
const params = new URLSearchParams(location.search);
let token = params.get('token');
let hasLogin = params.get('login') && params.get('login') == '1' ? true : false;
// console.log('params', token)
// debugger
if (token) {
const tokenParts = token.split('.')
token = tokenParts[1];
token = token.replace(/[\+]/g, '-');
token = token.replace(/[/]/g, '_');
const eqc = token.length % 4;
const ea: any = [];
if ( eqc != 0 ) {
ea.length = 4 - eqc;
token = `${token}${Array.from(ea).fill('=').join('')}`
}
let userInfo = Base64.decode(token);
userInfo = JSON.parse(userInfo)
console.log(userInfo)
// const userInfo = {
// id: `${data.username}`,
// class_id: "test_03__123",
// classRole: `${data.username}`==="1"?"tea":"",
// roomType: 1,
// nick_name: `${data.username}`,
// // data.username: session.yourName,
// // data.password: session.yourPass
// };
doCheckWithToken(userInfo);
}
const handleSubmit = () => { const handleSubmit = () => {
if (!session.yourName) { if (!session.yourName) {
setRequired({...required, yourName: 'missing your name'}); setRequired({...required, yourName: 'missing your name'});
...@@ -82,8 +220,9 @@ function HomePage() { ...@@ -82,8 +220,9 @@ function HomePage() {
/////////////////////////////// ///////////////////////////////
/*
if (window.location.origin.includes('://127.0.0.1') || window.location.origin.includes('://localhost')) { if (window.location.origin.includes('://127.0.0.1') || window.location.origin.includes('://localhost')) {
session.roomName = "test_01__123";// userInfo["class_id"]; session.roomName = "test_03__123";// userInfo["class_id"];
// session.yourName = userInfo["nick_name"]; // session.yourName = userInfo["nick_name"];
session.role = `${session.yourName}`==="1"?"teacher":"student"; session.role = `${session.yourName}`==="1"?"teacher":"student";
session.roomType = 1; session.roomType = 1;
...@@ -129,7 +268,7 @@ function HomePage() { ...@@ -129,7 +268,7 @@ function HomePage() {
}) })
} else { } else {
endPoint.login({username: session.yourName, password: session.yourPass}).then((userInfo: any) => { endPoint.login({username: session.yourName, password: session.yourPass, classid: session.classId}).then((userInfo: any) => {
console.log(userInfo); console.log(userInfo);
session.roomName = userInfo["class_id"];// userInfo["class_id"]; session.roomName = userInfo["class_id"];// userInfo["class_id"];
// session.yourName = userInfo["nick_name"]; // session.yourName = userInfo["nick_name"];
...@@ -186,6 +325,8 @@ function HomePage() { ...@@ -186,6 +325,8 @@ function HomePage() {
} }
*/
doCheckWithUser();
} }
...@@ -202,7 +343,7 @@ function HomePage() { ...@@ -202,7 +343,7 @@ function HomePage() {
</div> </div>
</div> </div>
} }
<div className="custom-card"> <div className={`custom-card`}>
<div className="flex-item cover"> <div className="flex-item cover">
{isElectron ? {isElectron ?
<> <>
...@@ -219,20 +360,43 @@ function HomePage() { ...@@ -219,20 +360,43 @@ function HomePage() {
<div className="position-top card-menu"> <div className="position-top card-menu">
<HomeBtn handleSetting={handleSetting}/> <HomeBtn handleSetting={handleSetting}/>
</div> </div>
<div className="position-content flex-direction-column"> <div className={`position-content flex-direction-column ${hasLogin ? '' : style.hide}`}>
<FormControl className={classes.formControl}> <FormControl className={style.formControl}>
<FormInput Label={"User Name"} value={session.yourName} onChange={ <FormInput Label={"账号"} value={session.yourName} onChange={
(val: string) => { (val: string) => {
setSessionInfo({ setSessionInfo({
...session, ...session,
yourName: val yourName: val
}); });
}} }}
onBlur={fetchClasses}
requiredText={required.yourName} requiredText={required.yourName}
/> />
</FormControl> </FormControl>
<FormControl className={classes.formControl}> <FormControl className={style.formControl}>
<FormInput Label={"Password"} type="password" value={session.yourPass} onChange={
<InputLabel>请选择班级</InputLabel>
<Select
value={session.classId}
onChange={handleClassChange}
>
{!classes.length ?
<MenuItem value="0">
<em>请正确输入账号</em>
</MenuItem>
:
classes.map((item: any, key: number) =>
<MenuItem key={key} value={item.id}>{item.name}</MenuItem>)
}
{/*<MenuItem value={10}>Ten</MenuItem>
<MenuItem value={20}>Twenty</MenuItem>
<MenuItem value={30}>Thirty</MenuItem>*/}
</Select>
</FormControl>
<FormControl className={style.formControl}>
<FormInput Label={"密码"} type="password" value={session.yourPass} onChange={
(val: string) => { (val: string) => {
setSessionInfo({ setSessionInfo({
...session, ...session,
...@@ -242,7 +406,7 @@ function HomePage() { ...@@ -242,7 +406,7 @@ function HomePage() {
requiredText={required.yourPass} requiredText={required.yourPass}
/> />
</FormControl> </FormControl>
<Button name={"Join"} onClick={handleSubmit}/> <Button disables={loading} name={"Join"} onClick={handleSubmit}/>
</div> </div>
</div> </div>
</div> </div>
......
...@@ -42,7 +42,31 @@ export interface RoomParams { ...@@ -42,7 +42,31 @@ export interface RoomParams {
enableAudio: number enableAudio: number
linkUsers: number[] linkUsers: number[]
} }
export function getApiServerHost(online = false) {
let host = `https://ac.iplayabc.com`;
if (window.location.host.includes('s-live.')) {
host = 'https://staging-ac.ireadabc.com';
} else if (window.location.host.includes('127.0.0.1')
|| window.location.host.includes('localhost')) {
if (online) {
host = 'https://staging-ac.ireadabc.com';
} else {
host = 'http://127.0.0.1:1338'
}
}
return host;
}
export function getTeachServerHost() {
let host = `https://teach.ireadabc.com`;
if (window.location.host.includes('s-live.')) {
host = 'https://staging-teach.ireadabc.com';
} else if (window.location.host.includes('127.0.0.1')
|| window.location.host.includes('localhost')) {
host = 'http://127.0.0.1:1338'
}
return host;
}
export class EndPoint { export class EndPoint {
appID: string = ''; appID: string = '';
...@@ -57,9 +81,39 @@ export class EndPoint { ...@@ -57,9 +81,39 @@ export class EndPoint {
let json = await response.json(); let json = await response.json();
return json.data; return json.data;
} }
async fetchClasses(username: string) {
const host = getApiServerHost(true);
let url = `${host}/api/classes?username=${username}`;
let json = await AgoraFetchJson({
url: url,
method: 'GET'
});
if(json.msg==="error"){
throw json.data;
}
console.log('json.data', json.data);
if (json.data && json.data.length) {
return json.data
}
return [];
}
async login(data: any) { async login(data: any) {
if (window.location.origin.includes('://127.0.0.1')
|| window.location.origin.includes('://localhost')) {
return {
id: `${data.username}`,
class_id: "test_03__123",
classRole: (`${data.username}`==="1" || `${data.username}`==="11")?"tea":"",
roomType: 1,
nick_name: `${data.username}`,
// data.username: session.yourName,
// data.password: session.yourPass
}
}
const host = getApiServerHost(true);
let url = `${host}/api/login`;
let json = await AgoraFetchJson({ let json = await AgoraFetchJson({
url: `${ENDPOINT}/api/login`, url: url,
method: 'POST', method: 'POST',
data: data data: data
}); });
...@@ -90,7 +144,8 @@ export class EndPoint { ...@@ -90,7 +144,8 @@ export class EndPoint {
this.userToken = roomStore.state.cwLink; this.userToken = roomStore.state.cwLink;
} }
console.log('getCourseUrl', this.userToken) console.log('getCourseUrl', this.userToken)
return `${ENDPOINT}/airclass_ol?token=${this.userToken}`; const host = getApiServerHost();
return `${host}/airclass_ol?token=${this.userToken}`;
} }
async config() { async config() {
......
...@@ -200,4 +200,6 @@ export class Root { ...@@ -200,4 +200,6 @@ export class Root {
} }
} }
export const globalStore = new Root(); export const globalStore = new Root();
\ No newline at end of file
This diff is collapsed.
...@@ -47,7 +47,7 @@ export const APP_ID = process.env.REACT_APP_AGORA_APP_ID as string; ...@@ -47,7 +47,7 @@ export const APP_ID = process.env.REACT_APP_AGORA_APP_ID as string;
export const APP_TOKEN = process.env.REACT_APP_AGORA_APP_TOKEN as string; export const APP_TOKEN = process.env.REACT_APP_AGORA_APP_TOKEN as string;
export const ENABLE_LOG = process.env.REACT_APP_AGORA_LOG as string === "true"; export const ENABLE_LOG = process.env.REACT_APP_AGORA_LOG as string === "true";
export const SHARE_ID = 9999999999999; export const SHARE_ID = 9999999999999;
const BindEventMap: any = {};
class AgoraRTCClient { class AgoraRTCClient {
private streamID: any; private streamID: any;
...@@ -145,9 +145,15 @@ class AgoraRTCClient { ...@@ -145,9 +145,15 @@ class AgoraRTCClient {
this.unsubscribeClientEvents(); this.unsubscribeClientEvents();
this._bus.removeAllListeners(); this._bus.removeAllListeners();
} }
offAll() {
for (const evtName of Object.keys(BindEventMap)) {
const cb = BindEventMap[evtName];
this._bus.off(evtName, cb);
}
}
// subscribe // subscribe
on(evtName: string, cb: (args: any) => void) { on(evtName: string, cb: (args: any) => void) {
BindEventMap[evtName] = cb;
this._bus.on(evtName, cb); this._bus.on(evtName, cb);
} }
...@@ -418,7 +424,11 @@ export default class AgoraWebClient { ...@@ -418,7 +424,11 @@ export default class AgoraWebClient {
async unpublishLocalStream() { console.log('unpublish LocalStream' , 4); async unpublishLocalStream() { console.log('unpublish LocalStream' , 4);
console.log("[agora-web] invoke unpublishStream"); console.log("[agora-web] invoke unpublishStream");
await this.rtc.unpublish(); try{
await this.rtc.unpublish();
} catch (e) {
}
this.published = false; this.published = false;
} }
......
...@@ -22,6 +22,7 @@ export enum RoomMessage { ...@@ -22,6 +22,7 @@ export enum RoomMessage {
unmuteBoard = 201, unmuteBoard = 201,
stageUp = 301, stageUp = 301,
stageDown = 302, stageDown = 302,
handsUp = 401,
} }
export interface MessageBody { export interface MessageBody {
...@@ -101,6 +102,7 @@ export default class AgoraRTMClient { ...@@ -101,6 +102,7 @@ export default class AgoraRTMClient {
return return
} }
async clearChannelAttributesByKeys(uids: string[]) { async clearChannelAttributesByKeys(uids: string[]) {
if (!this._logged) return
await this._client.deleteChannelAttributesByKeys(this._currentChannelName, uids, {enableNotificationToChannelMembers: true}); await this._client.deleteChannelAttributesByKeys(this._currentChannelName, uids, {enableNotificationToChannelMembers: true});
} }
......
...@@ -3,7 +3,7 @@ export class CustomStorage { ...@@ -3,7 +3,7 @@ export class CustomStorage {
private storage: Storage; private storage: Storage;
constructor() { constructor() {
this.storage = window.localStorage; // window.sessionStorage; this.storage = window.sessionStorage; // window.localStorage; //
} }
read(key: string): any { read(key: string): any {
......
...@@ -171,6 +171,9 @@ export function resolveMessage(peerId: string, { cmd, text }: { cmd: number, tex ...@@ -171,6 +171,9 @@ export function resolveMessage(peerId: string, { cmd, text }: { cmd: number, tex
case RoomMessage.stageUp: case RoomMessage.stageUp:
type = 'stage up' type = 'stage up'
break; break;
case RoomMessage.handsUp:
type = 'hands up'
break;
default: default:
return console.warn(`[RoomMessage] unknown type, from peerId: ${peerId}`); return console.warn(`[RoomMessage] unknown type, from peerId: ${peerId}`);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment