feat: Add new classroom learning page with course content display, video playback, progress tracking, lesson access control, and course announcements.

This commit is contained in:
supalerk-ar66 2026-02-10 11:21:29 +07:00
parent 8c495f3871
commit 350e3c27b3

View file

@ -133,15 +133,23 @@ const resetAndNavigate = (path: string) => {
}
}
// Logic loadLesson แยกออกมา
// Logic loadLesson ให้ลื่นไหลแบบ SPA
const handleLessonSelect = (lessonId: number) => {
if (currentLesson.value?.id === lessonId) return
const url = new URL(window.location.href)
url.searchParams.set('lesson_id', lessonId.toString())
resetAndNavigate(url.toString())
// 1. เปลี่ยน URL แบบนุ่มนวล
router.push({ query: { ...route.query, lesson_id: lessonId.toString() } })
// 2. โหลดเนื้อหาใหม่โดยไม่ Refresh หน้า
loadLesson(lessonId)
// ปิด Sidebar บนมือถือเมื่อเลือกบทเรียน
if (sidebarOpen.value) {
sidebarOpen.value = false
}
}
// Logic สำหรับการกดย้อนกลับหรืออกจากหน้าเรียน
// Logic สำหรับการกดย้อนกลับหรือออกจากหน้าเรียน (ใช้ Hard Reload ตามเดิม)
const handleExit = (path: string) => {
resetAndNavigate(path)
}
@ -155,24 +163,25 @@ const handleExit = (path: string) => {
const loadCourseData = async () => {
if (!courseId.value) return
isLoading.value = true
// Reset states before loading new course
courseData.value = null
currentLesson.value = null
announcements.value = []
try {
const res = await fetchCourseLearningInfo(courseId.value)
if (res.success) {
courseData.value = res.data
// Auto-load logic: ถ้ายังไม่ได้เลือกบทเรียน ให้โหลดบทแรกที่ไม่ล็อคมาแสดง
if (!currentLesson.value) {
const firstChapter = res.data.chapters[0]
if (firstChapter && firstChapter.lessons.length > 0) {
// Find first unlocked or just first
const availableLesson = firstChapter.lessons.find((l: any) => !l.is_locked) || firstChapter.lessons[0]
loadLesson(availableLesson.id)
}
// Auto-load logic: เช็คจาก URL ก่อน ถ้าไม่มีค่อยหาบทแรก
const urlLessonId = route.query.lesson_id ? Number(route.query.lesson_id) : null
if (urlLessonId) {
// ถ้ามีใน URL ให้โหลดบทนั้นเลย
loadLesson(urlLessonId)
} else if (!currentLesson.value) {
// ถ้าไม่มีใน URL ให้หาบทแรกที่ไม่ล็อค
const firstChapter = res.data.chapters[0]
if (firstChapter && firstChapter.lessons.length > 0) {
const availableLesson = firstChapter.lessons.find((l: any) => !l.is_locked) || firstChapter.lessons[0]
loadLesson(availableLesson.id)
}
}
// Fetch Announcements
@ -507,7 +516,7 @@ onBeforeUnmount(() => {
<!-- Header -->
<q-header bordered class="bg-[var(--bg-surface)] border-b border-gray-200 dark:border-white/5 text-[var(--text-main)] h-14">
<q-toolbar>
<q-btn flat round dense icon="menu" class="lg:hidden mr-2 text-slate-900 dark:text-white" @click="toggleSidebar" />
<q-btn flat round dense icon="menu" class="mr-2 text-slate-900 dark:text-white hover:bg-slate-100 dark:hover:bg-slate-800 transition-colors" @click="toggleSidebar" />
<!-- Back Button & Branding -->
<div class="flex items-center gap-2 mr-6">