|
|
@@ -1,190 +0,0 @@
|
|
|
-import React from 'react';
|
|
|
-import { useClassroomContext } from './ClassroomProvider';
|
|
|
-import { ClassStatus } from './useClassroom';
|
|
|
-import {
|
|
|
- StopIcon,
|
|
|
- UserGroupIcon,
|
|
|
- HandRaisedIcon,
|
|
|
- QuestionMarkCircleIcon
|
|
|
-} from '@heroicons/react/24/outline';
|
|
|
-import { Button } from '@/client/components/ui/button';
|
|
|
-import { Card, CardContent, CardHeader, CardTitle } from '@/client/components/ui/card';
|
|
|
-
|
|
|
-export const TeacherView: React.FC = () => {
|
|
|
- const {
|
|
|
- endClass,
|
|
|
- classStatus,
|
|
|
- handUpList,
|
|
|
- questions,
|
|
|
- students,
|
|
|
- toggleMuteMember,
|
|
|
- answerHandUp,
|
|
|
- kickStudent
|
|
|
- } = useClassroomContext();
|
|
|
-
|
|
|
- const handleEndClass = async () => {
|
|
|
- if (window.confirm('确定要结束课堂吗?所有学生将被断开连接。')) {
|
|
|
- await endClass();
|
|
|
- }
|
|
|
- };
|
|
|
-
|
|
|
- const handleMuteStudent = (studentId: string, studentName: string) => {
|
|
|
- if (window.confirm(`确定要静音 ${studentName} 吗?`)) {
|
|
|
- toggleMuteMember(studentId, true);
|
|
|
- }
|
|
|
- };
|
|
|
-
|
|
|
- const handleUnmuteStudent = (studentId: string, studentName: string) => {
|
|
|
- if (window.confirm(`确定要取消静音 ${studentName} 吗?`)) {
|
|
|
- toggleMuteMember(studentId, false);
|
|
|
- }
|
|
|
- };
|
|
|
-
|
|
|
- const handleAnswerHandUp = (studentId: string, studentName: string) => {
|
|
|
- answerHandUp(studentId);
|
|
|
- };
|
|
|
-
|
|
|
- const handleKickStudent = (studentId: string, studentName: string) => {
|
|
|
- if (window.confirm(`确定要移出 ${studentName} 吗?`)) {
|
|
|
- kickStudent(studentId);
|
|
|
- }
|
|
|
- };
|
|
|
-
|
|
|
- return (
|
|
|
- <div className="space-y-4 p-4">
|
|
|
- {/* 课堂控制区域 */}
|
|
|
- <Card>
|
|
|
- <CardHeader>
|
|
|
- <CardTitle className="text-lg flex items-center">
|
|
|
- <StopIcon className="w-5 h-5 mr-2 text-red-500" />
|
|
|
- 课堂控制
|
|
|
- </CardTitle>
|
|
|
- </CardHeader>
|
|
|
- <CardContent className="space-y-4">
|
|
|
- <Button
|
|
|
- onClick={handleEndClass}
|
|
|
- disabled={classStatus === ClassStatus.ENDED}
|
|
|
- variant={classStatus === ClassStatus.ENDED ? "secondary" : "destructive"}
|
|
|
- className="w-full"
|
|
|
- >
|
|
|
- {classStatus === ClassStatus.ENDED ? '课堂已结束' : '结束课堂'}
|
|
|
- </Button>
|
|
|
-
|
|
|
- </CardContent>
|
|
|
- </Card>
|
|
|
-
|
|
|
- {/* 学生管理区域 */}
|
|
|
- <Card>
|
|
|
- <CardHeader>
|
|
|
- <CardTitle className="text-lg flex items-center">
|
|
|
- <UserGroupIcon className="w-5 h-5 mr-2 text-blue-500" />
|
|
|
- 学生管理 ({students.length})
|
|
|
- </CardTitle>
|
|
|
- </CardHeader>
|
|
|
- <CardContent>
|
|
|
- {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">
|
|
|
- <span className="text-sm">{student.name}</span>
|
|
|
- <div className="flex gap-1">
|
|
|
- <Button
|
|
|
- onClick={() => handleMuteStudent(student.id, student.name)}
|
|
|
- variant="outline"
|
|
|
- size="sm"
|
|
|
- className="text-xs bg-yellow-100 text-yellow-700 hover:bg-yellow-200 border-yellow-300"
|
|
|
- >
|
|
|
- 静音
|
|
|
- </Button>
|
|
|
- <Button
|
|
|
- onClick={() => handleUnmuteStudent(student.id, student.name)}
|
|
|
- variant="outline"
|
|
|
- size="sm"
|
|
|
- className="text-xs bg-green-100 text-green-700 hover:bg-green-200 border-green-300"
|
|
|
- >
|
|
|
- 取消静音
|
|
|
- </Button>
|
|
|
- <Button
|
|
|
- onClick={() => handleKickStudent(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>
|
|
|
- )}
|
|
|
- </CardContent>
|
|
|
- </Card>
|
|
|
-
|
|
|
- {/* 举手管理区域 */}
|
|
|
- {handUpList.length > 0 && (
|
|
|
- <Card>
|
|
|
- <CardHeader>
|
|
|
- <CardTitle className="text-lg flex items-center">
|
|
|
- <HandRaisedIcon className="w-5 h-5 mr-2 text-orange-500" />
|
|
|
- 举手请求 ({handUpList.length})
|
|
|
- </CardTitle>
|
|
|
- </CardHeader>
|
|
|
- <CardContent>
|
|
|
- <div className="space-y-2">
|
|
|
- {handUpList.map((request, index) => (
|
|
|
- <div key={index} className="p-3 border rounded-lg bg-orange-50">
|
|
|
- <div className="flex items-center justify-between mb-2">
|
|
|
- <span className="font-medium">{request.studentName || request.studentId}</span>
|
|
|
- <span className="text-xs text-gray-500">
|
|
|
- {new Date(request.timestamp).toLocaleTimeString()}
|
|
|
- </span>
|
|
|
- </div>
|
|
|
- {request.question && (
|
|
|
- <p className="text-sm text-gray-600 mb-2">问题:{request.question}</p>
|
|
|
- )}
|
|
|
- <Button
|
|
|
- onClick={() => handleAnswerHandUp(request.studentId, request.studentName || request.studentId)}
|
|
|
- variant="default"
|
|
|
- size="sm"
|
|
|
- className="text-sm bg-green-500 text-white hover:bg-green-600"
|
|
|
- >
|
|
|
- 应答
|
|
|
- </Button>
|
|
|
- </div>
|
|
|
- ))}
|
|
|
- </div>
|
|
|
- </CardContent>
|
|
|
- </Card>
|
|
|
- )}
|
|
|
-
|
|
|
- {/* 问题管理区域 */}
|
|
|
- {questions.length > 0 && (
|
|
|
- <Card>
|
|
|
- <CardHeader>
|
|
|
- <CardTitle className="text-lg flex items-center">
|
|
|
- <QuestionMarkCircleIcon className="w-5 h-5 mr-2 text-purple-500" />
|
|
|
- 学生提问 ({questions.length})
|
|
|
- </CardTitle>
|
|
|
- </CardHeader>
|
|
|
- <CardContent>
|
|
|
- <div className="space-y-3">
|
|
|
- {questions.map((question, index) => (
|
|
|
- <div key={index} className="p-3 border rounded-lg bg-purple-50">
|
|
|
- <div className="flex items-center justify-between mb-2">
|
|
|
- <span className="font-medium">{question.studentName}</span>
|
|
|
- <span className="text-xs text-gray-500">
|
|
|
- {new Date(question.timestamp).toLocaleTimeString()}
|
|
|
- </span>
|
|
|
- </div>
|
|
|
- <p className="text-sm text-gray-700">{question.question}</p>
|
|
|
- </div>
|
|
|
- ))}
|
|
|
- </div>
|
|
|
- </CardContent>
|
|
|
- </Card>
|
|
|
- )}
|
|
|
- </div>
|
|
|
- );
|
|
|
-};
|