import React, { useState, useEffect, useRef, createContext, useContext } from 'react'; import AliRtcEngine, { AliRtcSubscribeState, AliRtcVideoTrack, AliRtcSdkChannelProfile } from 'aliyun-rtc-sdk'; import { ToastContainer, toast } from 'react-toastify'; // 从 SDK 中提取需要的类型 type ImEngine = InstanceType; type ImGroupManager = AliVCInteraction.AliVCIMGroupManager; type ImMessageManager = AliVCInteraction.AliVCIMMessageManager; type ImLogLevel = AliVCInteraction.ImLogLevel; type ImMessageLevel = AliVCInteraction.ImMessageLevel; interface ImUser { userId: string; userExtension?: string; } interface ImGroupMessage { groupId: string; type: number; data: string; sender?: ImUser; timestamp?: number; } // 课堂上下文类型 type ClassroomContextType = { userId: string; role: 'teacher' | 'student'; isLoggedIn: boolean; isJoinedClass: boolean; messageList: string[]; errorMessage: string; setRole: (role: 'teacher' | 'student') => void; }; const ClassroomContext = createContext(null); // 辅助函数 function hex(buffer: ArrayBuffer): string { const hexCodes = []; const view = new DataView(buffer); for (let i = 0; i < view.byteLength; i += 4) { const value = view.getUint32(i); const stringValue = value.toString(16); const padding = '00000000'; const paddedValue = (padding + stringValue).slice(-padding.length); hexCodes.push(paddedValue); } return hexCodes.join(''); } async function generateToken( appId: string, appKey: string, channelId: string, userId: string, timestamp: number ): Promise { const encoder = new TextEncoder(); const data = encoder.encode(`${appId}${appKey}${channelId}${userId}${timestamp}`); const hash = await crypto.subtle.digest('SHA-256', data); return hex(hash); } function showToast(type: 'info' | 'success' | 'error', message: string): void { switch(type) { case 'info': toast.info(message); break; case 'success': toast.success(message); break; case 'error': toast.error(message); break; } } // 从SDK获取枚举值 const { ImLogLevel, ImMessageLevel } = window.AliVCInteraction; // 配置信息 const IM_APP_ID = '4c2ab5e1b1b0'; const IM_APP_KEY = '314bb5eee5b623549e8a41574ba3ff32'; const IM_APP_SIGN = 'H4sIAAAAAAAE/wCQAG//zguHB+lYCilkv7diSkk4GmcvLuds+InRu9vFOFebMwm/jEgsK5bBT85Z0owObMxG58uXHyPFlPEBEDQm9FswNJ+KmX0VDYkcfdPPWkafA6Hc0B6F+p5De9yJfPEfHzwo/DHMaygbHfLmBgUtmKveq421sJr/gNBz9D04Ewsg39us+ao0NegzLt7xtXvFXXXJAAAA//8BAAD//yoav6aQAAAA'; const RTC_APP_ID = 'a5842c2a-d94a-43be-81de-1fdb712476e1'; const RTC_APP_KEY = 'b71d65f4f84c450f6f058f4ad507bd42'; export const ClassroomPage = () => { // 状态管理 const [userId, setUserId] = useState(''); const [role, setRole] = useState<'teacher' | 'student'>('student'); const [classId, setClassId] = useState(''); const [isLoggedIn, setIsLoggedIn] = useState(false); const [isJoinedClass, setIsJoinedClass] = useState(false); const [msgText, setMsgText] = useState(''); const [messageList, setMessageList] = useState([]); const [errorMessage, setErrorMessage] = useState(''); // SDK实例 const imEngine = useRef(null); const imGroupManager = useRef(null); const imMessageManager = useRef(null); const aliRtcEngine = useRef(null); const remoteVideoElMap = useRef>({}); const remoteVideoContainer = useRef(null); // 消息管理模块 const showMessage = (text: string): void => { setMessageList([...messageList, text]); }; const listenImEvents = (): void => { if (!imEngine.current) return; imEngine.current.on('connectsuccess', () => { showMessage('IM连接成功'); }); imEngine.current.on('disconnect', (code: number) => { showMessage(`IM断开连接: ${code}`); }); }; const listenGroupEvents = (): void => { if (!imGroupManager.current) return; imGroupManager.current.on('memberchange', (groupId: string, memberCount: number, joinUsers: ImUser[], leaveUsers: ImUser[]) => { showMessage(`成员变更: 加入${joinUsers.length}人, 离开${leaveUsers.length}人`); }); }; const listenMessageEvents = (): void => { if (!imMessageManager.current) return; imMessageManager.current.on('recvgroupmessage', (msg: AliVCInteraction.ImMessage, groupId: string) => { showMessage(`收到消息: ${msg.data}`); }); }; // 音视频模块 const removeRemoteVideo = (userId: string, type: 'camera' | 'screen' = 'camera') => { const vid = `${type}_${userId}`; const el = remoteVideoElMap.current[vid]; if (el) { aliRtcEngine.current!.setRemoteViewConfig(null, userId, type === 'camera' ? AliRtcVideoTrack.AliRtcVideoTrackCamera : AliRtcVideoTrack.AliRtcVideoTrackScreen); el.pause(); remoteVideoContainer.current?.removeChild(el); delete remoteVideoElMap.current[vid]; } }; const listenRtcEvents = () => { if (!aliRtcEngine.current) return; aliRtcEngine.current.on('remoteUserOnLineNotify', (userId: string) => { showMessage(`用户 ${userId} 加入课堂`); }); aliRtcEngine.current.on('remoteUserOffLineNotify', (userId: string) => { showMessage(`用户 ${userId} 离开课堂`); removeRemoteVideo(userId, 'camera'); removeRemoteVideo(userId, 'screen'); }); }; // 统一登录逻辑 const login = async (userId: string): Promise => { try { // 初始化IM const { ImEngine: ImEngineClass } = window.AliVCInteraction; imEngine.current = ImEngineClass.createEngine(); await imEngine.current.init({ deviceId: 'xxxx', appId: IM_APP_ID, appSign: IM_APP_SIGN, logLevel: ImLogLevel.ERROR, }); // 初始化RTC aliRtcEngine.current = AliRtcEngine.getInstance(); AliRtcEngine.setLogLevel(0); // 设置事件监听 listenImEvents(); listenRtcEvents(); setIsLoggedIn(true); setErrorMessage(''); showToast('success', '登录成功'); } catch (err: any) { setErrorMessage(`登录失败: ${err.message}`); showToast('error', '登录失败'); } }; // 加入课堂 const joinClass = async (classId: string): Promise => { if (!imEngine.current || !aliRtcEngine.current) return; try { // 加入IM群组 const gm = imEngine.current.getGroupManager(); const mm = imEngine.current.getMessageManager(); imGroupManager.current = gm || null; imMessageManager.current = mm || null; await gm!.joinGroup(classId); listenGroupEvents(); listenMessageEvents(); // 加入RTC频道 const timestamp = Math.floor(Date.now() / 1000) + 3600 * 3; const token = await generateToken(RTC_APP_ID, RTC_APP_KEY, classId, userId, timestamp); aliRtcEngine.current.setChannelProfile(AliRtcSdkChannelProfile.AliRtcSdkCommunication); await aliRtcEngine.current.joinChannel( { channelId: classId, userId, appId: RTC_APP_ID, token, timestamp, }, userId ); // 设置本地预览 aliRtcEngine.current.setLocalViewConfig('localPreviewer', AliRtcVideoTrack.AliRtcVideoTrackCamera); setIsJoinedClass(true); setErrorMessage(''); showToast('success', '加入课堂成功'); } catch (err: any) { setErrorMessage(`加入课堂失败: ${err.message}`); showToast('error', '加入课堂失败'); } }; // 离开课堂 const leaveClass = async (): Promise => { if (imGroupManager.current && classId) { await imGroupManager.current.leaveGroup(classId); } if (aliRtcEngine.current) { await aliRtcEngine.current.leaveChannel(); } setIsJoinedClass(false); showToast('info', '已离开课堂'); }; // 发送消息 const sendMessage = async (): Promise => { if (!imMessageManager.current || !classId) return; try { await imMessageManager.current.sendGroupMessage({ groupId: classId, data: msgText, type: 88888, level: ImMessageLevel.NORMAL, }); setMsgText(''); setErrorMessage(''); } catch (err: any) { setErrorMessage(`消息发送失败: ${err.message}`); } }; // 清理资源 useEffect(() => { return () => { if (imGroupManager.current) { imGroupManager.current.removeAllListeners(); } if (imMessageManager.current) { imMessageManager.current.removeAllListeners(); } if (imEngine.current) { imEngine.current.removeAllListeners(); } if (aliRtcEngine.current) { aliRtcEngine.current.destroy(); } }; }, []); return (

互动课堂

setUserId(e.target.value)} />
setClassId(e.target.value)} />
setMsgText(e.target.value)} />

消息记录

{messageList.map((msg, i) => (
{msg}
))}

视频区域

{errorMessage && (
{errorMessage}
)}
); };