feat: Scaffold new Nuxt.js application with initial pages, layouts, composables, and middleware.

This commit is contained in:
supalerk-ar66 2026-01-23 09:54:35 +07:00
parent ab3124628c
commit 9bfb852ad0
8 changed files with 113 additions and 48 deletions

View file

@ -1,13 +1,14 @@
// Interface สำหรับข้อมูลคอร์สเรียน (Public Course Data)
export interface Course {
id: number
title: string | { th: string; en: string }
title: string | { th: string; en: string } // รองรับ 2 ภาษา
slug: string
description: string | { th: string; en: string }
thumbnail_url: string
price: string
is_free: boolean
have_certificate: boolean
status: string
status: string // DRAFT, PUBLISHED
category_id: number
created_at?: string
updated_at?: string
@ -20,8 +21,9 @@ export interface Course {
rating?: string
lessons?: number | string
levelType?: 'neutral' | 'warning' | 'success'
levelType?: 'neutral' | 'warning' | 'success' // ใช้สำหรับการแสดงผล Badge ระดับความยาก (Frontend Logic)
// โครงสร้างบทเรียน (Chapters & Lessons)
chapters?: {
id: number
title: string | { th: string; en: string }
@ -41,6 +43,7 @@ interface CourseResponse {
total: number
}
// Interface สำหรับคอร์สที่ผู้ใช้ลงทะเบียนเรียนแล้ว (My Course)
export interface EnrolledCourse {
id: number
course_id: number
@ -75,11 +78,13 @@ export const useCourse = () => {
const { token } = useAuth()
// ฟังก์ชันดึงรายชื่อคอร์สทั้งหมด (Catalog)
// ใช้สำหรับหน้า Discover/Browse
// Endpoint: GET /courses
const fetchCourses = async () => {
try {
const data = await $fetch<CourseResponse>(`${API_BASE_URL}/courses`, {
method: 'GET',
// ส่ง Token ไปด้วยถ้ามี (เผื่อ Logic ในอนาคตที่ต้องเช็คสิทธิ์)
headers: token.value ? {
Authorization: `Bearer ${token.value}`
} : {}
@ -110,15 +115,14 @@ export const useCourse = () => {
} : {}
})
// API might return an array (list) or single object
// Logic จัดการข้อมูลที่ได้รับ (API อาจส่งกลับมาเป็น Array หรือ Object)
let courseData: any = null
if (Array.isArray(data.data)) {
// Try to find the matching course ID in the array
// ถ้าเป็น Array ให้หาอันที่ ID ตรงกัน
courseData = data.data.find((c: any) => c.id == id)
// Fallback: If not found, and array has length 1, it might be the one (if ID mismatch isn't the issue)
// But generally, we should expect a match. If not match, maybe the API returned a generic list.
// Fallback: ถ้าหาไม่เจอ แต่มีข้อมูลตัวเดียว อาจจะเป็นตัวนั้น
if (!courseData && data.data.length === 1) {
courseData = data.data[0]
}
@ -141,7 +145,7 @@ export const useCourse = () => {
}
}
// ฟังก์ชันลงทะเบียนเรียน
// ฟังก์ชันลงทะเบียนเรียน (Enroll)
// Endpoint: POST /students/courses/:id/enroll
const enrollCourse = async (courseId: number) => {
try {
@ -160,8 +164,7 @@ export const useCourse = () => {
} catch (err: any) {
console.error('Enroll course failed:', err)
// Check for 409 Conflict (Already Enrolled)
// ofetch/h3 error properties might vary, check common ones
// เช็ค Error 409 Conflict (กรณีลงทะเบียนไปแล้ว)
const status = err.statusCode || err.status || err.response?.status
if (status === 409) {
@ -180,6 +183,8 @@ export const useCourse = () => {
}
}
// ฟังก์ชันดึงคอร์สที่ฉันลงทะเบียนเรียน (My Courses)
// รองรับ Pagination และการกรอง Status (ENROLLED, IN_PROGRESS, COMPLETED)
const fetchEnrolledCourses = async (params: { page?: number; limit?: number; status?: string } = {}) => {
try {
const queryParams = new URLSearchParams()
@ -262,6 +267,9 @@ export const useCourse = () => {
}
}
// ฟังก์ชันเช็คสิทธิ์การเข้าถึงบทเรียน (Access Control)
// ต้อง Enrolled ก่อนถึงจะเข้าได้ และต้องผ่านเงื่อนไข Prerequisites (ถ้ามี)
// Endpoint: GET /students/courses/:cid/lessons/:lid/access-check
const checkLessonAccess = async (courseId: number, lessonId: number) => {
try {
const data = await $fetch<{ code: number; message: string; data: any }>(`${API_BASE_URL}/students/courses/${courseId}/lessons/${lessonId}/access-check`, {
@ -315,6 +323,8 @@ export const useCourse = () => {
}
}
// ฟังก์ชันดึง Video Progress ปัจจุบันของบทเรียน
// Endpoint: GET /students/lessons/:id/progress
const fetchVideoProgress = async (lessonId: number) => {
try {
const data = await $fetch<{ code: number; message: string; data: any }>(`${API_BASE_URL}/students/lessons/${lessonId}/progress`, {