2024-12-31 15:57:32 +08:00
|
|
|
|
|
|
|
import { ChevronDownIcon, ClockIcon, PlayCircleIcon } from '@heroicons/react/24/outline'
|
|
|
|
import { useState } from 'react'
|
2025-01-06 08:45:23 +08:00
|
|
|
import { Section, SectionDto } from "@nice/common"
|
2024-12-31 15:57:32 +08:00
|
|
|
interface CourseSyllabusProps {
|
|
|
|
sections: SectionDto[]
|
|
|
|
onLectureClick?: (lectureId: string) => void
|
|
|
|
}
|
|
|
|
|
|
|
|
export const CourseSyllabus: React.FC<CourseSyllabusProps> = ({
|
|
|
|
sections,
|
|
|
|
onLectureClick
|
|
|
|
}) => {
|
|
|
|
const [expandedSections, setExpandedSections] = useState<string[]>([])
|
|
|
|
|
|
|
|
const toggleSection = (sectionId: string) => {
|
|
|
|
setExpandedSections(prev =>
|
|
|
|
prev.includes(sectionId)
|
|
|
|
? prev.filter(id => id !== sectionId)
|
|
|
|
: [...prev, sectionId]
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
return (
|
|
|
|
<div className="space-y-4">
|
|
|
|
{sections.map((section) => (
|
|
|
|
<div key={section.id} className="border rounded-lg">
|
|
|
|
{/* 章节标题 */}
|
|
|
|
<button
|
|
|
|
className="w-full flex items-center justify-between p-4 hover:bg-gray-50"
|
|
|
|
onClick={() => toggleSection(section.id)}
|
|
|
|
>
|
|
|
|
<div className="flex items-center gap-4">
|
|
|
|
<span className="text-lg font-medium">
|
|
|
|
第{Math.floor(section.order)}章
|
|
|
|
</span>
|
|
|
|
<div>
|
|
|
|
<h3 className="text-left font-medium">{section.title}</h3>
|
|
|
|
<p className="text-sm text-gray-500">
|
|
|
|
{section.totalLectures}节课 · {Math.floor(section.totalDuration / 60)}分钟
|
|
|
|
</p>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<ChevronDownIcon
|
|
|
|
className={`w-5 h-5 transition-transform duration-200 ${expandedSections.includes(section.id) ? 'rotate-180' : ''
|
|
|
|
}`}
|
|
|
|
/>
|
|
|
|
</button>
|
|
|
|
|
|
|
|
{/* 课时列表 */}
|
|
|
|
{expandedSections.includes(section.id) && (
|
|
|
|
<div className="border-t">
|
|
|
|
{section.lectures.map((lecture) => (
|
|
|
|
<button
|
|
|
|
key={lecture.id}
|
|
|
|
className="w-full flex items-center gap-4 p-4 hover:bg-gray-50 text-left"
|
|
|
|
onClick={() => onLectureClick?.(lecture.id)}
|
|
|
|
>
|
|
|
|
<PlayCircleIcon className="w-5 h-5 text-blue-500 flex-shrink-0" />
|
|
|
|
<div className="flex-grow">
|
|
|
|
<h4 className="font-medium">{lecture.title}</h4>
|
|
|
|
{lecture.description && (
|
|
|
|
<p className="text-sm text-gray-500 mt-1">{lecture.description}</p>
|
|
|
|
)}
|
|
|
|
</div>
|
|
|
|
<div className="flex items-center gap-1 text-sm text-gray-500">
|
|
|
|
<ClockIcon className="w-4 h-4" />
|
|
|
|
<span>{lecture.duration}分钟</span>
|
|
|
|
</div>
|
|
|
|
</button>
|
|
|
|
))}
|
|
|
|
</div>
|
|
|
|
)}
|
|
|
|
</div>
|
|
|
|
))}
|
|
|
|
</div>
|
|
|
|
)
|
|
|
|
}
|