feat: Implement comprehensive quiz functionality, new browse pages, and a classroom learning page with i18n support.

This commit is contained in:
supalerk-ar66 2026-01-26 17:15:57 +07:00
parent b96f85e650
commit e082c77946
6 changed files with 234 additions and 107 deletions

View file

@ -1,4 +1,4 @@
<script setup lang="ts">
<script setup lang="ts">
/**
* @file learning.vue
* @description หนาเรยนออนไลน (Classroom Interface)
@ -17,6 +17,7 @@ useHead({
})
const route = useRoute()
const { t } = useI18n()
const { fetchCourseLearningInfo, fetchLessonContent, saveVideoProgress, markLessonComplete, checkLessonAccess } = useCourse()
// State
@ -43,8 +44,9 @@ const saveProgressInterval = ref<any>(null) // ตัวแปรเก็บ se
// Helper for localization
const getLocalizedText = (text: any) => {
if (!text) return ''
if (typeof text === 'string') return text
return text?.th || text?.en || ''
return text.th || text.en || ''
}
const toggleSidebar = () => {
@ -108,7 +110,7 @@ const loadLesson = async (lessonId: number) => {
// Optional: Check access first
const accessRes = await checkLessonAccess(courseId.value, lessonId)
if (accessRes.success && !accessRes.data.is_accessible) {
alert('บทเรียนนี้ยังไม่เปิดให้เข้าชม')
alert(t('classroom.notAvailable'))
isLessonLoading.value = false
return
}
@ -245,10 +247,10 @@ onBeforeUnmount(() => {
<q-toolbar>
<q-btn flat round dense icon="menu" class="lg:hidden mr-2" @click="toggleSidebar" />
<q-btn flat dense no-caps icon="arrow_back" label="กลับไปหน้าหลัก" to="/dashboard/my-courses" class="text-slate-600 dark:text-slate-300 mobile-hide-label" />
<q-btn flat dense no-caps icon="arrow_back" :label="$t('classroom.backToDashboard')" to="/dashboard/my-courses" class="text-slate-600 dark:text-slate-300 mobile-hide-label" />
<q-toolbar-title class="text-sm font-bold text-center lg:text-left truncate">
{{ courseData ? getLocalizedText(courseData.course.title) : 'กำลังโหลด...' }}
{{ courseData ? getLocalizedText(courseData.course.title) : $t('classroom.loadingTitle') }}
</q-toolbar-title>
<div class="flex items-center gap-2">
@ -306,7 +308,7 @@ onBeforeUnmount(() => {
</div>
<div v-else-if="isLoading" class="p-6 text-center text-slate-500">
<q-spinner color="primary" size="2em" />
<div class="mt-2 text-xs">กำลงโหลดเนอหา...</div>
<div class="mt-2 text-xs">{{ $t('classroom.loadingCurriculum') }}</div>
</div>
</q-drawer>
@ -314,9 +316,8 @@ onBeforeUnmount(() => {
<q-page-container class="bg-white dark:bg-slate-900">
<q-page class="flex flex-col h-full bg-slate-50 dark:bg-[#0B0F1A]">
<!-- Video Player & Content Area -->
<!-- Note: Using existing logic but wrapped -->
<div class="w-full max-w-7xl mx-auto p-4 md:p-6 flex-grow">
<!-- Video Player Component Placeholder logic -->
<!-- Video Player -->
<div v-if="currentLesson" class="bg-black rounded-xl overflow-hidden shadow-lg mb-6 aspect-video relative group">
<video
ref="videoRef"
@ -331,7 +332,7 @@ onBeforeUnmount(() => {
<div v-else class="flex items-center justify-center h-full text-white/50 bg-slate-900">
<div class="text-center">
<q-icon name="article" size="xl" />
<p class="mt-2">บทเรยนนเปนเอกสารประกอบการเรยน</p>
<p class="mt-2">{{ $t('classroom.readingMaterial') }}</p>
</div>
</div>
@ -351,11 +352,10 @@ onBeforeUnmount(() => {
<div v-if="currentLesson" class="bg-white dark:bg-slate-800 p-6 rounded-2xl shadow-sm border border-slate-100 dark:border-white/5">
<h1 class="text-2xl font-bold mb-2">{{ getLocalizedText(currentLesson.title) }}</h1>
<p class="text-slate-500 dark:text-slate-400" v-if="currentLesson.description">{{ currentLesson.description }}</p>
<div class="mt-6 prose dark:prose-invert max-w-none">
<!-- Content description or attachments here -->
<div v-if="!videoSrc" class="p-4 bg-slate-50 dark:bg-slate-900/50 rounded-xl border border-dashed border-slate-300 dark:border-slate-700 text-center">
<p>เนอหาบทเรยน</p>
</div>
<!-- Lesson Content Area -->
<div v-if="!videoSrc && currentLesson.content" class="mt-6 prose dark:prose-invert max-w-none p-6 bg-slate-50 dark:bg-slate-900 rounded-xl border border-slate-200 dark:border-white/5">
<div v-html="getLocalizedText(currentLesson.content)"></div>
</div>
</div>
</div>
@ -376,4 +376,3 @@ onBeforeUnmount(() => {
}
}
</style>