Browse Source

fix:优化

longyifan 6 months ago
parent
commit
c7a8921fd7

+ 1 - 0
.gitignore

@@ -13,3 +13,4 @@
 /.idea
 /package-lock.json
 .swc
+pnpm-lock.yaml

File diff suppressed because it is too large
+ 8519 - 7205
pnpm-lock.yaml


+ 6 - 2
src/app.ts

@@ -1,4 +1,5 @@
-import { history } from "@umijs/max";
+import { history, useModel } from "@umijs/max";
+
 
 // 运行时配置
 
@@ -34,11 +35,14 @@ export const request = {
 // 配置路由跳转
 export function onRouteChange({ location }: any) {
   const token = localStorage.getItem('token');
-
+  // 正确用法:解构 state 和 actions
+  
   // 未登录且不在登录页,跳转到登录页
   if (!token && (location.pathname !== '/login' && location.pathname !== '/login/callback' )) {
     history.push('/login?redirect=' + encodeURIComponent(location.pathname));
   }
+  if(location.pathname !== '/play') {
+  }
 
   // 已登录却访问登录页,跳转到首页
   if (token && location.pathname === '/login') {

+ 31 - 8
src/layouts/SideMenu.tsx

@@ -7,7 +7,7 @@ import './styles/side-menu.less';
 import { SearchOutlined } from '@ant-design/icons';
 import ProList from '@ant-design/pro-list';
 import { history } from '@@/core/history';
-import { useLocation } from '@@/exports';
+import { useLocation, useModel } from '@@/exports';
 import { getTeachers } from '@/services/side/SideController';
 import { getTeacherCourses } from '@/services/record/RecordController';
 import CourseImage from '@/assets/img/course_image.png';
@@ -33,7 +33,15 @@ function SideMenu  ({
   const [loading, setLoading] = useState(false);
   const [hasMore, setHasMore] = useState(true);
   const [page, setPage] = useState(1);
-
+  const {setCourseInfo,courseInfo} = useModel('global')
+  useEffect(() => {
+    const unlisten = history.listen((newLocation) => {
+      if (newLocation.location.pathname !== '/play') {
+        setCourseInfo(null)
+      }
+    });
+    return () => unlisten(); // 清理监听
+  }, []);
   async function getTeacherCourseList(current: number) {
     const searchParams = new URLSearchParams(location.search);
     setActiveCourseKey(searchParams.get('courseId') as string)
@@ -89,6 +97,11 @@ function SideMenu  ({
           setActiveKey(searchParams.get('teacherId') as string);
         } else {
           setActiveKey(data.data[0].teacherId as string)
+          setCourseInfo({
+            ...courseInfo,
+            teacherName: data.data[0].teacherName as string,
+            schoolName: data.data[0].schoolName as string
+          })
           localStorage.setItem('teacherName', data.data[0].teacherName as string)
           localStorage.setItem('schoolName', data.data[0].schoolName as string)
           history.push('/record?teacherId=' + data.data[0].teacherId);
@@ -194,7 +207,7 @@ function SideMenu  ({
               tableExtraRender={(_: any, list: any) => (
                 <div
                   ref={containerRef}
-                  style={{ height: 'calc(100vh - 170px)', overflow: 'auto', paddingRight: 30 }}
+                  style={{ height: 'calc(100vh - 170px)', overflow: 'auto' }}
                 >
                   {list.map((item: any) => (
                     <div
@@ -207,16 +220,23 @@ function SideMenu  ({
                       onClick={() => {
                         history.push(`/play?teacherId=${item.teacherId}&courseId=${item.id}`);
                         setActiveCourseKey(item.id);
+                        setCourseInfo({
+                          ...courseInfo,
+                          periodName: item.periodName,
+                          courseTitle: item.courseTitle,
+                          subjectName: item.subjectName,
+                          courseDate: `${item.courseDate.split(' ')[0]}(${item.lessonStartTime} ~ ${item.lessonEndTime})`
+                        })
                         localStorage.setItem('periodName', item.periodName);
                         localStorage.setItem('courseTitle', item.courseTitle);
                         localStorage.setItem('subjectName', item.subjectName);
-                        localStorage.setItem('courseDate', item.courseDate);
+                        localStorage.setItem('courseDate', `${item.courseDate.split(' ')[0]}(${item.lessonStartTime} ~ ${item.lessonEndTime})`);
                       }}
                       className={item.id === activeCourseKey ? 'course-active' : ''}
                     >
                       <Image
                         width={'100%'}
-                        style={{ aspectRatio: '16/9', borderRadius: '15px 15px 0 0' }}
+                        style={{ aspectRatio: '16/9', borderRadius: '10px 10px 0 0' }}
                         preview={false}
                         src={CourseImage}
                         // src={item.fullScreenOssUrl + '?x-oss-process=video/snapshot,t_0,f_jpg,w_800,h_450'}
@@ -224,10 +244,13 @@ function SideMenu  ({
                       <div className="course-info">
                         <div style={{ fontWeight: 'bold', fontSize: '18px' }}>{item.courseTitle}</div>
                         <div className="info-flex">
-                          <div>{item.subjectName}</div>
-                          <div>所属年级:{item.periodName}</div>
+                          <div>学科:{item.subjectName}</div>
+                          <div>班级:{`${item.periodName}${item.className}`}</div>
+                        </div>
+                        <div style={{ display: 'flex', justifyContent:'space-between', color: '#999999', fontSize: '12px' }}>
+                          <div>{`${item.courseDate.split(' ')[0]}`}</div>
+                          <div>{`${item.lessonStartTime} ~ ${item.lessonEndTime}`}</div>
                         </div>
-                        <div style={{ fontSize: '11px' }}>授课时间:{item.courseDate}</div>
                       </div>
                     </div>
                   ))}

+ 32 - 2
src/layouts/index.tsx

@@ -1,5 +1,5 @@
 import { CollaspedType } from '@/types/LayoutType';
-import { Outlet, useModel } from '@umijs/max';
+import { Outlet, useModel, history, useSearchParams } from '@umijs/max';
 import {Avatar, Layout, Popover} from 'antd';
 import { Header } from 'antd/es/layout/layout';
 import React, { useEffect, useState } from 'react';
@@ -7,6 +7,9 @@ import SideMenu from './SideMenu';
 import UserPopover from './UserPopContent';
 import './styles/index.less';
 import { UserInfoType } from '@/types/UserType';
+import { ArrowLeftOutlined } from '@ant-design/icons';
+import useUser from '@/models/global';
+
 const { Sider, Content } = Layout;
 
 const contentStyle: React.CSSProperties = {
@@ -31,7 +34,8 @@ const layoutStyle = {
 const App: React.FC = () => {
   const [menuWidth] = useState(CollaspedType.OPEN);
   const [userInfo, setUserInfo] = useState<UserInfoType>({ expertName: '', expertId: ''});
-
+  const {courseInfo} = useModel('global')
+  const [searchParams, setSearchParams] = useSearchParams();
   useEffect(() => {
     setUserInfo(JSON.parse(localStorage.getItem('userInfo') || '{}'))
   }, []);
@@ -45,6 +49,32 @@ const App: React.FC = () => {
       </Sider>
       <Layout>
         <Header className="app-header">
+          {
+            courseInfo && (
+              <div className='course-detail-title'>
+                <div className={'header-box'}>
+                  <div>
+                    <a
+                      onClick={() => {
+                        const teacherId = searchParams.get("teacherId")
+                        history.replace('/record?teacherId='+teacherId);
+                      }}
+                      style={{color: 'white', marginRight: '40px'}}
+                    >
+                      <ArrowLeftOutlined />
+                      课程播放
+                    </a>
+                  </div>
+                  <div className={'header-right-box'}>
+                    <div>授课学科: {courseInfo?.subjectName}</div>
+                    <div>课程主题: {courseInfo?.courseTitle}</div>
+                    <div>所属年级: {courseInfo?.periodName}</div>
+                    <div>授课时间: {courseInfo?.courseDate}</div>
+                  </div>
+                </div>
+              </div>
+            )
+          }
           <Popover placement="bottom" content={<UserPopover />}>
             <div className="header-user">
               <Avatar style={{ backgroundColor: '#fde3cf', color: '#f56a00' }}>

+ 16 - 2
src/layouts/styles/index.less

@@ -19,7 +19,7 @@
   padding: unset !important;
 }
 .page-box {
-  height: calc(100vh - 160px);
+  height: calc(100vh - 40px);
   display: flex;
   flex-direction: column;
 }
@@ -29,7 +29,7 @@
   padding: 10px 20px 20px;
   .ant-pro-card-body {
     .ant-spin-container {
-      height: calc(100vh - 360px);
+      height: calc(100vh - 280px);
       overflow: auto;
     }
     margin: 16px;
@@ -43,3 +43,17 @@
     }
   }
 }
+.course-detail-title {
+  flex: 1;
+}
+ .header-box {
+    display: flex;
+    .header-right-box {
+      padding: 0 20px;
+      flex: 1;
+      display: flex;
+      justify-content: space-between;
+      color: aliceblue;
+      
+    }
+  }

+ 2 - 1
src/layouts/styles/side-menu.less

@@ -46,7 +46,8 @@
     }
     .course-active {
         border: 2px solid #3C82F6;
-        border-radius: 18px;
+        border-radius: 12px;
+        box-sizing: border-box;
     }
     .course-info {
         padding: 10px;

+ 6 - 3
src/models/global.ts

@@ -3,17 +3,20 @@ import { DEFAULT_NAME } from '@/constants';
 import { UserInfoType } from '@/types/UserType';
 import { useState } from 'react';
 
-const useUser = () => {
+const useGlobal = () => {
   const [name, setName] = useState<string>(DEFAULT_NAME);
   const user = JSON.parse(localStorage.getItem('userInfo') || '{}');
   const userDataTemp = <UserInfoType>user
   const [userInfo, setUserInfo] = useState<UserInfoType>(userDataTemp);
+  const [courseInfo, setCourseInfo] = useState<any>(null)
   return {
     name,
     setName,
     userInfo,
-    setUserInfo
+    setUserInfo,
+    courseInfo,
+    setCourseInfo
   };
 };
 
-export default useUser;
+export default useGlobal;

+ 18 - 0
src/models/path.ts

@@ -0,0 +1,18 @@
+// src/models/path.ts
+export default {
+  namespace: 'path',
+  state: {
+    showInfo: false,  // 默认隐藏
+    infoContent: {},  // 显示的内容
+  },
+  reducers: {
+    // 更新显示状态
+    toggleInfo(state: any, { payload }: { payload: { show: boolean; content?: string } }) {
+      return {
+        ...state,
+        showInfo: payload.show,
+        infoContent: payload.content || state.infoContent,
+      };
+    },
+  },
+};

+ 1 - 1
src/pages/Login/index.tsx

@@ -7,7 +7,7 @@ const LoginPage: React.FC = () => {
   const navigate = useNavigate();
   return (
     <Flex style={{ height: '100vh' }} justify="center" align="center" gap="middle" vertical>
-      <h1>统一登录(甲方提供)</h1>
+      <h1>统一登录(没有测试账号,待提供)</h1>
       <Button
         style={{ width: "200px" }}
         color="primary"

+ 5 - 7
src/pages/Play/components/SyncPlayer.tsx

@@ -164,7 +164,7 @@ const SyncVideoPlayer: React.FC<SyncVideoPlayerProps> = ({
       setIsFullscreen(!!document.fullscreenElement);
     };
 
-    const handleKeyDown = (e) => {
+    const handleKeyDown = (e:any) => {
       if (e.key === 'Escape' && isFullscreen) {
         toggleFullscreen();
       }
@@ -192,9 +192,8 @@ const SyncVideoPlayer: React.FC<SyncVideoPlayerProps> = ({
           <video
             ref={topVideoRef}
             onEnded={togglePlay}
-            width={isFullscreen ? '1410' : '1210'}
-            height={isFullscreen ? '550' : '380'}
-            style={{ objectFit: 'contain',backgroundColor: 'grey' }}
+            
+            style={{ objectFit: 'contain',backgroundColor: 'grey', width:'100%', height: 'calc((100vh - (88px + 64px + 52px))/3 * 2)' }}
             muted
             controls={false}
             disablePictureInPicture
@@ -208,9 +207,8 @@ const SyncVideoPlayer: React.FC<SyncVideoPlayerProps> = ({
             <div key={pos} className="video-wrapper">
               <video
                 ref={pos === 'left' ? leftVideoRef : rightVideoRef}
-                width={isFullscreen ? '700' : '600'}
-                height={isFullscreen ? '420' : '240'}
-                style={{ objectFit: 'contain', backgroundColor: 'grey' }}
+                // width={isFullscreen ? '700' : '600'}
+                style={{ objectFit: 'contain', backgroundColor: 'grey',  width: '100%',height: 'calc((100vh - (88px + 64px + 52px))/3)' }}
                 muted
                 controls={false}
                 disablePictureInPicture

+ 4 - 23
src/pages/Play/index.tsx

@@ -41,29 +41,9 @@ const TableList: React.FC<unknown> = () => {
   return (
     <PageContainer className="play-page-box">
       <Card style={{ marginInline: 20, marginTop: 10 }}>
-        <div className={'header-box'}>
-          <div>
-            <a
-              onClick={() => {
-                history.go(-1);
-              }}
-            >
-              <ArrowLeftOutlined />
-              课程播放
-            </a>
-          </div>
-          <div className={'header-right-box'}>
-            <div>授课学科: {localStorage.getItem('subjectName')}</div>
-            <div>课程主题: {localStorage.getItem('courseTitle')}</div>
-            <div>所属学校: {localStorage.getItem('schoolName')}</div>
-            <div>所属年级: {localStorage.getItem('periodName')}</div>
-            <div>授课老师: {localStorage.getItem('teacherName')}</div>
-            <div>授课时间: {localStorage.getItem('courseDate')}</div>
-          </div>
-        </div>
-      </Card>
-      <Card className={'video-box'} style={{ marginInline: 20, marginTop: 10 }}>
-        { fullClassRoom ? (
+        
+        <div>
+           { fullClassRoom ? (
           <div style={{ display: 'flex' }}>
             <Flex vertical gap={10}>
               <Button
@@ -104,6 +84,7 @@ const TableList: React.FC<unknown> = () => {
             <h1>暂无视频资源</h1>
           </Flex>
         )}
+        </div>
       </Card>
     </PageContainer>
   );

+ 12 - 11
src/pages/Record/index.tsx

@@ -6,7 +6,7 @@ import ProList from '@ant-design/pro-list';
 import { Image, Tabs } from 'antd';
 import './style/index.less';
 import { history } from "@umijs/max";
-import { useLocation, useRouteProps } from '@@/exports';
+import { useLocation, useModel, useRouteProps } from '@@/exports';
 import { getExpertActives, getSelectSubject, getTeacherCourses } from '@/services/record/RecordController';
 import { ActionType } from '@ant-design/pro-table/lib';
 
@@ -20,7 +20,7 @@ const TableList: React.FC<unknown> = () => {
   const [gradeSubjects, setGradeSubjects] = useState<{ label: string, value: string }[]>([]);
   const [courseStart, setCourseStart] = useState<string>();
   const [courseEnd, setCourseEnd] = useState<string>();
-
+  const { setCourseInfo } = useModel("global")
   useEffect(() => {
     if(location.pathname) {
       setSelectedKeys(location.pathname);
@@ -64,12 +64,7 @@ const TableList: React.FC<unknown> = () => {
   }, []);
 
   return (
-    <PageContainer className="page-box">
-      <Tabs
-        tabBarStyle={{ backgroundColor: '#fff', padding: '5px 20px 0' }}
-        items={routeProps.custom}
-        defaultActiveKey={selectedKeys}
-      />
+    <PageContainer style={{height: 'calc(100vh - 20px)'}} className="page-box">
       <ProList<any>
         search={{}}
         actionRef={actionRef}
@@ -91,10 +86,16 @@ const TableList: React.FC<unknown> = () => {
             style={{ backgroundColor: '#F8FAFC', cursor: 'pointer' }}
             onClick={() => {
               history.push('/play?teacherId=' + teacherId + '&courseId=' + item.id);
+              setCourseInfo({
+                periodName: item.periodName,
+                courseTitle: item.courseTitle,
+                subjectName: item.subjectName,
+                courseDate: `${item.courseDate.split(' ')[0]}(${item.lessonStartTime} ~ ${item.lessonEndTime})`
+              })
               localStorage.setItem('periodName', item.periodName);
               localStorage.setItem('courseTitle', item.courseTitle);
               localStorage.setItem('subjectName', item.subjectName);
-              localStorage.setItem('courseDate', item.courseDate);
+              localStorage.setItem('courseDate', `${item.courseDate.split(' ')[0]}(${item.lessonStartTime} ~ ${item.lessonEndTime})`);
             }}
           >
             <Image
@@ -113,8 +114,8 @@ const TableList: React.FC<unknown> = () => {
                 <div>授课老师:{localStorage.getItem('teacherName')}</div>
               </div>
               <div className="info-flex">
-                <div>授课时间:{item.courseDate}</div>
-                <div>授课班级:{item.classroomName}</div>
+                <div>授课日期:{item.courseDate.split(' ')[0]}</div>
+                <div>授课班级:{`${item.periodName}${item.className}`}</div>
               </div>
             </div>
           </div>

+ 1 - 1
src/types/LayoutType.ts

@@ -1,5 +1,5 @@
 /** 菜单展开状态枚举 */
 export enum CollaspedType {
     CLOSE = 68,
-    OPEN = 226
+    OPEN = 266
 }