|
|
@@ -22,6 +22,13 @@ interface ImGroupMessage {
|
|
|
timestamp?: number;
|
|
|
}
|
|
|
|
|
|
+// 课堂状态枚举
|
|
|
+enum ClassStatus {
|
|
|
+ NOT_STARTED = 'not_started',
|
|
|
+ IN_PROGRESS = 'in_progress',
|
|
|
+ ENDED = 'ended'
|
|
|
+}
|
|
|
+
|
|
|
// 课堂上下文类型
|
|
|
type ClassroomContextType = {
|
|
|
userId: string;
|
|
|
@@ -30,7 +37,11 @@ type ClassroomContextType = {
|
|
|
isJoinedClass: boolean;
|
|
|
messageList: string[];
|
|
|
errorMessage: string;
|
|
|
+ classStatus: ClassStatus;
|
|
|
setRole: (role: 'teacher' | 'student') => void;
|
|
|
+ startClass: () => Promise<void>;
|
|
|
+ endClass: () => Promise<void>;
|
|
|
+ toggleMuteMember: (userId: string, mute: boolean) => Promise<void>;
|
|
|
};
|
|
|
|
|
|
const ClassroomContext = createContext<ClassroomContextType | null>(null);
|
|
|
@@ -96,6 +107,7 @@ export const ClassroomPage = () => {
|
|
|
const [msgText, setMsgText] = useState<string>('');
|
|
|
const [messageList, setMessageList] = useState<string[]>([]);
|
|
|
const [errorMessage, setErrorMessage] = useState<string>('');
|
|
|
+ const [classStatus, setClassStatus] = useState<ClassStatus>(ClassStatus.NOT_STARTED);
|
|
|
|
|
|
// SDK实例
|
|
|
const imEngine = useRef<ImEngine | null>(null);
|
|
|
@@ -134,7 +146,31 @@ export const ClassroomPage = () => {
|
|
|
if (!imMessageManager.current) return;
|
|
|
|
|
|
imMessageManager.current.on('recvgroupmessage', (msg: AliVCInteraction.ImMessage, groupId: string) => {
|
|
|
- showMessage(`收到消息: ${msg.data}`);
|
|
|
+ if (msg.type === 88889) { // 课堂状态消息
|
|
|
+ try {
|
|
|
+ const data = JSON.parse(msg.data);
|
|
|
+ if (data.action === 'start_class') {
|
|
|
+ setClassStatus(ClassStatus.IN_PROGRESS);
|
|
|
+ showMessage('老师已开始上课');
|
|
|
+ } else if (data.action === 'end_class') {
|
|
|
+ setClassStatus(ClassStatus.ENDED);
|
|
|
+ showMessage('老师已结束上课');
|
|
|
+ }
|
|
|
+ } catch (err) {
|
|
|
+ console.error('解析课堂状态消息失败', err);
|
|
|
+ }
|
|
|
+ } else if (msg.type === 88890) { // 静音指令
|
|
|
+ try {
|
|
|
+ const data = JSON.parse(msg.data);
|
|
|
+ if (data.action === 'toggle_mute' && data.userId === userId) {
|
|
|
+ showMessage(data.mute ? '你已被老师静音' : '老师已取消你的静音');
|
|
|
+ }
|
|
|
+ } catch (err) {
|
|
|
+ console.error('解析静音指令失败', err);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ showMessage(`收到消息: ${msg.data}`);
|
|
|
+ }
|
|
|
});
|
|
|
};
|
|
|
|
|
|
@@ -266,6 +302,63 @@ export const ClassroomPage = () => {
|
|
|
}
|
|
|
};
|
|
|
|
|
|
+ // 开始上课
|
|
|
+ const startClass = async (): Promise<void> => {
|
|
|
+ if (!imMessageManager.current || !classId || role !== 'teacher') return;
|
|
|
+
|
|
|
+ try {
|
|
|
+ await imMessageManager.current.sendGroupMessage({
|
|
|
+ groupId: classId,
|
|
|
+ data: JSON.stringify({ action: 'start_class' }),
|
|
|
+ type: 88889, // 自定义消息类型
|
|
|
+ level: ImMessageLevel.HIGH,
|
|
|
+ });
|
|
|
+ setClassStatus(ClassStatus.IN_PROGRESS);
|
|
|
+ showToast('success', '课堂已开始');
|
|
|
+ } catch (err: any) {
|
|
|
+ setErrorMessage(`开始上课失败: ${err.message}`);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ // 结束上课
|
|
|
+ const endClass = async (): Promise<void> => {
|
|
|
+ if (!imMessageManager.current || !classId || role !== 'teacher') return;
|
|
|
+
|
|
|
+ try {
|
|
|
+ await imMessageManager.current.sendGroupMessage({
|
|
|
+ groupId: classId,
|
|
|
+ data: JSON.stringify({ action: 'end_class' }),
|
|
|
+ type: 88889, // 自定义消息类型
|
|
|
+ level: ImMessageLevel.HIGH,
|
|
|
+ });
|
|
|
+ setClassStatus(ClassStatus.ENDED);
|
|
|
+ showToast('success', '课堂已结束');
|
|
|
+ } catch (err: any) {
|
|
|
+ setErrorMessage(`结束上课失败: ${err.message}`);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ // 静音/取消静音成员
|
|
|
+ const toggleMuteMember = async (userId: string, mute: boolean): Promise<void> => {
|
|
|
+ if (!imMessageManager.current || !classId || role !== 'teacher') return;
|
|
|
+
|
|
|
+ try {
|
|
|
+ await imMessageManager.current.sendGroupMessage({
|
|
|
+ groupId: classId,
|
|
|
+ data: JSON.stringify({
|
|
|
+ action: 'toggle_mute',
|
|
|
+ userId,
|
|
|
+ mute
|
|
|
+ }),
|
|
|
+ type: 88890, // 自定义消息类型
|
|
|
+ level: ImMessageLevel.HIGH,
|
|
|
+ });
|
|
|
+ showToast('info', mute ? `已静音用户 ${userId}` : `已取消静音用户 ${userId}`);
|
|
|
+ } catch (err: any) {
|
|
|
+ setErrorMessage(`操作失败: ${err.message}`);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
// 清理资源
|
|
|
useEffect(() => {
|
|
|
return () => {
|
|
|
@@ -292,7 +385,11 @@ export const ClassroomPage = () => {
|
|
|
isJoinedClass,
|
|
|
messageList,
|
|
|
errorMessage,
|
|
|
+ classStatus,
|
|
|
setRole,
|
|
|
+ startClass,
|
|
|
+ endClass,
|
|
|
+ toggleMuteMember
|
|
|
}}>
|
|
|
<div className="container mx-auto p-4">
|
|
|
<h1 className="text-2xl font-bold mb-4">互动课堂</h1>
|