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

✨ feat(classroom): 统一组件库使用,优化UI界面

- 替换原生button为Button组件,统一按钮样式和交互
- 引入Card组件包装各功能区块,增强视觉层次感
- 使用Textarea和Input组件替换原生textarea和input
- 优化角色选择页面按钮样式,使用主次要变体区分
- 重构分享链接、消息输入框等UI元素,提升一致性和美观度
yourname 7 месяцев назад
Родитель
Сommit
6f7f20d9dc

+ 52 - 34
src/client/mobile/components/Classroom/ClassroomLayout.tsx

@@ -9,6 +9,9 @@ import {
   ClipboardDocumentIcon,
   PaperAirplaneIcon
 } from '@heroicons/react/24/outline';
+import { Button } from '@/client/components/ui/button';
+import { Textarea } from '@/client/components/ui/textarea';
+import { Card, CardContent } from '@/client/components/ui/card';
 
 interface ClassroomLayoutProps {
   children: ReactNode;
@@ -65,16 +68,17 @@ export const ClassroomLayout = ({ children, role }: ClassroomLayoutProps) => {
           </div>
           
           {/* 摄像头小窗开关按钮 */}
-          <button
+          <Button
             type="button"
             onClick={() => setShowCameraOverlay(!showCameraOverlay)}
             className={`absolute top-4 right-4 z-20 p-2 rounded-full ${
               showCameraOverlay ? 'bg-green-500' : 'bg-gray-500'
             } text-white`}
             title={showCameraOverlay ? '隐藏摄像头小窗' : '显示摄像头小窗'}
+            size="icon"
           >
             <CameraIcon className="w-4 h-4" />
-          </button>
+          </Button>
         </div>
       )}
 
@@ -96,72 +100,85 @@ export const ClassroomLayout = ({ children, role }: ClassroomLayoutProps) => {
             <div className="p-2 flex flex-col gap-3 mb-1 border-b border-gray-200">
               <div className="flex flex-wrap gap-2">
                 {role === Role.Teacher && (
-                  <button
+                  <Button
                     type="button"
                     onClick={() => setShowVideo(!showVideo)}
                     className={`p-2 rounded-full ${showVideo ? 'bg-gray-500' : 'bg-gray-300'} text-white`}
                     title={showVideo ? '隐藏视频' : '显示视频'}
+                    size="icon"
+                    variant="ghost"
                   >
                     <VideoCameraIcon className="w-4 h-4" />
-                  </button>
+                  </Button>
                 )}
-                <button
+                <Button
                   type="button"
                   onClick={toggleCamera}
                   className={`p-2 rounded-full ${isCameraOn ? 'bg-green-500' : 'bg-red-500'} text-white`}
                   title={isCameraOn ? '关闭摄像头' : '开启摄像头'}
+                  size="icon"
+                  variant="ghost"
                 >
                   <CameraIcon className="w-4 h-4" />
-                </button>
-                <button
+                </Button>
+                <Button
                   type="button"
                   onClick={toggleAudio}
                   className={`p-2 rounded-full ${isAudioOn ? 'bg-green-500' : 'bg-red-500'} text-white`}
                   title={isAudioOn ? '关闭麦克风' : '开启麦克风'}
+                  size="icon"
+                  variant="ghost"
                 >
                   <MicrophoneIcon className="w-4 h-4" />
-                </button>
+                </Button>
                 {role === Role.Teacher && (
-                  <button
+                  <Button
                     type="button"
                     onClick={toggleScreenShare}
                     className={`p-2 rounded-full ${isScreenSharing ? 'bg-green-500' : 'bg-blue-500'} text-white`}
                     title={isScreenSharing ? '停止共享' : '共享屏幕'}
+                    size="icon"
+                    variant="ghost"
                   >
                     <ShareIcon className="w-4 h-4" />
-                  </button>
+                  </Button>
                 )}
                 {role === Role.Teacher && shareLink && (
-                  <button
+                  <Button
                     type="button"
                     onClick={() => setShowShareLink(!showShareLink)}
                     className="p-2 rounded-full bg-blue-500 text-white"
                     title="分享链接"
+                    size="icon"
+                    variant="ghost"
                   >
                     <ClipboardDocumentIcon className="w-4 h-4" />
-                  </button>
+                  </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
-                      type="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>
+                <Card className="bg-blue-50 p-2">
+                  <CardContent className="p-0">
+                    <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
+                        type="button"
+                        onClick={() => navigator.clipboard.writeText(shareLink)}
+                        className="p-2 bg-blue-500 text-white rounded"
+                        title="复制链接"
+                        size="icon"
+                      >
+                        <ClipboardDocumentIcon className="w-4 h-4" />
+                      </Button>
+                    </div>
+                  </CardContent>
+                </Card>
               )}
               
               {/* 角色特定内容 */}
@@ -172,7 +189,7 @@ export const ClassroomLayout = ({ children, role }: ClassroomLayoutProps) => {
 
             {/* 消息输入框 */}
             <div className="relative mt-2">
-              <textarea
+              <Textarea
                 value={msgText}
                 onChange={(e) => setMsgText(e.target.value)}
                 onKeyDown={(e) => {
@@ -181,17 +198,18 @@ export const ClassroomLayout = ({ children, role }: ClassroomLayoutProps) => {
                     sendMessage();
                   }
                 }}
-                className="w-full border rounded px-2 py-1 pr-10"
+                className="w-full pr-10"
                 placeholder="输入消息..."
                 rows={3}
               />
-              <button
+              <Button
                 type="button"
                 onClick={sendMessage}
                 className="absolute right-2 bottom-2 p-1 bg-blue-500 text-white rounded-full"
+                size="icon"
               >
                 <PaperAirplaneIcon className="w-4 h-4" />
-              </button>
+              </Button>
             </div>
           </div>
       </div>

+ 65 - 54
src/client/mobile/components/Classroom/StudentView.tsx

@@ -1,9 +1,12 @@
 import React, { useState } from 'react';
 import { useClassroomContext } from './ClassroomProvider';
-import { 
+import {
   HandRaisedIcon,
   QuestionMarkCircleIcon
 } from '@heroicons/react/24/outline';
+import { Button } from '@/client/components/ui/button';
+import { Textarea } from '@/client/components/ui/textarea';
+import { Card, CardContent, CardHeader, CardTitle } from '@/client/components/ui/card';
 
 export const StudentView: React.FC = () => {
   const {
@@ -33,64 +36,72 @@ export const StudentView: React.FC = () => {
   return (
     <div className="space-y-4 p-4">
       {/* 举手功能 */}
-      <div className="bg-white rounded-lg shadow p-4">
-        <h3 className="text-lg font-semibold mb-4 flex items-center">
-          <HandRaisedIcon className="w-5 h-5 mr-2 text-orange-500" />
-          举手提问
-        </h3>
-        
-        <button
-          onClick={handleHandUp}
-          disabled={classStatus === 'ended'}
-          className={`w-full py-3 px-4 rounded-lg text-white font-medium transition-colors ${
-            classStatus === 'ended'
-              ? 'bg-gray-400 cursor-not-allowed'
-              : 'bg-orange-500 hover:bg-orange-600'
-          }`}
-        >
-          举手提问
-        </button>
-        
-        <p className="text-sm text-gray-500 mt-2">
-          点击举手后,老师会收到通知并可以应答您的问题
-        </p>
-      </div>
+      <Card>
+        <CardHeader>
+          <CardTitle className="text-lg flex items-center">
+            <HandRaisedIcon className="w-5 h-5 mr-2 text-orange-500" />
+            举手提问
+          </CardTitle>
+        </CardHeader>
+        <CardContent className="space-y-3">
+          <Button
+            onClick={handleHandUp}
+            disabled={classStatus === 'ended'}
+            className={`w-full ${
+              classStatus === 'ended'
+                ? 'bg-gray-400 cursor-not-allowed'
+                : 'bg-orange-500 hover:bg-orange-600'
+            }`}
+          >
+            举手提问
+          </Button>
+          
+          <p className="text-sm text-gray-500">
+            点击举手后,老师会收到通知并可以应答您的问题
+          </p>
+        </CardContent>
+      </Card>
 
       {/* 发送问题 */}
-      <div className="bg-white rounded-lg shadow p-4">
-        <h3 className="text-lg font-semibold mb-4 flex items-center">
-          <QuestionMarkCircleIcon className="w-5 h-5 mr-2 text-purple-500" />
-          发送问题
-        </h3>
-        
-        <textarea
-          value={questionText}
-          onChange={(e) => setQuestionText(e.target.value)}
-          placeholder="请输入您的问题..."
-          className="w-full border rounded px-3 py-2 mb-3"
-          rows={3}
-        />
-        
-        <button
-          onClick={handleSendQuestion}
-          disabled={classStatus === 'ended' || !questionText.trim()}
-          className={`w-full py-2 px-4 rounded text-white transition-colors ${
-            classStatus === 'ended' || !questionText.trim()
-              ? 'bg-gray-400 cursor-not-allowed'
-              : 'bg-purple-500 hover:bg-purple-600'
-          }`}
-        >
-          发送问题
-        </button>
-      </div>
+      <Card>
+        <CardHeader>
+          <CardTitle className="text-lg flex items-center">
+            <QuestionMarkCircleIcon className="w-5 h-5 mr-2 text-purple-500" />
+            发送问题
+          </CardTitle>
+        </CardHeader>
+        <CardContent className="space-y-3">
+          <Textarea
+            value={questionText}
+            onChange={(e) => setQuestionText(e.target.value)}
+            placeholder="请输入您的问题..."
+            className="w-full"
+            rows={3}
+          />
+          
+          <Button
+            onClick={handleSendQuestion}
+            disabled={classStatus === 'ended' || !questionText.trim()}
+            className={`w-full ${
+              classStatus === 'ended' || !questionText.trim()
+                ? 'bg-gray-400 cursor-not-allowed'
+                : 'bg-purple-500 hover:bg-purple-600'
+            }`}
+          >
+            发送问题
+          </Button>
+        </CardContent>
+      </Card>
 
       {/* 课堂状态提示 */}
       {classStatus === 'ended' && (
-        <div className="bg-yellow-50 border border-yellow-200 rounded-lg p-4">
-          <p className="text-yellow-800 text-sm">
-            课堂已结束,您无法再进行互动操作
-          </p>
-        </div>
+        <Card className="bg-yellow-50 border-yellow-200">
+          <CardContent className="p-4">
+            <p className="text-yellow-800 text-sm">
+              课堂已结束,您无法再进行互动操作
+            </p>
+          </CardContent>
+        </Card>
       )}
     </div>
   );

+ 143 - 123
src/client/mobile/components/Classroom/TeacherView.tsx

@@ -1,12 +1,15 @@
 import React from 'react';
 import { useClassroomContext } from './ClassroomProvider';
 import { ClassStatus } from './useClassroom';
-import { 
-  StopIcon, 
-  UserGroupIcon, 
+import {
+  StopIcon,
+  UserGroupIcon,
   HandRaisedIcon,
   QuestionMarkCircleIcon
 } from '@heroicons/react/24/outline';
+import { Button } from '@/client/components/ui/button';
+import { Input } from '@/client/components/ui/input';
+import { Card, CardContent, CardHeader, CardTitle } from '@/client/components/ui/card';
 
 export const TeacherView: React.FC = () => {
   const {
@@ -53,139 +56,156 @@ export const TeacherView: React.FC = () => {
   return (
     <div className="space-y-4 p-4">
       {/* 课堂控制区域 */}
-      <div className="bg-white rounded-lg shadow p-4">
-        <h3 className="text-lg font-semibold mb-4 flex items-center">
-          <StopIcon className="w-5 h-5 mr-2 text-red-500" />
-          课堂控制
-        </h3>
-        
-        <button
-          onClick={handleEndClass}
-          disabled={classStatus === ClassStatus.ENDED}
-          className={`w-full py-3 px-4 rounded-lg text-white font-medium transition-colors ${
-            classStatus === ClassStatus.ENDED
-              ? 'bg-gray-400 cursor-not-allowed'
-              : 'bg-red-500 hover:bg-red-600'
-          }`}
-        >
-          {classStatus === ClassStatus.ENDED ? '课堂已结束' : '结束课堂'}
-        </button>
-        
-        {shareLink && (
-          <div className="mt-4 p-3 bg-blue-50 rounded-lg">
-            <p className="text-sm text-blue-800 mb-2">课堂邀请链接:</p>
-            <div className="flex items-center gap-2">
-              <input
-                type="text"
-                value={shareLink}
-                readOnly
-                className="flex-1 text-sm border border-blue-200 rounded px-3 py-2 bg-white"
-              />
-              <button
-                onClick={() => navigator.clipboard.writeText(shareLink)}
-                className="px-3 py-2 bg-blue-500 text-white rounded text-sm hover:bg-blue-600"
-              >
-                复制
-              </button>
+      <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}
+            className={`w-full ${
+              classStatus === ClassStatus.ENDED
+                ? 'bg-gray-400 cursor-not-allowed'
+                : 'bg-red-500 hover:bg-red-600'
+            }`}
+          >
+            {classStatus === ClassStatus.ENDED ? '课堂已结束' : '结束课堂'}
+          </Button>
+          
+          {shareLink && (
+            <div className="p-3 bg-blue-50 rounded-lg">
+              <p className="text-sm text-blue-800 mb-2">课堂邀请链接:</p>
+              <div className="flex items-center gap-2">
+                <Input
+                  type="text"
+                  value={shareLink}
+                  readOnly
+                  className="flex-1 text-sm"
+                />
+                <Button
+                  onClick={() => navigator.clipboard.writeText(shareLink)}
+                  className="px-3 py-2 bg-blue-500 text-white rounded text-sm hover:bg-blue-600"
+                  size="sm"
+                >
+                  复制
+                </Button>
+              </div>
             </div>
-          </div>
-        )}
-      </div>
+          )}
+        </CardContent>
+      </Card>
 
       {/* 学生管理区域 */}
-      <div className="bg-white rounded-lg shadow p-4">
-        <h3 className="text-lg font-semibold mb-4 flex items-center">
-          <UserGroupIcon className="w-5 h-5 mr-2 text-blue-500" />
-          学生管理 ({students.length})
-        </h3>
-        
-        {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)}
-                    className="px-2 py-1 bg-yellow-500 text-white text-xs rounded hover:bg-yellow-600"
-                  >
-                    静音
-                  </button>
-                  <button
-                    onClick={() => handleUnmuteStudent(student.id, student.name)}
-                    className="px-2 py-1 bg-green-500 text-white text-xs rounded hover:bg-green-600"
-                  >
-                    取消静音
-                  </button>
-                  <button
-                    onClick={() => handleKickStudent(student.id, student.name)}
-                    className="px-2 py-1 bg-red-500 text-white text-xs rounded hover:bg-red-600"
-                  >
-                    移出
-                  </button>
+      <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)}
+                      className="px-2 py-1 bg-yellow-500 text-white text-xs rounded hover:bg-yellow-600"
+                      size="sm"
+                    >
+                      静音
+                    </Button>
+                    <Button
+                      onClick={() => handleUnmuteStudent(student.id, student.name)}
+                      className="px-2 py-1 bg-green-500 text-white text-xs rounded hover:bg-green-600"
+                      size="sm"
+                    >
+                      取消静音
+                    </Button>
+                    <Button
+                      onClick={() => handleKickStudent(student.id, student.name)}
+                      className="px-2 py-1 bg-red-500 text-white text-xs rounded hover:bg-red-600"
+                      size="sm"
+                    >
+                      移出
+                    </Button>
+                  </div>
                 </div>
-              </div>
-            ))}
-          </div>
-        )}
-      </div>
+              ))}
+            </div>
+          )}
+        </CardContent>
+      </Card>
 
       {/* 举手管理区域 */}
       {handUpList.length > 0 && (
-        <div className="bg-white rounded-lg shadow p-4">
-          <h3 className="text-lg font-semibold mb-4 flex items-center">
-            <HandRaisedIcon className="w-5 h-5 mr-2 text-orange-500" />
-            举手请求 ({handUpList.length})
-          </h3>
-          
-          <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>
+        <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)}
+                    className="px-3 py-1 bg-green-500 text-white text-sm rounded hover:bg-green-600"
+                    size="sm"
+                  >
+                    应答
+                  </Button>
                 </div>
-                {request.question && (
-                  <p className="text-sm text-gray-600 mb-2">问题:{request.question}</p>
-                )}
-                <button
-                  onClick={() => handleAnswerHandUp(request.studentId, request.studentName || request.studentId)}
-                  className="px-3 py-1 bg-green-500 text-white text-sm rounded hover:bg-green-600"
-                >
-                  应答
-                </button>
-              </div>
-            ))}
-          </div>
-        </div>
+              ))}
+            </div>
+          </CardContent>
+        </Card>
       )}
 
       {/* 问题管理区域 */}
       {questions.length > 0 && (
-        <div className="bg-white rounded-lg shadow p-4">
-          <h3 className="text-lg font-semibold mb-4 flex items-center">
-            <QuestionMarkCircleIcon className="w-5 h-5 mr-2 text-purple-500" />
-            学生提问 ({questions.length})
-          </h3>
-          
-          <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>
+        <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>
-                <p className="text-sm text-gray-700">{question.question}</p>
-              </div>
-            ))}
-          </div>
-        </div>
+              ))}
+            </div>
+          </CardContent>
+        </Card>
       )}
     </div>
   );

+ 61 - 50
src/client/mobile/pages/ClassroomPage.tsx

@@ -8,6 +8,9 @@ import { ClassroomProvider, useClassroomContext } from "@/client/mobile/componen
 import { TeacherView } from '@/client/mobile/components/Classroom/TeacherView';
 import { StudentView } from '@/client/mobile/components/Classroom/StudentView';
 import { ToastContainer } from 'react-toastify';
+import { Button } from '@/client/components/ui/button';
+import { Input } from '@/client/components/ui/input';
+import { Card, CardContent, CardHeader, CardTitle } from '@/client/components/ui/card';
 
 const RoleSelection = () => {
   const { setRole, login } = useClassroomContext();
@@ -21,20 +24,19 @@ const RoleSelection = () => {
     <div className="flex flex-col items-center justify-center h-full">
       <h2 className="text-2xl font-bold mb-8">请选择您的角色</h2>
       <div className="flex space-x-4">
-        <button
-          type="button"
+        <Button
           onClick={() => chooseRole(Role.Teacher)}
-          className="px-6 py-3 bg-blue-500 text-white rounded-lg hover:bg-blue-600 transition-colors"
+          className="px-6 py-3"
         >
           我是老师
-        </button>
-        <button
-          type="button"
+        </Button>
+        <Button
           onClick={() => chooseRole(Role.Student)}
-          className="px-6 py-3 bg-green-500 text-white rounded-lg hover:bg-green-600 transition-colors"
+          variant="secondary"
+          className="px-6 py-3"
         >
           我是学生
-        </button>
+        </Button>
       </div>
     </div>
   );
@@ -50,25 +52,27 @@ const JoinClassSection = () => {
   };
 
   return (
-    <div className="bg-white p-4 rounded shadow mb-4">
-      <h3 className="font-bold mb-2">加入课堂</h3>
-      <div className="flex space-x-2">
-        <input
-          type="text"
-          value={classId}
-          onChange={(e) => setClassId(e.target.value)}
-          placeholder="输入课堂ID"
-          className="flex-1 px-3 py-2 border rounded"
-        />
-        <button
-          type="button"
-          onClick={handleJoinClass}
-          className="px-4 py-2 bg-blue-500 text-white rounded"
-        >
-          加入课堂
-        </button>
-      </div>
-    </div>
+    <Card className="mb-4">
+      <CardHeader>
+        <CardTitle className="text-lg">加入课堂</CardTitle>
+      </CardHeader>
+      <CardContent>
+        <div className="flex space-x-2">
+          <Input
+            type="text"
+            value={classId}
+            onChange={(e) => setClassId(e.target.value)}
+            placeholder="输入课堂ID"
+            className="flex-1"
+          />
+          <Button
+            onClick={handleJoinClass}
+          >
+            加入课堂
+          </Button>
+        </div>
+      </CardContent>
+    </Card>
   );
 };
 
@@ -87,25 +91,28 @@ const CreateClassSection = () => {
   if (classStatus !== ClassStatus.NOT_STARTED) return null;
 
   return (
-    <div className="bg-white p-4 rounded shadow mb-4">
-      <h3 className="font-bold mb-2">创建新课堂</h3>
-      <div className="flex space-x-2">
-        <input
-          type="text"
-          value={className}
-          onChange={(e) => setClassName(e.target.value)}
-          placeholder="输入课堂名称"
-          className="flex-1 px-3 py-2 border rounded"
-        />
-        <button
-          type="button"
-          onClick={handleCreateClass}
-          className="px-4 py-2 bg-green-500 text-white rounded"
-        >
-          创建课堂
-        </button>
-      </div>
-    </div>
+    <Card className="mb-4">
+      <CardHeader>
+        <CardTitle className="text-lg">创建新课堂</CardTitle>
+      </CardHeader>
+      <CardContent>
+        <div className="flex space-x-2">
+          <Input
+            type="text"
+            value={className}
+            onChange={(e) => setClassName(e.target.value)}
+            placeholder="输入课堂名称"
+            className="flex-1"
+          />
+          <Button
+            onClick={handleCreateClass}
+            variant="secondary"
+          >
+            创建课堂
+          </Button>
+        </div>
+      </CardContent>
+    </Card>
   );
 };
 
@@ -176,10 +183,14 @@ const Classroom = () => {
 
   if (classStatus === ClassStatus.ENDED) {
     return (
-      <div className="text-center py-8">
-        <h2 className="text-xl font-bold">课堂已结束</h2>
-        <p>感谢参与本次课堂</p>
-      </div>
+      <Card className="text-center py-8">
+        <CardHeader>
+          <CardTitle className="text-xl">课堂已结束</CardTitle>
+        </CardHeader>
+        <CardContent>
+          <p>感谢参与本次课堂</p>
+        </CardContent>
+      </Card>
     );
   }