feat: Introduce core e-learning features with new pages for course details, dashboard, authentication, browsing, and learning, supported by a useCourse composable.

This commit is contained in:
supalerk-ar66 2026-01-23 09:47:32 +07:00
parent c982ab2c05
commit 0eb9b522f6
6 changed files with 109 additions and 38 deletions

View file

@ -1,12 +1,12 @@
<script setup lang="ts">
/**
* @file learning.vue
* @description Course Learning Interface ("Classroom" view).
* Defines the main learning environment where users watch video lessons and track progress.
* Layout mimics a typical LMS with a sidebar for curriculum and a main content area for video/details.
* @important Matches the provided design mockups pixel-perfectly.
* @description หนาเรยนออนไลน (Classroom Interface)
* ดการแสดงผลวโอรายการบทเรยน และตดตามความคบหน
* ออกแบบใหเหมอนระบบ LMS มาตรฐาน
*/
definePageMeta({
layout: false, // Custom layout defined within this component
middleware: 'auth'
@ -24,18 +24,23 @@ const sidebarOpen = ref(false)
const activeTab = ref<'details' | 'announcements'>('details')
const courseId = computed(() => Number(route.query.course_id))
// ==========================================
// 1. State ( UI)
// ==========================================
// courseData: ()
const courseData = ref<any>(null)
// currentLesson:
const currentLesson = ref<any>(null)
const isLoading = ref(true)
const isLessonLoading = ref(false)
const isLoading = ref(true) //
const isLessonLoading = ref(false) //
// Video Player Logic
// Video Player State ()
const videoRef = ref<HTMLVideoElement | null>(null)
const isPlaying = ref(false)
const videoProgress = ref(0)
const currentTime = ref(0)
const duration = ref(0)
const saveProgressInterval = ref<any>(null)
const saveProgressInterval = ref<any>(null) // setInterval
// Helper for localization
const getLocalizedText = (text: any) => {
@ -59,6 +64,11 @@ const switchTab = (tab: 'details' | 'announcements', lessonId: any = null) => {
}
// Data Fetching
// ==========================================
// 2. (Data Fetching)
// ==========================================
//
const loadCourseData = async () => {
if (!courseId.value) return
isLoading.value = true
@ -67,7 +77,7 @@ const loadCourseData = async () => {
if (res.success) {
courseData.value = res.data
// Auto-load first unlocked lesson if no current lesson
// Auto-load logic:
if (!currentLesson.value) {
const firstChapter = res.data.chapters[0]
if (firstChapter && firstChapter.lessons.length > 0) {
@ -164,7 +174,10 @@ const videoSrc = computed(() => {
return ''
})
// Save progress periodically
// ==========================================
// 3. (Progress Tracking)
// ==========================================
// 10
watch(() => isPlaying.value, (playing) => {
if (playing) {
saveProgressInterval.value = setInterval(() => {
@ -190,11 +203,12 @@ watch(() => isPlaying.value, (playing) => {
}
})
// (Complete)
const onVideoEnded = async () => {
isPlaying.value = false
if (currentLesson.value) {
await markLessonComplete(courseId.value, currentLesson.value.id)
// Reload course data to update sidebar progress/locks
//
await loadCourseData()
// Auto play next logic could go here