线上课新建无章节课时选择逻辑优化

This commit is contained in:
禺狨 2023-03-17 12:18:17 +08:00
parent 60aa433589
commit 0460da6974
6 changed files with 155 additions and 47 deletions

View File

@ -12,8 +12,9 @@ interface VideoItem {
}
interface PropsInterface {
defaultKeys: any[];
open: boolean;
onSelected: (arr: any[], label: any[]) => void;
onSelected: (arr: any[], videos: any[]) => void;
onCancel: () => void;
}
@ -21,7 +22,7 @@ export const SelectResource = (props: PropsInterface) => {
const [refresh, setRefresh] = useState(true);
const [tabKey, setTabKey] = useState(1);
const [selectKeys, setSelectKeys] = useState<any>([]);
const [selectLabel, setSelectLabel] = useState<any>([]);
const [selectVideos, setSelectVideos] = useState<any>([]);
const items: TabsProps["items"] = [
{
@ -31,11 +32,11 @@ export const SelectResource = (props: PropsInterface) => {
<div className="float-left">
<UploadVideoSub
label="视频"
defaultCheckedList={[]}
defaultCheckedList={props.defaultKeys}
open={refresh}
onSelected={(arr: any[], label: any[]) => {
onSelected={(arr: any[], videos: any[]) => {
setSelectKeys(arr);
setSelectLabel(label);
setSelectVideos(videos);
}}
/>
</div>
@ -60,7 +61,7 @@ export const SelectResource = (props: PropsInterface) => {
open={props.open}
width={800}
maskClosable={false}
onOk={() => props.onSelected(selectKeys, selectLabel)}
onOk={() => props.onSelected(selectKeys, selectVideos)}
>
<Row>
<Tabs defaultActiveKey="1" items={items} onChange={onChange} />

View File

@ -20,7 +20,7 @@ interface PropsInterface {
defaultCheckedList: any[];
label: string;
open: boolean;
onSelected: (arr: any[], label: any) => void;
onSelected: (arr: any[], videos: []) => void;
}
export const UploadVideoSub = (props: PropsInterface) => {
@ -36,9 +36,7 @@ export const UploadVideoSub = (props: PropsInterface) => {
const [categoryCount, setCategoryCount] = useState<any>({});
const [plainOptions, setPlainOptions] = useState<any>([]);
const [checkedList, setCheckedList] = useState<CheckboxValueType[]>(
props.defaultCheckedList
);
const [checkedList, setCheckedList] = useState<CheckboxValueType[]>([]);
const [indeterminate, setIndeterminate] = useState(false);
const [checkAll, setCheckAll] = useState(false);
@ -89,6 +87,10 @@ export const UploadVideoSub = (props: PropsInterface) => {
setVideoList([]);
setRefresh(!refresh);
};
//重置选中的key
useEffect(() => {
setCheckedList(props.defaultCheckedList);
}, [props.defaultCheckedList]);
// 加载列表
useEffect(() => {
@ -99,16 +101,21 @@ export const UploadVideoSub = (props: PropsInterface) => {
setCheckedList(list);
setIndeterminate(!!list.length && list.length < plainOptions.length);
setCheckAll(list.length === plainOptions.length);
let arrLabel: any = [];
let arrVideos: any = [];
for (let i = 0; i < list.length; i++) {
videoList.map((item: any) => {
if (item.id === list[i]) {
arrLabel.push(item.name);
arrVideos.push({
name: item.name,
type: item.type,
rid: item.id,
duration: videosExtra[item.id].duration,
});
}
});
}
props.onSelected(list, arrLabel);
props.onSelected(list, arrVideos);
};
const onCheckAllChange = (e: CheckboxChangeEvent) => {
@ -116,9 +123,17 @@ export const UploadVideoSub = (props: PropsInterface) => {
setCheckedList(e.target.checked ? arr : []);
setIndeterminate(false);
setCheckAll(e.target.checked);
const arrLabel = videoList.map((item: any) => item.name);
let arrVideos: any = [];
videoList.map((item: any) => {
arrVideos.push({
name: item.name,
type: item.type,
rid: item.id,
duration: videosExtra[item.id].duration,
});
});
if (e.target.checked) {
props.onSelected(arr, arrLabel);
props.onSelected(arr, arrVideos);
} else {
props.onSelected([], []);
}

View File

@ -526,3 +526,11 @@ textarea.ant-input {
flex-direction: row-reverse;
}
}
.tree-video-title {
margin-left: 4px;
width: 346px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}

View File

@ -32,7 +32,7 @@
/* Firefox */
-webkit-box-sizing: border-box;
/* Safari */
padding: 16px;
padding: 16px 16px 16px 0;
margin-left: 42px;
.no-hours {
height: 24px;
@ -40,5 +40,6 @@
font-weight: 400;
color: rgba(0, 0, 0, 0.25);
line-height: 24px;
margin-left: 16px;
}
}

View File

@ -16,6 +16,7 @@ import { course, department } from "../../../api/index";
import { UploadImageButton, SelectResource } from "../../../compenents";
import { ExclamationCircleFilled } from "@ant-design/icons";
import { getHost } from "../../../utils/index";
import { TreeHours } from "./hours";
const { confirm } = Modal;
@ -44,6 +45,7 @@ export const CourseCreate: React.FC<PropInterface> = ({ open, onCancel }) => {
const [chapters, setChapters] = useState<any>([]);
const [hours, setHours] = useState<any>([]);
const [videoVisible, setVideoVisible] = useState<boolean>(false);
const [treeData, setTreeData] = useState<any>([]);
useEffect(() => {
getParams();
@ -61,8 +63,10 @@ export const CourseCreate: React.FC<PropInterface> = ({ open, onCancel }) => {
hasChapter: 0,
});
setThumb(defaultThumb1);
setChapterType(0);
setChapters([]);
setHours([]);
setTreeData([]);
}, [form, open]);
const getParams = () => {
@ -107,8 +111,10 @@ export const CourseCreate: React.FC<PropInterface> = ({ open, onCancel }) => {
const onFinish = (values: any) => {
let dep_ids: any[] = [];
for (let i = 0; i < values.dep_ids.length; i++) {
dep_ids.push(values.dep_ids[i][values.dep_ids[i].length - 1]);
if (type === "elective") {
for (let i = 0; i < values.dep_ids.length; i++) {
dep_ids.push(values.dep_ids[i][values.dep_ids[i].length - 1]);
}
}
let category_ids: any[] = [];
for (let j = 0; j < values.category_ids.length; j++) {
@ -117,7 +123,15 @@ export const CourseCreate: React.FC<PropInterface> = ({ open, onCancel }) => {
);
}
course
.storeCourse(values.title, values.thumb, 1, dep_ids, category_ids, [], [])
.storeCourse(
values.title,
values.thumb,
1,
dep_ids,
category_ids,
chapters,
treeData
)
.then((res: any) => {
message.success("保存成功!");
onCancel();
@ -132,6 +146,12 @@ export const CourseCreate: React.FC<PropInterface> = ({ open, onCancel }) => {
setType(e.target.value);
};
const selectData = (arr: any, videos: any) => {
setHours(arr);
setTreeData(videos);
setVideoVisible(false);
};
const getChapterType = (e: any) => {
confirm({
title: "操作确认",
@ -153,6 +173,22 @@ export const CourseCreate: React.FC<PropInterface> = ({ open, onCancel }) => {
});
};
const delHour = (id: number) => {
const data = [...treeData];
const index = data.findIndex((i: any) => i.id === 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([]);
}
};
return (
<>
<Drawer
@ -172,13 +208,13 @@ export const CourseCreate: React.FC<PropInterface> = ({ open, onCancel }) => {
>
<div className="float-left mt-24">
<SelectResource
defaultKeys={hours}
open={videoVisible}
onCancel={() => {
setVideoVisible(false);
}}
onSelected={(arr: any, label: any) => {
console.log("sel", arr, label);
setVideoVisible(false);
onSelected={(arr: any, videos: any) => {
selectData(arr, videos);
}}
/>
<Form
@ -224,24 +260,28 @@ export const CourseCreate: React.FC<PropInterface> = ({ open, onCancel }) => {
<Radio value="elective"></Radio>
</Radio.Group>
</Form.Item>
<Form.Item
label="指派部门"
name="dep_ids"
rules={[
{
required: type === "elective" ? true : false,
message: "请选择课程指派部门!",
},
]}
>
<Cascader
style={{ width: 424 }}
options={departments}
multiple
maxTagCount="responsive"
placeholder="请选择课程指派部门"
/>
</Form.Item>
{type === "elective" && (
<Form.Item
label="指派部门"
name="dep_ids"
rules={[
{
required: true,
message: "请选择课程指派部门!",
},
]}
>
<Cascader
style={{ width: 424 }}
options={departments}
multiple
maxTagCount="responsive"
placeholder="请选择课程指派部门"
/>
</Form.Item>
)}
<Form.Item
label="课程封面"
name="thumb"
@ -365,10 +405,17 @@ export const CourseCreate: React.FC<PropInterface> = ({ open, onCancel }) => {
</div>
</Form.Item>
<div className={styles["hous-box"]}>
{hours.length === 0 && (
{treeData.length === 0 && (
<span className={styles["no-hours"]}></span>
)}
{hours.length > 0 && 13}
{treeData.length > 0 && (
<TreeHours
data={treeData}
onRemoveItem={(id: number) => {
delHour(id);
}}
/>
)}
</div>
</div>
)}

View File

@ -1,14 +1,14 @@
import { message, Tree } from "antd";
import { message, Tree, Tooltip } from "antd";
import { useState, useEffect } from "react";
interface Option {
id: string | number;
id: number;
name: string;
}
interface PropInterface {
data: Option[];
onUpdate: () => void;
onRemoveItem: (id: number) => void;
}
export const TreeHours = (props: PropInterface) => {
@ -16,18 +16,54 @@ export const TreeHours = (props: PropInterface) => {
const [loading, setLoading] = useState<boolean>(true);
useEffect(() => {
const hours = props.data;
if (hours.length === 0) {
return;
}
checkTree(hours);
}, [props.data]);
const checkTree = (hours: any) => {
const arr = [];
for (let i = 0; i < hours.length; i++) {
arr.push({
title: hours[i].name,
title: (
<div className="d-flex">
<div className="d-flex">
<i
className="iconfont icon-icon-video"
style={{
fontSize: 16,
color: "rgba(0,0,0,0.3)",
}}
/>
<div className="tree-video-title mr-24">{hours[i].name}</div>
</div>
<Tooltip placement="top" title="可拖拽排序">
<i
className="iconfont icon-icon-drag mr-16"
style={{ fontSize: 24 }}
/>
</Tooltip>
<i
className="iconfont icon-icon-delete"
style={{ fontSize: 24 }}
onClick={() => removeItem(hours[i].id)}
/>
</div>
),
key: hours[i].id,
});
}
setTreeData(arr);
}, [props.data]);
};
const removeItem = (id: number) => {
if (id === 0) {
return;
}
props.onRemoveItem(id);
};
return (
<div>