feat: Implement initial frontend for instructor and admin course management functionalities.
All checks were successful
Build and Deploy Frontend Management to Dev Server / Build Frontend Management Docker Image (push) Successful in 4m21s
Build and Deploy Frontend Management to Dev Server / Deploy E-learning Frontend Management to Dev Server (push) Successful in 7s
Build and Deploy Frontend Management to Dev Server / Notify Deployment Status (push) Successful in 1s
All checks were successful
Build and Deploy Frontend Management to Dev Server / Build Frontend Management Docker Image (push) Successful in 4m21s
Build and Deploy Frontend Management to Dev Server / Deploy E-learning Frontend Management to Dev Server (push) Successful in 7s
Build and Deploy Frontend Management to Dev Server / Notify Deployment Status (push) Successful in 1s
This commit is contained in:
parent
c8ef372d4e
commit
03f16cf2fd
15 changed files with 197 additions and 36 deletions
|
|
@ -182,6 +182,7 @@
|
|||
|
||||
<script setup lang="ts">
|
||||
import { adminService, type PendingCourse, type AuditLog } from '~/services/admin.service';
|
||||
import { useQuasar } from 'quasar';
|
||||
|
||||
definePageMeta({
|
||||
layout: 'admin',
|
||||
|
|
@ -190,6 +191,7 @@ definePageMeta({
|
|||
|
||||
const authStore = useAuthStore();
|
||||
const router = useRouter();
|
||||
const $q = useQuasar();
|
||||
|
||||
// State
|
||||
const loading = ref(true);
|
||||
|
|
@ -207,8 +209,23 @@ const goToProfile = () => {
|
|||
};
|
||||
|
||||
const handleLogout = () => {
|
||||
authStore.logout();
|
||||
router.push('/login');
|
||||
$q.dialog({
|
||||
title: 'ยืนยันการออกจากระบบ',
|
||||
message: 'คุณต้องการออกจากระบบใช่หรือไม่?',
|
||||
cancel: {
|
||||
label: 'ยกเลิก',
|
||||
flat: true,
|
||||
color: 'grey-8'
|
||||
},
|
||||
ok: {
|
||||
label: 'ออกจากระบบ',
|
||||
color: 'negative'
|
||||
},
|
||||
persistent: true
|
||||
}).onOk(() => {
|
||||
authStore.logout();
|
||||
router.push('/login');
|
||||
});
|
||||
};
|
||||
|
||||
// Data Fetching
|
||||
|
|
|
|||
|
|
@ -171,7 +171,7 @@
|
|||
</div>
|
||||
|
||||
<!-- Stats -->
|
||||
<div class="grid grid-cols-3 gap-2">
|
||||
<!-- <div class="grid grid-cols-3 gap-2">
|
||||
<div class="bg-blue-50 p-2 rounded-lg text-center">
|
||||
<div class="text-2xl font-bold text-blue-800">{{ selectedCourse.chapters_count || 0 }}</div>
|
||||
<div class="text-blue-600 text-sm">Chapters</div>
|
||||
|
|
@ -180,7 +180,7 @@
|
|||
<div class="text-2xl font-bold text-purple-800">{{ selectedCourse.lessons_count || 0 }}</div>
|
||||
<div class="text-purple-600 text-sm">Lessons</div>
|
||||
</div>
|
||||
</div>
|
||||
</div> -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -204,7 +204,7 @@
|
|||
>
|
||||
<q-icon name="article" color="primary" size="20px" />
|
||||
<span class="text-gray-700">{{ lessonIndex + 1 }}. {{ lesson.title.th }}</span>
|
||||
<span v-if="lesson.title.en" class="text-gray-400 text-xs ml-auto">{{ lesson.title.en }}</span>
|
||||
<!-- <span v-if="lesson.title.en" class="text-gray-400 text-xs ml-auto">{{ lesson.title.en }}</span> -->
|
||||
</div>
|
||||
</div>
|
||||
</q-expansion-item>
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@
|
|||
<q-icon v-else name="person" color="primary" />
|
||||
</div>
|
||||
<div>
|
||||
<div class="font-medium text-primary-600 hover:underline cursor-pointer">
|
||||
<div class="font-medium text-primary-600">
|
||||
{{ getFullName(props.row) }}
|
||||
</div>
|
||||
<div class="text-sm text-gray-500">{{ props.row.email }}</div>
|
||||
|
|
|
|||
|
|
@ -40,28 +40,37 @@
|
|||
<!-- Title English -->
|
||||
<q-input
|
||||
v-model="form.title.en"
|
||||
label="ชื่อแบบทดสอบ (English)"
|
||||
label="ชื่อแบบทดสอบ (English) *"
|
||||
outlined
|
||||
:rules="[val => !!val || 'กรุณากรอกชื่อแบบทดสอบ']"
|
||||
lazy-rules="ondemand"
|
||||
hide-bottom-space
|
||||
/>
|
||||
|
||||
<!-- Content Thai -->
|
||||
<q-input
|
||||
v-model="form.content.th"
|
||||
label="คำอธิบาย (ภาษาไทย)"
|
||||
label="คำอธิบาย (ภาษาไทย) *"
|
||||
type="textarea"
|
||||
outlined
|
||||
autogrow
|
||||
rows="2"
|
||||
:rules="[val => !!val || 'กรุณากรอกคำอธิบาย']"
|
||||
lazy-rules="ondemand"
|
||||
hide-bottom-space
|
||||
/>
|
||||
|
||||
<!-- Content English -->
|
||||
<q-input
|
||||
v-model="form.content.en"
|
||||
label="คำอธิบาย (English)"
|
||||
label="คำอธิบาย (English) *"
|
||||
type="textarea"
|
||||
outlined
|
||||
autogrow
|
||||
rows="2"
|
||||
:rules="[val => !!val || 'กรุณากรอกคำอธิบาย']"
|
||||
lazy-rules="ondemand"
|
||||
hide-bottom-space
|
||||
/>
|
||||
</div>
|
||||
</q-card-section>
|
||||
|
|
@ -607,7 +616,6 @@ const saveQuestion = async () => {
|
|||
try {
|
||||
const questionData: CreateQuestionRequest = {
|
||||
question: questionForm.value.text,
|
||||
explanation: { th: '', en: '' },
|
||||
question_type: 'MULTIPLE_CHOICE',
|
||||
sort_order: editingQuestionIndex.value !== null
|
||||
? questions.value[editingQuestionIndex.value].id ? editingQuestionIndex.value + 1 : questions.value.length + 1
|
||||
|
|
|
|||
|
|
@ -39,28 +39,37 @@
|
|||
<!-- Title English -->
|
||||
<q-input
|
||||
v-model="form.title.en"
|
||||
label="ชื่อบทเรียน (English)"
|
||||
label="ชื่อบทเรียน (English) *"
|
||||
outlined
|
||||
:rules="[val => !!val || 'กรุณากรอกชื่อบทเรียน']"
|
||||
lazy-rules="ondemand"
|
||||
hide-bottom-space
|
||||
/>
|
||||
|
||||
<!-- Content Thai -->
|
||||
<q-input
|
||||
v-model="form.content.th"
|
||||
label="คำอธิบาย (ภาษาไทย)"
|
||||
label="คำอธิบาย (ภาษาไทย) *"
|
||||
type="textarea"
|
||||
outlined
|
||||
autogrow
|
||||
rows="3"
|
||||
:rules="[val => !!val || 'กรุณากรอกคำอธิบาย']"
|
||||
lazy-rules="ondemand"
|
||||
hide-bottom-space
|
||||
/>
|
||||
|
||||
<!-- Content English -->
|
||||
<q-input
|
||||
v-model="form.content.en"
|
||||
label="คำอธิบาย (English)"
|
||||
label="คำอธิบาย (English) *"
|
||||
type="textarea"
|
||||
outlined
|
||||
autogrow
|
||||
rows="3"
|
||||
:rules="[val => !!val || 'กรุณากรอกคำอธิบาย']"
|
||||
lazy-rules="ondemand"
|
||||
hide-bottom-space
|
||||
/>
|
||||
<q-card-section class="flex justify-end gap-2">
|
||||
<q-btn
|
||||
|
|
|
|||
|
|
@ -68,22 +68,28 @@
|
|||
<div class="mb-6">
|
||||
<q-input
|
||||
v-model="form.description.th"
|
||||
label="คำอธิบาย (ภาษาไทย)"
|
||||
label="คำอธิบาย (ภาษาไทย) *"
|
||||
type="textarea"
|
||||
outlined
|
||||
autogrow
|
||||
rows="3"
|
||||
:rules="[val => !!val || 'กรุณากรอกคำอธิบาย']"
|
||||
lazy-rules="ondemand"
|
||||
hide-bottom-space
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="mb-6">
|
||||
<q-input
|
||||
v-model="form.description.en"
|
||||
label="คำอธิบาย (English)"
|
||||
label="คำอธิบาย (English) *"
|
||||
type="textarea"
|
||||
outlined
|
||||
autogrow
|
||||
rows="3"
|
||||
:rules="[val => !!val || 'กรุณากรอกคำอธิบาย']"
|
||||
lazy-rules="ondemand"
|
||||
hide-bottom-space
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -156,25 +156,34 @@
|
|||
/>
|
||||
<q-input
|
||||
v-model="chapterForm.title.en"
|
||||
label="ชื่อบท (English)"
|
||||
label="ชื่อบท (English) *"
|
||||
outlined
|
||||
class="mb-4"
|
||||
:rules="[val => !!val || 'กรุณากรอกชื่อบท']"
|
||||
lazy-rules="ondemand"
|
||||
hide-bottom-space
|
||||
/>
|
||||
<q-input
|
||||
v-model="chapterForm.description.th"
|
||||
label="คำอธิบาย (ภาษาไทย)"
|
||||
label="คำอธิบาย (ภาษาไทย) *"
|
||||
type="textarea"
|
||||
outlined
|
||||
autogrow
|
||||
class="mb-4"
|
||||
:rules="[val => !!val || 'กรุณากรอกคำอธิบาย']"
|
||||
lazy-rules="ondemand"
|
||||
hide-bottom-space
|
||||
/>
|
||||
<q-input
|
||||
v-model="chapterForm.description.en"
|
||||
label="คำอธิบาย (English)"
|
||||
label="คำอธิบาย (English) *"
|
||||
type="textarea"
|
||||
outlined
|
||||
autogrow
|
||||
class="mb-4"
|
||||
:rules="[val => !!val || 'กรุณากรอกคำอธิบาย']"
|
||||
lazy-rules="ondemand"
|
||||
hide-bottom-space
|
||||
/>
|
||||
|
||||
<div class="flex justify-end gap-2 mt-4">
|
||||
|
|
@ -208,7 +217,7 @@
|
|||
/>
|
||||
<q-input
|
||||
v-model="lessonForm.title.en"
|
||||
label="ชื่อบทเรียน (English)"
|
||||
label="ชื่อบทเรียน (English) *"
|
||||
outlined
|
||||
class="mb-4"
|
||||
/>
|
||||
|
|
@ -235,22 +244,29 @@
|
|||
<q-input
|
||||
v-if="lessonForm.type"
|
||||
v-model="lessonForm.content.th"
|
||||
label="เนื้อหา (ภาษาไทย)"
|
||||
label="เนื้อหา (ภาษาไทย) *"
|
||||
type="textarea"
|
||||
outlined
|
||||
autogrow
|
||||
rows="3"
|
||||
class="mb-4"
|
||||
:rules="[val => !!val || 'กรุณากรอกเนื้อหา']"
|
||||
lazy-rules="ondemand"
|
||||
hide-bottom-space
|
||||
/>
|
||||
|
||||
<q-input
|
||||
v-if="lessonForm.type"
|
||||
v-model="lessonForm.content.en"
|
||||
label="เนื้อหา (English)"
|
||||
label="เนื้อหา (English) *"
|
||||
type="textarea"
|
||||
outlined
|
||||
autogrow
|
||||
rows="3"
|
||||
class="mb-4"
|
||||
:rules="[val => !!val || 'กรุณากรอกเนื้อหา']"
|
||||
lazy-rules="ondemand"
|
||||
hide-bottom-space
|
||||
/>
|
||||
|
||||
<div class="flex justify-end gap-2 mt-4">
|
||||
|
|
|
|||
|
|
@ -163,13 +163,13 @@
|
|||
<q-btn flat round dense icon="more_vert">
|
||||
<q-menu>
|
||||
<q-list style="min-width: 150px">
|
||||
<q-item clickable v-close-popup @click="duplicateCourse(course)">
|
||||
<q-item v-if="course.status === 'APPROVED'" clickable v-close-popup @click="duplicateCourse(course)">
|
||||
<q-item-section avatar>
|
||||
<q-icon name="content_copy" />
|
||||
</q-item-section>
|
||||
<q-item-section>ทำสำเนา</q-item-section>
|
||||
</q-item>
|
||||
<q-separator />
|
||||
<q-separator v-if="course.status === 'APPROVED'" />
|
||||
<q-item clickable v-close-popup @click="confirmDelete(course)">
|
||||
<q-item-section avatar>
|
||||
<q-icon name="delete" color="negative" />
|
||||
|
|
@ -250,13 +250,13 @@
|
|||
<q-btn flat round dense icon="more_vert" size="sm">
|
||||
<q-menu>
|
||||
<q-list style="min-width: 150px">
|
||||
<q-item clickable v-close-popup @click="duplicateCourse(props.row)">
|
||||
<q-item v-if="props.row.status === 'APPROVED'" clickable v-close-popup @click="duplicateCourse(props.row)">
|
||||
<q-item-section avatar>
|
||||
<q-icon name="content_copy" />
|
||||
</q-item-section>
|
||||
<q-item-section>ทำสำเนา</q-item-section>
|
||||
</q-item>
|
||||
<q-separator />
|
||||
<q-separator v-if="props.row.status === 'APPROVED'" />
|
||||
<q-item clickable v-close-popup @click="confirmDelete(props.row)">
|
||||
<q-item-section avatar>
|
||||
<q-icon name="delete" color="negative" />
|
||||
|
|
|
|||
|
|
@ -171,6 +171,8 @@
|
|||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useQuasar } from 'quasar';
|
||||
|
||||
definePageMeta({
|
||||
layout: 'instructor',
|
||||
middleware: 'auth'
|
||||
|
|
@ -179,6 +181,7 @@ definePageMeta({
|
|||
const authStore = useAuthStore();
|
||||
const instructorStore = useInstructorStore();
|
||||
const router = useRouter();
|
||||
const $q = useQuasar();
|
||||
|
||||
// Navigation functions
|
||||
const goToProfile = () => {
|
||||
|
|
@ -190,8 +193,23 @@ const goToSettings = () => {
|
|||
};
|
||||
|
||||
const handleLogout = () => {
|
||||
authStore.logout();
|
||||
router.push('/login');
|
||||
$q.dialog({
|
||||
title: 'ยืนยันการออกจากระบบ',
|
||||
message: 'คุณต้องการออกจากระบบใช่หรือไม่?',
|
||||
cancel: {
|
||||
label: 'ยกเลิก',
|
||||
flat: true,
|
||||
color: 'grey-8'
|
||||
},
|
||||
ok: {
|
||||
label: 'ออกจากระบบ',
|
||||
color: 'negative'
|
||||
},
|
||||
persistent: true
|
||||
}).onOk(() => {
|
||||
authStore.logout();
|
||||
router.push('/login');
|
||||
});
|
||||
};
|
||||
|
||||
// Fetch dashboard data on mount
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue