@@ -0,0 +1,99 @@
|
||||
import { register } from '@/services/mock/registry'
|
||||
import { endpoints } from '@/services/api/endpoints'
|
||||
import { adminExams } from '@/services/mock/fixtures/admin-exams'
|
||||
import { adminCourses } from '@/services/mock/fixtures/admin-courses'
|
||||
import { filterItems, isoNow, makeId, paginate } from '@/services/mock/helpers'
|
||||
|
||||
// In-memory attempt history for the mock student. Submissions append here and
|
||||
// surface on the exam page via GET /student/exam-results.
|
||||
const studentResults = [
|
||||
{
|
||||
id: 9001,
|
||||
examId: 201,
|
||||
score: 20,
|
||||
isPassed: true,
|
||||
correctCount: 2,
|
||||
totalQuestions: 2,
|
||||
startedAt: '2026-04-12T15:00:00+03:30',
|
||||
submittedAt: '2026-04-12T15:30:00+03:30',
|
||||
deadlineAt: '2026-04-12T15:30:00+03:30',
|
||||
},
|
||||
]
|
||||
|
||||
// examId → un-submitted attempt, so POST /start is idempotent.
|
||||
const openAttempts = new Map()
|
||||
|
||||
const termIdOfExam = (exam) => {
|
||||
const course = adminCourses.find((c) => c.id === Number(exam.course?.id))
|
||||
return course?.termId ?? course?.term?.id ?? null
|
||||
}
|
||||
|
||||
register('GET', endpoints.getStudentExamsList, ({ query }) => {
|
||||
const list = filterItems(adminExams, query, {
|
||||
sessionId: (item, v) => String(item.sessionId) === String(v),
|
||||
courseId: (item, v) => String(item.course?.id) === String(v),
|
||||
termId: (item, v) => String(termIdOfExam(item)) === String(v),
|
||||
})
|
||||
const { data: items, meta } = paginate(list, query)
|
||||
return { success: true, message: 'OK', data: { items, meta } }
|
||||
})
|
||||
|
||||
register('GET', endpoints.getStudentExamResults, ({ query }) => {
|
||||
const { data: items, meta } = paginate([...studentResults].reverse(), query)
|
||||
return { success: true, message: 'OK', data: { items, meta } }
|
||||
})
|
||||
|
||||
register('POST', endpoints.startExam, ({ params }) => {
|
||||
const examId = Number(params.examId)
|
||||
const existing = openAttempts.get(examId)
|
||||
if (existing) return { success: true, message: 'Exam started.', data: existing }
|
||||
const exam = adminExams.find((e) => String(e.id) === String(examId))
|
||||
const duration = exam?.durationMinutes || 30
|
||||
const attempt = {
|
||||
id: makeId(),
|
||||
examId,
|
||||
score: 0,
|
||||
isPassed: false,
|
||||
correctCount: 0,
|
||||
totalQuestions: (exam?.questions || []).length,
|
||||
startedAt: isoNow(),
|
||||
submittedAt: null,
|
||||
deadlineAt: new Date(Date.now() + duration * 60_000).toISOString(),
|
||||
}
|
||||
openAttempts.set(examId, attempt)
|
||||
return { success: true, message: 'Exam started.', data: attempt }
|
||||
})
|
||||
|
||||
register('POST', endpoints.submitExam, ({ params, data }) => {
|
||||
const examId = Number(params.examId)
|
||||
const exam = adminExams.find((e) => String(e.id) === String(examId))
|
||||
const questions = exam?.questions || []
|
||||
const answers = Array.isArray(data.answers) ? data.answers : []
|
||||
|
||||
let score = 0
|
||||
let correctCount = 0
|
||||
for (const q of questions) {
|
||||
const correct = (q.options || []).find((o) => o.isCorrect)
|
||||
const ans = answers.find((a) => String(a.questionId) === String(q.id))
|
||||
if (ans && correct && String(ans.selectedOptionId) === String(correct.id)) {
|
||||
score += q.score || 0
|
||||
correctCount += 1
|
||||
}
|
||||
}
|
||||
|
||||
const open = openAttempts.get(examId)
|
||||
const attempt = {
|
||||
id: open?.id ?? makeId(),
|
||||
examId,
|
||||
score,
|
||||
isPassed: score >= (exam?.minimumScore ?? 0),
|
||||
correctCount,
|
||||
totalQuestions: questions.length,
|
||||
startedAt: open?.startedAt ?? isoNow(),
|
||||
submittedAt: isoNow(),
|
||||
deadlineAt: open?.deadlineAt ?? isoNow(),
|
||||
}
|
||||
studentResults.push(attempt)
|
||||
openAttempts.delete(examId)
|
||||
return { success: true, message: 'Exam submitted.', data: attempt }
|
||||
})
|
||||
Reference in New Issue
Block a user