2025-09-03 13:26:13 +08:00
|
|
|
|
import { useState, useEffect } from "react";
|
|
|
|
|
|
import { Collapse, Timeline, Spin } from "@arco-design/web-react";
|
|
|
|
|
|
import { getCourseLiveList } from "@/services/courseLive";
|
|
|
|
|
|
import "./index.css";
|
|
|
|
|
|
|
|
|
|
|
|
const TimelineItem = Timeline.Item;
|
|
|
|
|
|
const CollapseItem = Collapse.Item;
|
|
|
|
|
|
|
|
|
|
|
|
const CourseList = ({ className = "", onCourseClick }) => {
|
|
|
|
|
|
const [courseLiveList, setCourseLiveList] = useState([]);
|
|
|
|
|
|
const [loading, setLoading] = useState(false);
|
|
|
|
|
|
const [selectedCourseId, setSelectedCourseId] = useState(null);
|
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
|
fetchCourseList();
|
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
|
|
const fetchCourseList = async () => {
|
|
|
|
|
|
setLoading(true);
|
|
|
|
|
|
try {
|
|
|
|
|
|
const res = await getCourseLiveList();
|
|
|
|
|
|
if (res.success) {
|
|
|
|
|
|
const courseList = res.data || [];
|
|
|
|
|
|
setCourseLiveList(courseList);
|
|
|
|
|
|
|
|
|
|
|
|
// 设置默认选中今天的课程(如果有)
|
|
|
|
|
|
const todayStr = new Date().toISOString().split('T')[0];
|
|
|
|
|
|
let foundTodayCourse = false;
|
|
|
|
|
|
|
|
|
|
|
|
for (const unit of courseList) {
|
|
|
|
|
|
const todayCourse = unit.courses.find(c => c.date === todayStr);
|
|
|
|
|
|
if (todayCourse) {
|
|
|
|
|
|
setSelectedCourseId(todayCourse.courseId);
|
|
|
|
|
|
// 触发课程选择事件
|
|
|
|
|
|
if (onCourseClick) {
|
|
|
|
|
|
onCourseClick({
|
|
|
|
|
|
...todayCourse,
|
|
|
|
|
|
unitName: unit.unitName
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
foundTodayCourse = true;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 如果没有今天的课程,选中第一个current或upcoming的课程
|
|
|
|
|
|
if (!foundTodayCourse) {
|
|
|
|
|
|
for (const unit of courseList) {
|
|
|
|
|
|
const activeCourse = unit.courses.find(c => c.current || c.upcoming);
|
|
|
|
|
|
if (activeCourse) {
|
|
|
|
|
|
setSelectedCourseId(activeCourse.courseId);
|
|
|
|
|
|
if (onCourseClick) {
|
|
|
|
|
|
onCourseClick({
|
|
|
|
|
|
...activeCourse,
|
|
|
|
|
|
unitName: unit.unitName
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error("获取课程列表失败:", error);
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
setLoading(false);
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 判断课程状态
|
|
|
|
|
|
const getCourseStatus = (course) => {
|
|
|
|
|
|
if (course.completed) return "finish";
|
|
|
|
|
|
if (course.current) return "active";
|
|
|
|
|
|
|
|
|
|
|
|
// 判断未来课程的具体状态
|
|
|
|
|
|
if (course.upcoming) {
|
|
|
|
|
|
const courseDate = new Date(course.date);
|
|
|
|
|
|
const today = new Date();
|
|
|
|
|
|
|
|
|
|
|
|
// 重置时间部分只比较日期
|
|
|
|
|
|
courseDate.setHours(0, 0, 0, 0);
|
|
|
|
|
|
today.setHours(0, 0, 0, 0);
|
|
|
|
|
|
|
|
|
|
|
|
const timeDiff = courseDate - today;
|
|
|
|
|
|
const daysDiff = Math.floor(timeDiff / (24 * 60 * 60 * 1000));
|
|
|
|
|
|
|
|
|
|
|
|
// 未来7天内的课程显示为"即将开始"
|
|
|
|
|
|
if (daysDiff > 0 && daysDiff <= 7) {
|
|
|
|
|
|
return "coming";
|
|
|
|
|
|
}
|
|
|
|
|
|
// 7天后的课程显示为"未开始"
|
|
|
|
|
|
return "not-started";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 默认状态
|
|
|
|
|
|
return "pending";
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 获取图标类型
|
|
|
|
|
|
const getDotIcon = (course) => {
|
|
|
|
|
|
if (course.completed) return <div className="time-line-dot-icon" />;
|
|
|
|
|
|
if (course.current) return <div className="time-line-clock-icon" />;
|
|
|
|
|
|
return <div className="time-line-lock-icon" />;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
if (loading) {
|
|
|
|
|
|
return (
|
|
|
|
|
|
<div className={`${className} course-list-wrapper`}>
|
|
|
|
|
|
<p className="course-list-title">课程列表</p>
|
|
|
|
|
|
<div className="course-list-content">
|
|
|
|
|
|
<Spin />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
|
<div className={`${className} course-list-wrapper`}>
|
|
|
|
|
|
<p className="course-list-title">课程列表</p>
|
|
|
|
|
|
<div className="course-list-content">
|
|
|
|
|
|
<Collapse
|
|
|
|
|
|
lazyload
|
|
|
|
|
|
className="course-list"
|
|
|
|
|
|
bordered={false}
|
|
|
|
|
|
expandIconPosition="right"
|
|
|
|
|
|
defaultActiveKey={["1"]}
|
|
|
|
|
|
>
|
|
|
|
|
|
{courseLiveList.map((unit, index) => (
|
|
|
|
|
|
<CollapseItem
|
|
|
|
|
|
key={unit.unitId}
|
|
|
|
|
|
header={unit.unitName}
|
|
|
|
|
|
name={String(index + 1)}
|
|
|
|
|
|
className="course-list-item"
|
|
|
|
|
|
>
|
|
|
|
|
|
<Timeline>
|
|
|
|
|
|
{unit.courses.map((course) => (
|
|
|
|
|
|
<TimelineItem
|
|
|
|
|
|
key={course.courseId}
|
|
|
|
|
|
dot={getDotIcon(course)}
|
|
|
|
|
|
lineType="dashed"
|
|
|
|
|
|
>
|
|
|
|
|
|
<div
|
|
|
|
|
|
className={`time-line-item ${getCourseStatus(course)} ${selectedCourseId === course.courseId ? 'selected' : ''}`}
|
|
|
|
|
|
onClick={() => {
|
|
|
|
|
|
setSelectedCourseId(course.courseId);
|
|
|
|
|
|
onCourseClick && onCourseClick({ ...course, unitName: unit.unitName });
|
|
|
|
|
|
}}
|
|
|
|
|
|
style={{ cursor: 'pointer' }}
|
|
|
|
|
|
>
|
2025-09-05 20:46:03 +08:00
|
|
|
|
<p style={{
|
|
|
|
|
|
overflow: 'visible',
|
|
|
|
|
|
textOverflow: 'unset',
|
|
|
|
|
|
whiteSpace: 'normal',
|
|
|
|
|
|
wordBreak: 'break-word',
|
|
|
|
|
|
WebkitLineClamp: 'unset',
|
|
|
|
|
|
WebkitBoxOrient: 'unset',
|
|
|
|
|
|
display: 'block',
|
|
|
|
|
|
maxWidth: 'calc(100% - 70px)'
|
|
|
|
|
|
}}>{course.courseName}</p>
|
2025-09-03 13:26:13 +08:00
|
|
|
|
<div className="time-line-item-info">
|
|
|
|
|
|
<span>{course.teacherName}</span>
|
|
|
|
|
|
<span>{course.date}</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</TimelineItem>
|
|
|
|
|
|
))}
|
|
|
|
|
|
</Timeline>
|
|
|
|
|
|
</CollapseItem>
|
|
|
|
|
|
))}
|
|
|
|
|
|
</Collapse>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
export default CourseList;
|