mirror of
https://github.com/PlayEdu/backend
synced 2025-06-07 14:04:07 +08:00
资源视频编辑组件、视频预览组件
This commit is contained in:
parent
7cb408a1cb
commit
87d1fc8e01
@ -8,9 +8,15 @@
|
||||
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"
|
||||
/>
|
||||
<title>管理后台</title>
|
||||
<script src="/js/DPlayer.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
<script
|
||||
crossorigin="anonymous"
|
||||
integrity="sha512-oHrfR/z2wkuRuaHrdZ9NhoT/o/1kteub+QvmQgVzOKK7NTvIKQMvnY9+/RR0+eW311o4lAE/YzzLXXmP2XUvig=="
|
||||
src="https://lib.baomitu.com/hls.js/1.1.4/hls.min.js"
|
||||
></script>
|
||||
</body>
|
||||
</html>
|
||||
|
1
public/js/DPlayer.min.js
vendored
Normal file
1
public/js/DPlayer.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
public/js/xg/hls.min.js
vendored
Normal file
1
public/js/xg/hls.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
21
public/js/xg/index.js
Normal file
21
public/js/xg/index.js
Normal file
File diff suppressed because one or more lines are too long
@ -62,6 +62,10 @@ export function destroyResourceMulti(ids: number[]) {
|
||||
});
|
||||
}
|
||||
|
||||
export function videoDetail(id: number) {
|
||||
return client.get(`/backend/v1/resource/${id}`, {});
|
||||
}
|
||||
|
||||
export function videoUpdate(id: number, params: any) {
|
||||
return client.put(`/backend/v1/resource/${id}`, params);
|
||||
}
|
||||
|
BIN
src/assets/images/commen/close.png
Normal file
BIN
src/assets/images/commen/close.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 736 B |
138
src/pages/resource/videos/compenents/update-dialog/index.tsx
Normal file
138
src/pages/resource/videos/compenents/update-dialog/index.tsx
Normal file
@ -0,0 +1,138 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { Modal, Form, Input, message, TreeSelect } from "antd";
|
||||
import { resource, resourceCategory } from "../../../../../api/index";
|
||||
|
||||
interface PropInterface {
|
||||
id: number;
|
||||
open: boolean;
|
||||
onCancel: () => void;
|
||||
}
|
||||
|
||||
export const VideosUpdateDialog: React.FC<PropInterface> = ({
|
||||
id,
|
||||
open,
|
||||
onCancel,
|
||||
}) => {
|
||||
const [form] = Form.useForm();
|
||||
const [loading, setLoading] = useState<boolean>(true);
|
||||
const [categories, setCategories] = useState<any>([]);
|
||||
|
||||
useEffect(() => {
|
||||
if (id === 0) {
|
||||
return;
|
||||
}
|
||||
if (open) {
|
||||
getCategory();
|
||||
getDetail();
|
||||
}
|
||||
}, [id, open]);
|
||||
|
||||
const getCategory = () => {
|
||||
resourceCategory.resourceCategoryList().then((res: any) => {
|
||||
const categories = res.data.categories;
|
||||
if (JSON.stringify(categories) !== "{}") {
|
||||
const new_arr: any = checkArr(categories, 0, null);
|
||||
setCategories(new_arr);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const getDetail = () => {
|
||||
resource.videoDetail(id).then((res: any) => {
|
||||
let data = res.data.resources;
|
||||
form.setFieldsValue({
|
||||
name: data.name,
|
||||
category_id: res.data.category_ids,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const checkArr = (departments: any[], id: number, counts: any) => {
|
||||
const arr = [];
|
||||
for (let i = 0; i < departments[id].length; i++) {
|
||||
if (!departments[departments[id][i].id]) {
|
||||
arr.push({
|
||||
title: departments[id][i].name,
|
||||
value: departments[id][i].id,
|
||||
});
|
||||
} else {
|
||||
const new_arr: any = checkArr(
|
||||
departments,
|
||||
departments[id][i].id,
|
||||
counts
|
||||
);
|
||||
arr.push({
|
||||
title: departments[id][i].name,
|
||||
value: departments[id][i].id,
|
||||
children: new_arr,
|
||||
});
|
||||
}
|
||||
}
|
||||
return arr;
|
||||
};
|
||||
|
||||
const onFinish = (values: any) => {
|
||||
resource.videoUpdate(id, values).then((res: any) => {
|
||||
message.success("保存成功!");
|
||||
onCancel();
|
||||
});
|
||||
};
|
||||
|
||||
const onFinishFailed = (errorInfo: any) => {
|
||||
console.log("Failed:", errorInfo);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Modal
|
||||
title="编辑视频"
|
||||
centered
|
||||
forceRender
|
||||
open={open}
|
||||
width={416}
|
||||
onOk={() => form.submit()}
|
||||
onCancel={() => onCancel()}
|
||||
maskClosable={false}
|
||||
>
|
||||
<div className="float-left mt-24">
|
||||
<Form
|
||||
form={form}
|
||||
name="videos-update"
|
||||
labelCol={{ span: 8 }}
|
||||
wrapperCol={{ span: 16 }}
|
||||
initialValues={{ remember: true }}
|
||||
onFinish={onFinish}
|
||||
onFinishFailed={onFinishFailed}
|
||||
autoComplete="off"
|
||||
>
|
||||
<Form.Item
|
||||
label="视频分类"
|
||||
name="category_id"
|
||||
rules={[{ required: true, message: "请选择视频分类!" }]}
|
||||
>
|
||||
<TreeSelect
|
||||
showCheckedStrategy={TreeSelect.SHOW_ALL}
|
||||
allowClear
|
||||
style={{ width: 200 }}
|
||||
treeData={categories}
|
||||
placeholder="视频分类"
|
||||
treeDefaultExpandAll
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="视频名称"
|
||||
name="name"
|
||||
rules={[{ required: true, message: "请输入视频名称!" }]}
|
||||
>
|
||||
<Input
|
||||
allowClear
|
||||
style={{ width: 200 }}
|
||||
placeholder="请输入视频名称"
|
||||
/>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</div>
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
};
|
@ -0,0 +1,40 @@
|
||||
.play-mask {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
position: fixed;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 200;
|
||||
.play-dialog {
|
||||
width: 800px;
|
||||
height: 450px;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
.close-button {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
position: absolute;
|
||||
top: 24px;
|
||||
right: 24px;
|
||||
cursor: pointer;
|
||||
z-index: 1000;
|
||||
&:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
img {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
}
|
||||
}
|
||||
.play-box {
|
||||
width: 800px;
|
||||
height: 450px;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import styles from "./index.module.less";
|
||||
import closeIcon from "../../../../../assets/images/commen/close.png";
|
||||
|
||||
interface PropInterface {
|
||||
id: number;
|
||||
url: string;
|
||||
open: boolean;
|
||||
onCancel: () => void;
|
||||
}
|
||||
|
||||
declare const window: any;
|
||||
|
||||
export const VideoPlayDialog: React.FC<PropInterface> = ({
|
||||
id,
|
||||
url,
|
||||
open,
|
||||
onCancel,
|
||||
}) => {
|
||||
const [loading, setLoading] = useState<boolean>(true);
|
||||
|
||||
useEffect(() => {
|
||||
if (open && url) {
|
||||
initDPlayer(url);
|
||||
}
|
||||
}, [id, open, url]);
|
||||
|
||||
const initDPlayer = (playUrl: string) => {
|
||||
window.player = new window.DPlayer({
|
||||
container: document.getElementById("meedu-player-container"),
|
||||
autoplay: false,
|
||||
video: {
|
||||
url: playUrl,
|
||||
},
|
||||
});
|
||||
window.player.on("ended", () => {
|
||||
window.player && window.player.destroy();
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{open && (
|
||||
<div className={styles["play-mask"]}>
|
||||
<div className={styles["play-dialog"]}>
|
||||
<div
|
||||
className={styles["close-button"]}
|
||||
onClick={() => {
|
||||
window.player && window.player.destroy();
|
||||
onCancel();
|
||||
}}
|
||||
>
|
||||
<img src={closeIcon} />
|
||||
</div>
|
||||
<div
|
||||
className={styles["play-box"]}
|
||||
id="meedu-player-container"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
@ -9,6 +9,8 @@ import type { ColumnsType } from "antd/es/table";
|
||||
import { dateFormat } from "../../../utils/index";
|
||||
import { TreeCategory, DurationText, PerButton } from "../../../compenents";
|
||||
import { UploadVideoButton } from "../../../compenents/upload-video-button";
|
||||
import { VideoPlayDialog } from "./compenents/video-play-dialog";
|
||||
import { VideosUpdateDialog } from "./compenents/update-dialog";
|
||||
|
||||
const { confirm } = Modal;
|
||||
|
||||
@ -39,6 +41,7 @@ const ResourceVideosPage = () => {
|
||||
const [playVisible, setPlayeVisible] = useState<boolean>(false);
|
||||
const [multiConfig, setMultiConfig] = useState<boolean>(false);
|
||||
const [updateId, setUpdateId] = useState(0);
|
||||
const [playUrl, setPlayUrl] = useState<string>("");
|
||||
|
||||
useEffect(() => {
|
||||
setCateId(Number(result.get("cid")));
|
||||
@ -131,6 +134,8 @@ const ResourceVideosPage = () => {
|
||||
size="small"
|
||||
className="b-n-link c-red"
|
||||
onClick={() => {
|
||||
setUpdateId(record.id);
|
||||
setPlayUrl(record.url);
|
||||
setPlayeVisible(true);
|
||||
}}
|
||||
>
|
||||
@ -332,6 +337,17 @@ const ResourceVideosPage = () => {
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<VideoPlayDialog
|
||||
id={Number(updateId)}
|
||||
open={playVisible}
|
||||
url={playUrl}
|
||||
onCancel={() => setPlayeVisible(false)}
|
||||
></VideoPlayDialog>
|
||||
<VideosUpdateDialog
|
||||
id={Number(updateId)}
|
||||
open={updateVisible}
|
||||
onCancel={() => setUpdateVisible(false)}
|
||||
></VideosUpdateDialog>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
Loading…
x
Reference in New Issue
Block a user