| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161 |
- import React, { ReactNode } from 'react';
- import { Role } from './useClassroom.ts';
- import { useClassroomContext } from './ClassroomProvider.tsx';
- import {
- VideoCameraIcon,
- CameraIcon,
- MicrophoneIcon,
- ShareIcon,
- ClipboardDocumentIcon,
- PaperAirplaneIcon
- } from '@heroicons/react/24/outline';
- interface ClassroomLayoutProps {
- children: ReactNode;
- role: Role;
- }
- export const ClassroomLayout = ({ children, role }: ClassroomLayoutProps) => {
- const [showVideo, setShowVideo] = React.useState(role !== Role.Teacher);
- const [showShareLink, setShowShareLink] = React.useState(false);
- const {
- remoteVideoContainer,
- isCameraOn,
- isAudioOn,
- isScreenSharing,
- toggleCamera,
- toggleAudio,
- toggleScreenShare,
- messageList,
- msgText,
- setMsgText,
- sendMessage,
- handUpList,
- questions,
- classStatus,
- shareLink
- } = useClassroomContext();
- return (
- <div className="flex flex-col h-screen bg-gray-100">
- <div className="flex-1 flex">
- {/* 视频区域 */}
- {showVideo && (
- <div className="flex-1 p-4">
- <div className="bg-white rounded-lg shadow p-4 h-full">
- <div
- id="remoteVideoContainer"
- ref={remoteVideoContainer}
- className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4"
- >
- {/* 远程视频将在这里动态添加 */}
- </div>
- </div>
- </div>
- )}
- {/* 消息和控制面板列 */}
- <div className={`${showVideo ? 'w-96' : 'flex-1'} flex flex-col`}>
- {/* 控制面板 */}
- <div className="bg-white shadow-lg p-3 flex flex-col gap-3">
- <div className="flex flex-wrap gap-2">
- {role === Role.Teacher && (
- <button
- onClick={() => setShowVideo(!showVideo)}
- className={`p-2 rounded-full ${showVideo ? 'bg-gray-500' : 'bg-gray-300'} text-white`}
- title={showVideo ? '隐藏视频' : '显示视频'}
- >
- <VideoCameraIcon className="w-5 h-5" />
- </button>
- )}
- <button
- onClick={toggleCamera}
- className={`p-2 rounded-full ${isCameraOn ? 'bg-green-500' : 'bg-red-500'} text-white`}
- title={isCameraOn ? '关闭摄像头' : '开启摄像头'}
- >
- <CameraIcon className="w-5 h-5" />
- </button>
- <button
- onClick={toggleAudio}
- className={`p-2 rounded-full ${isAudioOn ? 'bg-green-500' : 'bg-red-500'} text-white`}
- title={isAudioOn ? '关闭麦克风' : '开启麦克风'}
- >
- <MicrophoneIcon className="w-5 h-5" />
- </button>
- {role === Role.Teacher && (
- <button
- onClick={toggleScreenShare}
- className={`p-2 rounded-full ${isScreenSharing ? 'bg-green-500' : 'bg-blue-500'} text-white`}
- title={isScreenSharing ? '停止共享' : '共享屏幕'}
- >
- <ShareIcon className="w-5 h-5" />
- </button>
- )}
- {role === Role.Teacher && shareLink && (
- <button
- onClick={() => setShowShareLink(!showShareLink)}
- className="p-2 rounded-full bg-blue-500 text-white"
- title="分享链接"
- >
- <ClipboardDocumentIcon className="w-5 h-5" />
- </button>
- )}
- </div>
- {showShareLink && shareLink && (
- <div className="bg-blue-50 p-2 rounded">
- <div className="flex items-center gap-1">
- <input
- type="text"
- value={shareLink}
- readOnly
- className="flex-1 text-xs border rounded px-2 py-1 truncate"
- />
- <button
- onClick={() => navigator.clipboard.writeText(shareLink)}
- className="p-2 bg-blue-500 text-white rounded"
- title="复制链接"
- >
- <ClipboardDocumentIcon className="w-4 h-4" />
- </button>
- </div>
- </div>
- )}
- {/* 角色特定内容 */}
- <div className="flex-1 overflow-y-auto">
- {children}
- </div>
- </div>
- {/* 消息区域 */}
- <div className="bg-white shadow-lg p-4 flex-1">
- <div className="h-full flex flex-col">
- <div className="flex-1 overflow-y-auto mb-2">
- {messageList.map((msg, i) => (
- <div key={i} className="text-sm mb-1">{msg}</div>
- ))}
- </div>
- <div className="relative">
- <textarea
- value={msgText}
- onChange={(e) => setMsgText(e.target.value)}
- className="w-full border rounded px-2 py-1 pr-10"
- placeholder="输入消息..."
- rows={3}
- />
- <button
- onClick={sendMessage}
- className="absolute right-2 bottom-2 p-1 bg-blue-500 text-white rounded-full"
- >
- <PaperAirplaneIcon className="w-5 h-5" />
- </button>
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
- );
- };
|