|
@@ -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;
|