Implement Vue quiz screen and fix route authority
This commit is contained in:
1 parent
aaa051c7f7
commit
392ac642b0
4 files changed
+250
No files matched your search
@@ -0,0 +1,100 @@
|
||||
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,
|
||||
};
|
||||
},
|
||||
});
|
||||
Reference in new issue
Block a user