105 lines
2.9 KiB
Vue
105 lines
2.9 KiB
Vue
|
|
<template>
|
||
|
|
<div class="h-full">
|
||
|
|
<!-- Loading -->
|
||
|
|
<div v-if="loading" class="flex justify-center py-10">
|
||
|
|
<q-spinner-dots size="40px" color="primary" />
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<!-- Empty State -->
|
||
|
|
<div v-else-if="history.length === 0" class="text-center py-10 text-gray-500">
|
||
|
|
<div class="flex flex-col items-center">
|
||
|
|
<q-icon name="history" size="40px" class="mb-2" />
|
||
|
|
<p>ไม่พบประวัติการขออนุมัติ</p>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<!-- Timeline -->
|
||
|
|
<div v-else class="px-4 py-2">
|
||
|
|
<q-timeline color="primary">
|
||
|
|
<q-timeline-entry
|
||
|
|
v-for="item in history"
|
||
|
|
:key="item.id"
|
||
|
|
:title="titleMap[item.action] || item.action"
|
||
|
|
:subtitle="formatDate(item.created_at)"
|
||
|
|
:color="colorMap[item.action] || 'grey'"
|
||
|
|
:icon="iconMap[item.action] || 'circle'"
|
||
|
|
>
|
||
|
|
<div class="text-gray-600">
|
||
|
|
<div class="font-medium text-gray-900 mb-1">
|
||
|
|
โดย: {{ getActorName(item) }}
|
||
|
|
</div>
|
||
|
|
<div v-if="item.comment" class="mt-2 p-3 bg-gray-50 rounded-lg border border-gray-100 italic">
|
||
|
|
"{{ item.comment }}"
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</q-timeline-entry>
|
||
|
|
</q-timeline>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</template>
|
||
|
|
|
||
|
|
<script setup lang="ts">
|
||
|
|
import { useQuasar } from 'quasar';
|
||
|
|
import { instructorService, type ApprovalHistory } from '~/services/instructor.service';
|
||
|
|
|
||
|
|
const props = defineProps<{
|
||
|
|
courseId: number;
|
||
|
|
}>();
|
||
|
|
|
||
|
|
const $q = useQuasar();
|
||
|
|
const loading = ref(true);
|
||
|
|
const history = ref<ApprovalHistory[]>([]);
|
||
|
|
|
||
|
|
const titleMap: Record<string, string> = {
|
||
|
|
SUBMITTED: 'ส่งขออนุมัติ',
|
||
|
|
APPROVED: 'อนุมัติแล้ว',
|
||
|
|
REJECTED: 'ไม่อนุมัติ'
|
||
|
|
};
|
||
|
|
|
||
|
|
const colorMap: Record<string, string> = {
|
||
|
|
SUBMITTED: 'orange',
|
||
|
|
APPROVED: 'green',
|
||
|
|
REJECTED: 'red'
|
||
|
|
};
|
||
|
|
|
||
|
|
const iconMap: Record<string, string> = {
|
||
|
|
SUBMITTED: 'send',
|
||
|
|
APPROVED: 'check_circle',
|
||
|
|
REJECTED: 'cancel'
|
||
|
|
};
|
||
|
|
|
||
|
|
const fetchHistory = async () => {
|
||
|
|
loading.value = true;
|
||
|
|
try {
|
||
|
|
history.value = await instructorService.getCourseApprovalHistory(props.courseId);
|
||
|
|
} catch (error: any) {
|
||
|
|
console.error('Failed to fetch approval history:', error);
|
||
|
|
$q.notify({
|
||
|
|
type: 'negative',
|
||
|
|
message: error.data?.message || 'ไม่สามารถโหลดประวัติการอนุมัติได้',
|
||
|
|
position: 'top'
|
||
|
|
});
|
||
|
|
} finally {
|
||
|
|
loading.value = false;
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
const getActorName = (item: ApprovalHistory) => {
|
||
|
|
const actor = item.action === 'SUBMITTED' ? item.submitter : item.reviewer;
|
||
|
|
if (!actor) return 'System/Admin';
|
||
|
|
|
||
|
|
return actor.username || actor.email || 'Unknown User';
|
||
|
|
};
|
||
|
|
|
||
|
|
const formatDate = (dateString: string) => {
|
||
|
|
return new Date(dateString).toLocaleString('th-TH', {
|
||
|
|
dateStyle: 'medium',
|
||
|
|
timeStyle: 'short'
|
||
|
|
});
|
||
|
|
};
|
||
|
|
|
||
|
|
onMounted(() => {
|
||
|
|
fetchHistory();
|
||
|
|
});
|
||
|
|
</script>
|