From b68006e32f7a1f90f1523dda0a033f3a84662d03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A6=BA=E7=8B=A8?= <18119604035@163.com> Date: Thu, 20 Apr 2023 09:36:22 +0800 Subject: [PATCH 01/14] =?UTF-8?q?=E7=99=BB=E5=BD=95=E8=B7=B3=E8=BD=AC?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=E7=BB=84=E4=BB=B6=E7=BC=93=E5=AD=98=E4=BC=98?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/login/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/login/index.tsx b/src/pages/login/index.tsx index b472b6b..5a7d043 100644 --- a/src/pages/login/index.tsx +++ b/src/pages/login/index.tsx @@ -86,7 +86,7 @@ const LoginPage: React.FC = () => { const data = res.data; dispatch(loginAction(data)); setLoading(false); - navigate("/"); + navigate("/", { replace: true }); }); }; From bebe5aa6f500bb84c35a70e3194bb19bf67637d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A6=BA=E7=8B=A8?= <18119604035@163.com> Date: Sun, 23 Apr 2023 09:34:30 +0800 Subject: [PATCH 02/14] =?UTF-8?q?=E6=9C=80=E8=BF=91=E5=AD=A6=E4=B9=A0?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2=E6=A0=B7=E5=BC=8F=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/latest-learn/index.tsx | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/pages/latest-learn/index.tsx b/src/pages/latest-learn/index.tsx index 6df6a91..412131e 100644 --- a/src/pages/latest-learn/index.tsx +++ b/src/pages/latest-learn/index.tsx @@ -55,13 +55,15 @@ const LatestLearnPage = () => { navigate(`/course/${item.course.id}`); }} > - +
+ +
{item.course.is_required === 1 && ( From 071061f895b5b41e40ca0207ba8f03deef949b43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A6=BA=E7=8B=A8?= <18119604035@163.com> Date: Sun, 23 Apr 2023 09:38:59 +0800 Subject: [PATCH 03/14] =?UTF-8?q?=E6=9C=80=E8=BF=91=E5=AD=A6=E4=B9=A0?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2=E6=A0=B7=E5=BC=8F=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/latest-learn/index.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/pages/latest-learn/index.tsx b/src/pages/latest-learn/index.tsx index 412131e..523f288 100644 --- a/src/pages/latest-learn/index.tsx +++ b/src/pages/latest-learn/index.tsx @@ -46,10 +46,9 @@ const LatestLearnPage = () => { {!loading && courses.length > 0 && courses.map((item: any) => ( - <> +
{item.course && (
{ navigate(`/course/${item.course.id}`); @@ -124,7 +123,7 @@ const LatestLearnPage = () => {
)} - +
))}
{systemConfig.pcIndexFooterMsg}
From f2e6da5329fd496a2d8b492eef9f74f0fe1c4da0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A6=BA=E7=8B=A8?= <18119604035@163.com> Date: Sun, 23 Apr 2023 09:55:24 +0800 Subject: [PATCH 04/14] =?UTF-8?q?=E8=A7=86=E9=A2=91=E6=92=AD=E6=94=BE?= =?UTF-8?q?=E7=AD=89=E6=AF=94=E4=BE=8B=E6=B5=8F=E8=A7=88=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/index.scss | 8 ++++---- src/pages/course/compenents/video.module.scss | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/index.scss b/src/index.scss index c37285b..b2dd0e6 100644 --- a/src/index.scss +++ b/src/index.scss @@ -50,7 +50,7 @@ body { height: auto; margin: 0 auto; display: flex; - flex-direction: column + flex-direction: column; } h1 { @@ -291,7 +291,7 @@ h1 { } #meedu-player-container { - width: 1200px; - height: 675px; - float: left; + width: 100%; + height: auto; + position: relative; } diff --git a/src/pages/course/compenents/video.module.scss b/src/pages/course/compenents/video.module.scss index 31d56aa..c9ebaff 100644 --- a/src/pages/course/compenents/video.module.scss +++ b/src/pages/course/compenents/video.module.scss @@ -42,7 +42,7 @@ } } .video-body { - width: 1200px; + width: 62.5%; height: auto; display: flex; flex-direction: column; @@ -51,7 +51,7 @@ margin-top: 60px; animation: scaleBig 0.3s; .video-title { - width: 1200px; + width: 100%; height: 36px; font-size: 20px; font-weight: 600; @@ -62,8 +62,8 @@ } .video-box { - width: 1200px; - height: 675px; + width: 100%; + padding-bottom: calc(9 / 16 * 100%); margin: 0 auto; border-radius: 8px; overflow: hidden; From 89ef2401cf12430ea5a539f233130caf70f458fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A6=BA=E7=8B=A8?= <18119604035@163.com> Date: Sun, 23 Apr 2023 10:36:04 +0800 Subject: [PATCH 05/14] =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E5=9B=BE=E7=89=87?= =?UTF-8?q?=E9=94=99=E8=AF=AF=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/compenents/header/index.module.scss | 4 +- src/compenents/user-info/index.tsx | 4 +- src/pages/login/index.module.scss | 108 +++++++++++++----------- src/utils/index.ts | 9 ++ 4 files changed, 70 insertions(+), 55 deletions(-) diff --git a/src/compenents/header/index.module.scss b/src/compenents/header/index.module.scss index 6d3956d..3fb38e2 100644 --- a/src/compenents/header/index.module.scss +++ b/src/compenents/header/index.module.scss @@ -29,7 +29,7 @@ display: flex; align-items: center; .nav-item { - width: 64px; + width: auto; height: 40px; font-size: 16px; font-weight: 400; @@ -47,7 +47,7 @@ } .nav-active-item { - width: 64px; + width: auto; height: 40px; font-size: 16px; font-weight: 600; diff --git a/src/compenents/user-info/index.tsx b/src/compenents/user-info/index.tsx index 22dc743..50fa17b 100644 --- a/src/compenents/user-info/index.tsx +++ b/src/compenents/user-info/index.tsx @@ -6,7 +6,7 @@ import { useDispatch } from "react-redux"; import { loginAction } from "../../store/user/loginUserSlice"; import type { UploadProps } from "antd"; import config from "../../js/config"; -import { getToken } from "../../utils/index"; +import { getToken, changeAppUrl } from "../../utils/index"; interface PropInterface { open: boolean; @@ -40,7 +40,7 @@ export const UserInfoModel: React.FC = ({ open, onCancel }) => { name: "file", multiple: false, method: "PUT", - action: config.app_url + "api/v1/user/avatar", + action: changeAppUrl(config.app_url) + "api/v1/user/avatar", headers: { Accept: "application/json", authorization: "Bearer " + getToken(), diff --git a/src/pages/login/index.module.scss b/src/pages/login/index.module.scss index 7da7581..48cd192 100644 --- a/src/pages/login/index.module.scss +++ b/src/pages/login/index.module.scss @@ -7,65 +7,71 @@ display: flex; flex-direction: column; justify-content: space-between; - .title { - width: 120px; - height: auto; - font-size: 30px; - font-weight: 600; - color: #333333; - line-height: 30px; - border-bottom: 4px solid #ff4d4f; - box-sizing: border-box; - padding-bottom: 10px; - margin: 0 auto; - margin-top: 100px; - } - .login-box { - width: 1200px; - height: 366px; - background: #ffffff; + .top-content { + width: 100%; display: flex; - margin: 0 auto; - margin-top: 80px; - .left-box { - width: 595px; - height: 100%; + flex-direction: column; + align-items: flex-start; + .title { + min-width: 125px; + height: auto; + font-size: 30px; + font-weight: 600; + color: #333333; + line-height: 30px; + border-bottom: 4px solid #ff4d4f; box-sizing: border-box; - padding: 33px 60px; - .icon { - width: 475px; - height: 300px; - } + padding-bottom: 10px; + margin: 0 auto; + margin-top: 100px; } - .right-box { - width: 520px; - height: 100%; - box-sizing: border-box; - border-left: 1px solid #d8d8d8; - padding: 0px 60px; + .login-box { + width: 1200px; + height: 366px; + background: #ffffff; display: flex; - flex-direction: column; - .captcha-box { - width: 125px; - height: 54px; - margin-left: 15px; - border-radius: 8px; - background-color: rgba(#ff4d4f, 0.1); - display: flex; - - .catpcha-loading-box { - width: 125px; - height: 54px; - line-height: 54px; - text-align: center; + margin: 0 auto; + margin-top: 80px; + .left-box { + width: 595px; + height: 100%; + box-sizing: border-box; + padding: 33px 60px; + .icon { + width: 475px; + height: 300px; } - - .captcha { + } + .right-box { + width: 520px; + height: 100%; + box-sizing: border-box; + border-left: 1px solid #d8d8d8; + padding: 0px 60px; + display: flex; + flex-direction: column; + .captcha-box { width: 125px; height: 54px; - border: none; - cursor: pointer; + margin-left: 15px; border-radius: 8px; + background-color: rgba(#ff4d4f, 0.1); + display: flex; + + .catpcha-loading-box { + width: 125px; + height: 54px; + line-height: 54px; + text-align: center; + } + + .captcha { + width: 125px; + height: 54px; + border: none; + cursor: pointer; + border-radius: 8px; + } } } } diff --git a/src/utils/index.ts b/src/utils/index.ts index 52657e3..7a18b20 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -95,3 +95,12 @@ export function setDepName(token: string) { export function clearDepName() { window.localStorage.removeItem("playedu-frontend-depatmentName"); } + +export function changeAppUrl(str: string) { + let key = str.slice(str.length - 1); + if (key === "/") { + return str; + } else { + return str + "/"; + } +} From 09707c1fffb1db6cafe4efe1b5022e0be4a9ccb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A6=BA=E7=8B=A8?= <18119604035@163.com> Date: Sun, 23 Apr 2023 11:43:43 +0800 Subject: [PATCH 06/14] =?UTF-8?q?=E8=A7=86=E9=A2=91=E6=92=AD=E6=94=BE?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2=E9=87=8D=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/course.ts | 5 + src/pages/course/compenents/hour.tsx | 69 +----- src/pages/course/compenents/video.tsx | 169 -------------- src/pages/course/index.tsx | 24 -- .../course/{compenents => }/video.module.scss | 12 +- src/pages/course/video.tsx | 206 ++++++++++++++++++ src/pages/init/index.tsx | 7 +- src/pages/latest-learn/index.tsx | 4 +- src/routes/index.tsx | 7 +- 9 files changed, 229 insertions(+), 274 deletions(-) delete mode 100644 src/pages/course/compenents/video.tsx rename src/pages/course/{compenents => }/video.module.scss (94%) create mode 100644 src/pages/course/video.tsx diff --git a/src/api/course.ts b/src/api/course.ts index 603604c..53d62bf 100644 --- a/src/api/course.ts +++ b/src/api/course.ts @@ -5,6 +5,11 @@ export function detail(id: number) { return client.get(`/api/v1/course/${id}`, {}); } +// 线上课课时详情 +export function play(courseId: number, id: number) { + return client.get(`/api/v1/course/${courseId}/hour/${id}`, {}); +} + // 获取播放地址 export function playUrl(courseId: number, hourId: number) { return client.get(`/api/v1/course/${courseId}/hour/${hourId}/play`, {}); diff --git a/src/pages/course/compenents/hour.tsx b/src/pages/course/compenents/hour.tsx index 23be64b..02a30bf 100644 --- a/src/pages/course/compenents/hour.tsx +++ b/src/pages/course/compenents/hour.tsx @@ -1,8 +1,7 @@ -import React, { useState, useEffect } from "react"; +import React from "react"; import { useNavigate } from "react-router-dom"; import styles from "./hour.module.scss"; import { durationFormat } from "../../../utils/index"; -import { VideoModel } from "./video"; interface PropInterface { id: number; @@ -11,9 +10,6 @@ interface PropInterface { duration: number; record: any; progress: number; - totalHours: any; - records: any; - onChange: () => void; } export const HourCompenent: React.FC = ({ @@ -23,73 +19,14 @@ export const HourCompenent: React.FC = ({ duration, record, progress, - totalHours, - records, - onChange, }) => { - // const navigate = useNavigate(); - const [visible, setVisible] = useState(false); - const [currentId, setCurrentId] = useState(id); - const [currentTitle, setCurrentTitle] = useState(title); - const [isLastpage, setIsLastpage] = useState(false); - const [lastSeeDuration, setLastSeeDuration] = useState(0); - - useEffect(() => { - getData(); - }, [totalHours]); - - const getData = () => { - const index = totalHours.findIndex((i: any) => i.id === id); - if (index === totalHours.length - 1) { - setIsLastpage(true); - } - if (records[totalHours[index].id]) { - setLastSeeDuration(records[totalHours[index].id].finished_duration); - } - }; - - const goNextVideo = () => { - const index = totalHours.findIndex((i: any) => i.id === currentId); - if (index === totalHours.length - 1) { - setIsLastpage(true); - } else if (index < totalHours.length - 1) { - setCurrentId(totalHours[index + 1].id); - setCurrentTitle(totalHours[index + 1].title); - if (index + 1 === totalHours.length - 1) { - setIsLastpage(true); - } - if (records[totalHours[index + 1].id]) { - setLastSeeDuration(records[totalHours[index + 1].id].finished_duration); - } - } - setVisible(true); - }; - + const navigate = useNavigate(); return ( <> - { - setVisible(false); - onChange(); - }} - goNextVideo={() => { - setVisible(false); - goNextVideo(); - }} - >
{ - setCurrentId(id); - setCurrentTitle(title); - setVisible(true); + navigate(`/course/${cid}/hour/${id}`); }} >
diff --git a/src/pages/course/compenents/video.tsx b/src/pages/course/compenents/video.tsx deleted file mode 100644 index fbd0930..0000000 --- a/src/pages/course/compenents/video.tsx +++ /dev/null @@ -1,169 +0,0 @@ -import React, { useState, useRef, useEffect } from "react"; -import styles from "./video.module.scss"; -import { course } from "../../../api/index"; -import { ArrowLeftOutlined } from "@ant-design/icons"; -import { useSelector } from "react-redux"; - -declare const window: any; - -interface PropInterface { - id: number; - cid: number; - title: string; - open: boolean; - isLastpage: boolean; - lastSeeDuration: number; - progress: number; - onCancel: () => void; - goNextVideo: () => void; -} - -export const VideoModel: React.FC = ({ - id, - cid, - title, - open, - isLastpage, - lastSeeDuration, - progress, - onCancel, - goNextVideo, -}) => { - const systemConfig = useSelector((state: any) => state.systemConfig.value); - const user = useSelector((state: any) => state.loginUser.value.user); - const [playUrl, setPlayUrl] = useState(""); - const [playDuration, setPlayDuration] = useState(0); - const [playendedStatus, setPlayendedStatus] = useState(false); - const [lastSeeValue, setLastSeeValue] = useState({}); - const [loading, setLoading] = useState(false); - const myRef = useRef(0); - - useEffect(() => { - let params = null; - if (open) { - if (lastSeeDuration > 0 && progress < 100) { - params = { - time: 5, - pos: lastSeeDuration, - }; - setLastSeeValue(params); - } - setPlayendedStatus(false); - getVideoUrl(params); - } - }, [open, id, cid, lastSeeDuration]); - - useEffect(() => { - myRef.current = playDuration; - }, [playDuration]); - - const getVideoUrl = (params: any) => { - course.playUrl(cid, id).then((res: any) => { - setPlayUrl(res.data.url); - initDPlayer(res.data.url, 0, params); - }); - }; - - const initDPlayer = (playUrl: string, isTrySee: number, params: any) => { - window.player = new window.DPlayer({ - container: document.getElementById("meedu-player-container"), - autoplay: false, - video: { - url: playUrl, - pic: systemConfig.playerPoster, - }, - try: isTrySee === 1, - bulletSecret: { - enabled: systemConfig.playerIsEnabledBulletSecret, - text: systemConfig.playerBulletSecretText - .replace("{name}", user.name) - .replace("{email}", user.email) - .replace("{idCard}", user.id_card), - size: "14px", - color: systemConfig.playerBulletSecretColor || "red", - opacity: Number(systemConfig.playerBulletSecretOpacity), - }, - ban_drag: false, - last_see_pos: params, - }); - // 监听播放进度更新evt - window.player.on("timeupdate", () => { - playTimeUpdate(parseInt(window.player.video.currentTime), false); - }); - window.player.on("ended", () => { - setPlayendedStatus(true); - playTimeUpdate(parseInt(window.player.video.currentTime), true); - window.player && window.player.destroy(); - }); - setLoading(false); - }; - - const playTimeUpdate = (duration: number, isEnd: boolean) => { - if (duration - myRef.current >= 10 || isEnd === true) { - setPlayDuration(duration); - course.record(cid, id, duration).then((res: any) => {}); - course.playPing(cid, id).then((res: any) => {}); - } - }; - - return ( - <> - {open && ( -
-
-
-
{ - window.player && window.player.destroy(); - onCancel(); - }} - > - - 返回 -
-
-
-
-
{title}
-
-
- {playendedStatus && ( -
- {isLastpage && ( -
{ - window.player && window.player.destroy(); - onCancel(); - }} - > - 恭喜你学完最后一节 -
- )} - {!isLastpage && ( -
{ - if (loading) { - return; - } - window.player && window.player.destroy(); - setLoading(true); - setLastSeeValue({}); - setPlayendedStatus(false); - goNextVideo(); - }} - > - 播放下一节 -
- )} -
- )} -
-
-
- )} - - ); -}; diff --git a/src/pages/course/index.tsx b/src/pages/course/index.tsx index 233da2d..220e1dd 100644 --- a/src/pages/course/index.tsx +++ b/src/pages/course/index.tsx @@ -15,7 +15,6 @@ const CoursePage = () => { const [hours, setHours] = useState({}); const [learnRecord, setLearnRecord] = useState({}); const [learnHourRecord, setLearnHourRecord] = useState({}); - const [totalHours, setTotalHours] = useState([]); useEffect(() => { getDetail(); @@ -35,17 +34,6 @@ const CoursePage = () => { if (res.data.learn_hour_records) { setLearnHourRecord(res.data.learn_hour_records); } - if (res.data.chapters.length === 0) { - setTotalHours(res.data.hours[0]); - } else if (res.data.chapters.length > 0) { - const arr: any = []; - for (let key in res.data.hours) { - res.data.hours[key].map((item: any) => { - arr.push(item); - }); - } - setTotalHours(arr); - } setLoading(false); }) .catch((e) => { @@ -159,14 +147,11 @@ const CoursePage = () => { cid={item.course_id} title={item.title} record={learnHourRecord[item.id]} - records={learnHourRecord} duration={item.duration} progress={ (learnHourRecord[item.id].finished_duration * 100) / learnHourRecord[item.id].total_duration } - totalHours={totalHours} - onChange={() => getDetail()} > )} {!learnHourRecord[item.id] && ( @@ -175,11 +160,8 @@ const CoursePage = () => { cid={item.course_id} title={item.title} record={null} - records={learnHourRecord} duration={item.duration} progress={0} - totalHours={totalHours} - onChange={() => getDetail()} > )}
@@ -199,14 +181,11 @@ const CoursePage = () => { cid={item.course_id} title={it.title} record={learnHourRecord[it.id]} - records={learnHourRecord} duration={it.duration} progress={ (learnHourRecord[it.id].finished_duration * 100) / learnHourRecord[it.id].total_duration } - onChange={() => getDetail()} - totalHours={totalHours} > )} {!learnHourRecord[it.id] && ( @@ -215,11 +194,8 @@ const CoursePage = () => { cid={item.course_id} title={it.title} record={null} - records={learnHourRecord} duration={it.duration} progress={0} - totalHours={totalHours} - onChange={() => getDetail()} > )}
diff --git a/src/pages/course/compenents/video.module.scss b/src/pages/course/video.module.scss similarity index 94% rename from src/pages/course/compenents/video.module.scss rename to src/pages/course/video.module.scss index c9ebaff..d94ee1f 100644 --- a/src/pages/course/compenents/video.module.scss +++ b/src/pages/course/video.module.scss @@ -1,15 +1,10 @@ .video-mask { width: 100%; - height: 100%; - top: 0; - bottom: 0; - left: 0; - right: 0; - position: fixed; + height: 100vh; + min-height: 100vh; background-color: #0e0e1e; display: flex; justify-content: center; - z-index: 100; .top-cont { position: fixed; top: 0; @@ -18,9 +13,8 @@ width: 100%; height: 60px; background: rgba(255, 255, 255, 0.1); - .box { - width: 1200px; + width: 62.5%; height: 60px; display: flex; align-items: center; diff --git a/src/pages/course/video.tsx b/src/pages/course/video.tsx new file mode 100644 index 0000000..a2c5df5 --- /dev/null +++ b/src/pages/course/video.tsx @@ -0,0 +1,206 @@ +import { useEffect, useRef, useState } from "react"; +import styles from "./video.module.scss"; +import { useParams, useNavigate } from "react-router-dom"; +import { useSelector } from "react-redux"; +import { course as Course } from "../../api/index"; +import { ArrowLeftOutlined } from "@ant-design/icons"; +import { message } from "antd"; + +declare const window: any; + +const CoursePalyPage = () => { + const navigate = useNavigate(); + const params = useParams(); + const systemConfig = useSelector((state: any) => state.systemConfig.value); + const user = useSelector((state: any) => state.loginUser.value.user); + const [playUrl, setPlayUrl] = useState(""); + const [playDuration, setPlayDuration] = useState(0); + const [playendedStatus, setPlayendedStatus] = useState(false); + const [lastSeeValue, setLastSeeValue] = useState({}); + const [course, setCourse] = useState({}); + const [hour, setHour] = useState({}); + const [loading, setLoading] = useState(false); + const [isLastpage, setIsLastpage] = useState(false); + const [totalHours, setTotalHours] = useState([]); + const myRef = useRef(0); + + useEffect(() => { + getCourse(); + getDetail(); + }, [params.courseId, params.hourId]); + + useEffect(() => { + myRef.current = playDuration; + }, [playDuration]); + + const getCourse = () => { + Course.detail(Number(params.courseId)).then((res: any) => { + let totalHours: any = []; + if (res.data.chapters.length === 0) { + setTotalHours(res.data.hours[0]); + totalHours = res.data.hours[0]; + } else if (res.data.chapters.length > 0) { + const arr: any = []; + for (let key in res.data.hours) { + res.data.hours[key].map((item: any) => { + arr.push(item); + }); + } + setTotalHours(arr); + totalHours = arr; + } + const index = totalHours.findIndex( + (i: any) => i.id === Number(params.hourId) + ); + if (index === totalHours.length - 1) { + setIsLastpage(true); + } + }); + }; + + const getDetail = () => { + if (loading) { + return true; + } + setLoading(true); + Course.play(Number(params.courseId), Number(params.hourId)) + .then((res: any) => { + setCourse(res.data.course); + setHour(res.data.hour); + document.title = res.data.hour.title; + let record = res.data.user_hour_record; + let params = null; + if (record && record.finished_duration && record.is_finished === 0) { + params = { + time: 5, + pos: record.finished_duration, + }; + setLastSeeValue(params); + setLastSeeValue(params); + } + getVideoUrl(params); + setLoading(false); + }) + .catch((e) => { + setLoading(false); + }); + }; + + const getVideoUrl = (data: any) => { + Course.playUrl(Number(params.courseId), Number(params.hourId)).then( + (res: any) => { + setPlayUrl(res.data.url); + initDPlayer(res.data.url, 0, data); + } + ); + }; + + const initDPlayer = (playUrl: string, isTrySee: number, params: any) => { + window.player = new window.DPlayer({ + container: document.getElementById("meedu-player-container"), + autoplay: false, + video: { + url: playUrl, + pic: systemConfig.playerPoster, + }, + try: isTrySee === 1, + bulletSecret: { + enabled: systemConfig.playerIsEnabledBulletSecret, + text: systemConfig.playerBulletSecretText + .replace("{name}", user.name) + .replace("{email}", user.email) + .replace("{idCard}", user.id_card), + size: "14px", + color: systemConfig.playerBulletSecretColor || "red", + opacity: Number(systemConfig.playerBulletSecretOpacity), + }, + ban_drag: false, + last_see_pos: params, + }); + // 监听播放进度更新evt + window.player.on("timeupdate", () => { + playTimeUpdate(parseInt(window.player.video.currentTime), false); + }); + window.player.on("ended", () => { + setPlayendedStatus(true); + playTimeUpdate(parseInt(window.player.video.currentTime), true); + window.player && window.player.destroy(); + }); + setLoading(false); + }; + + const playTimeUpdate = (duration: number, isEnd: boolean) => { + if (duration - myRef.current >= 10 || isEnd === true) { + setPlayDuration(duration); + Course.record( + Number(params.courseId), + Number(params.hourId), + duration + ).then((res: any) => {}); + Course.playPing(Number(params.courseId), Number(params.hourId)).then( + (res: any) => {} + ); + } + }; + + const goNextVideo = () => { + const index = totalHours.findIndex( + (i: any) => i.id === Number(params.hourId) + ); + if (index === totalHours.length - 1) { + setIsLastpage(true); + message.error("已经是最后一节了!"); + } else if (index < totalHours.length - 1) { + navigate(`/course/${params.courseId}/hour/${totalHours[index + 1].id}`, { + replace: true, + }); + } + }; + + return ( +
+
+
+
{ + window.player && window.player.destroy(); + navigate(-1); + }} + > + + 返回 +
+
+
+
+
{hour.title}
+
+
+ {playendedStatus && ( +
+ {isLastpage && ( +
恭喜你学完最后一节
+ )} + {!isLastpage && ( +
{ + window.player && window.player.destroy(); + setLastSeeValue({}); + setPlayendedStatus(false); + goNextVideo(); + }} + > + 播放下一节 +
+ )} +
+ )} +
+
+
+ ); +}; + +export default CoursePalyPage; diff --git a/src/pages/init/index.tsx b/src/pages/init/index.tsx index 7347448..de3d729 100644 --- a/src/pages/init/index.tsx +++ b/src/pages/init/index.tsx @@ -7,7 +7,7 @@ import { } from "../../store/system/systemConfigSlice"; import { loginAction } from "../../store/user/loginUserSlice"; import { Header, NoHeader, Footer } from "../../compenents"; -import { useLocation } from "react-router-dom"; +import { useParams, useLocation } from "react-router-dom"; interface Props { loginData?: any; @@ -44,14 +44,15 @@ export const InitPage = (props: Props) => { } const pathname = useLocation().pathname; + const params = useParams(); return ( <>
{pathname === "/login" && } - {pathname !== "/login" &&
} + {pathname !== "/login" && !params.hourId &&
} - {pathname !== "/login" &&
} + {pathname !== "/login" && !params.hourId &&
}
); diff --git a/src/pages/latest-learn/index.tsx b/src/pages/latest-learn/index.tsx index 523f288..c9f4010 100644 --- a/src/pages/latest-learn/index.tsx +++ b/src/pages/latest-learn/index.tsx @@ -45,8 +45,8 @@ const LatestLearnPage = () => { )} {!loading && courses.length > 0 && - courses.map((item: any) => ( -
+ courses.map((item: any, index: number) => ( +
{item.course && (
, }, + { + path: "/course/:courseId/hour/:hourId", + element: , + }, { path: "/latest-learn", element: , From 244bf68c6505b99f2c82ad6f72ac6e469f23ecb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A6=BA=E7=8B=A8?= <18119604035@163.com> Date: Tue, 25 Apr 2023 09:57:47 +0800 Subject: [PATCH 07/14] =?UTF-8?q?=E7=99=BB=E5=BD=95=E5=AD=A6=E5=91=98?= =?UTF-8?q?=E5=90=8E=E6=A3=80=E6=B5=8B=E9=83=A8=E9=97=A8=E9=80=BB=E8=BE=91?= =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/compenents/header/index.tsx | 3 +-- src/pages/course/video.module.scss | 1 - src/pages/init/index.tsx | 5 ++--- src/store/user/loginUserSlice.ts | 12 +++++++++++- 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/compenents/header/index.tsx b/src/compenents/header/index.tsx index 9c9bd77..3c47df9 100644 --- a/src/compenents/header/index.tsx +++ b/src/compenents/header/index.tsx @@ -73,8 +73,7 @@ export const Header: React.FC = () => { cancelText: "取消", onOk() { dispatch(logoutAction()); - clearToken(); - navigate("/login"); + navigate("/login", { replace: true }); }, onCancel() { console.log("Cancel"); diff --git a/src/pages/course/video.module.scss b/src/pages/course/video.module.scss index d94ee1f..e16947c 100644 --- a/src/pages/course/video.module.scss +++ b/src/pages/course/video.module.scss @@ -43,7 +43,6 @@ box-sizing: border-box; padding-top: 30px; margin-top: 60px; - animation: scaleBig 0.3s; .video-title { width: 100%; height: 36px; diff --git a/src/pages/init/index.tsx b/src/pages/init/index.tsx index de3d729..ea30b9a 100644 --- a/src/pages/init/index.tsx +++ b/src/pages/init/index.tsx @@ -15,6 +15,8 @@ interface Props { } export const InitPage = (props: Props) => { + const pathname = useLocation().pathname; + const params = useParams(); const dispatch = useDispatch(); if (props.loginData) { dispatch(loginAction(props.loginData)); @@ -43,9 +45,6 @@ export const InitPage = (props: Props) => { dispatch(saveConfigAction(config)); } - const pathname = useLocation().pathname; - const params = useParams(); - return ( <>
diff --git a/src/store/user/loginUserSlice.ts b/src/store/user/loginUserSlice.ts index 237e761..d75f83e 100644 --- a/src/store/user/loginUserSlice.ts +++ b/src/store/user/loginUserSlice.ts @@ -1,5 +1,11 @@ import { createSlice } from "@reduxjs/toolkit"; -import { getDepKey } from "../../utils/index"; +import { + getDepKey, + clearDepKey, + clearDepName, + setDepName, + clearToken, +} from "../../utils/index"; type UserStoreInterface = { user: null; @@ -27,6 +33,7 @@ const loginUserSlice = createSlice({ stage.value.isLogin = true; if (e.payload.departments.length > 0 && stage.value.currentDepId === 0) { stage.value.currentDepId = e.payload.departments[0].id; + setDepName(e.payload.departments[0].name); } }, logoutAction(stage) { @@ -34,6 +41,9 @@ const loginUserSlice = createSlice({ stage.value.departments = []; stage.value.isLogin = false; stage.value.currentDepId = 0; + clearToken(); + clearDepKey(); + clearDepName(); }, saveCurrentDepId(stage, e) { stage.value.currentDepId = e.payload; From ed016ce0a267e412ff6d1a222adef3dc85e47e9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A6=BA=E7=8B=A8?= <18119604035@163.com> Date: Tue, 25 Apr 2023 10:02:09 +0800 Subject: [PATCH 08/14] =?UTF-8?q?=E8=A7=86=E9=A2=91=E6=92=AD=E6=94=BE?= =?UTF-8?q?=E8=83=8C=E6=99=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.scss | 1 - src/pages/course/video.module.scss | 5 +++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/App.scss b/src/App.scss index a9c2cc8..210bd65 100644 --- a/src/App.scss +++ b/src/App.scss @@ -1,6 +1,5 @@ #root { width: 100%; - min-height: 900px; margin: 0 auto; text-align: center; background-color: #ffffff; diff --git a/src/pages/course/video.module.scss b/src/pages/course/video.module.scss index e16947c..dc6b942 100644 --- a/src/pages/course/video.module.scss +++ b/src/pages/course/video.module.scss @@ -1,6 +1,6 @@ .video-mask { width: 100%; - height: 100vh; + height: 100%; min-height: 100vh; background-color: #0e0e1e; display: flex; @@ -56,7 +56,8 @@ .video-box { width: 100%; - padding-bottom: calc(9 / 16 * 100%); + // padding-bottom: calc(9 / 16 * 100%); + height: auto; margin: 0 auto; border-radius: 8px; overflow: hidden; From 10d7630550e85e99a30a7e9b2176752e9494e011 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A6=BA=E7=8B=A8?= <18119604035@163.com> Date: Tue, 25 Apr 2023 10:06:06 +0800 Subject: [PATCH 09/14] =?UTF-8?q?=E8=BF=94=E5=9B=9E=E8=AF=A6=E6=83=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/course/video.module.scss | 1 - src/pages/course/video.tsx | 7 ++++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/pages/course/video.module.scss b/src/pages/course/video.module.scss index dc6b942..2ce65ee 100644 --- a/src/pages/course/video.module.scss +++ b/src/pages/course/video.module.scss @@ -60,7 +60,6 @@ height: auto; margin: 0 auto; border-radius: 8px; - overflow: hidden; position: relative; .alert-message { position: absolute; diff --git a/src/pages/course/video.tsx b/src/pages/course/video.tsx index a2c5df5..05f938e 100644 --- a/src/pages/course/video.tsx +++ b/src/pages/course/video.tsx @@ -180,7 +180,12 @@ const CoursePalyPage = () => { {playendedStatus && (
{isLastpage && ( -
恭喜你学完最后一节
+
navigate(`/course/${params.courseId}`)} + > + 恭喜你学完最后一节 +
)} {!isLastpage && (
Date: Tue, 25 Apr 2023 10:30:36 +0800 Subject: [PATCH 10/14] =?UTF-8?q?=E9=A6=96=E9=A1=B5=E5=AD=A6=E4=B9=A0?= =?UTF-8?q?=E8=BF=9B=E5=BA=A6=E6=98=BE=E7=A4=BA=E9=80=BB=E8=BE=91=E4=BC=98?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/index/compenents/courses-model.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/index/compenents/courses-model.tsx b/src/pages/index/compenents/courses-model.tsx index 614ebca..cf8ac7e 100644 --- a/src/pages/index/compenents/courses-model.tsx +++ b/src/pages/index/compenents/courses-model.tsx @@ -63,7 +63,7 @@ export const CoursesModel: React.FC = ({ trailColor="#F6F6F6" /> )} - {progress === 100 && ( + {progress >= 100 && (
恭喜你学完此课程! From 8a991f3f31092816eb0c5a62b563479c35b20859 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A6=BA=E7=8B=A8?= <18119604035@163.com> Date: Tue, 25 Apr 2023 10:52:20 +0800 Subject: [PATCH 11/14] =?UTF-8?q?=E8=A7=86=E9=A2=91=E6=92=AD=E6=94=BE?= =?UTF-8?q?=E7=BB=93=E6=9D=9F=E6=A0=B7=E5=BC=8F=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/course/video.module.scss | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/pages/course/video.module.scss b/src/pages/course/video.module.scss index 2ce65ee..c3a07e1 100644 --- a/src/pages/course/video.module.scss +++ b/src/pages/course/video.module.scss @@ -56,8 +56,7 @@ .video-box { width: 100%; - // padding-bottom: calc(9 / 16 * 100%); - height: auto; + padding-bottom: calc(9 / 16 * 100%); margin: 0 auto; border-radius: 8px; position: relative; From 4db0331df5b96c399edb748d05474ed2a61a0bf1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A6=BA=E7=8B=A8?= <18119604035@163.com> Date: Tue, 25 Apr 2023 11:33:28 +0800 Subject: [PATCH 12/14] =?UTF-8?q?=E9=A6=96=E9=A1=B5=E6=A0=87=E9=A2=98?= =?UTF-8?q?=E8=AE=BE=E7=BD=AE=E5=90=8E=E5=8F=B0=E6=A0=87=E9=A2=98=E6=95=B0?= =?UTF-8?q?=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/index/index.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/pages/index/index.tsx b/src/pages/index/index.tsx index 5fb956b..377e284 100644 --- a/src/pages/index/index.tsx +++ b/src/pages/index/index.tsx @@ -12,7 +12,6 @@ import iconRoute from "../../assets/images/commen/icon-route.png"; import { studyTimeFormat } from "../../utils/index"; const IndexPage = () => { - document.title = "首页"; const systemConfig = useSelector((state: any) => state.systemConfig.value); const [loading, setLoading] = useState(false); const [tabKey, setTabKey] = useState(0); @@ -36,7 +35,7 @@ const IndexPage = () => { }, [tabKey, currentDepId]); useEffect(() => { - document.title = systemConfig.systemName; + document.title = systemConfig.systemName || "首页"; }, [systemConfig]); const getData = () => { From 43854d14d6ec33a95c47802f762ffee2654bb9fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A6=BA=E7=8B=A8?= <18119604035@163.com> Date: Tue, 25 Apr 2023 17:40:30 +0800 Subject: [PATCH 13/14] =?UTF-8?q?=E7=99=BB=E5=BD=95=E5=88=B7=E6=96=B0?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/init/index.tsx | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/src/pages/init/index.tsx b/src/pages/init/index.tsx index ea30b9a..fd76a09 100644 --- a/src/pages/init/index.tsx +++ b/src/pages/init/index.tsx @@ -1,3 +1,4 @@ +import { useState, useEffect } from "react"; import { useDispatch } from "react-redux"; import { Outlet } from "react-router-dom"; // import styles from "./index.module.scss"; @@ -18,6 +19,9 @@ export const InitPage = (props: Props) => { const pathname = useLocation().pathname; const params = useParams(); const dispatch = useDispatch(); + const [showHeader, setShowHeader] = useState(true); + const [showNoHeader, setShowNoHeader] = useState(false); + const [showFooter, setShowFooter] = useState(true); if (props.loginData) { dispatch(loginAction(props.loginData)); } @@ -45,13 +49,32 @@ export const InitPage = (props: Props) => { dispatch(saveConfigAction(config)); } + useEffect(() => { + setShowHeader(true); + setShowNoHeader(false); + setShowFooter(true); + if (pathname === "/login") { + setShowNoHeader(true); + setShowHeader(false); + setShowFooter(false); + } else if (!params.hourId) { + setShowNoHeader(false); + setShowHeader(true); + setShowFooter(true); + } else { + setShowNoHeader(false); + setShowHeader(false); + setShowFooter(false); + } + }, [pathname, params]); + return ( <>
- {pathname === "/login" && } - {pathname !== "/login" && !params.hourId &&
} + {showNoHeader && } + {showHeader &&
} - {pathname !== "/login" && !params.hourId &&
} + {showFooter && }
); From f5ba28c435529ec52793d7b748fda1ee6c17dee3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A6=BA=E7=8B=A8?= <18119604035@163.com> Date: Wed, 26 Apr 2023 16:35:31 +0800 Subject: [PATCH 14/14] =?UTF-8?q?=E7=99=BB=E5=BD=95=E8=B4=A6=E5=8F=B7?= =?UTF-8?q?=E5=90=B9=E5=87=BA=E6=8A=A5=E9=94=99=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/compenents/header/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compenents/header/index.tsx b/src/compenents/header/index.tsx index 3c47df9..0608a7b 100644 --- a/src/compenents/header/index.tsx +++ b/src/compenents/header/index.tsx @@ -73,7 +73,7 @@ export const Header: React.FC = () => { cancelText: "取消", onOk() { dispatch(logoutAction()); - navigate("/login", { replace: true }); + window.location.href = "/login"; }, onCancel() { console.log("Cancel");