177 lines
7.8 KiB
Vue
177 lines
7.8 KiB
Vue
<script setup lang="ts">
|
|
/**
|
|
* @file quiz.vue
|
|
* @description Quiz Interface.
|
|
* Manages the entire quiz lifecycle: Start -> Taking -> Results -> Review.
|
|
* Features a timer, question navigation, and detailed result analysis.
|
|
*/
|
|
|
|
definePageMeta({
|
|
layout: false,
|
|
middleware: 'auth'
|
|
})
|
|
|
|
useHead({
|
|
title: 'แบบทดสอบ - e-Learning'
|
|
})
|
|
|
|
const router = useRouter()
|
|
|
|
// Quiz State Management
|
|
// Tracks the current screen/step in the quiz flow
|
|
const currentScreen = ref<'start' | 'taking' | 'result' | 'review'>('start')
|
|
const timeLeft = ref(30 * 60) // 30 minutes in seconds
|
|
let timerInterval: ReturnType<typeof setInterval> | null = null
|
|
|
|
// Display formatted time (MM:SS)
|
|
const timerDisplay = computed(() => {
|
|
const minutes = Math.floor(timeLeft.value / 60)
|
|
const seconds = timeLeft.value % 60
|
|
return `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`
|
|
})
|
|
|
|
const showReview = () => {
|
|
currentScreen.value = 'review'
|
|
}
|
|
|
|
const startQuiz = () => {
|
|
currentScreen.value = 'taking'
|
|
// Start countdown
|
|
timerInterval = setInterval(() => {
|
|
if (timeLeft.value > 0) timeLeft.value--
|
|
else submitQuiz(true)
|
|
}, 1000)
|
|
}
|
|
|
|
const submitQuiz = (auto = false) => {
|
|
if (auto || confirm('คุณแน่ใจหรือไม่ว่าต้องการส่งคำตอบ?')) {
|
|
if (timerInterval) clearInterval(timerInterval)
|
|
currentScreen.value = 'result'
|
|
}
|
|
}
|
|
|
|
const route = useRoute()
|
|
|
|
const confirmExit = () => {
|
|
const courseId = route.query.course_id
|
|
const target = courseId ? `/classroom/learning?course_id=${courseId}` : '/classroom/learning'
|
|
|
|
if (currentScreen.value === 'taking') {
|
|
if (confirm('คุณกำลังทำแบบทดสอบอยู่ หากออกตอนนี้ความคืบหน้าจะหายไป ยืนยันที่จะออก?')) {
|
|
router.push(target)
|
|
}
|
|
} else {
|
|
router.push(target)
|
|
}
|
|
}
|
|
|
|
onUnmounted(() => {
|
|
if (timerInterval) clearInterval(timerInterval)
|
|
})
|
|
</script>
|
|
|
|
<template>
|
|
<div class="quiz-shell min-h-screen bg-slate-50 dark:bg-[#0b0f1a] text-slate-900 dark:text-slate-200 font-main antialiased selection:bg-blue-500/20 transition-colors">
|
|
<!-- Header -->
|
|
<header class="h-14 bg-white dark:bg-[#161b22] fixed top-0 inset-x-0 z-[100] flex items-center px-6 border-b border-slate-200 dark:border-white/5 transition-colors">
|
|
<div class="flex items-center">
|
|
<button class="flex items-center gap-2 text-sm font-bold text-slate-500 hover:text-slate-800 dark:text-slate-400 dark:hover:text-white transition-colors" @click="confirmExit">
|
|
<span>←</span>
|
|
<span>ออกจากแบบทดสอบ</span>
|
|
</button>
|
|
<div class="w-[1px] h-4 bg-slate-300 dark:bg-white/10 mx-4"/>
|
|
<h1 class="text-base font-black text-slate-900 dark:text-white uppercase tracking-tight">แบบทดสอบท้ายบท: พื้นฐาน UX</h1>
|
|
</div>
|
|
</header>
|
|
|
|
<!-- Main Content Area -->
|
|
<main class="pt-14 h-screen flex items-center justify-center overflow-y-auto px-4 custom-scrollbar">
|
|
|
|
<!-- 1. START SCREEN -->
|
|
<div v-if="currentScreen === 'start'" class="w-full max-w-[640px] animate-fade-in py-12">
|
|
<div class="bg-white dark:!bg-[#1e293b] border border-slate-200 dark:border-white/5 rounded-[32px] p-8 md:p-14 shadow-lg dark:shadow-2xl relative overflow-hidden transition-colors">
|
|
|
|
<!-- Top Icon Wrapper -->
|
|
<div class="flex justify-center mb-10">
|
|
<div class="w-20 h-20 rounded-3xl bg-blue-50 dark:bg-blue-500/10 border border-blue-100 dark:border-blue-500/20 flex items-center justify-center shadow-inner">
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="w-10 h-10 text-blue-600 dark:text-blue-500" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
<path d="M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z"/>
|
|
<polyline points="14 2 14 8 20 8"/>
|
|
<path d="M10 12h4"/><path d="M10 16h4"/><path d="M10 8h1"/>
|
|
<circle cx="16" cy="16" r="3" fill="currentColor" class="text-orange-500 opacity-80" />
|
|
</svg>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="text-center mb-10">
|
|
<h2 class="text-[32px] font-black text-slate-900 dark:text-white mb-2 tracking-tight">แบบทดสอบท้ายบท</h2>
|
|
<p class="text-[13px] font-bold text-slate-500 dark:text-slate-400 uppercase tracking-widest leading-none">เตรียมความพร้อมก่อนเริ่มทำ</p>
|
|
</div>
|
|
|
|
<!-- Instruction Box -->
|
|
<div class="bg-slate-50 dark:bg-[#0b121f]/80 p-8 rounded-3xl mb-8 border border-slate-100 dark:border-white/5">
|
|
<h3 class="text-[12px] font-black text-slate-500 dark:text-slate-400 mb-6 uppercase tracking-[0.2em] flex items-center gap-2">
|
|
คำชี้แจง
|
|
</h3>
|
|
<ul class="space-y-4">
|
|
<li class="flex items-start gap-3">
|
|
<span class="w-1.5 h-1.5 rounded-full bg-blue-500 mt-1.5 flex-shrink-0"/>
|
|
<span class="text-[14px] text-slate-600 dark:text-slate-300 font-medium leading-relaxed">ตั้งใจทำแบบทดสอบเพื่อวัดผลการเรียนรู้</span>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<!-- Action Button -->
|
|
<button
|
|
class="w-full py-5 bg-blue-600 hover:bg-blue-500 text-white rounded-[20px] font-black text-[14px] tracking-wider transition-all shadow-xl shadow-blue-600/20 active:scale-[0.98]"
|
|
@click="startQuiz"
|
|
>
|
|
เริ่มทำแบบทดสอบ
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 2. TAKING SCREEN (Placeholder for Real API) -->
|
|
<div v-if="currentScreen === 'taking'" class="w-full max-w-[840px] animate-fade-in py-12 text-center">
|
|
<div class="bg-white dark:!bg-[#1e293b] rounded-[32px] p-10 shadow-xl">
|
|
<h2 class="text-xl font-bold mb-4">ส่วนนี้อยู่ระหว่างการเชื่อมต่อกับระบบข้อสอบจริง</h2>
|
|
<p class="text-slate-500">ระบบข้อสอบจะสามารถใช้งานได้เมื่อมีการเชื่อมต่อ API สมบูรณ์</p>
|
|
<button @click="currentScreen = 'result'" class="mt-8 btn btn-primary">ข้ามไปหน้าผลลัพธ์ (จำลอง)</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 3. RESULT SCREEN (Empty/Placeholder) -->
|
|
<div v-if="currentScreen === 'result'" class="w-full max-w-[640px] animate-fade-in py-12">
|
|
<div class="bg-white dark:!bg-[#1e293b] rounded-[40px] p-10 shadow-2xl text-center">
|
|
<h2 class="text-2xl font-black mb-4">จบการทำแบบทดสอบ</h2>
|
|
<div class="space-y-4 mt-8">
|
|
<NuxtLink
|
|
to="/classroom/learning"
|
|
class="w-full py-5 bg-slate-100 text-slate-600 rounded-[24px] font-black text-[14px] block"
|
|
>
|
|
กลับไปหน้าบทเรียน
|
|
</NuxtLink>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</main>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped>
|
|
|
|
.custom-scrollbar::-webkit-scrollbar {
|
|
width: 4px;
|
|
}
|
|
.custom-scrollbar::-webkit-scrollbar-thumb {
|
|
background: rgba(255, 255, 255, 0.05);
|
|
border-radius: 10px;
|
|
}
|
|
.animate-fade-in {
|
|
animation: fadeIn 0.4s ease-out forwards;
|
|
}
|
|
@keyframes fadeIn {
|
|
from { opacity: 0; transform: translateY(8px); }
|
|
to { opacity: 1; transform: translateY(0); }
|
|
}
|
|
</style>
|