gavin.chen 1 year ago
parent
commit
9d84319617

+ 25 - 0
.vscode/launch.json

@@ -0,0 +1,25 @@
+{
+  "version": "0.2.0",
+  "configurations": [
+    {
+      "type": "node",
+      "request": "launch",
+      "name": "启动React项目",
+      "runtimeExecutable": "npm",
+      "runtimeArgs": ["run-script", "start"]
+    },
+    {
+      "type": "chrome",
+      "request": "launch",
+      "name": "调试Chrome",
+      "url": "http://localhost:3000",
+      "webRoot": "${workspaceFolder}"
+    }
+  ],
+  "compounds": [
+    {
+      "name": "Launch Next Dev Server and Chrome",
+      "configurations": ["启动React项目", "调试Chrome"]
+    }
+  ]
+}

+ 6 - 6
.vscode/settings.json

@@ -1,7 +1,7 @@
 {
-    "editor.detectIndentation": false,
-    "editor.tabSize": 4,
-    "editor.formatOnPaste": true,
-    "editor.formatOnSave": true,
-    "editor.defaultFormatter": null
-}
+  "editor.detectIndentation": false,
+  "editor.tabSize": 2,
+  "editor.formatOnPaste": true,
+  "editor.formatOnSave": true,
+  "editor.defaultFormatter": null
+}

+ 1 - 7
src/app-pages/CourseAlbumAllListPage.jsx

@@ -1,23 +1,17 @@
 "use client";
 import React, { useState, useCallback, useEffect } from "react";
-import TopTabs from "../components/public/TopTabs";
 import Pagination from "../components/public/Pagination";
 import CoursesList from "../components/courses/CoursesList";
 import * as coursesAPI from "../apis/coursesAPI";
 import { useSessionStorage } from "react-use";
-import PopularCourses from "../components/courses/PopularCourses";
-import PopularCourseAlbums from "../components/courses/PopularCourseAlbums";
 import { useParams, useNavigate } from "react-router-dom";
-import { ConfigProvider, DatePicker, message } from "antd";
-import zhCN from "antd/locale/zh_CN";
 import { ArrowLeftIcon } from "@radix-ui/react-icons";
 
 // import * as Select from '@radix-ui/react-select';
 // import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from '@radix-ui/react-icons';
 export default function CourseAlbumAllListPage() {
-  const { token, subsetTab } = useParams();
+  const { subsetTab } = useParams();
 
-  const [kToken, setKToken] = useSessionStorage("token", token);
   const navigate = useNavigate();
 
   // 在浏览器会话缓存中存页面状态

+ 1 - 1
src/app-pages/CourseDetailPage.jsx

@@ -260,7 +260,7 @@ export default function CourseDetailPage() {
       <div className="flex mt-5 md:mt-0 justify-between md:justify-normal">
         {
           // 只有未报名并且不是付费课程的才有报名的按钮
-          courseData.SignCourseStatus === 2 && !courseData.NeedPay && courseData.TeacherCode !== sessionStorage.getItem('userCode')  && (
+          courseData.SignCourseStatus === 2 && !courseData.NeedPay && courseData.TeacherCode !== sessionStorage.getItem('userCode') && (
             <button
               className="flex-1 md:flex-none bg-blue-500 hover:bg-blue-700 text-white py-2 px-8 rounded mr-5"
               onClick={() => {

+ 1 - 3
src/app-pages/CreateAlbumPage.jsx

@@ -1,7 +1,5 @@
 import dayjs from "dayjs";
 import {
-  Button,
-  Space,
   Form,
   Input,
   InputNumber,
@@ -87,7 +85,7 @@ function CreateAlbum(param) {
       file.name || file.url.substring(file.url.lastIndexOf("/") + 1)
     );
   };
-  const handleRemove = () => {};
+  const handleRemove = () => { };
   const handleChange = async (info) => {
     console.log("%c Line:127 🥥 info", "color:#42b983", info);
     console.log(

+ 1 - 1
src/app-pages/CreateCoursePage.jsx

@@ -120,7 +120,7 @@ function CreateCourse(param) {
       file.name || file.url.substring(file.url.lastIndexOf("/") + 1)
     );
   };
-  const handleRemove = () => {};
+  const handleRemove = () => { };
   const handleChange = async (info) => {
     setLoading(false);
     if (isImage(info.file)) {

+ 2 - 2
src/app-pages/MyCoursePage.jsx

@@ -21,7 +21,7 @@ const CreateCourseModal = ({ isOpen, onRequestClose, code, qrCodeValue }) => {
   const handleCloseModal = () => {
     onRequestClose();
   };
-  useEffect(() => {}, [code]);
+  useEffect(() => { }, [code]);
   return (
     <AntdModal
       title={typeof code === "string" ? "编辑课程" : "创建课程"}
@@ -60,7 +60,7 @@ const CreateAlbumModal = ({ isOpen, onRequestClose, code, qrCodeValue }) => {
   const handleCloseModal = () => {
     onRequestClose();
   };
-  useEffect(() => {}, [code]);
+  useEffect(() => { }, [code]);
   return (
     <AntdModal
       title={typeof code === "string" ? "编辑专辑" : "创建专辑"}

+ 395 - 395
src/app-pages/VideoCoursePlayerPage.jsx

@@ -1,10 +1,10 @@
 import React, { useState, useCallback, useEffect, useRef } from "react";
 import Plyr from "plyr-react";
 import {
-    Worker,
-    Viewer,
-    ScrollMode,
-    LocalizationMap,
+  Worker,
+  Viewer,
+  ScrollMode,
+  LocalizationMap,
 } from "@react-pdf-viewer/core";
 import { defaultLayoutPlugin } from "@react-pdf-viewer/default-layout";
 import { bookmarkPlugin } from "@react-pdf-viewer/bookmark";
@@ -26,435 +26,435 @@ import Icon from "@ant-design/icons";
 import { findAllByDisplayValue } from "@testing-library/react";
 
 const OpenSoundIcon = () => (
-    <img
-        src={process.env.PUBLIC_URL + "/openSound.svg"}
-        className="text-white"
-        alt="开始声音"
-    />
+  <img
+    src={process.env.PUBLIC_URL + "/openSound.svg"}
+    className="text-white"
+    alt="开始声音"
+  />
 );
 const CloseSoundIcon = () => (
-    <img src={process.env.PUBLIC_URL + "/closeSound.svg"} alt="支付宝" />
+  <img src={process.env.PUBLIC_URL + "/closeSound.svg"} alt="支付宝" />
 );
 
 const MyVideoPlayer = ({ url }) => {
-    const divRef = useRef(null);
-    const [dimensions, setDimensions] = useState({ width: 0, height: 0 });
-    const [isMuted, setIsMuted] = useState(
-        sessionStorage.getItem("token") === "null" ? true : false
-    );
-    const [isFullScreen, setIsFullScreen] = useState(false);
-    const [player, setPlayer] = useState(null);
-    const [isLiveStreamNotStart, setIsLiveStreamNotStart] = useState(true);
+  const divRef = useRef(null);
+  const [dimensions, setDimensions] = useState({ width: 0, height: 0 });
+  const [isMuted, setIsMuted] = useState(
+    sessionStorage.getItem("token") === "null" ? true : false
+  );
+  const [isFullScreen, setIsFullScreen] = useState(false);
+  const [player, setPlayer] = useState(null);
+  const [isLiveStreamNotStart, setIsLiveStreamNotStart] = useState(true);
 
-    // 动态加载 NodePlayer.min.js 脚本
-    useEffect(() => {
-        const script = document.createElement("script");
-        script.src =
-            process.env.PUBLIC_URL + "/node_player/0.12.6/NodePlayer.min.js";
-        script.async = true;
+  // 动态加载 NodePlayer.min.js 脚本
+  useEffect(() => {
+    const script = document.createElement("script");
+    script.src =
+      process.env.PUBLIC_URL + "/node_player/0.12.6/NodePlayer.min.js";
+    script.async = true;
 
-        try {
-            // 检查 NodePlayer 是否加载成功
-            script.onload = async () => {
-                if (window.NodePlayer !== undefined) {
-                    await LivePlayer.init();
-                    var newPlayer = new LivePlayer("mian_canvas", url);
-                    newPlayer.onError = function (state) {
-                        setIsLiveStreamNotStart(true);
-                    };
+    try {
+      // 检查 NodePlayer 是否加载成功
+      script.onload = async () => {
+        if (window.NodePlayer !== undefined) {
+          await LivePlayer.init();
+          var newPlayer = new LivePlayer("mian_canvas", url);
+          newPlayer.onError = function (state) {
+            setIsLiveStreamNotStart(true);
+          };
 
-                    newPlayer.onPlay = function () {
-                        setIsLiveStreamNotStart(false);
-                    };
-                    setPlayer(newPlayer);
-                    newPlayer.play(true);
-                    function onResize() {
-                        if (divRef.current) {
-                            const width = divRef.current.clientWidth;
-                            const height = divRef.current.clientHeight;
-                            console.log("Div width:", width, "Div height:", height);
-                            newPlayer.setViewSize(width, height);
-                        }
-                    }
-                    if (divRef.current) {
-                        const resizeObserver = new ResizeObserver((entries) => {
-                            window.requestAnimationFrame(() => {
-                                for (let entry of entries) {
-                                    setDimensions({
-                                        width: entry.contentRect.width,
-                                        height: entry.contentRect.height,
-                                    });
-                                }
-                            });
-                        });
-                        resizeObserver.observe(divRef.current);
-                        // 在组件卸载时取消观察
-                        return () => {
-                            if (resizeObserver && divRef.current) {
-                                resizeObserver.unobserve(divRef.current);
-                            }
-                        };
-                    }
-                    onResize();
-                } else {
-                    console.log("NodePlayer failed to load");
+          newPlayer.onPlay = function () {
+            setIsLiveStreamNotStart(false);
+          };
+          setPlayer(newPlayer);
+          newPlayer.play(true);
+          function onResize() {
+            if (divRef.current) {
+              const width = divRef.current.clientWidth;
+              const height = divRef.current.clientHeight;
+              console.log("Div width:", width, "Div height:", height);
+              newPlayer.setViewSize(width, height);
+            }
+          }
+          if (divRef.current) {
+            const resizeObserver = new ResizeObserver((entries) => {
+              window.requestAnimationFrame(() => {
+                for (let entry of entries) {
+                  setDimensions({
+                    width: entry.contentRect.width,
+                    height: entry.contentRect.height,
+                  });
                 }
+              });
+            });
+            resizeObserver.observe(divRef.current);
+            // 在组件卸载时取消观察
+            return () => {
+              if (resizeObserver && divRef.current) {
+                resizeObserver.unobserve(divRef.current);
+              }
             };
-
-            document.head.appendChild(script);
-        } catch (err) {
-            console.log("%c Line:90 🥤 err", "color:#33a5ff", err);
+          }
+          onResize();
+        } else {
+          console.log("NodePlayer failed to load");
         }
+      };
 
-        return () => {
-            document.head.removeChild(script);
-        };
-    }, []);
-    if (player) {
-        player.onTimeout = function () {
-            var newPlayer = new LivePlayer("mian_canvas", url);
-
-            setIsLiveStreamNotStart(true);
-            setPlayer(newPlayer);
-            newPlayer.play(true);
-            newPlayer.onError = function (state) {
-                setIsLiveStreamNotStart(true);
-            };
-
-            newPlayer.onPlay = function () {
-                setIsLiveStreamNotStart(false);
-            };
-        };
+      document.head.appendChild(script);
+    } catch (err) {
+      console.log("%c Line:90 🥤 err", "color:#33a5ff", err);
     }
 
-    useEffect(() => { }, [isLiveStreamNotStart]);
-    const handleToggleMute = () => {
-        setIsMuted(!isMuted);
-        player.audioResume();
-        player.enableAudio(isMuted);
-        // event.stopPropagation()
+    return () => {
+      document.head.removeChild(script);
     };
+  }, []);
+  if (player) {
+    player.onTimeout = function () {
+      var newPlayer = new LivePlayer("mian_canvas", url);
 
-    const handleToggleFullScreen = () => {
-        setIsFullScreen(!isFullScreen);
-        const main = document.getElementById("node_player_video");
-        if (!isFullScreen) {
-            main.requestFullscreen();
-        } else {
-            document.exitFullscreen();
-        }
+      setIsLiveStreamNotStart(true);
+      setPlayer(newPlayer);
+      newPlayer.play(true);
+      newPlayer.onError = function (state) {
+        setIsLiveStreamNotStart(true);
+      };
+
+      newPlayer.onPlay = function () {
+        setIsLiveStreamNotStart(false);
+      };
     };
+  }
 
-    return (
-        <div id="node_player_video">
-            <div id="main">
-                <canvas
-                    id="mian_canvas"
-                    ref={divRef}
-                    style={{ resize: "both", overflow: "auto", backgroundColor: "black" }}
-                    className="h-full w-full"
-                ></canvas>
-                {isLiveStreamNotStart && (
-                    <div className="absolute inset-0 flex items-center justify-center ">
-                        <div className="text-white">直播未开始,请稍等</div>
-                    </div>
-                )}
-                {!isLiveStreamNotStart && (
-                    <div className="flex justify-end bg-black text-white">
-                        <button onClick={handleToggleMute} className="border-none p-1">
-                            {!isMuted ? (
-                                <img
-                                    src={process.env.PUBLIC_URL + "/openSound.svg"}
-                                    className="text-white w-10"
-                                    alt="开始声音"
-                                />
-                            ) : (
-                                <img
-                                    src={process.env.PUBLIC_URL + "/closeSound.svg"}
-                                    className="text-white w-10"
-                                    alt="关闭声音"
-                                />
-                            )}
-                        </button>
-                        <div className="w-5"></div>
-                        <button onClick={handleToggleFullScreen} className="border-none p-1">
-                            {isFullScreen ? (
-                                <img
-                                    src={process.env.PUBLIC_URL + "/cancelFullScreen.svg"}
-                                    className="text-white w-10"
-                                    alt="取消全屏"
-                                />
-                            ) : (
-                                <img
-                                    src={process.env.PUBLIC_URL + "/fullScreen.svg"}
-                                    className="text-white w-10"
-                                    alt="全屏"
-                                />
-                            )}
-                        </button>
-                    </div>
-                )}
-            </div>
-        </div>
-    );
-};
+  useEffect(() => { }, [isLiveStreamNotStart]);
+  const handleToggleMute = () => {
+    setIsMuted(!isMuted);
+    player.audioResume();
+    player.enableAudio(isMuted);
+    // event.stopPropagation()
+  };
 
-const VideoCoursePlayerPage = () => {
-    const { courseCode, currentPlatform, token } = useParams();
-    const [courseData, setcourseData] = useState(null);
-    const [courseFileUrl, setCourseFileUrl] = useState("");
-    const [isShowPdf, setShowPdf] = useState(true);
-    const [courseItems, setCourseItems] = useState([]);
-    if (token) {
-        sessionStorage.setItem("token", JSON.stringify(token));
+  const handleToggleFullScreen = () => {
+    setIsFullScreen(!isFullScreen);
+    const main = document.getElementById("node_player_video");
+    if (!isFullScreen) {
+      main.requestFullscreen();
     } else {
-        sessionStorage.setItem("token", null);
+      document.exitFullscreen();
     }
+  };
 
-    const [plyrProps, setPlyrProps] = useState({
-        source: {
-            type: "video",
-            title: "Example Video",
-            sources: [
-                {
-                    src: courseFileUrl,
-                    type: "video/mp4",
-                    size: 720,
-                },
-            ],
-        }, // https://github.com/sampotts/plyr#the-source-setter
-        options: {
-            playsinline: false,
-        }, // https://github.com/sampotts/plyr#options
-    });
-    //   const [courseCatalogData, setCourseCatalogData] = useState(null);
-
-    const [isShellWeb, setIsShellWeb] = useState(false);
-    const [currentTab, setCurrentTab] = useState("简介");
-    const [isAssistant, setIsAssistant] = useState(false);
-    const [tabsList, setTabsList] = useState(["简介", "资料"]);
-    const [isStartRecord, setIsStartRecord] = useState(true);
-    // 常量
+  return (
+    <div id="node_player_video">
+      <div id="main">
+        <canvas
+          id="mian_canvas"
+          ref={divRef}
+          style={{ resize: "both", overflow: "auto", backgroundColor: "black" }}
+          className="h-full w-full"
+        ></canvas>
+        {isLiveStreamNotStart && (
+          <div className="absolute inset-0 flex items-center justify-center ">
+            <div className="text-white">直播未开始,请稍等</div>
+          </div>
+        )}
+        {!isLiveStreamNotStart && (
+          <div className="flex justify-end bg-black text-white">
+            <button onClick={handleToggleMute} className="border-none p-1">
+              {!isMuted ? (
+                <img
+                  src={process.env.PUBLIC_URL + "/openSound.svg"}
+                  className="text-white w-10"
+                  alt="开始声音"
+                />
+              ) : (
+                <img
+                  src={process.env.PUBLIC_URL + "/closeSound.svg"}
+                  className="text-white w-10"
+                  alt="关闭声音"
+                />
+              )}
+            </button>
+            <div className="w-5"></div>
+            <button onClick={handleToggleFullScreen} className="border-none p-1">
+              {isFullScreen ? (
+                <img
+                  src={process.env.PUBLIC_URL + "/cancelFullScreen.svg"}
+                  className="text-white w-10"
+                  alt="取消全屏"
+                />
+              ) : (
+                <img
+                  src={process.env.PUBLIC_URL + "/fullScreen.svg"}
+                  className="text-white w-10"
+                  alt="全屏"
+                />
+              )}
+            </button>
+          </div>
+        )}
+      </div>
+    </div>
+  );
+};
 
-    // 数据获取:课程数据
-    const getCourseDeatil = useCallback(async () => {
-        const data = await coursesAPI.fetchCourseDetail(courseCode, "course");
-        setcourseData(data);
-        if (data.CourseType === 1) {
-            setCourseFileUrl(data.CourseChannel.HttpPullUrl);
-        } else {
-            setCourseFileUrl(data.DefaultVideoToken);
-        }
-        if (data.IsAssistant) {
-            setIsAssistant(true);
-        }
-        setCourseItems(data.CourseMaterials ?? []);
-    }, [courseCode]);
-    const getUserInfo = async () => {
+const VideoCoursePlayerPage = () => {
+  const { courseCode, currentPlatform, token } = useParams();
+  const [courseData, setcourseData] = useState(null);
+  const [courseFileUrl, setCourseFileUrl] = useState("");
+  const [isShowPdf, setShowPdf] = useState(true);
+  const [courseItems, setCourseItems] = useState([]);
+  if (token) {
+    sessionStorage.setItem("token", JSON.stringify(token));
+  } else {
+    sessionStorage.setItem("token", null);
+  }
 
-        if (sessionStorage.getItem("token") !== "null") {
-            console.log("%c Line:162 🥖 token", "color:#7f2b82", token);
-            const { UserCode } = await coursesAPI.getUserInfo();
-            sessionStorage.setItem("userCode", UserCode);
-        }
-    };
-    useEffect(() => {
-        getCourseDeatil();
-        getUserInfo();
-        if (isMobileDevice()) {
-            setTabsList(["简介", "资料", "讨论区"]);
-        }
-    }, [getCourseDeatil, courseCode]);
+  const [plyrProps, setPlyrProps] = useState({
+    source: {
+      type: "video",
+      title: "Example Video",
+      sources: [
+        {
+          src: courseFileUrl,
+          type: "video/mp4",
+          size: 720,
+        },
+      ],
+    }, // https://github.com/sampotts/plyr#the-source-setter
+    options: {
+      playsinline: false,
+    }, // https://github.com/sampotts/plyr#options
+  });
+  //   const [courseCatalogData, setCourseCatalogData] = useState(null);
 
-    useEffect(() => {
-        console.log("%c Line:271 🥑 courseFileUrl", "color:#93c0a4", courseFileUrl);
-        setShowPdf(courseFileUrl.endsWith(".pdf"));
-        setPlyrProps({
-            source: {
-                type: "video",
-                title: "Example Video",
-                sources: [
-                    {
-                        src: courseFileUrl,
-                        type: "video/mp4",
-                        size: 720,
-                    },
-                ],
-            },
-            options: undefined,
-        });
+  const [isShellWeb, setIsShellWeb] = useState(false);
+  const [currentTab, setCurrentTab] = useState("简介");
+  const [isAssistant, setIsAssistant] = useState(false);
+  const [tabsList, setTabsList] = useState(["简介", "资料"]);
+  const [isStartRecord, setIsStartRecord] = useState(true);
+  // 常量
 
-    }, [courseFileUrl]);
+  // 数据获取:课程数据
+  const getCourseDeatil = useCallback(async () => {
+    const data = await coursesAPI.fetchCourseDetail(courseCode, "course");
+    setcourseData(data);
+    if (data.CourseType === 1) {
+      setCourseFileUrl(data.CourseChannel.HttpPullUrl);
+    } else {
+      setCourseFileUrl(data.DefaultVideoToken);
+    }
+    if (data.IsAssistant) {
+      setIsAssistant(true);
+    }
+    setCourseItems(data.CourseMaterials ?? []);
+  }, [courseCode]);
+  const getUserInfo = async () => {
 
-    useEffect(() => {
-        if (
-            currentPlatform === "FPlatformEnum.webOnWin" ||
-            currentPlatform === "FPlatformEnum.webOnMac"
-        ) {
-            setIsShellWeb(true);
-        } else {
-            setIsShellWeb(false);
-        }
-    }, [currentPlatform]);
+    if (sessionStorage.getItem("token") !== "null") {
+      console.log("%c Line:162 🥖 token", "color:#7f2b82", token);
+      const { UserCode } = await coursesAPI.getUserInfo();
+      sessionStorage.setItem("userCode", UserCode);
+    }
+  };
+  useEffect(() => {
+    getCourseDeatil();
+    getUserInfo();
+    if (isMobileDevice()) {
+      setTabsList(["简介", "资料", "讨论区"]);
+    }
+  }, [getCourseDeatil, courseCode]);
 
-    const defaultLayoutPluginInstance = defaultLayoutPlugin({});
-    const scrollModePluginInstance = scrollModePlugin({
-        scrollMode: ScrollMode.Page,
+  useEffect(() => {
+    console.log("%c Line:271 🥑 courseFileUrl", "color:#93c0a4", courseFileUrl);
+    setShowPdf(courseFileUrl.endsWith(".pdf"));
+    setPlyrProps({
+      source: {
+        type: "video",
+        title: "Example Video",
+        sources: [
+          {
+            src: courseFileUrl,
+            type: "video/mp4",
+            size: 720,
+          },
+        ],
+      },
+      options: undefined,
     });
 
-    const bookmarkPluginInstance = bookmarkPlugin();
-    const DisplayRemotePDF = () => {
-        return (
-            <Worker workerUrl={process.env.PUBLIC_URL + "/pdf.worker.min.js"} async>
-                <Viewer
-                    fileUrl={courseFileUrl}
-                    theme="dark"
-                    localization={zh_CN}
-                    plugins={[
-                        defaultLayoutPluginInstance,
-                        scrollModePluginInstance,
-                        bookmarkPluginInstance,
-                    ]}
-                    style={{ width: "100%" }}
-                />
-            </Worker>
-        );
-    };
-    // 交互事件
-    // 切换 Tab
-    const handleTabChange = (index) => {
-        console.log("Tab 切换至", tabsList[index]);
-        setCurrentTab(tabsList[index]);
-    };
-    const handleChildData = (data) => {
-        setCourseFileUrl(data);
-    };
+  }, [courseFileUrl]);
 
-    // 【课程列表】与【简介】Tab
-    const buildTopTabs = () => {
-        return (
-            <NomalTabs
-                className="w-100"
-                tabs={tabsList}
-                initTab={currentTab}
-                onChangeTab={handleTabChange}
-            ></NomalTabs>
-        );
-    };
-    const isMobileDevice = () => {
-        return (
-            typeof window.orientation !== "undefined" ||
-            navigator.userAgent.indexOf("IEMobile") !== -1
-        );
-    };
-    const startRecord = () => {
-        setIsStartRecord(false);
-        coursesAPI.sendCourseEntryNotice(`target=record?code=${courseData.Code}`);
-    };
-    const endRecord = () => {
-        setIsStartRecord(true);
-        coursesAPI.sendCourseEntryNotice(
-            `target=endRecord?code=${courseData.Code}`
-        );
-    };
+  useEffect(() => {
+    if (
+      currentPlatform === "FPlatformEnum.webOnWin" ||
+      currentPlatform === "FPlatformEnum.webOnMac"
+    ) {
+      setIsShellWeb(true);
+    } else {
+      setIsShellWeb(false);
+    }
+  }, [currentPlatform]);
 
-    // 内容主题区域,显示【课程列表】或【简介】
-    const buildContentArea = () => {
-        console.log("当前 Tab", currentTab);
-        if (currentTab === "简介") {
-            return (
-                <div className="flex-grow flex flex-col  bg-gray-50 rounded p-5">
-                    <div className="text-xl mb-2">课程简介</div>
-                    <div className="text-sm text-gray-600">
-                        {courseData == null || courseData.CourseIntro == null
-                            ? "暂无简介"
-                            : courseData.CourseIntro}
-                    </div>
-                </div>
-            );
-        } else if (currentTab === "讨论区") {
-            return (
-                <div className=" h-full">
-                    <InteractiveArea h5courseCode={courseCode} />
-                </div>
-            );
-        }
-        return (
-            <div className="flex flex-col  bg-gray-50 rounded">
-                <CourseInformation
-                    courseItems={courseItems}
-                    onChildData={handleChildData}
-                    currentPlatform={currentPlatform}
-                />
-            </div>
-        );
-    };
+  const defaultLayoutPluginInstance = defaultLayoutPlugin({});
+  const scrollModePluginInstance = scrollModePlugin({
+    scrollMode: ScrollMode.Page,
+  });
 
+  const bookmarkPluginInstance = bookmarkPlugin();
+  const DisplayRemotePDF = () => {
     return (
-        <main className="flex min-h-screen flex-col p-5 h-[100vh]">
-            <div className="flex-grow flex ">
-                {/* 视频播放器与PDF显示器 */}
-                <div className={`h-full ${isMobileDevice() ? "w-full" : "w-3/4"}`}>
-                    {(courseData === null || courseData.CourseType !== 1) && (
-                        <div>
-                            {isShowPdf && (
-                                <div className={`h-[70vh]`}>{DisplayRemotePDF()}</div>
-                            )}
-                            {!isShowPdf && (
-                                <div>
-                                    {" "}
-                                    <Plyr {...plyrProps} />{" "}
-                                </div>
-                            )}
-                        </div>
-                    )}
+      <Worker workerUrl={process.env.PUBLIC_URL + "/pdf.worker.min.js"} async>
+        <Viewer
+          fileUrl={courseFileUrl}
+          theme="dark"
+          localization={zh_CN}
+          plugins={[
+            defaultLayoutPluginInstance,
+            scrollModePluginInstance,
+            bookmarkPluginInstance,
+          ]}
+          style={{ width: "100%" }}
+        />
+      </Worker>
+    );
+  };
+  // 交互事件
+  // 切换 Tab
+  const handleTabChange = (index) => {
+    console.log("Tab 切换至", tabsList[index]);
+    setCurrentTab(tabsList[index]);
+  };
+  const handleChildData = (data) => {
+    setCourseFileUrl(data);
+  };
 
-                    {courseData != null && courseData.CourseType === 1 && (
-                        <div className="relative">
-                            <MyVideoPlayer url={courseFileUrl} />
-                            {/* 录制按钮 */}
-                            {/* isAssistant 后面加上 */}
-                            {isShellWeb && (
-                                <div className="absolute top-0 right-0 mt-2 mr-2 flex">
-                                    {isStartRecord && (
-                                        <button
-                                            className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded-full"
-                                            onClick={() => startRecord()}
-                                        >
-                                            开始录制
-                                        </button>
-                                    )}
-                                    {!isStartRecord && (
-                                        <button
-                                            className="bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 ml-2 rounded-full"
-                                            onClick={() => endRecord()}
-                                        >
-                                            结束录制
-                                        </button>
-                                    )}
-                                </div>
-                            )}
-                        </div>
-                    )}
-                    {/* 课程简介 */}
-                    <div
-                        className={`mt-2 flex flex-col flex-grow ${isMobileDevice() ? "w-[90vw]" : ""
-                            }`}
-                    >
-                        {buildTopTabs()}
-                        {buildContentArea()}
-                    </div>
+  // 【课程列表】与【简介】Tab
+  const buildTopTabs = () => {
+    return (
+      <NomalTabs
+        className="w-100"
+        tabs={tabsList}
+        initTab={currentTab}
+        onChangeTab={handleTabChange}
+      ></NomalTabs>
+    );
+  };
+  const isMobileDevice = () => {
+    return (
+      typeof window.orientation !== "undefined" ||
+      navigator.userAgent.indexOf("IEMobile") !== -1
+    );
+  };
+  const startRecord = () => {
+    setIsStartRecord(false);
+    coursesAPI.sendCourseEntryNotice(`target=record?code=${courseData.Code}`);
+  };
+  const endRecord = () => {
+    setIsStartRecord(true);
+    coursesAPI.sendCourseEntryNotice(
+      `target=endRecord?code=${courseData.Code}`
+    );
+  };
+
+  // 内容主题区域,显示【课程列表】或【简介】
+  const buildContentArea = () => {
+    console.log("当前 Tab", currentTab);
+    if (currentTab === "简介") {
+      return (
+        <div className="flex-grow flex flex-col  bg-gray-50 rounded p-5">
+          <div className="text-xl mb-2">课程简介</div>
+          <div className="text-sm text-gray-600">
+            {courseData == null || courseData.CourseIntro == null
+              ? "暂无简介"
+              : courseData.CourseIntro}
+          </div>
+        </div>
+      );
+    } else if (currentTab === "讨论区") {
+      return (
+        <div className=" h-full">
+          <InteractiveArea h5courseCode={courseCode} />
+        </div>
+      );
+    }
+    return (
+      <div className="flex flex-col  bg-gray-50 rounded">
+        <CourseInformation
+          courseItems={courseItems}
+          onChildData={handleChildData}
+          currentPlatform={currentPlatform}
+        />
+      </div>
+    );
+  };
+
+  return (
+    <main className="flex min-h-screen flex-col p-5 h-[100vh]">
+      <div className="flex-grow flex ">
+        {/* 视频播放器与PDF显示器 */}
+        <div className={`h-full ${isMobileDevice() ? "w-full" : "w-3/4"}`}>
+          {(courseData === null || courseData.CourseType !== 1) && (
+            <div>
+              {isShowPdf && (
+                <div className={`h-[70vh]`}>{DisplayRemotePDF()}</div>
+              )}
+              {!isShowPdf && (
+                <div>
+                  {" "}
+                  <Plyr {...plyrProps} />{" "}
                 </div>
+              )}
+            </div>
+          )}
 
-                {/* 互动交流区 */}
-                {!isMobileDevice() && (
-                    <div className="w-1/4 h-full">
-                        <InteractiveArea courseCode={courseCode} />
-                    </div>
-                )}
+          {courseData != null && courseData.CourseType === 1 && (
+            <div className="relative">
+              <MyVideoPlayer url={courseFileUrl} />
+              {/* 录制按钮 */}
+              {/* isAssistant 后面加上 */}
+              {isShellWeb && (
+                <div className="absolute top-0 right-0 mt-2 mr-2 flex">
+                  {isStartRecord && (
+                    <button
+                      className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded-full"
+                      onClick={() => startRecord()}
+                    >
+                      开始录制
+                    </button>
+                  )}
+                  {!isStartRecord && (
+                    <button
+                      className="bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 ml-2 rounded-full"
+                      onClick={() => endRecord()}
+                    >
+                      结束录制
+                    </button>
+                  )}
+                </div>
+              )}
             </div>
-        </main>
-    );
+          )}
+          {/* 课程简介 */}
+          <div
+            className={`mt-2 flex flex-col flex-grow ${isMobileDevice() ? "w-[90vw]" : ""
+              }`}
+          >
+            {buildTopTabs()}
+            {buildContentArea()}
+          </div>
+        </div>
+
+        {/* 互动交流区 */}
+        {!isMobileDevice() && (
+          <div className="w-1/4 h-full">
+            <InteractiveArea courseCode={courseCode} />
+          </div>
+        )}
+      </div>
+    </main>
+  );
 };
 
 export default VideoCoursePlayerPage;