feat: 播放期
This commit is contained in:
parent
57ff9c0356
commit
d4a845c59c
|
@ -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",
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
function Material() {
|
||||||
|
return <div>1</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Material;
|
|
@ -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;
|
||||||
}
|
// }
|
|
@ -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,
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,167 +42,106 @@ 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 notFound = (
|
||||||
|
<Result
|
||||||
|
status="403"
|
||||||
|
subTitle="挖宝藏,请加入矿工"
|
||||||
|
extra={<Button type="text">1</Button>}
|
||||||
|
></Result>
|
||||||
|
);
|
||||||
|
|
||||||
|
useMount(() => {
|
||||||
|
const first = toc.find((t) => t.level === 2) as any;
|
||||||
|
setToc((p: any) =>
|
||||||
|
p.map((i: any) => ({ ...i, active: i.title === first.title }))
|
||||||
|
);
|
||||||
|
setView(first?.view);
|
||||||
|
});
|
||||||
|
|
||||||
const onclickItem = (i: any) => {
|
const onclickItem = (i: any) => {
|
||||||
setVideo(i.video);
|
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 (
|
return (
|
||||||
<div className="course-detail container">
|
<div className="course-detail">
|
||||||
<ResizeBox.Split
|
<ResizeBox.Split
|
||||||
direction="horizontal"
|
direction="horizontal"
|
||||||
style={{ height: "100vh" }}
|
style={{ height: "calc(100vh - 60px)" }}
|
||||||
// max={0.8}
|
max={0.9}
|
||||||
// min={0.2}
|
min={0.1}
|
||||||
size={0.6}
|
size={0.2}
|
||||||
panes={[
|
panes={[
|
||||||
|
<PerfectScrollbar>
|
||||||
|
<aside>
|
||||||
|
<h2>基础架构:一条SQL查询语句是如何执行的?</h2>
|
||||||
|
<div>
|
||||||
|
<Space style={{ color: "var(--color-text-3)" }}>
|
||||||
|
<span>2023年3月2日</span>
|
||||||
|
</Space>
|
||||||
|
</div>
|
||||||
|
<div className="toc">
|
||||||
|
{toc.map((i) => {
|
||||||
|
if (i.level === 1) {
|
||||||
|
return (
|
||||||
|
<div className="level-1" key={i.title}>
|
||||||
|
{i.title}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
} else if (i.level === 2) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={`level-2 ${i.active ? "active" : ""}`}
|
||||||
|
key={i.title}
|
||||||
|
onClick={() => onclickItem(i)}
|
||||||
|
>
|
||||||
|
<span className="bs-ellipsis">{i.title}</span>
|
||||||
|
<span className="time">{i.time}</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</aside>
|
||||||
|
</PerfectScrollbar>,
|
||||||
<article>
|
<article>
|
||||||
<Result
|
{spinVisible ? (
|
||||||
status="403"
|
<div className="mask">
|
||||||
subTitle="挖宝藏,请加入矿工"
|
<Spin tip="内容准备中..." loading />
|
||||||
extra={<Button type="text">上舰</Button>}
|
</div>
|
||||||
></Result>
|
) : (
|
||||||
{/* <div className="player-container">
|
<main>
|
||||||
<Player video={video} />
|
{view}
|
||||||
</div> */}
|
{/* 默认隐藏播放器 */}
|
||||||
|
<div
|
||||||
|
style={{ display: !view ? "block" : "none" }}
|
||||||
|
className="player-container"
|
||||||
|
>
|
||||||
|
<Player video={video} />
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
)}
|
||||||
</article>,
|
</article>,
|
||||||
<aside className="bs-scrollbar">
|
|
||||||
<h2>基础架构:一条SQL查询语句是如何执行的?</h2>
|
|
||||||
<div>
|
|
||||||
<Space style={{ color: "var(--color-text-3)" }}>
|
|
||||||
<span>2023年3月2日</span>
|
|
||||||
</Space>
|
|
||||||
</div>
|
|
||||||
<div className="toc">
|
|
||||||
{toc.map((i) => {
|
|
||||||
if (i.level === 1) {
|
|
||||||
return (
|
|
||||||
<div className="level-1" key={i.title}>
|
|
||||||
{i.title}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
} else if (i.level === 2) {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className="level-2"
|
|
||||||
key={i.title}
|
|
||||||
onClick={() => onclickItem(i)}
|
|
||||||
>
|
|
||||||
<span className="bs-ellipsis">{i.title}</span>
|
|
||||||
<span className="time">{i.time}</span>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</aside>,
|
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue
Block a user