feat: 播放期

This commit is contained in:
mozzie 2023-03-02 15:28:02 +08:00
parent 57ff9c0356
commit d4a845c59c
7 changed files with 190 additions and 191 deletions

View File

@ -17,7 +17,8 @@
"@ricons/fluent": "0.12.0", "@ricons/fluent": "0.12.0",
"@ricons/utils": "0.1.6", "@ricons/utils": "0.1.6",
"dayjs": "1.11.7", "dayjs": "1.11.7",
"identicon": "3.1.1" "identicon": "3.1.1",
"react-perfect-scrollbar": "1.5.8"
}, },
"devDependencies": { "devDependencies": {
"@types/react": "^18.0.27", "@types/react": "^18.0.27",

View File

@ -0,0 +1,5 @@
function Material() {
return <div>1</div>;
}
export default Material;

View File

@ -37,18 +37,18 @@
} }
// 圆角 // 圆角
.vjs-poster, // .vjs-poster,
.video-js { // .video-js {
border-radius: 10px !important; // border-radius: 10px !important;
video { // video {
border-radius: 10px !important; // border-radius: 10px !important;
} // }
} // }
.video-js { // .video-js {
// box-shadow: 0 0 100px #c8c8c8 !important; // // box-shadow: 0 0 100px #c8c8c8 !important;
} // }
.vjs-control-bar { // .vjs-control-bar {
border-radius: 0 0 10px 10px !important; // border-radius: 0 0 10px 10px !important;
} // }

View File

@ -1,5 +1,5 @@
import { useEffect, useRef, useState } from "react"; import { useEffect, useRef, useState } from "react";
import { useScript } from "../../hook"; import { useScript } from "../../../../hook";
import "./index.less"; import "./index.less";
export interface IVideo { export interface IVideo {
@ -35,8 +35,9 @@ function Player(props: IProps) {
if (libReady) { if (libReady) {
const TCPlayer = (window as any).TCPlayer; const TCPlayer = (window as any).TCPlayer;
playerRef.current = TCPlayer("player", { playerRef.current = TCPlayer("player", {
fileID: "243791579995468466", // fileID: "243791579995468466",
appID: "1500018521", // appID: "1500018521",
...props.video,
plugins: { plugins: {
ContinuePlay: { ContinuePlay: {
auto: true, auto: true,

View File

@ -1,25 +1,8 @@
.course-detail { .course-detail {
padding-top: 60px; padding-top: 60px;
article {
padding: 20px 40px 0 0;
.player-container {
position: relative;
height: 360px;
&.float {
position: fixed !important;
left: 0;
top: 60px;
bottom: 0;
height: auto !important;
right: calc((100% - 1120px) / 2);
z-index: 20;
}
}
}
aside { aside {
padding-left: 20px; padding: 20px;
> h2 { > h2 {
margin-bottom: 10px; margin-bottom: 10px;
} }
@ -31,8 +14,17 @@
} }
.level-2 { .level-2 {
display: grid; display: grid;
padding-left: 10px;
line-height: 30px;
grid-template-columns: 9fr 1fr; grid-template-columns: 9fr 1fr;
color: var(--color-text-2); color: var(--color-text-2);
cursor: pointer;
&:hover {
color: var(--color-text-1);
}
&.active {
color: rgb(var(--primary-4));
}
.time { .time {
color: var(--color-text-4); color: var(--color-text-4);
text-align: right; text-align: right;
@ -40,4 +32,38 @@
} }
} }
} }
article {
position: relative;
height: 100%;
.mask {
position: absolute;
left: 0;
right: 0;
bottom: 0;
top: 0;
z-index: 30;
background: rgba(255, 255, 255, 1);
display: flex;
justify-content: center;
align-items: center;
}
> main {
height: 100%;
.player-container {
height: 100%;
position: relative;
overflow: hidden;
&.float {
position: fixed !important;
left: 0;
top: 60px;
bottom: 0;
height: auto !important;
right: calc((100% - 1120px) / 2);
z-index: 20;
}
}
}
}
} }

View File

@ -1,8 +1,12 @@
import { useState } from "react"; import { useEffect, useState } from "react";
import Player, { IVideo } from "../../components/Player";
import "./index.less"; import "./index.less";
import { ResizeBox, Space, Result, Button } from "@arco-design/web-react"; import { ResizeBox, Space, Result, Button, Spin } from "@arco-design/web-react";
import { Icon } from "@ricons/utils"; import { Icon } from "@ricons/utils";
import "react-perfect-scrollbar/dist/css/styles.css";
import PerfectScrollbar from "react-perfect-scrollbar";
import Player, { IVideo } from "./components/Player";
import Material from "./components/Material";
import { useMount } from "../../hook";
function CourseDetail() { function CourseDetail() {
const [toc, setToc] = useState([ const [toc, setToc] = useState([
@ -10,25 +14,25 @@ function CourseDetail() {
title: "准备", title: "准备",
level: 1, level: 1,
}, },
{
title: "资料下载",
level: 2,
active: false,
view: <Material />,
},
{ {
title: "学习 html, css, javascript 前的准备", title: "学习 html, css, javascript 前的准备",
level: 2, level: 2,
time: "3:23", time: "3:23",
get: false, active: false,
video: { video: { fileID: "243791579995468466", appID: "1500018521" },
fileID: "243791579995468466",
appID: "1500018521",
},
}, },
{ {
title: "css 样式的写法", title: "Vite + React + TS - Google Chrome 2023-02-15 09-55-08",
level: 2, level: 2,
time: "4:13", time: "4:13",
get: false, active: false,
video: { video: { fileID: "243791580097740418", appID: "1500018521" },
fileID: "243791580097740418",
appID: "1500018521",
},
}, },
{ {
title: "使用CSS", title: "使用CSS",
@ -38,138 +42,58 @@ function CourseDetail() {
title: "使用 css行内样式", title: "使用 css行内样式",
level: 2, level: 2,
time: "5:55", time: "5:55",
get: false, active: false,
}, },
{ {
title: "使用 css行内样式2", title: "使用 css行内样式2",
level: 2, level: 2,
time: "6:55", time: "6:55",
get: false, active: false,
},
{
title: "使用CSS",
level: 1,
},
{
title: "使用 css行内样式",
level: 2,
time: "5:55",
get: false,
},
{
title: "使用 css行内样式2",
level: 2,
time: "6:55",
get: false,
},
{
title: "使用CSS",
level: 1,
},
{
title: "使用 css行内样式",
level: 2,
time: "5:55",
get: false,
},
{
title: "使用 css行内样式2",
level: 2,
time: "6:55",
get: false,
},
{
title: "使用CSS",
level: 1,
},
{
title: "使用 css行内样式",
level: 2,
time: "5:55",
get: false,
},
{
title: "使用 css行内样式2",
level: 2,
time: "6:55",
get: false,
},
{
title: "使用CSS",
level: 1,
},
{
title: "使用 css行内样式",
level: 2,
time: "5:55",
get: false,
},
{
title: "使用 css行内样式2",
level: 2,
time: "6:55",
get: false,
},
{
title: "使用CSS",
level: 1,
},
{
title: "使用 css行内样式",
level: 2,
time: "5:55",
get: false,
},
{
title: "使用 css行内样式2",
level: 2,
time: "6:55",
get: false,
},
{
title: "使用CSS",
level: 1,
},
{
title: "使用 css行内样式",
level: 2,
time: "5:55",
get: false,
},
{
title: "使用 css行内样式2",
level: 2,
time: "6:55",
get: false,
}, },
]); ]);
const [spinVisible, setSpinVisible] = useState(false);
const [video, setVideo] = useState<IVideo | null>(null); const [video, setVideo] = useState<IVideo | null>(null);
const [view, setView] = useState<any>(null);
const onclickItem = (i: any) => { const notFound = (
setVideo(i.video);
};
return (
<div className="course-detail container">
<ResizeBox.Split
direction="horizontal"
style={{ height: "100vh" }}
// max={0.8}
// min={0.2}
size={0.6}
panes={[
<article>
<Result <Result
status="403" status="403"
subTitle="挖宝藏,请加入矿工" subTitle="挖宝藏,请加入矿工"
extra={<Button type="text"></Button>} extra={<Button type="text">1</Button>}
></Result> ></Result>
{/* <div className="player-container"> );
<Player video={video} />
</div> */} useMount(() => {
</article>, const first = toc.find((t) => t.level === 2) as any;
<aside className="bs-scrollbar"> setToc((p: any) =>
p.map((i: any) => ({ ...i, active: i.title === first.title }))
);
setView(first?.view);
});
const onclickItem = (i: any) => {
setToc((t: any) =>
t.map((p: any) => ({ ...p, active: i.title === p.title }))
);
if (i.video) {
setVideo(i.video);
setView(null);
} else {
setView(i.view ?? notFound);
}
};
return (
<div className="course-detail">
<ResizeBox.Split
direction="horizontal"
style={{ height: "calc(100vh - 60px)" }}
max={0.9}
min={0.1}
size={0.2}
panes={[
<PerfectScrollbar>
<aside>
<h2>SQL查询语句是如何执行的</h2> <h2>SQL查询语句是如何执行的</h2>
<div> <div>
<Space style={{ color: "var(--color-text-3)" }}> <Space style={{ color: "var(--color-text-3)" }}>
@ -187,7 +111,7 @@ function CourseDetail() {
} else if (i.level === 2) { } else if (i.level === 2) {
return ( return (
<div <div
className="level-2" className={`level-2 ${i.active ? "active" : ""}`}
key={i.title} key={i.title}
onClick={() => onclickItem(i)} onClick={() => onclickItem(i)}
> >
@ -198,7 +122,26 @@ function CourseDetail() {
} }
})} })}
</div> </div>
</aside>, </aside>
</PerfectScrollbar>,
<article>
{spinVisible ? (
<div className="mask">
<Spin tip="内容准备中..." loading />
</div>
) : (
<main>
{view}
{/* 默认隐藏播放器 */}
<div
style={{ display: !view ? "block" : "none" }}
className="player-container"
>
<Player video={video} />
</div>
</main>
)}
</article>,
]} ]}
/> />
</div> </div>

View File

@ -189,6 +189,7 @@ importers:
less: ^4.1.3 less: ^4.1.3
react: ^18.2.0 react: ^18.2.0
react-dom: ^18.2.0 react-dom: ^18.2.0
react-perfect-scrollbar: 1.5.8
react-router-dom: 6.8.0 react-router-dom: 6.8.0
typescript: ^4.9.3 typescript: ^4.9.3
vite: ^4.1.0 vite: ^4.1.0
@ -202,6 +203,7 @@ importers:
less: registry.npmmirror.com/less/4.1.3 less: registry.npmmirror.com/less/4.1.3
react: registry.npmmirror.com/react/18.2.0 react: registry.npmmirror.com/react/18.2.0
react-dom: registry.npmmirror.com/react-dom/18.2.0_react@18.2.0 react-dom: registry.npmmirror.com/react-dom/18.2.0_react@18.2.0
react-perfect-scrollbar: registry.npmmirror.com/react-perfect-scrollbar/1.5.8_biqbaboplfbrettd7655fr4n2y
react-router-dom: registry.npmmirror.com/react-router-dom/6.8.0_biqbaboplfbrettd7655fr4n2y react-router-dom: registry.npmmirror.com/react-router-dom/6.8.0_biqbaboplfbrettd7655fr4n2y
devDependencies: devDependencies:
'@types/react': registry.npmmirror.com/@types/react/18.0.27 '@types/react': registry.npmmirror.com/@types/react/18.0.27
@ -9831,6 +9833,12 @@ packages:
engines: {node: '>=8'} engines: {node: '>=8'}
dev: true dev: true
registry.npmmirror.com/perfect-scrollbar/1.5.5:
resolution: {integrity: sha512-dzalfutyP3e/FOpdlhVryN4AJ5XDVauVWxybSkLZmakFE2sS3y3pc4JnSprw8tGmHvkaG5Edr5T7LBTZ+WWU2g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/perfect-scrollbar/-/perfect-scrollbar-1.5.5.tgz}
name: perfect-scrollbar
version: 1.5.5
dev: false
registry.npmmirror.com/performance-now/2.1.0: registry.npmmirror.com/performance-now/2.1.0:
resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/performance-now/-/performance-now-2.1.0.tgz} resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/performance-now/-/performance-now-2.1.0.tgz}
name: performance-now name: performance-now
@ -11302,6 +11310,21 @@ packages:
version: 16.13.1 version: 16.13.1
dev: false dev: false
registry.npmmirror.com/react-perfect-scrollbar/1.5.8_biqbaboplfbrettd7655fr4n2y:
resolution: {integrity: sha512-bQ46m70gp/HJtiBOF3gRzBISSZn8FFGNxznTdmTG8AAwpxG1bJCyn7shrgjEvGSQ5FJEafVEiosY+ccER11OSA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/react-perfect-scrollbar/-/react-perfect-scrollbar-1.5.8.tgz}
id: registry.npmmirror.com/react-perfect-scrollbar/1.5.8
name: react-perfect-scrollbar
version: 1.5.8
peerDependencies:
react: '>=16.3.3'
react-dom: '>=16.3.3'
dependencies:
perfect-scrollbar: registry.npmmirror.com/perfect-scrollbar/1.5.5
prop-types: registry.npmmirror.com/prop-types/15.8.1
react: registry.npmmirror.com/react/18.2.0
react-dom: registry.npmmirror.com/react-dom/18.2.0_react@18.2.0
dev: false
registry.npmmirror.com/react-refresh/0.14.0: registry.npmmirror.com/react-refresh/0.14.0:
resolution: {integrity: sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/react-refresh/-/react-refresh-0.14.0.tgz} resolution: {integrity: sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/react-refresh/-/react-refresh-0.14.0.tgz}
name: react-refresh name: react-refresh