feat: Implement instructor course and lesson management with dedicated views for quizzes, videos, and admin categories.

This commit is contained in:
Missez 2026-01-30 10:56:48 +07:00
parent 344e1e4341
commit 878a17f922
9 changed files with 903 additions and 399 deletions

View file

@ -149,7 +149,10 @@
v-model="chapterForm.title.th"
label="ชื่อบท (ภาษาไทย) *"
outlined
class="mb-4"
:rules="[val => !!val || 'กรุณากรอกชื่อบท']"
lazy-rules="ondemand"
hide-bottom-space
/>
<q-input
v-model="chapterForm.title.en"
@ -199,6 +202,8 @@
label="ชื่อบทเรียน (ภาษาไทย) *"
outlined
:rules="[val => !!val || 'กรุณากรอกชื่อบทเรียน']"
lazy-rules="ondemand"
hide-bottom-space
/>
<q-input
v-model="lessonForm.title.en"
@ -298,14 +303,14 @@ const onChapterDragEnd = async (event: { oldIndex: number; newIndex: number }) =
if (!chapter) return;
try {
await instructorService.reorderChapter(courseId.value, chapter.id, newIndex + 1);
$q.notify({ type: 'positive', message: 'เรียงลำดับบทสำเร็จ', position: 'top' });
} catch (error) {
const response = await instructorService.reorderChapter(courseId.value, chapter.id, newIndex + 1);
$q.notify({ type: 'positive', message: response.message, position: 'top' });
} catch (error: any) {
console.error('Failed to reorder chapter:', error);
// Revert
const [item] = chapters.value.splice(newIndex, 1);
chapters.value.splice(oldIndex, 0, item);
$q.notify({ type: 'negative', message: 'ไม่สามารถเรียงลำดับได้', position: 'top' });
$q.notify({ type: 'negative', message: error.data?.error?.message || error.data?.message || 'ไม่สามารถเรียงลำดับได้', position: 'top' });
}
};
@ -317,14 +322,14 @@ const onLessonDragEnd = async (chapter: ChapterResponse & { expanded?: boolean }
if (!lesson) return;
try {
await instructorService.reorderLesson(courseId.value, chapter.id, lesson.id, newIndex + 1);
$q.notify({ type: 'positive', message: 'เรียงลำดับบทเรียนสำเร็จ', position: 'top' });
} catch (error) {
const response = await instructorService.reorderLesson(courseId.value, chapter.id, lesson.id, newIndex + 1);
$q.notify({ type: 'positive', message: response.message, position: 'top' });
} catch (error: any) {
console.error('Failed to reorder lesson:', error);
// Revert
const [item] = chapter.lessons.splice(newIndex, 1);
chapter.lessons.splice(oldIndex, 0, item);
$q.notify({ type: 'negative', message: 'ไม่สามารถเรียงลำดับได้', position: 'top' });
$q.notify({ type: 'negative', message: error.data?.error?.message || error.data?.message || 'ไม่สามารถเรียงลำดับได้', position: 'top' });
}
};
@ -429,21 +434,21 @@ const saveChapter = async () => {
saving.value = true;
try {
if (editingChapter.value) {
await instructorService.updateChapter(courseId.value, editingChapter.value.id, chapterForm.value);
$q.notify({ type: 'positive', message: 'แก้ไขบทสำเร็จ', position: 'top' });
const response = await instructorService.updateChapter(courseId.value, editingChapter.value.id, chapterForm.value);
$q.notify({ type: 'positive', message: response.message, position: 'top' });
} else {
// Calculate sort_order for new chapter
const sortOrder = chapters.value.length + 1;
await instructorService.createChapter(courseId.value, {
const response = await instructorService.createChapter(courseId.value, {
...chapterForm.value,
sort_order: sortOrder
});
$q.notify({ type: 'positive', message: 'เพิ่มบทสำเร็จ', position: 'top' });
$q.notify({ type: 'positive', message: response.message, position: 'top' });
}
chapterDialog.value = false;
fetchChapters();
} catch (error) {
$q.notify({ type: 'negative', message: 'เกิดข้อผิดพลาด', position: 'top' });
} catch (error: any) {
$q.notify({ type: 'negative', message: error.data?.error?.message || error.data?.message || 'เกิดข้อผิดพลาด', position: 'top' });
} finally {
saving.value = false;
}
@ -457,11 +462,11 @@ const confirmDeleteChapter = (chapter: ChapterResponse) => {
persistent: true
}).onOk(async () => {
try {
await instructorService.deleteChapter(courseId.value, chapter.id);
$q.notify({ type: 'positive', message: 'ลบบทสำเร็จ', position: 'top' });
const response = await instructorService.deleteChapter(courseId.value, chapter.id);
$q.notify({ type: 'positive', message: response.message, position: 'top' });
fetchChapters();
} catch (error) {
$q.notify({ type: 'negative', message: 'ไม่สามารถลบได้', position: 'top' });
} catch (error: any) {
$q.notify({ type: 'negative', message: error.data?.error?.message || error.data?.message || 'ไม่สามารถลบได้', position: 'top' });
}
});
};
@ -498,30 +503,30 @@ const saveLesson = async () => {
title: lessonForm.value.title,
content: lessonForm.value.content
};
await instructorService.updateLesson(
const response = await instructorService.updateLesson(
courseId.value,
selectedChapter.value.id,
editingLesson.value.id,
updateData
);
$q.notify({ type: 'positive', message: 'แก้ไขบทเรียนสำเร็จ', position: 'top' });
$q.notify({ type: 'positive', message: response.message, position: 'top' });
} else {
// Create - include type and sort_order
const createData = {
...lessonForm.value,
sort_order: (selectedChapter.value.lessons?.length || 0) + 1
};
await instructorService.createLesson(
const response = await instructorService.createLesson(
courseId.value,
selectedChapter.value.id,
createData
);
$q.notify({ type: 'positive', message: 'เพิ่มบทเรียนสำเร็จ', position: 'top' });
$q.notify({ type: 'positive', message: response.message, position: 'top' });
}
lessonDialog.value = false;
fetchChapters();
} catch (error) {
$q.notify({ type: 'negative', message: 'เกิดข้อผิดพลาด', position: 'top' });
} catch (error: any) {
$q.notify({ type: 'negative', message: error.data?.error?.message || error.data?.message || 'เกิดข้อผิดพลาด', position: 'top' });
} finally {
saving.value = false;
}
@ -535,11 +540,11 @@ const confirmDeleteLesson = (chapter: ChapterResponse, lesson: LessonResponse) =
persistent: true
}).onOk(async () => {
try {
await instructorService.deleteLesson(courseId.value, chapter.id, lesson.id);
$q.notify({ type: 'positive', message: 'ลบบทเรียนสำเร็จ', position: 'top' });
const response = await instructorService.deleteLesson(courseId.value, chapter.id, lesson.id);
$q.notify({ type: 'positive', message: response.message, position: 'top' });
fetchChapters();
} catch (error) {
$q.notify({ type: 'negative', message: 'ไม่สามารถลบได้', position: 'top' });
} catch (error: any) {
$q.notify({ type: 'negative', message: error.data?.error?.message || error.data?.message || 'ไม่สามารถลบได้', position: 'top' });
}
});
};