Kaynağa Gözat

feat(classroom): 添加学生列表管理和课堂分享功能

- 新增students状态和fetchStudents函数获取学生列表
- 添加shareLink状态和分享链接UI组件
- 改进成员管理界面使用真实学生数据
- 调整登录按钮位置
yourname 7 ay önce
ebeveyn
işleme
99b8c49930
1 değiştirilmiş dosya ile 91 ekleme ve 29 silme
  1. 91 29
      client/mobile/pages_classroom.tsx

+ 91 - 29
client/mobile/pages_classroom.tsx

@@ -150,6 +150,8 @@ export const ClassroomPage = () => {
   const [classStatus, setClassStatus] = useState<ClassStatus>(ClassStatus.NOT_STARTED);
   const [handUpList, setHandUpList] = useState<HandUpRequest[]>([]);
   const [questions, setQuestions] = useState<string[]>([]);
+  const [students, setStudents] = useState<Array<{id: string, name: string}>>([]);
+  const [shareLink, setShareLink] = useState<string>('');
 
   // SDK实例
   const imEngine = useRef<ImEngine | null>(null);
@@ -294,6 +296,35 @@ export const ClassroomPage = () => {
     });
   };
 
+  // 获取学生列表
+  const fetchStudents = async (classId: string) => {
+    try {
+      if (!imEngine.current) {
+        throw new Error('IM引擎未初始化');
+      }
+
+      const groupManager = imEngine.current.getGroupManager();
+      if (!groupManager) {
+        throw new Error('IM群组管理器未初始化');
+      }
+
+      // 使用classId作为群组ID获取成员
+      const response = await groupManager.listRecentGroupUser(classId);
+      
+      // 转换IM用户数据格式
+      const students = response.userList.map((user: ImUser) => ({
+        id: user.userId,
+        name: user.userExtension || `用户${user.userId}`
+      }));
+
+      setStudents(students);
+    } catch (err) {
+      console.error('从IM获取学生列表失败:', err);
+      // 可选: 显示错误提示给用户
+      // setError('获取学生列表失败,请稍后重试');
+    }
+  };
+
   // 统一登录逻辑
   const login = async (userId: string): Promise<void> => {
     try {
@@ -333,6 +364,9 @@ export const ClassroomPage = () => {
       setIsLoggedIn(true);
       setErrorMessage('');
       showToast('success', '登录成功');
+      
+      // 登录后获取分享链接占位符
+      setShareLink(`${window.location.href.split('?')[0]}?classId=${classId || '12345'}`);
     } catch (err: any) {
       setErrorMessage(`登录失败: ${err.message}`);
       showToast('error', '登录失败');
@@ -520,6 +554,9 @@ export const ClassroomPage = () => {
         const createTime = new Date();
         showMessage(`创建时间: ${createTime.toLocaleString()}`);
         
+        // 创建成功后生成分享链接
+        setShareLink(`${window.location.href.split('?')[0]}?classId=${response.groupId}`);
+        
         return response.groupId;
       } catch (joinErr: any) {
         throw new Error(`创建成功但加入失败: ${joinErr.message}`);
@@ -646,6 +683,29 @@ export const ClassroomPage = () => {
 
         <div className="grid grid-cols-1 md:grid-cols-3 gap-4">
           <div className="md:col-span-1">
+            {shareLink && (
+              <div className="mb-4 p-4 bg-white rounded-md shadow">
+                <h4 className="text-lg font-medium mb-2">课堂分享链接</h4>
+                <div className="flex items-center">
+                  <input
+                    type="text"
+                    readOnly
+                    value={shareLink}
+                    className="flex-1 px-3 py-2 border border-gray-300 rounded-l-md"
+                  />
+                  <button
+                    type="button"
+                    className="px-3 py-2 bg-blue-600 text-white rounded-r-md"
+                    onClick={() => {
+                      navigator.clipboard.writeText(shareLink);
+                      showToast('info', '链接已复制');
+                    }}
+                  >
+                    复制
+                  </button>
+                </div>
+              </div>
+            )}
             <form>
               {!isLoggedIn && (
                 <div className="mb-2">
@@ -689,6 +749,16 @@ export const ClassroomPage = () => {
               </div>
               
               <div className="flex space-x-2 mb-2">
+                {!isLoggedIn && (
+                  <button
+                    type="button"
+                    className="px-3 py-2 bg-blue-600 text-white rounded-md"
+                    onClick={() => login(userId)}
+                  >
+                    登录
+                  </button>
+                )}
+                
                 {isLoggedIn && role === Role.Teacher && (
                   <button
                     type="button"
@@ -704,15 +774,6 @@ export const ClassroomPage = () => {
                     创建课堂
                   </button>
                 )}
-                <button
-                  type="button"
-                  className="px-3 py-2 bg-blue-600 text-white rounded-md"
-                  disabled={isLoggedIn}
-                  onClick={() => login(userId)}
-                >
-                  登录
-                </button>
-                
                 <button
                   type="button"
                   className="px-3 py-2 bg-blue-600 text-white rounded-md"
@@ -856,26 +917,27 @@ export const ClassroomPage = () => {
                 <div>
                   <h5 className="font-medium mb-2">成员管理</h5>
                   <div className="space-y-2">
-                    <div className="flex items-center justify-between">
-                      <span>学生A</span>
-                      <button
-                        type="button"
-                        className="px-2 py-1 bg-yellow-500 text-white rounded text-sm"
-                        onClick={() => toggleMuteMember('studentA', true)}
-                      >
-                        静音
-                      </button>
-                    </div>
-                    <div className="flex items-center justify-between">
-                      <span>学生B</span>
-                      <button
-                        type="button"
-                        className="px-2 py-1 bg-blue-500 text-white rounded text-sm"
-                        onClick={() => toggleMuteMember('studentB', false)}
-                      >
-                        取消静音
-                      </button>
-                    </div>
+                    {students.map(student => (
+                      <div key={student.id} className="flex items-center justify-between">
+                        <span>{student.name}</span>
+                        <div className="space-x-2">
+                          <button
+                            type="button"
+                            className="px-2 py-1 bg-yellow-500 text-white rounded text-sm"
+                            onClick={() => toggleMuteMember(student.id, true)}
+                          >
+                            静音
+                          </button>
+                          <button
+                            type="button"
+                            className="px-2 py-1 bg-blue-500 text-white rounded text-sm"
+                            onClick={() => toggleMuteMember(student.id, false)}
+                          >
+                            取消静音
+                          </button>
+                        </div>
+                      </div>
+                    ))}
                   </div>
                 </div>
               </div>