NeeDaye пре 6 месеци
родитељ
комит
e196c55adb

+ 157 - 40
src/layouts/SideMenu.tsx

@@ -1,11 +1,14 @@
-import React, { useState } from 'react';
-import { Button, Input, Space } from 'antd';
+import React, { useEffect, useState } from 'react';
+import { Button, Image, Input, Space } from 'antd';
 import { ReactComponent as SvgLogo } from '@/icons/logo.svg';
 
 
 import './styles/side-menu.less';
 import { SearchOutlined } from '@ant-design/icons';
 import ProList from '@ant-design/pro-list';
+import { history } from '@@/core/history';
+import CourseImage from '@/assets/img/course_image.png';
+import { useLocation } from '@@/exports';
 
 
 interface SideMenuProps {
@@ -16,8 +19,10 @@ interface SideMenuProps {
 function SideMenu  ({
     initWidth = 200,
 }: SideMenuProps) {
+  const location = useLocation();
+  const [isLessionPage, setIsLessionPage] = useState<boolean>(false);
   const [activeKey, setActiveKey] = useState<string | number>('');
-  const data = [
+  const teacherData = [
     {
       teacherName: '张三',
       schoolName: '清华大学',
@@ -41,6 +46,47 @@ function SideMenu  ({
     avatar: false,
   }));
 
+  const lessonData = [
+    {
+      lessonId: '1',
+      lessonName: '第一课第一节',
+      subjectName: '数学',
+      grade: '初一',
+      teachTime: '2025-05-01 10:00:00',
+    },
+    {
+      lessonId: '2',
+      lessonName: '第一课第一节',
+      subjectName: '数学',
+      grade: '初一',
+      teachTime: '2025-05-01 10:00:00',
+    },
+    {
+      lessonId: '3',
+      lessonName: '第一课第一节',
+      subjectName: '数学',
+      grade: '初一',
+      teachTime: '2025-05-01 10:00:00',
+    },
+    {
+      lessonId: '4',
+      lessonName: '第一课第一节',
+      subjectName: '数学',
+      grade: '初一',
+      teachTime: '2025-05-01 10:00:00',
+    },
+  ];
+
+  useEffect(() => {
+    if(location.pathname) {
+      if(location.pathname.includes('play')) {
+        setIsLessionPage(true);
+      } else {
+        setIsLessionPage(false);
+      }
+    }
+  }, [location.pathname]);
+
   return (
     <div style={{ width: initWidth, height: '100vh' }}>
       <div className="side-header">
@@ -48,45 +94,116 @@ function SideMenu  ({
         <h3 className="header-title-text">评审管理系统</h3>
       </div>
       <div className="side-search">
-        <div
-          style={{
-            color: 'black',
-            fontSize: 16,
-            fontWeight: 'bold',
-            margin: '20px 0 20px 10px',
-            textAlign: 'left',
-          }}
-        >
-          参评教师
-        </div>
-        <Space direction="horizontal" style={{ padding: '0 10px' }}>
-          <Input placeholder="输入教师姓名搜索" />
-          <Button icon={<SearchOutlined />} type="primary" />
-        </Space>
+        {
+          isLessionPage ?
+            (
+              <div>
+                <div
+                  style={{
+                    color: 'black',
+                    fontSize: 16,
+                    fontWeight: 'bold',
+                    margin: '20px 0 20px 10px',
+                    textAlign: 'left',
+                  }}
+                >
+                  张三
+                </div>
+                <Space direction="horizontal" style={{ padding: '0 10px' }}>
+                  <Input placeholder="输入课时名称搜索" />
+                  <Button icon={<SearchOutlined />} type="primary" />
+                </Space>
+              </div>) :
+              (
+                <div>
+                  <div
+                    style={{
+                      color: 'black',
+                      fontSize: 16,
+                      fontWeight: 'bold',
+                      margin: '20px 0 20px 10px',
+                      textAlign: 'left',
+                    }}
+                  >
+                    参评教师
+                  </div>
+                  <Space direction="horizontal" style={{ padding: '0 10px' }}>
+                    <Input placeholder="输入教师姓名搜索" />
+                    <Button icon={<SearchOutlined />} type="primary" />
+                  </Space>
+                </div>
+              )
+        }
       </div>
       <div className="menu-area">
-        <ProList<any>
-          pagination={false}
-          showActions="hover"
-          onItem={(record) => {
-            return {
-              onClick: () => {
-                setActiveKey(record.title);
-              },
-            };
-          }}
-          rowClassName={(record: { title: string }) =>
-            record.title === activeKey ? 'active' : ''
-          }
-          metas={{
-            title: {},
-            description: {
-              render: (text) => <div style={{ textAlign: 'left' }}>{text}</div>,
-            },
-            avatar: {},
-          }}
-          dataSource={data}
-        />
+        {
+          isLessionPage ? (
+            <ProList<any>
+              pagination={false}
+              showActions="hover"
+              onItem={(record) => {
+                return {
+                  onClick: () => {
+                    setActiveKey(record.lessonId);
+                  },
+                };
+              }}
+              rowClassName={(record: { lessonId: string }) =>
+                record.lessonId === activeKey ? 'active' : ''
+              }
+              renderItem={(item) => (
+                <div
+                  style={{ backgroundColor: '#F8FAFC', cursor: 'pointer', margin: '0 10px' }}
+                  onClick={() => {
+                    history.push('/play?id=' + item.lessonId);
+                  }}
+                >
+                  <Image
+                    width={'100%'}
+                    style={{ aspectRatio: '16/9', borderRadius: '15px 15px 0 0' }}
+                    preview={false}
+                    src={CourseImage}
+                  />
+                  <div className="course-info">
+                    <div style={{ fontWeight: 'bold', fontSize: '18px' }}>{item.lessonName}</div>
+                    <div className="info-flex">
+                      <div>{item.subjectName}</div>
+                      <div>所属年级:{item.grade}</div>
+                    </div>
+                    <div style={{ fontSize: '11px' }}>授课时间:{item.teachTime}</div>
+                  </div>
+                </div>
+              )}
+              metas={{
+                actions: {},
+              }}
+              dataSource={lessonData}
+            />
+            ) : (
+            <ProList<any>
+              pagination={false}
+              showActions="hover"
+              onItem={(record) => {
+                return {
+                  onClick: () => {
+                    setActiveKey(record.title);
+                  },
+                };
+              }}
+              rowClassName={(record: { title: string }) =>
+                record.title === activeKey ? 'active' : ''
+              }
+              metas={{
+                title: {},
+                description: {
+                  render: (text) => <div style={{ textAlign: 'left' }}>{text}</div>,
+                },
+                avatar: {},
+              }}
+              dataSource={teacherData}
+            />
+          )
+        }
       </div>
     </div>
   );

+ 9 - 0
src/layouts/styles/side-menu.less

@@ -44,6 +44,15 @@
             color: #3C82F6 !important;
         }
     }
+    .course-info {
+        padding: 10px;
+        text-align: left;
+        .info-flex {
+            display: flex;
+            justify-content: space-between;
+            margin-bottom: 5px;
+        }
+    }
 }
 .ant-menu-item-selected::before {
     content: ' ';

+ 48 - 41
src/pages/Play/components/Player.tsx

@@ -4,6 +4,7 @@ import './style/index.less';
 import { Button } from 'antd';
 
 interface VideoPlayerProps {
+  syncPlay: boolean;
   topVideoSrc: string;
   leftVideoSrc: string;
   rightVideoSrc: string;
@@ -11,6 +12,7 @@ interface VideoPlayerProps {
 }
 
 const VideoPlayer: React.FC<VideoPlayerProps> = ({
+   syncPlay,
    topVideoSrc,
    leftVideoSrc,
    rightVideoSrc,
@@ -131,30 +133,33 @@ const VideoPlayer: React.FC<VideoPlayerProps> = ({
         <div>
           <video
             ref={topVideoRef}
-            width="1150"
-            height="475"
-            style={{ objectFit: 'cover' }}
-            muted
+            width='1150'
+            height={isFullscreen ? '550' : '380'}
+            style={{ objectFit: 'contain',backgroundColor: 'black' }}
+            muted={syncPlay}
+            controls={!syncPlay}
           >
             <source src={topVideoSrc} type="video/mp4" />
           </video>
         </div>
-        <div style={{ display: 'flex', justifyContent: 'center', gap: 25 }}>
+        <div style={{ display: 'flex', justifyContent: 'center', gap: 10 }}>
           <video
             ref={leftVideoRef}
-            width={isFullscreen ? '640' : '565'}
-            height={isFullscreen ? '480' : '375'}
-            style={{ objectFit: 'cover' }}
-            muted
+            width={isFullscreen ? '650' : '570'}
+            height={isFullscreen ? '480' : '240'}
+            style={{ objectFit: 'contain',backgroundColor: 'black' }}
+            muted={syncPlay}
+            controls={!syncPlay}
           >
             <source src={leftVideoSrc} type="video/mp4" />
           </video>
           <video
             ref={rightVideoRef}
-            width={isFullscreen ? '640' : '565'}
-            height={isFullscreen ? '480' : '375'}
-            style={{ objectFit: 'cover' }}
-            muted
+            width={isFullscreen ? '650' : '570'}
+            height={isFullscreen ? '480' : '240'}
+            style={{ objectFit: 'contain',backgroundColor: 'black' }}
+            muted={syncPlay}
+            controls={!syncPlay}
           >
             <source src={rightVideoSrc} type="video/mp4" />
           </video>
@@ -164,36 +169,38 @@ const VideoPlayer: React.FC<VideoPlayerProps> = ({
       <audio ref={audioRef} src={audioSrc} />
 
       {/* 自定义控制器 */}
-      <div className="video-controls">
-        <Button onClick={togglePlay}>
-          {isPlaying ? '❚❚' : '▶'}
-        </Button>
-        <input
-          type="range"
-          min="0"
-          max={duration || 100}
-          value={currentTime}
-          onChange={handleSeek}
-          onMouseDown={handleSeekMouseDown}
-          onMouseUp={handleSeekMouseUp}
-          className="progress"
-        />
-        <span className="time-display">
+      {syncPlay && (
+        <div className="video-controls">
+          <Button onClick={togglePlay}>
+            {isPlaying ? '❚❚' : '▶'}
+          </Button>
+          <input
+            type="range"
+            min="0"
+            max={duration || 100}
+            value={currentTime}
+            onChange={handleSeek}
+            onMouseDown={handleSeekMouseDown}
+            onMouseUp={handleSeekMouseUp}
+            className="progress"
+          />
+          <span className="time-display">
            {formatTime(currentTime)} / {formatTime(duration)}
         </span>
-        <input
-          type="range"
-          min="0"
-          max="1"
-          step="0.01"
-          value={volume}
-          onChange={handleVolumeChange}
-          className="volume"
-        />
-        <Button onClick={toggleFullscreen}>
-          {isFullscreen ? '⤢' : '⤡'}
-        </Button>
-      </div>
+          <input
+            type="range"
+            min="0"
+            max="1"
+            step="0.01"
+            value={volume}
+            onChange={handleVolumeChange}
+            className="volume"
+          />
+          <Button onClick={toggleFullscreen}>
+            {isFullscreen ? '⤢' : '⤡'}
+          </Button>
+        </div>
+      )}
     </div>
   );
 };

+ 2 - 0
src/pages/Play/components/style/index.less

@@ -5,6 +5,8 @@ ideo-container {
 }
 
 .video-controls {
+  width: 80%;
+  margin: 0 auto;
   display: flex;
   align-items: center;
   padding: 10px;

+ 29 - 25
src/pages/Play/index.tsx

@@ -1,9 +1,9 @@
 import {
   PageContainer,
 } from '@ant-design/pro-components';
-import React from 'react';
+import React, { useState } from 'react';
 import './style/index.less';
-import { Card } from 'antd';
+import { Button, Card, Flex } from 'antd';
 import { ArrowLeftOutlined } from '@ant-design/icons';
 import dayjs from 'dayjs';
 import './style/index.less'
@@ -11,6 +11,7 @@ import VideoPlayer from '@/pages/Play/components/Player';
 // import ReactPlayer from 'react-player'
 
 const TableList: React.FC<unknown> = () => {
+  const [selected, setSelected] = useState<string>('sync');
   return (
     <PageContainer className="play-page-box">
       <Card style={{ marginInline: 20, marginTop: 10 }}>
@@ -35,30 +36,33 @@ const TableList: React.FC<unknown> = () => {
           </div>
         </div>
       </Card>
-      <Card style={{ marginInline: 20, marginTop: 10 }}>
+      <Card className={'video-box'} style={{ marginInline: 20, marginTop: 10 }}>
         <div style={{ display: 'flex' }}>
-          <div>左侧切换播放模式</div>
-          {/*<div style={{ flex: 1, display: 'flex', flexDirection: 'column' }}>*/}
-          {/*  <div>*/}
-          {/*    <video width="1150" height="475" style={{ objectFit: 'cover' }} autoPlay>*/}
-          {/*      <source src="http://player.alicdn.com/video/aliyunmedia.mp4" type="video/ogg" />*/}
-          {/*    </video>*/}
-          {/*  </div>*/}
-          {/*  <div style={{ display: 'flex', justifyContent:'center', gap: 25 }}>*/}
-          {/*    <video width="565" height="375" style={{ objectFit: 'cover' }} autoPlay>*/}
-          {/*      <source src="http://player.alicdn.com/video/aliyunmedia.mp4" type="video/ogg" />*/}
-          {/*    </video>*/}
-          {/*    <video width="565" height="375" style={{ objectFit: 'cover' }} autoPlay>*/}
-          {/*      <source src="http://player.alicdn.com/video/aliyunmedia.mp4" type="video/ogg" />*/}
-          {/*    </video>*/}
-          {/*  </div>*/}
-          {/*</div>*/}
-          <VideoPlayer
-            topVideoSrc={'http://player.alicdn.com/video/aliyunmedia.mp4'}
-            leftVideoSrc={'http://player.alicdn.com/video/aliyunmedia.mp4'}
-            rightVideoSrc={'http://player.alicdn.com/video/aliyunmedia.mp4'}
-            audioSrc={''}
-          />
+          <Flex vertical gap={10}>
+            <Button
+              color={selected === 'sync' ? "primary" : "default"}
+              variant={selected === 'sync' ? "solid" : "filled"}
+              onClick={() => setSelected('sync')}
+            >
+              同步播放
+            </Button>
+            <Button
+              color={selected === 'single' ? "primary" : "default"}
+              variant={selected === 'single' ? "solid" : "filled"}
+              onClick={() => setSelected('single')}
+            >
+              单路播放
+            </Button>
+          </Flex>
+          <div style={{ flex: 1 }}>
+            <VideoPlayer
+              syncPlay={selected === 'sync'}
+              topVideoSrc={'http://player.alicdn.com/video/aliyunmedia.mp4'}
+              leftVideoSrc={'http://player.alicdn.com/video/aliyunmedia.mp4'}
+              rightVideoSrc={'http://player.alicdn.com/video/aliyunmedia.mp4'}
+              audioSrc={''}
+            />
+          </div>
         </div>
       </Card>
     </PageContainer>

+ 4 - 0
src/pages/Play/style/index.less

@@ -9,4 +9,8 @@
       justify-content: space-between;
     }
   }
+  .video-box {
+    height: calc(100vh - 185px);
+    overflow: auto;
+  }
 }

+ 1 - 0
src/pages/Record/style/index.less

@@ -1,5 +1,6 @@
 .course-info {
   padding: 10px;
+  text-align: left;
   .info-flex {
     display: flex;
     justify-content: space-between;