101 lines
2.6 KiB
TypeScript
101 lines
2.6 KiB
TypeScript
import { defineComponent, onMounted, ref } from 'vue';
|
|
import {
|
|
type ExamQuestionView,
|
|
type ExamResult,
|
|
type OptionKey,
|
|
type SubjectItem,
|
|
fetchActiveSubjects,
|
|
loadQuestions,
|
|
startExam,
|
|
submitExam,
|
|
} from './quiz.service';
|
|
|
|
export default defineComponent({
|
|
name: 'QuizView',
|
|
setup() {
|
|
const subjects = ref<SubjectItem[]>([]);
|
|
const selectedSubjectId = ref<number | null>(null);
|
|
const attemptId = ref<number | null>(null);
|
|
const questions = ref<ExamQuestionView[]>([]);
|
|
const selectedAnswers = ref<Record<number, OptionKey | null>>({});
|
|
const result = ref<ExamResult | null>(null);
|
|
const errorMessage = ref<string | null>(null);
|
|
const loading = ref(false);
|
|
|
|
onMounted(async () => {
|
|
try {
|
|
subjects.value = await fetchActiveSubjects();
|
|
} catch {
|
|
errorMessage.value = '과목 목록을 불러오지 못했습니다.';
|
|
}
|
|
});
|
|
|
|
const handleStartExam = async () => {
|
|
if (!selectedSubjectId.value) return;
|
|
|
|
errorMessage.value = null;
|
|
loading.value = true;
|
|
|
|
try {
|
|
const started = await startExam(selectedSubjectId.value);
|
|
attemptId.value = started.attemptId;
|
|
|
|
const loadedQuestions = await loadQuestions(started.attemptId);
|
|
questions.value = loadedQuestions;
|
|
selectedAnswers.value = {};
|
|
|
|
loadedQuestions.forEach(q => {
|
|
selectedAnswers.value[q.questionId] = null;
|
|
});
|
|
} catch (err: any) {
|
|
errorMessage.value = err?.response?.data?.detail || '응시를 시작할 수 없습니다.';
|
|
attemptId.value = null;
|
|
} finally {
|
|
loading.value = false;
|
|
}
|
|
};
|
|
|
|
const handleSubmitExam = async () => {
|
|
if (!attemptId.value) return;
|
|
|
|
errorMessage.value = null;
|
|
loading.value = true;
|
|
|
|
try {
|
|
const payload = questions.value.map(q => ({
|
|
questionId: q.questionId,
|
|
selectedOption: selectedAnswers.value[q.questionId] ?? null,
|
|
}));
|
|
|
|
result.value = await submitExam(attemptId.value, payload);
|
|
} catch (err: any) {
|
|
errorMessage.value = err?.response?.data?.detail || '답안 제출 중 오류가 발생했습니다.';
|
|
} finally {
|
|
loading.value = false;
|
|
}
|
|
};
|
|
|
|
const resetQuiz = () => {
|
|
attemptId.value = null;
|
|
questions.value = [];
|
|
selectedAnswers.value = {};
|
|
result.value = null;
|
|
errorMessage.value = null;
|
|
};
|
|
|
|
return {
|
|
subjects,
|
|
selectedSubjectId,
|
|
attemptId,
|
|
questions,
|
|
selectedAnswers,
|
|
result,
|
|
errorMessage,
|
|
loading,
|
|
handleStartExam,
|
|
handleSubmitExam,
|
|
resetQuiz,
|
|
};
|
|
},
|
|
});
|