线上课编辑和课时管理初步

This commit is contained in:
禺狨 2023-03-21 18:01:23 +08:00
parent 9fc6e79b3d
commit faa03f19e0
12 changed files with 687 additions and 367 deletions

View File

@ -1,11 +1,11 @@
import client from "./internal/httpClient";
export function courseChapterList(courseId: number) {
return client.get(`/backend/v1/course/${courseId}/course-chapter/index`, {});
return client.get(`/backend/v1/course/${courseId}/chapter/index`, {});
}
export function createCourseChapter(courseId: number) {
return client.get(`/backend/v1/course/${courseId}/course-chapter/create`, {});
return client.get(`/backend/v1/course/${courseId}/chapter/create`, {});
}
export function storeCourseChapter(
@ -13,7 +13,7 @@ export function storeCourseChapter(
name: string,
sort: number
) {
return client.post(`/backend/v1/course/${courseId}/course-chapter/create`, {
return client.post(`/backend/v1/course/${courseId}/chapter/create`, {
name: name,
sort: sort,
});
@ -29,12 +29,18 @@ export function updateCourseChapter(
name: string,
sort: number
) {
return client.post(`/backend/v1/course/${courseId}/course-chapter/${id}`, {
return client.put(`/backend/v1/course/${courseId}/chapter/${id}`, {
name: name,
sort: sort,
});
}
export function destroyCourseChapter(courseId: number, id: number) {
return client.destroy(`/backend/v1/course/${courseId}/course-chapter/${id}`);
return client.destroy(`/backend/v1/course/${courseId}/chapter/${id}`);
}
export function transCourseChapter(courseId: number, ids: number[]) {
return client.put(`/backend/v1/course/${courseId}/chapter/update/sort`, {
ids: ids,
});
}

View File

@ -1,11 +1,11 @@
import client from "./internal/httpClient";
export function courseHourList(courseId: number) {
return client.get(`/backend/v1/course/${courseId}/course-hour/index`, {});
return client.get(`/backend/v1/course/${courseId}/hour/index`, {});
}
export function createCourseHour(courseId: number) {
return client.get(`/backend/v1/course/${courseId}/course-hour/create`, {});
return client.get(`/backend/v1/course/${courseId}/hour/create`, {});
}
export function storeCourseHour(
@ -14,19 +14,26 @@ export function storeCourseHour(
title: string,
type: string,
druation: number,
publishedAt: string
rid: number
) {
return client.post(`/backend/v1/course/${courseId}/course-hour/create`, {
return client.post(`/backend/v1/course/${courseId}/hour/create`, {
chapter_id: chapterId,
title,
type,
druation,
published_at: publishedAt,
sort: 0,
rid,
});
}
export function storeCourseHourMulti(courseId: number, hours: number[]) {
return client.post(`/backend/v1/course/${courseId}/hour/create-batch`, {
hours: hours,
});
}
export function courseHour(courseId: number, id: number) {
return client.get(`/backend/v1/course/${courseId}/course-hour/${id}`, {});
return client.get(`/backend/v1/course/${courseId}/hour/${id}`, {});
}
export function updateCourseHour(
@ -36,17 +43,24 @@ export function updateCourseHour(
title: string,
type: string,
druation: number,
publishedAt: string
rid: number
) {
return client.post(`/backend/v1/course/${courseId}/course-hour/${id}`, {
return client.put(`/backend/v1/course/${courseId}/hour/${id}`, {
chapter_id: chapterId,
title,
type,
druation,
published_at: publishedAt,
sort: 0,
rid,
});
}
export function destroyCourseHour(courseId: number, id: number) {
return client.destroy(`/backend/v1/course/${courseId}/course-hour/${id}`);
return client.destroy(`/backend/v1/course/${courseId}/hour/${id}`);
}
export function transCourseHour(courseId: number, ids: number[]) {
return client.put(`/backend/v1/course/${courseId}/hour/update/sort`, {
ids: ids,
});
}

View File

@ -1,8 +1,8 @@
@font-face {
font-family: "iconfont"; /* Project id 3943555 */
src: url('iconfont.woff2?t=1679377698528') format('woff2'),
url('iconfont.woff?t=1679377698528') format('woff'),
url('iconfont.ttf?t=1679377698528') format('truetype');
src: url('iconfont.woff2?t=1679383201256') format('woff2'),
url('iconfont.woff?t=1679383201256') format('woff'),
url('iconfont.ttf?t=1679383201256') format('truetype');
}
.iconfont {
@ -13,6 +13,10 @@
-moz-osx-font-smoothing: grayscale;
}
.icon-icon-tips:before {
content: "\e74a";
}
.icon-icon-fold:before {
content: "\e749";
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -213,14 +213,13 @@ code {
height: 40px;
border-radius: 6px;
font-size: 14px;
font-weight: 500;
color: rgba(0, 0, 0, 0.88);
line-height: 40px;
box-sizing: border-box;
padding-left: 16px;
cursor: pointer;
&.active {
background: rgba(#ff4d4f, 0.1);
background-color: #fff2f0;
}
}

View File

@ -168,6 +168,8 @@ export const CourseCreate: React.FC<PropInterface> = ({ open, onCancel }) => {
};
const getChapterType = (e: any) => {
const arr = [...chapters];
if (arr.length > 0) {
confirm({
title: "操作确认",
icon: <ExclamationCircleFilled />,
@ -188,6 +190,9 @@ export const CourseCreate: React.FC<PropInterface> = ({ open, onCancel }) => {
});
},
});
} else {
setChapterType(e.target.value);
}
};
const delHour = (id: number) => {
@ -378,7 +383,9 @@ export const CourseCreate: React.FC<PropInterface> = ({ open, onCancel }) => {
rules={[{ required: true, message: "请选择课程类型!" }]}
>
<Radio.Group onChange={getType}>
<Radio value="open"></Radio>
<Radio value="open">
<i className="iconfont icon-icon-tips c-gray ml-8" />
</Radio>
<Radio value="elective"></Radio>
</Radio.Group>
</Form.Item>

View File

@ -0,0 +1,109 @@
.top-content {
width: 502px;
height: 80px;
background: rgba(255, 77, 79, 0.1);
border-radius: 6px;
display: flex;
flex-direction: column;
justify-content: center;
box-sizing: border-box;
padding: 16px;
margin: 0 auto;
p {
font-size: 14px;
font-weight: 400;
color: #ff4d4f;
line-height: 24px;
margin: 0;
}
}
.thumb-item {
width: 80px;
height: 60px;
cursor: pointer;
margin-right: 8px;
border-radius: 6px;
&:last-child {
margin-right: 0;
}
}
.thumb-item-avtive {
width: 80px;
height: 60px;
border: 2px solid #ff4d4f;
cursor: pointer;
margin-right: 8px;
border-radius: 8px;
&:last-child {
margin-right: 0;
}
}
.hous-box {
width: 502px;
min-height: 56px;
background: #ffffff;
border-radius: 6px;
border: 1px solid rgba(0, 0, 0, 0.15);
box-sizing: border-box;
-moz-box-sizing: border-box;
/* Firefox */
-webkit-box-sizing: border-box;
/* Safari */
padding: 16px 16px 16px 0;
margin-left: 42px;
.no-hours {
height: 24px;
font-size: 14px;
font-weight: 400;
color: rgba(0, 0, 0, 0.25);
line-height: 24px;
margin-left: 16px;
}
}
.chapter-item {
width: 502px;
height: auto;
display: flex;
flex-direction: column;
margin-left: 42px;
margin-bottom: 16px;
.label {
width: 78px;
height: 32px;
font-size: 14px;
font-weight: 400;
color: rgba(0, 0, 0, 0.85);
line-height: 32px;
}
.input {
width: 208px;
height: 32px;
margin-right: 24px;
}
.chapter-hous-box {
width: 502px;
min-height: 56px;
background: #ffffff;
border-radius: 6px;
border: 1px solid rgba(0, 0, 0, 0.15);
box-sizing: border-box;
-moz-box-sizing: border-box;
/* Firefox */
-webkit-box-sizing: border-box;
/* Safari */
padding: 16px 16px 16px 0;
margin-top: 16px;
.no-hours {
height: 24px;
font-size: 14px;
font-weight: 400;
color: rgba(0, 0, 0, 0.25);
line-height: 24px;
margin-left: 16px;
}
}
}

View File

@ -0,0 +1,462 @@
import React, { useState, useEffect } from "react";
import { Space, Button, Drawer, Form, Input, Modal, message } from "antd";
import styles from "./hour-update.module.less";
import { course, courseHour, courseChapter } from "../../../api/index";
import { SelectResource } from "../../../compenents";
import { ExclamationCircleFilled } from "@ant-design/icons";
import { TreeHours } from "./hours";
const { confirm } = Modal;
interface PropInterface {
id: number;
open: boolean;
onCancel: () => void;
}
interface Option {
value: string | number;
label: string;
children?: Option[];
}
export const CourseHourUpdate: React.FC<PropInterface> = ({
id,
open,
onCancel,
}) => {
const [form] = Form.useForm();
const [chapterType, setChapterType] = useState(0);
const [chapters, setChapters] = useState<any>([]);
const [hours, setHours] = useState<any>([]);
const [chapterHours, setChapterHours] = useState<any>([]);
const [videoVisible, setVideoVisible] = useState<boolean>(false);
const [treeData, setTreeData] = useState<any>([]);
const [addvideoCurrent, setAddvideoCurrent] = useState(0);
useEffect(() => {
if (id === 0) {
return;
}
getDetail();
}, [id]);
const getDetail = () => {
course.course(id).then((res: any) => {
let chapterType = res.data.chapters.length > 0 ? 1 : 0;
setChapterType(chapterType);
if (chapterType === 1) {
setTreeData([]);
setHours([]);
let hours = res.data.hours;
let chapters = res.data.chapters;
const arr: any = [];
const keys: any = [];
for (let i = 0; i < chapters.length; i++) {
arr.push({
id: chapters[i].id,
name: chapters[i].name,
hours: resetHours(hours[chapters[i].id]).arr,
});
keys.push(resetHours(hours[chapters[i].id]).keys);
}
setChapters(arr);
setChapterHours(keys);
} else {
setChapters([]);
setChapterHours([]);
let hours = res.data.hours;
if (JSON.stringify(hours) !== "{}") {
const arr: any = resetHours(hours[0]).arr;
const keys: any = resetHours(hours[0]).keys;
setTreeData(arr);
setHours(keys);
} else {
setTreeData([]);
setHours([]);
}
}
});
};
const resetHours = (data: any) => {
const arr: any = [];
const keys: any = [];
if (data) {
for (let i = 0; i < data.length; i++) {
arr.push({
duration: data[i].duration,
type: data[i].type,
name: data[i].title,
rid: data[i].rid,
id: data[i].id,
});
keys.push(data[i].rid);
}
}
return { arr, keys };
};
const onFinish = (values: any) => {};
const onFinishFailed = (errorInfo: any) => {
console.log("Failed:", errorInfo);
};
const selectData = (arr: any, videos: any) => {
const hours: any = [];
for (let i = 0; i < videos.length; i++) {
hours.push({
chapter_id: 0,
sort: i,
title: videos[i].name,
type: videos[i].type,
duration: videos[i].duration,
rid: videos[i].rid,
});
}
courseHour
.storeCourseHourMulti(id, hours)
.then((res: any) => {
console.log("ok");
setVideoVisible(false);
getDetail();
})
.catch((err) => {
message.error(err.message);
});
};
const selectChapterData = (arr: any, videos: any) => {
const data = [...chapters];
if (!data[addvideoCurrent].id) {
message.error("添加课时失败");
return;
}
const hours: any = [];
for (let i = 0; i < videos.length; i++) {
hours.push({
chapter_id: data[addvideoCurrent].id,
sort: i,
title: videos[i].name,
type: videos[i].type,
duration: videos[i].duration,
rid: videos[i].rid,
});
}
courseHour
.storeCourseHourMulti(id, hours)
.then((res: any) => {
console.log("ok");
setVideoVisible(false);
getDetail();
})
.catch((err) => {
message.error(err.message);
});
};
const delHour = (hid: number) => {
const data = [...treeData];
const index = data.findIndex((i: any) => i.rid === hid);
let delId = data[index].id;
if (index >= 0) {
data.splice(index, 1);
}
if (data.length > 0) {
setTreeData(data);
const keys = data.map((item: any) => item.rid);
setHours(keys);
} else {
setTreeData([]);
setHours([]);
}
if (delId) {
courseHour.destroyCourseHour(id, delId).then((res: any) => {
console.log("ok");
});
}
};
const transHour = (arr: any) => {
setHours(arr);
const data = [...treeData];
const newArr: any = [];
const hourIds: any = [];
for (let i = 0; i < arr.length; i++) {
data.map((item: any) => {
if (item.rid === arr[i]) {
newArr.push(item);
hourIds.push(item.id);
}
});
}
setTreeData(newArr);
courseHour.transCourseHour(id, hourIds).then((res: any) => {
console.log("ok");
});
};
const addNewChapter = () => {
const arr = [...chapters];
const keys = [...chapterHours];
arr.push({
name: "",
hours: [],
});
keys.push([]);
setChapters(arr);
setChapterHours(keys);
};
const setChapterName = (index: number, value: string) => {
const arr = [...chapters];
arr[index].name = value;
setChapters(arr);
};
const saveChapterName = (index: number, value: string) => {
const arr = [...chapters];
if (arr[index].id) {
courseChapter
.updateCourseChapter(id, arr[index].id, value, arr.length)
.then((res: any) => {
console.log("ok");
getDetail();
})
.catch((err) => {
message.error(err.message);
});
} else {
courseChapter
.storeCourseChapter(id, value, arr.length)
.then((res: any) => {
console.log("ok");
getDetail();
})
.catch((err) => {
message.error(err.message);
});
}
};
const delChapter = (index: number) => {
const arr = [...chapters];
const keys = [...chapterHours];
confirm({
title: "操作确认",
icon: <ExclamationCircleFilled />,
content: "删除章节会清空已添加课时,确认删除?",
centered: true,
okText: "确认",
cancelText: "取消",
onOk() {
if (arr[index].id) {
courseChapter
.destroyCourseChapter(id, arr[index].id)
.then((res: any) => {
console.log("ok");
getDetail();
})
.catch((err) => {
message.error(err.message);
});
}
},
onCancel() {},
});
};
const delChapterHour = (index: number, hid: number) => {
const keys = [...chapterHours];
const data = [...chapters];
const current = data[index].hours.findIndex((i: any) => i.rid === hid);
let delId = data[index].hours.map((item: any) => item.id);
if (current >= 0) {
data[index].hours.splice(current, 1);
}
if (data[index].hours.length > 0) {
setChapters(data);
keys[index] = data[index].hours.map((item: any) => item.rid);
setChapterHours(keys);
} else {
keys[index] = [];
data[index].hours = [];
setChapters(data);
setChapterHours(keys);
}
if (delId) {
courseHour.destroyCourseHour(id, delId).then((res: any) => {
console.log("ok");
});
}
};
const transChapterHour = (index: number, arr: any) => {
const keys = [...chapterHours];
keys[index] = arr;
setChapterHours(keys);
const data = [...chapters];
const newArr: any = [];
const hourIds: any = [];
for (let i = 0; i < arr.length; i++) {
data[index].hours.map((item: any) => {
if (item.rid === arr[i]) {
newArr.push(item);
hourIds.push(item.id);
}
});
}
data[index].hours = newArr;
setChapters(data);
courseHour.transCourseHour(id, hourIds).then((res: any) => {
console.log("ok");
});
};
return (
<>
<Drawer
title="课时管理"
onClose={onCancel}
maskClosable={false}
open={open}
width={634}
>
<div className={styles["top-content"]}>
<p>1.线</p>
<p>2.</p>
</div>
<div className="float-left mt-24">
<SelectResource
defaultKeys={
chapterType == 0 ? hours : chapterHours[addvideoCurrent]
}
open={videoVisible}
onCancel={() => {
setVideoVisible(false);
}}
onSelected={(arr: any, videos: any) => {
if (chapterType == 0) {
selectData(arr, videos);
} else {
selectChapterData(arr, videos);
}
}}
/>
<Form
form={form}
name="basic"
labelCol={{ span: 5 }}
wrapperCol={{ span: 19 }}
initialValues={{ remember: true }}
onFinish={onFinish}
onFinishFailed={onFinishFailed}
autoComplete="off"
>
{chapterType === 0 && (
<div className="c-flex">
<Form.Item>
<div className="ml-120">
<Button
onClick={() => setVideoVisible(true)}
type="primary"
>
</Button>
</div>
</Form.Item>
<div className={styles["hous-box"]}>
{treeData.length === 0 && (
<span className={styles["no-hours"]}>
</span>
)}
{treeData.length > 0 && (
<TreeHours
data={treeData}
onRemoveItem={(id: number) => {
delHour(id);
}}
onUpdate={(arr: any[]) => {
transHour(arr);
}}
/>
)}
</div>
</div>
)}
{chapterType === 1 && (
<div className="c-flex">
{chapters.length > 0 &&
chapters.map((item: any, index: number) => {
return (
<div
key={item.hours.length + "章节" + index}
className={styles["chapter-item"]}
>
<div className="d-flex">
<div className={styles["label"]}>
{index + 1}
</div>
<Input
value={item.name}
className={styles["input"]}
onChange={(e) => {
setChapterName(index, e.target.value);
}}
onBlur={(e) => {
saveChapterName(index, e.target.value);
}}
placeholder="请在此处输入章节名称"
/>
<Button
className="mr-16"
type="primary"
onClick={() => {
setVideoVisible(true);
setAddvideoCurrent(index);
}}
>
</Button>
<Button onClick={() => delChapter(index)}>
</Button>
</div>
<div className={styles["chapter-hous-box"]}>
{item.hours.length === 0 && (
<span className={styles["no-hours"]}>
</span>
)}
{item.hours.length > 0 && (
<TreeHours
data={item.hours}
onRemoveItem={(id: number) => {
delChapterHour(index, id);
}}
onUpdate={(arr: any[]) => {
transChapterHour(index, arr);
}}
/>
)}
</div>
</div>
);
})}
<Form.Item>
<div className="ml-120">
<Button onClick={() => addNewChapter()}></Button>
</div>
</Form.Item>
</div>
)}
</Form>
</div>
</Drawer>
</>
);
};

View File

@ -13,10 +13,8 @@ import {
} from "antd";
import styles from "./update.module.less";
import { course, department } from "../../../api/index";
import { UploadImageButton, SelectResource } from "../../../compenents";
import { ExclamationCircleFilled } from "@ant-design/icons";
import { UploadImageButton } from "../../../compenents";
import { getHost } from "../../../utils/index";
import { TreeHours } from "./hours";
const { confirm } = Modal;
@ -46,13 +44,6 @@ export const CourseUpdate: React.FC<PropInterface> = ({
const [categories, setCategories] = useState<any>([]);
const [thumb, setThumb] = useState<string>("");
const [type, setType] = useState<string>("open");
const [chapterType, setChapterType] = useState(0);
const [chapters, setChapters] = useState<any>([]);
const [hours, setHours] = useState<any>([]);
const [chapterHours, setChapterHours] = useState<any>([]);
const [videoVisible, setVideoVisible] = useState<boolean>(false);
const [treeData, setTreeData] = useState<any>([]);
const [addvideoCurrent, setAddvideoCurrent] = useState(0);
useEffect(() => {
if (id === 0) {
@ -143,53 +134,7 @@ export const CourseUpdate: React.FC<PropInterface> = ({
});
setType(type);
setThumb(res.data.course.thumb);
setChapterType(chapterType);
if (chapterType === 1) {
setTreeData([]);
setHours([]);
let hours = res.data.hours;
let chapters = res.data.chapters;
const arr: any = [];
const keys: any = [];
for (let i = 0; i < chapters.length; i++) {
arr.push({
name: chapters[i].name,
hours: resetHours(hours[chapters[i].id]).arr,
});
keys.push(resetHours(hours[chapters[i].id]).keys);
}
setChapters(arr);
setChapterHours(keys);
} else {
setChapters([]);
setChapterHours([]);
let hours = res.data.hours;
if (JSON.stringify(hours) !== "{}") {
const arr: any = resetHours(hours[0]).arr;
const keys: any = resetHours(hours[0]).keys;
setTreeData(arr);
setHours(keys);
} else {
setTreeData([]);
setHours([]);
}
}
});
};
const resetHours = (data: any) => {
const arr: any = [];
const keys: any = [];
for (let i = 0; i < data.length; i++) {
arr.push({
duration: data[i].duration,
type: data[i].type,
name: data[i].title,
rid: data[i].rid,
});
keys.push(data[i].rid);
}
return { arr, keys };
};
const checkChild = (departments: any[], id: number) => {
@ -247,8 +192,8 @@ export const CourseUpdate: React.FC<PropInterface> = ({
values.isRequired,
dep_ids,
category_ids,
chapters,
treeData
[],
[]
)
.then((res: any) => {
message.success("保存成功!");
@ -264,150 +209,6 @@ export const CourseUpdate: React.FC<PropInterface> = ({
setType(e.target.value);
};
const selectData = (arr: any, videos: any) => {
setHours(arr);
setTreeData(videos);
setVideoVisible(false);
};
const selectChapterData = (arr: any, videos: any) => {
const data = [...chapters];
const keys = [...chapterHours];
keys[addvideoCurrent] = arr;
data[addvideoCurrent].hours = videos;
setChapters(data);
setChapterHours(keys);
setVideoVisible(false);
};
const getChapterType = (e: any) => {
confirm({
title: "操作确认",
icon: <ExclamationCircleFilled />,
content: "切换列表选项会清空已添加课时,确认切换?",
centered: true,
okText: "确认",
cancelText: "取消",
onOk() {
setChapterType(e.target.value);
setChapters([]);
setHours([]);
setChapterHours([]);
setTreeData([]);
},
onCancel() {
form.setFieldsValue({
hasChapter: chapterType,
});
},
});
};
const delHour = (id: number) => {
const data = [...treeData];
const index = data.findIndex((i: any) => i.rid === id);
if (index >= 0) {
data.splice(index, 1);
}
if (data.length > 0) {
setTreeData(data);
const keys = data.map((item: any) => item.rid);
setHours(keys);
} else {
setTreeData([]);
setHours([]);
}
};
const transHour = (arr: any) => {
setHours(arr);
const data = [...treeData];
const newArr: any = [];
for (let i = 0; i < arr.length; i++) {
data.map((item: any) => {
if (item.rid === arr[i]) {
newArr.push(item);
}
});
}
setTreeData(newArr);
};
const addNewChapter = () => {
const arr = [...chapters];
const keys = [...chapterHours];
arr.push({
name: "",
hours: [],
});
keys.push([]);
setChapters(arr);
setChapterHours(keys);
};
const setChapterName = (index: number, value: string) => {
const arr = [...chapters];
arr[index].name = value;
setChapters(arr);
};
const delChapter = (index: number) => {
const arr = [...chapters];
const keys = [...chapterHours];
confirm({
title: "操作确认",
icon: <ExclamationCircleFilled />,
content: "删除章节会清空已添加课时,确认删除?",
centered: true,
okText: "确认",
cancelText: "取消",
onOk() {
arr.splice(index, 1);
keys.splice(index, 1);
setChapters(arr);
setChapterHours(keys);
},
onCancel() {},
});
};
const delChapterHour = (index: number, id: number) => {
const keys = [...chapterHours];
const data = [...chapters];
const current = data[index].hours.findIndex((i: any) => i.rid === id);
if (current >= 0) {
data[index].hours.splice(current, 1);
}
if (data[index].hours.length > 0) {
setChapters(data);
keys[index] = data[index].hours.map((item: any) => item.rid);
setChapterHours(keys);
} else {
keys[index] = [];
data[index].hours = [];
setChapters(data);
setChapterHours(keys);
}
};
const transChapterHour = (index: number, arr: any) => {
const keys = [...chapterHours];
keys[index] = arr;
setChapterHours(keys);
const data = [...chapters];
const newArr: any = [];
for (let i = 0; i < arr.length; i++) {
data[index].hours.map((item: any) => {
if (item.rid === arr[i]) {
newArr.push(item);
}
});
}
data[index].hours = newArr;
setChapters(data);
};
return (
<>
<Drawer
@ -426,22 +227,6 @@ export const CourseUpdate: React.FC<PropInterface> = ({
width={634}
>
<div className="float-left mt-24">
<SelectResource
defaultKeys={
chapterType == 0 ? hours : chapterHours[addvideoCurrent]
}
open={videoVisible}
onCancel={() => {
setVideoVisible(false);
}}
onSelected={(arr: any, videos: any) => {
if (chapterType == 0) {
selectData(arr, videos);
} else {
selectChapterData(arr, videos);
}
}}
/>
<Form
form={form}
name="basic"
@ -491,7 +276,10 @@ export const CourseUpdate: React.FC<PropInterface> = ({
rules={[{ required: true, message: "请选择课程类型!" }]}
>
<Radio.Group onChange={getType}>
<Radio value="open"></Radio>
<Radio value="open">
<i className="iconfont icon-icon-tips c-gray ml-8" />
</Radio>
<Radio value="elective"></Radio>
</Radio.Group>
</Form.Item>
@ -617,111 +405,6 @@ export const CourseUpdate: React.FC<PropInterface> = ({
placeholder="请输入课程简介"
/>
</Form.Item>
<Form.Item
label="课时列表"
name="hasChapter"
rules={[{ required: true, message: "请选择课时列表!" }]}
>
<Radio.Group onChange={getChapterType}>
<Radio value={0}></Radio>
<Radio value={1}></Radio>
</Radio.Group>
</Form.Item>
{chapterType === 0 && (
<div className="c-flex">
<Form.Item>
<div className="ml-120">
<Button
onClick={() => setVideoVisible(true)}
type="primary"
>
</Button>
</div>
</Form.Item>
<div className={styles["hous-box"]}>
{treeData.length === 0 && (
<span className={styles["no-hours"]}>
</span>
)}
{treeData.length > 0 && (
<TreeHours
data={treeData}
onRemoveItem={(id: number) => {
delHour(id);
}}
onUpdate={(arr: any[]) => {
transHour(arr);
}}
/>
)}
</div>
</div>
)}
{chapterType === 1 && (
<div className="c-flex">
{chapters.length > 0 &&
chapters.map((item: any, index: number) => {
return (
<div
key={item.hours.length + "章节" + index}
className={styles["chapter-item"]}
>
<div className="d-flex">
<div className={styles["label"]}>
{index + 1}
</div>
<Input
value={item.name}
className={styles["input"]}
onChange={(e) => {
setChapterName(index, e.target.value);
}}
placeholder="请在此处输入章节名称"
/>
<Button
className="mr-16"
type="primary"
onClick={() => {
setVideoVisible(true);
setAddvideoCurrent(index);
}}
>
</Button>
<Button onClick={() => delChapter(index)}>
</Button>
</div>
<div className={styles["chapter-hous-box"]}>
{item.hours.length === 0 && (
<span className={styles["no-hours"]}>
</span>
)}
{item.hours.length > 0 && (
<TreeHours
data={item.hours}
onRemoveItem={(id: number) => {
delChapterHour(index, id);
}}
onUpdate={(arr: any[]) => {
transChapterHour(index, arr);
}}
/>
)}
</div>
</div>
);
})}
<Form.Item>
<div className="ml-120">
<Button onClick={() => addNewChapter()}></Button>
</div>
</Form.Item>
</div>
)}
</Form>
</div>
</Drawer>

View File

@ -10,7 +10,7 @@ import {
Space,
Tabs,
} from "antd";
import { course, department, resourceCategory } from "../../api";
import { course } from "../../api";
import styles from "./index.module.less";
import { PlusOutlined, ExclamationCircleFilled } from "@ant-design/icons";
import type { ColumnsType } from "antd/es/table";
@ -20,6 +20,7 @@ import { TreeDepartment, TreeCategory, PerButton } from "../../compenents";
import type { TabsProps } from "antd";
import { CourseCreate } from "./compenents/create";
import { CourseUpdate } from "./compenents/update";
import { CourseHourUpdate } from "./compenents/hour-update";
const { confirm } = Modal;
@ -50,6 +51,7 @@ export const CoursePage = () => {
const [createVisible, setCreateVisible] = useState<boolean>(false);
const [updateVisible, setUpdateVisible] = useState<boolean>(false);
const [updateHourVisible, setHourUpdateVisible] = useState<boolean>(false);
const [cid, setCid] = useState<number>(0);
const items: TabsProps["items"] = [
@ -133,9 +135,35 @@ export const CoursePage = () => {
title: "操作",
key: "action",
fixed: "right",
width: 100,
width: 210,
render: (_, record: any) => (
<Space size="small">
<PerButton
type="link"
text="学员"
class="b-link c-red"
icon={null}
p="course"
onClick={() => {
setCid(Number(record.id));
console.log("学员" + record.id);
}}
disabled={null}
/>
<div className="form-column"></div>
<PerButton
type="link"
text="课时"
class="b-link c-red"
icon={null}
p="course"
onClick={() => {
setCid(Number(record.id));
setHourUpdateVisible(true);
}}
disabled={null}
/>
<div className="form-column"></div>
<PerButton
type="link"
text="编辑"
@ -305,6 +333,14 @@ export const CoursePage = () => {
setRefresh(!refresh);
}}
/>
<CourseHourUpdate
id={cid}
open={updateHourVisible}
onCancel={() => {
setHourUpdateVisible(false);
setRefresh(!refresh);
}}
/>
<CourseUpdate
id={cid}
open={updateVisible}