@@ -22,9 +22,10 @@ export const apiAddAdminExamQuestion = (examId, payload) =>
|
||||
export const apiAddAdminQuestionOption = (questionId, payload) =>
|
||||
http.post(buildUrl(endpoints.addQuestionOption, { questionId }), payload)
|
||||
|
||||
// Mock-only — backend has no /exams/:id/participants endpoint yet.
|
||||
export const apiGetAdminExamParticipants = (examId, params) =>
|
||||
http.get(buildUrl(endpoints.getExamParticipants, { examId }), { params })
|
||||
// GET /exams/:examId/attempts — paginated list, each row is one attempt with
|
||||
// the attempting user embedded (multiple rows per user possible).
|
||||
export const apiGetAdminExamAttempts = (examId, params) =>
|
||||
http.get(buildUrl(endpoints.getExamAttempts, { examId }), { params })
|
||||
|
||||
export const apiShowAdminExamParticipant = (examId, participantId) =>
|
||||
http.get(buildUrl(endpoints.showExamParticipant, { examId, participantId }))
|
||||
|
||||
@@ -122,8 +122,10 @@ export const endpoints = {
|
||||
// Sessions — attendance roster
|
||||
getSessionsAttendance: '/admin/sessions/:sessionId/attendances',
|
||||
|
||||
// Exams — participants only (backend has /exams/:id but no participants endpoints)
|
||||
getExamParticipants: '/admin/exams/:examId/participants',
|
||||
// Exams — admin/teacher view of attempts. Each row is one attempt with the
|
||||
// attempting user embedded; multiple rows per user are possible. The
|
||||
// single-attempt detail endpoint is still mock-only.
|
||||
getExamAttempts: '/exams/:examId/attempts',
|
||||
showExamParticipant: '/admin/exams/:examId/participants/:participantId',
|
||||
|
||||
// Homeworks — list, show, submissions list, show submission
|
||||
|
||||
@@ -77,13 +77,69 @@ export const adminExams = [
|
||||
},
|
||||
]
|
||||
|
||||
// FE-mock-only — no backend endpoint for exam participants.
|
||||
// Mirrors GET /exams/:examId/attempts. Each row is one attempt with the user
|
||||
// embedded; multiple rows per user are possible.
|
||||
export const examAttempts = new Map([
|
||||
[
|
||||
201,
|
||||
[
|
||||
{
|
||||
id: 14,
|
||||
examId: 201,
|
||||
score: 85,
|
||||
isPassed: true,
|
||||
startedAt: '2026-04-12T15:00:00+03:30',
|
||||
submittedAt: '2026-04-12T15:30:00+03:30',
|
||||
deadlineAt: '2026-04-12T15:30:00+03:30',
|
||||
user: {
|
||||
id: 100,
|
||||
name: 'فاطمه رضایی',
|
||||
email: 'fatemeh.r@example.com',
|
||||
phone: '+989121234567',
|
||||
provinceId: 8,
|
||||
cityId: 47,
|
||||
province: { id: 8, name: 'تهران' },
|
||||
city: { id: 47, provinceId: 8, name: 'تهران' },
|
||||
roles: ['student'],
|
||||
avatarUrl: null,
|
||||
avatarDownloadUrl: null,
|
||||
createdAt: '2026-02-01T10:00:00+00:00',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 15,
|
||||
examId: 201,
|
||||
score: 42,
|
||||
isPassed: false,
|
||||
startedAt: '2026-04-13T09:00:00+03:30',
|
||||
submittedAt: '2026-04-13T09:25:00+03:30',
|
||||
deadlineAt: '2026-04-13T09:30:00+03:30',
|
||||
user: {
|
||||
id: 102,
|
||||
name: 'مریم احمدی',
|
||||
email: 'maryam.a@example.com',
|
||||
phone: '+989121111111',
|
||||
provinceId: 15,
|
||||
cityId: 90,
|
||||
province: { id: 15, name: 'اصفهان' },
|
||||
city: { id: 90, provinceId: 15, name: 'اصفهان' },
|
||||
roles: ['student'],
|
||||
avatarUrl: null,
|
||||
avatarDownloadUrl: null,
|
||||
createdAt: '2026-02-03T10:00:00+00:00',
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
])
|
||||
|
||||
// Kept for the FE-mock-only single-participant detail endpoint (no backend yet).
|
||||
export const examParticipants = new Map([
|
||||
[
|
||||
201,
|
||||
[
|
||||
{
|
||||
id: 1,
|
||||
id: 100,
|
||||
userId: 100,
|
||||
firstName: 'فاطمه',
|
||||
lastName: 'رضایی',
|
||||
@@ -91,21 +147,21 @@ export const examParticipants = new Map([
|
||||
avatarUrl: '',
|
||||
address: { province: { name: 'تهران' }, city: { name: 'تهران' } },
|
||||
location: 'تهران، تهران',
|
||||
submittedAt: '2026-05-05T10:30:00.000Z',
|
||||
submittedAt: '2026-04-12T15:30:00+03:30',
|
||||
attempts: [
|
||||
{
|
||||
id: 1,
|
||||
id: 14,
|
||||
title: 'تلاش اول',
|
||||
courseTitle: 'اصول اخلاق اسلامی',
|
||||
sessionTitle: 'مقدمهای بر اخلاق اسلامی',
|
||||
date: '2026-05-05T10:30:00.000Z',
|
||||
date: '2026-04-12T15:30:00+03:30',
|
||||
score: 17,
|
||||
scoreTone: 'good',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
id: 102,
|
||||
userId: 102,
|
||||
firstName: 'مریم',
|
||||
lastName: 'احمدی',
|
||||
@@ -113,14 +169,14 @@ export const examParticipants = new Map([
|
||||
avatarUrl: '',
|
||||
address: { province: { name: 'اصفهان' }, city: { name: 'اصفهان' } },
|
||||
location: 'اصفهان، اصفهان',
|
||||
submittedAt: '2026-05-06T11:00:00.000Z',
|
||||
submittedAt: '2026-04-13T09:25:00+03:30',
|
||||
attempts: [
|
||||
{
|
||||
id: 2,
|
||||
id: 15,
|
||||
title: 'تلاش اول',
|
||||
courseTitle: 'اصول اخلاق اسلامی',
|
||||
sessionTitle: 'مقدمهای بر اخلاق اسلامی',
|
||||
date: '2026-05-06T11:00:00.000Z',
|
||||
date: '2026-04-13T09:25:00+03:30',
|
||||
score: 9,
|
||||
scoreTone: 'bad',
|
||||
},
|
||||
|
||||
@@ -2,7 +2,7 @@ import { register } from '@/services/mock/registry'
|
||||
import { endpoints } from '@/services/api/endpoints'
|
||||
import { adminCourses } from '@/services/mock/fixtures/admin-courses'
|
||||
import { adminSessions } from '@/services/mock/fixtures/admin-sessions'
|
||||
import { adminExams, examParticipants } from '@/services/mock/fixtures/admin-exams'
|
||||
import { adminExams, examAttempts, examParticipants } from '@/services/mock/fixtures/admin-exams'
|
||||
import {
|
||||
filterDateRange,
|
||||
filterItems,
|
||||
@@ -151,12 +151,13 @@ register('POST', endpoints.addQuestionOption, ({ params, data }) => {
|
||||
return { success: false, message: 'Question not found.', data: null }
|
||||
})
|
||||
|
||||
// FE-mock-only.
|
||||
register('GET', endpoints.getExamParticipants, ({ params, query }) => {
|
||||
const list = examParticipants.get(Number(params.examId)) || []
|
||||
return paginate(list, query)
|
||||
register('GET', endpoints.getExamAttempts, ({ params, query }) => {
|
||||
const list = examAttempts.get(Number(params.examId)) || []
|
||||
const { data: items, meta } = paginate(list, query)
|
||||
return { success: true, message: 'OK', data: { items, meta } }
|
||||
})
|
||||
|
||||
// FE-mock-only — single-participant detail not yet on the backend.
|
||||
register('GET', endpoints.showExamParticipant, ({ params }) => {
|
||||
const list = examParticipants.get(Number(params.examId)) || []
|
||||
const found = list.find((p) => String(p.id) === String(params.participantId))
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
apiAddAdminQuestionOption,
|
||||
apiDeleteAdminExam,
|
||||
apiGetAdminExams,
|
||||
apiGetAdminExamParticipants,
|
||||
apiGetAdminExamAttempts,
|
||||
apiShowAdminExam,
|
||||
apiShowAdminExamParticipant,
|
||||
apiUpdateAdminExam,
|
||||
@@ -16,10 +16,10 @@ export const adminExamsKeys = {
|
||||
all: ['admin', 'exams'],
|
||||
list: (filters, pagination) => ['admin', 'exams', 'list', filters, pagination],
|
||||
detail: (id) => ['admin', 'exams', 'detail', id],
|
||||
participants: (examId, filters, pagination) => [
|
||||
attempts: (examId, filters, pagination) => [
|
||||
'admin',
|
||||
'exams',
|
||||
'participants',
|
||||
'attempts',
|
||||
examId,
|
||||
filters,
|
||||
pagination,
|
||||
@@ -53,14 +53,18 @@ export const useAdminExamQuery = (idRef, options = {}) =>
|
||||
...options,
|
||||
})
|
||||
|
||||
export const useAdminExamParticipantsQuery = (examIdRef, filtersRef, paginationRef, options = {}) =>
|
||||
export const useAdminExamAttemptsQuery = (examIdRef, filtersRef, paginationRef, options = {}) =>
|
||||
useQuery({
|
||||
queryKey: ['admin', 'exams', 'participants', examIdRef, filtersRef, paginationRef],
|
||||
queryKey: ['admin', 'exams', 'attempts', examIdRef, filtersRef, paginationRef],
|
||||
queryFn: () =>
|
||||
apiGetAdminExamParticipants(examIdRef.value, {
|
||||
apiGetAdminExamAttempts(examIdRef.value, {
|
||||
...cleanFilters(filtersRef?.value || {}),
|
||||
...paginationRef?.value,
|
||||
}),
|
||||
select: (response) => ({
|
||||
data: response?.data?.items ?? response?.data ?? [],
|
||||
meta: response?.data?.meta ?? response?.meta,
|
||||
}),
|
||||
...options,
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user