2
0
Просмотр исходного кода

♻️ refactor(classroom): 重构教师学生管理按钮组件

- 将学生管理面板从自定义悬浮div重构为使用Dialog组件
- 移除XMarkIcon导入,使用Dialog组件的内置关闭功能
- 调整组件结构,优化样式和布局
- 保持原有功能不变,提升UI一致性和可维护性
yourname 6 месяцев назад
Родитель
Сommit
2082faab56

+ 75 - 77
src/client/mobile/components/Classroom/TeacherStudentManagementButton.tsx

@@ -1,6 +1,6 @@
 import React, { useState } from 'react';
 import { useClassroomContext } from './ClassroomProvider';
-import { UserGroupIcon, XMarkIcon, EyeIcon, UsersIcon } from '@heroicons/react/24/outline';
+import { UserGroupIcon, EyeIcon, UsersIcon } from '@heroicons/react/24/outline';
 import { Button } from '@/client/components/ui/button';
 import { Card, CardContent, CardHeader, CardTitle } from '@/client/components/ui/card';
 import {
@@ -13,6 +13,13 @@ import {
   AlertDialogHeader,
   AlertDialogTitle,
 } from '@/client/components/ui/alert-dialog';
+import {
+  Dialog,
+  DialogContent,
+  DialogHeader,
+  DialogTitle,
+  DialogTrigger,
+} from '@/client/components/ui/dialog';
 import { IMToggleMuteButton } from './IMToggleMuteButton';
 import { RTCToggleMuteButton } from './RTCToggleMuteButton';
 
@@ -67,83 +74,74 @@ export const TeacherStudentManagementButton: React.FC = () => {
   };
 
   return (
-    <div className="relative">
-      <Button
-        type="button"
-        onClick={() => setShowPanel(!showPanel)}
-        className="p-2 rounded-full bg-blue-500 text-white relative"
-        title={`学生管理 (${students.length})`}
-        size="icon"
-        variant="ghost"
-      >
-        <UserGroupIcon className="w-4 h-4" />
-        {students.length > 0 && (
-          <span className="absolute -top-1 -right-1 bg-red-500 text-white text-xs rounded-full w-4 h-4 flex items-center justify-center">
-            {students.length}
-          </span>
-        )}
-      </Button>
-
-      {showPanel && (
-        <div className="absolute bottom-full right-0 mb-2 w-80 bg-white shadow-lg rounded-lg z-50">
-          <Card className="border-0">
-            <CardHeader className="p-3 flex flex-row items-center justify-between">
-              <CardTitle className="text-sm flex items-center">
-                <UserGroupIcon className="w-4 h-4 mr-2 text-blue-500" />
-                学生管理 ({students.length})
-              </CardTitle>
-              <Button
-                type="button"
-                onClick={() => setShowPanel(false)}
-                className="p-1 rounded-full"
-                size="icon"
-                variant="ghost"
-              >
-                <XMarkIcon className="w-4 h-4" />
-              </Button>
-            </CardHeader>
-            <CardContent className="p-3">
-              {/* 统计信息 */}
-              <div className="flex justify-between mb-3 p-2 bg-gray-50 rounded text-sm">
-                <div className="flex items-center">
-                  <UsersIcon className="w-4 h-4 mr-1 text-blue-500" />
-                  <span>在线: {onlineCount}人</span>
-                </div>
-                <div className="flex items-center">
-                  <EyeIcon className="w-4 h-4 mr-1 text-green-500" />
-                  <span>看过: {pvCount}人</span>
-                </div>
+    <Dialog open={showPanel} onOpenChange={setShowPanel}>
+      <DialogTrigger asChild>
+        <Button
+          type="button"
+          className="p-2 rounded-full bg-blue-500 text-white relative"
+          title={`学生管理 (${students.length})`}
+          size="icon"
+          variant="ghost"
+        >
+          <UserGroupIcon className="w-4 h-4" />
+          {students.length > 0 && (
+            <span className="absolute -top-1 -right-1 bg-red-500 text-white text-xs rounded-full w-4 h-4 flex items-center justify-center">
+              {students.length}
+            </span>
+          )}
+        </Button>
+      </DialogTrigger>
+      
+      <DialogContent className="sm:max-w-md">
+        <DialogHeader>
+          <DialogTitle className="flex items-center">
+            <UserGroupIcon className="w-4 h-4 mr-2 text-blue-500" />
+            学生管理 ({students.length})
+          </DialogTitle>
+        </DialogHeader>
+        
+        <Card className="border-0 shadow-none">
+          <CardContent className="p-0">
+            {/* 统计信息 */}
+            <div className="flex justify-between mb-3 p-2 bg-gray-50 rounded text-sm">
+              <div className="flex items-center">
+                <UsersIcon className="w-4 h-4 mr-1 text-blue-500" />
+                <span>在线: {onlineCount}人</span>
               </div>
-              
-              <div className="max-h-60 overflow-y-auto">
-                {students.length === 0 ? (
-                  <p className="text-gray-500 text-sm">暂无学生加入</p>
-                ) : (
-                  <div className="space-y-2">
-                    {students.map((student) => (
-                      <div key={student.id} className="flex items-center justify-between p-2 border rounded text-sm">
-                        <span>{student.name}</span>
-                        <div className="flex gap-1 flex-wrap">
-                         <RTCToggleMuteButton userId={student.id} userName={student.name} />
-                         <IMToggleMuteButton userId={student.id} userName={student.name} />
-                         <Button
-                           onClick={() => openConfirmDialog('kick', student.id, student.name)}
-                           variant="outline"
-                           size="sm"
-                           className="text-xs bg-red-100 text-red-700 hover:bg-red-200 border-red-300"
-                         >
-                           移出
-                         </Button>
-                        </div>
-                      </div>
-                    ))}
-                  </div>
-                )}
+              <div className="flex items-center">
+                <EyeIcon className="w-4 h-4 mr-1 text-green-500" />
+                <span>看过: {pvCount}人</span>
               </div>
-            </CardContent>
-          </Card>
-        </div>
-      )}
+            </div>
+            
+            <div className="max-h-60 overflow-y-auto">
+              {students.length === 0 ? (
+                <p className="text-gray-500 text-sm">暂无学生加入</p>
+              ) : (
+                <div className="space-y-2">
+                  {students.map((student) => (
+                    <div key={student.id} className="flex items-center justify-between p-2 border rounded text-sm">
+                      <span>{student.name}</span>
+                      <div className="flex gap-1 flex-wrap">
+                       <RTCToggleMuteButton userId={student.id} userName={student.name} />
+                       <IMToggleMuteButton userId={student.id} userName={student.name} />
+                       <Button
+                         onClick={() => openConfirmDialog('kick', student.id, student.name)}
+                         variant="outline"
+                         size="sm"
+                         className="text-xs bg-red-100 text-red-700 hover:bg-red-200 border-red-300"
+                       >
+                         移出
+                       </Button>
+                      </div>
+                    </div>
+                  ))}
+                </div>
+              )}
+            </div>
+          </CardContent>
+        </Card>
+      </DialogContent>
 
       <AlertDialog open={confirmDialog.open} onOpenChange={(open) => !open && handleCancel()}>
         <AlertDialogContent>
@@ -161,6 +159,6 @@ export const TeacherStudentManagementButton: React.FC = () => {
           </AlertDialogFooter>
         </AlertDialogContent>
       </AlertDialog>
-    </div>
+    </Dialog>
   );
 };