Done: bagian halaman ujian only

This commit is contained in:
Mahayoga 2026-05-11 14:53:56 +07:00
parent fbb03ba9fe
commit 46040fa886
5 changed files with 233 additions and 33 deletions

View File

@ -13,12 +13,12 @@ class FinishUjianController extends Controller
public function getAllAnswer(Request $request) { public function getAllAnswer(Request $request) {
$data_session = TestSessionsModel::where('id_test_sessions', $request->id_test_sessions)->first(); $data_session = TestSessionsModel::where('id_test_sessions', $request->id_test_sessions)->first();
if($data_session != null) { if($data_session != null) {
if($data_session->status_session != '1') { if($data_session->status_session == '0') {
return response()->json([ return response()->json([
'status' => false, 'status' => false,
'message' => 'Data sesi tes belum dimulai atau telah usai. Silahkan cek status dengan kode untuk informasi lebih lanjut.' 'message' => 'Data sesi tes dinonaktifkan. Silahkan cek status dengan kode untuk informasi lebih lanjut.'
]); ]);
} else if($data_session->status_session == '1') { } else if($data_session->status_session == '2') {
$detail_test = DetailTestModel::where('id_test_sessions', $request->id_test_sessions)->get(); $detail_test = DetailTestModel::where('id_test_sessions', $request->id_test_sessions)->get();
$data_ujian = []; $data_ujian = [];
foreach($detail_test as $detail) { foreach($detail_test as $detail) {
@ -73,13 +73,15 @@ public function index(Request $request)
$data_session = TestSessionsModel::where('id_test_sessions', $id_session)->first(); $data_session = TestSessionsModel::where('id_test_sessions', $id_session)->first();
if($data_session != null) { if($data_session != null) {
if($data_session->status_session != '1') { if($data_session->status_session == '0') {
return redirect()->route('cek-status.index')->with('error', 'Data sesi tes belum dimulai atau telah usai. Silahkan cek status dengan kode untuk informasi lebih lanjut.'); return redirect()->route('cek-status.index')->with('error', 'Data sesi tes dinonaktifkan. Silahkan cek status dengan kode untuk informasi lebih lanjut.');
} else if($data_session->status_session == '1') { } else if($data_session->status_session == '1') {
// $data_session->update([ $data_session->update([
// 'status_session' => '2', 'status_session' => '2',
// 'is_active' => '0' 'is_active' => '0'
// ]); ]);
return view('user.pages.finish_ujian.index', compact('id_session'));
} else if($data_session->status_session == '2') {
return view('user.pages.finish_ujian.index', compact('id_session')); return view('user.pages.finish_ujian.index', compact('id_session'));
} }
} else { } else {

View File

@ -14,7 +14,7 @@ class HalamanUjianController extends Controller
function fetchQuestion(Request $request) { function fetchQuestion(Request $request) {
$data_question = DataSoalModel::all(); $data_question = DataSoalModel::all();
if($data_question != null) { if($data_question != null) {
$number_question = $request->question_number; $number_question = $request->question_index;
if($number_question <= 0 || $number_question > count($data_question)) { if($number_question <= 0 || $number_question > count($data_question)) {
$number_question = 1; $number_question = 1;
} }
@ -66,6 +66,12 @@ public function getCurrentAnswer(Request $request) {
]; ];
} }
} }
} else {
return response()->json([
'status' => false,
'jawaban' => null,
'choices' => null
]);
} }
$data_answer = DetailTestModel::where('id_soal', $request->id_question) $data_answer = DetailTestModel::where('id_soal', $request->id_question)
->where('id_test_sessions', $request->session_id) ->where('id_test_sessions', $request->session_id)
@ -86,6 +92,45 @@ public function getCurrentAnswer(Request $request) {
} }
} }
public function getNavigationField(Request $request) {
$id_session = null;
if(session('session_id') != null) {
$id_session = session('session_id');
} else if($request->session_id != null) {
$id_session = $request->session_id;
} else {
return response()->json([
'status' => false,
'msg' => 'Test session id tidak ditemukan'
]);
}
$data_soal = DataSoalModel::all();
$result = [];
$index = 1;
foreach($data_soal as $soal) {
$data_jawaban = DetailTestModel::where(['id_soal' => $soal->id_soal, 'id_test_sessions' => $id_session])->first();
if($data_jawaban != null) {
$result[] = [
'index' => $index,
'answered' => true,
'data' => $data_jawaban
];
} else {
$result[] = [
'index' => $index,
'answered' => false
];
}
$index += 1;
}
return response()->json([
'status' => true,
'data' => $result
]);
}
public function getTimeLeft(Request $request) { public function getTimeLeft(Request $request) {
$data_session = TestSessionsModel::where('id_test_sessions', $request->session_id)->first(); $data_session = TestSessionsModel::where('id_test_sessions', $request->session_id)->first();
if($data_session != null) { if($data_session != null) {

View File

@ -180,6 +180,10 @@ function searchUserStatus() {
$('#result_test_status').html('Selesai'); $('#result_test_status').html('Selesai');
$('#result_test_status').removeClass(); $('#result_test_status').removeClass();
$('#result_test_status').addClass('fw-bold text-white bg-success p-2 rounded-pill'); $('#result_test_status').addClass('fw-bold text-white bg-success p-2 rounded-pill');
let test_url = '{{ route('hasil-tes.index', ['id_test_sessions' => '__ID_TEST_SESSIONS__']) }}';
$('#result_test_link').show();
$('#result_test_link').html('Tes Sudah Selesai, Klik untuk melihat hasil');
$('#result_test_link').attr('href', test_url.replace('__ID_TEST_SESSIONS__', test_session.id_test_sessions));
} }
} else if(!test_session.status) { } else if(!test_session.status) {
$('#id_booking_input').val(response.id_booking); $('#id_booking_input').val(response.id_booking);

View File

@ -29,34 +29,16 @@
<div class="col-md-9 border-end"> <div class="col-md-9 border-end">
<div class="row justify-content-center flex-column p-4"> <div class="row justify-content-center flex-column p-4">
<div class="col-md-12 border-bottom fs-4 fw-bold p-2">Soal</div> <div class="col-md-12 border-bottom fs-4 fw-bold p-2">Soal</div>
<div class="col-md-12 p-2 d-none" id="id_question" style="text-align: justify"></div>
<div class="col-md-12 p-2" id="text_question" style="text-align: justify"></div> <div class="col-md-12 p-2" id="text_question" style="text-align: justify"></div>
<div class="col-md-12" id="answer_field"> <div class="col-md-12" id="answer_field">
<div class="fs-4 fw-bold p-2">Jawaban:</div> <div class="fs-4 fw-bold p-2">Jawaban:</div>
{{-- <div class="form-check m-2">
<input class="form-check-input" type="radio" name="jawaban_final" id="jawaban_{{ $item['key'] }}">
<label class="form-check-label" for="jawaban_{{ $item['key'] }}">{{ $item['value'] }}</label>
</div> --}}
</div> </div>
</div> </div>
</div> </div>
<div class="col-md-3"> <div class="col-md-3">
<div class="row p-3"> <div class="row p-3" id="navigation_field">
<div class="col-md-12 border-bottom fs-4 fw-bold p-2 mb-3" id="navigation_field">Navigasi Soal</div> <div class="col-md-12 border-bottom fs-4 fw-bold p-2 mb-3">Navigasi Soal</div>
{{-- @foreach ($answered_question as $question)
<div onclick="changeQuestion({{ $question['nomor_soal'] }})" id="nomor_{{ $question['nomor_soal'] }}" class="col-md-1 btn d-flex justify-content-center align-items-center {{ $question['answered'] ? 'bg-secondary-subtle' : 'bg-light-subtle' }} border rounded p-0 m-1" style="aspect-ratio: 1/1.5;">{{ $question['nomor_soal'] }}</div>
@endforeach
<div class="col-md-12 p-0 mt-3">
@if ($question_number > 1)
<div class="btn btn-secondary" onclick="changeQuestion({{ $question_number - 1 }})">Previous</div>
@endif
@if ($is_last_question)
<div class="btn btn-success" onclick="finishExam()">Finish</div>
@else
<div class="btn btn-primary" onclick="changeQuestion({{ $question_number + 1 }})">Next</div>
@endif
</div> --}}
</div> </div>
<div class="row p-3"> <div class="row p-3">
<div class="col-md-12"> <div class="col-md-12">
@ -93,6 +75,53 @@
const TOKEN_SESSION = '{{ $data_session->token_session }}'; const TOKEN_SESSION = '{{ $data_session->token_session }}';
let UNIX_END_TIME = null; let UNIX_END_TIME = null;
let QUESTION_INDEX = 1; let QUESTION_INDEX = 1;
let QUESTION_ID = null;
let CURRENT_BTN = null;
let CAPTION_BTN = null;
function changeQuestion(num) {
Swal.showLoading();
let xhttp = new XMLHttpRequest();
let the_answer = null;
let token = document.getElementById('_token').getAttribute('value');
let formData = new FormData();
if(QUESTION_INDEX == num) {
console.log('same question');
Swal.close();
return;
}
document.getElementsByName('jawaban_final').forEach(element => {
if (element.checked) {
the_answer = {
key: element.id.split('_')[1],
};
}
});
if(the_answer) {
formData.append('jawaban_final', the_answer.key);
formData.append('_token', token);
formData.append('question', num);
formData.append('id_question', QUESTION_ID);
formData.append('session_id', SESSION_ID);
xhttp.open("POST", "{{ route('ujian.store') }}", false);
xhttp.send(formData);
}
// stopTobii();
QUESTION_INDEX = num;
getNavigationField();
setCurrentNavigation();
fetchQuestion(QUESTION_INDEX);
Swal.close();
}
function setCurrentNavigation() {
$('#nomor_' + QUESTION_INDEX).removeClass('bg-light-subtle');
$('#nomor_' + QUESTION_INDEX).removeClass('bg-secondary-subtle');
$('#nomor_' + QUESTION_INDEX).addClass('bg-info');
}
function fetchQuestion(question_index) { function fetchQuestion(question_index) {
let xhttp = new XMLHttpRequest(); let xhttp = new XMLHttpRequest();
@ -102,6 +131,7 @@ function fetchQuestion(question_index) {
let response = JSON.parse(this.responseText); let response = JSON.parse(this.responseText);
if(response.status) { if(response.status) {
$('#text_question').html(response.data.pertanyaan); $('#text_question').html(response.data.pertanyaan);
QUESTION_ID = response.data.id_soal;
getCurrentAnswer(response.data.id_soal); getCurrentAnswer(response.data.id_soal);
} else { } else {
Swal.fire({ Swal.fire({
@ -118,6 +148,65 @@ function fetchQuestion(question_index) {
xhttp.send(); xhttp.send();
} }
function finishExam() {
Swal.fire({
title: 'Alert',
icon: 'question',
text: 'Apakah Anda yakin ingin mengakhiri ujian? (aksi tidak dapat dikembalikan)',
confirmButtonText: 'Ya',
cancelButtonText: 'Tidak',
showCancelButton: true,
showCloseButton: true,
}).then((result) => {
if (result.isConfirmed) {
event.preventDefault();
let xhttp = new XMLHttpRequest();
let the_answer = null;
let token = document.getElementById('_token').getAttribute('value');
let formData = new FormData();
document.getElementsByName('jawaban_final').forEach(element => {
if (element.checked) {
the_answer = {
key: element.id.split('_')[1],
};
}
});
if(the_answer) {
formData.append('jawaban_final', the_answer.key);
formData.append('_token', token);
formData.append('question', QUESTION_INDEX);
formData.append('id_question', QUESTION_ID);
formData.append('session_id', SESSION_ID);
xhttp.open("POST", "{{ route('ujian.store') }}", false);
xhttp.send(formData);
console.log("sending answer (finish)");
}
ws.send(JSON.stringify({
type: "command",
action: "stop",
session_id: SESSION_ID
}));
//send_data_to_db
ws.send(JSON.stringify({
type: "send_data_to_db",
session_id: SESSION_ID
}));
ws.send(JSON.stringify({
type: "update_status",
status_sessions: false,
session_id: SESSION_ID
}));
window.location.href = "{{ route('hasil-tes.index') }}?id_test_sessions=" + SESSION_ID;
}
});
}
function getCurrentAnswer(id_question) { function getCurrentAnswer(id_question) {
let xhttp = new XMLHttpRequest(); let xhttp = new XMLHttpRequest();
@ -136,6 +225,13 @@ function getCurrentAnswer(id_question) {
`; `;
}); });
$('#answer_field').append(choices_html); $('#answer_field').append(choices_html);
if(response.jawaban != null) {
document.getElementsByName('jawaban_final').forEach(element => {
if (element.id.split('_')[1] == response.jawaban) {
element.checked = true;
}
});
}
} }
} }
}; };
@ -143,6 +239,57 @@ function getCurrentAnswer(id_question) {
xhttp.send(); xhttp.send();
} }
function getNavigationField() {
let xhttp = new XMLHttpRequest();
let total_question = 0;
xhttp.onreadystatechange = function() {
if(this.readyState == 4 && this.status == 200) {
let response = JSON.parse(this.responseText);
if(response.status) {
let navigation_field = '<div class="col-md-12 border-bottom fs-4 fw-bold p-2 mb-3">Navigasi Soal</div>';
$('#navigation_field').html(navigation_field);
response.data.forEach((q) => {
let answered = 'bg-light-subtle';
if(q.answered) {
answered = 'bg-secondary-subtle'
}
navigation_field += `
<div onclick="changeQuestion(${q.index})" id="nomor_${q.index}" class="col-md-1 btn d-flex justify-content-center align-items-center ${answered} border rounded p-0 m-1" style="aspect-ratio: 1/1.5;">${q.index}</div>
`;
total_question += 1;
});
if(QUESTION_INDEX <= total_question) {
let next_num = 0;
next_num = QUESTION_INDEX + 1;
if(next_num > total_question) {
// tombol finish dan back
navigation_field += `
<div class="btn btn-secondary mb-2" onclick="changeQuestion(${QUESTION_INDEX - 1})">Back</div>
`;
navigation_field += `
<div class="btn btn-success" onclick="finishExam()">Finish</div>
`;
} else {
if((QUESTION_INDEX - 1) != 0) {
navigation_field += `
<div class="btn btn-secondary mb-2" onclick="changeQuestion(${QUESTION_INDEX - 1})">Back</div>
`;
}
navigation_field += `
<div class="btn btn-primary" status="false" onclick="changeQuestion(${QUESTION_INDEX + 1})">Next</div>
`;
}
}
$('#navigation_field').html(navigation_field);
}
}
};
xhttp.open('GET', '{{ route('ujian.navigationField') }}?session_id=' + SESSION_ID, false);
xhttp.send();
}
function getTimeLeft() { function getTimeLeft() {
let xhttp = new XMLHttpRequest(); let xhttp = new XMLHttpRequest();
@ -248,7 +395,6 @@ function checkFullscreen() {
})); }));
document.addEventListener('fullscreenchange', checkFullscreen); document.addEventListener('fullscreenchange', checkFullscreen);
// checkFullscreen();
ws.send(JSON.stringify({ ws.send(JSON.stringify({
type: "update_status", type: "update_status",
@ -281,9 +427,11 @@ function checkFullscreen() {
}; };
startTobii(); startTobii();
// getCurrentAnswer(); checkFullscreen();
getTimeLeft(); getTimeLeft();
setInterval(updateTimeLeft, 1000); setInterval(updateTimeLeft, 1000);
getNavigationField();
setCurrentNavigation();
fetchQuestion(QUESTION_INDEX); fetchQuestion(QUESTION_INDEX);
}; };
}); });

View File

@ -42,6 +42,7 @@
Route::get('ujian/get/current-answer', [HalamanUjianController::class, 'getCurrentAnswer'])->name('ujian.getCurrentAnswer'); Route::get('ujian/get/current-answer', [HalamanUjianController::class, 'getCurrentAnswer'])->name('ujian.getCurrentAnswer');
Route::get('ujian/get/time-left', [HalamanUjianController::class, 'getTimeLeft'])->name('ujian.getTimeLeft'); Route::get('ujian/get/time-left', [HalamanUjianController::class, 'getTimeLeft'])->name('ujian.getTimeLeft');
Route::get('ujian/fetch/question', [HalamanUjianController::class, 'fetchQuestion'])->name('ujian.fetchQuestion'); Route::get('ujian/fetch/question', [HalamanUjianController::class, 'fetchQuestion'])->name('ujian.fetchQuestion');
Route::get('ujian/fetch/navigation-field', [HalamanUjianController::class, 'getNavigationField'])->name('ujian.navigationField');
Route::resource('hasil-tes', FinishUjianController::class)->only(['index', 'show']); Route::resource('hasil-tes', FinishUjianController::class)->only(['index', 'show']);
Route::get('hasil-tes/get/all-answer', [FinishUjianController::class, 'getAllAnswer'])->name('hasil-tes.getAllAnswer'); Route::get('hasil-tes/get/all-answer', [FinishUjianController::class, 'getAllAnswer'])->name('hasil-tes.getAllAnswer');
Route::middleware(['auth', 'role.auth'])->group(function() { Route::middleware(['auth', 'role.auth'])->group(function() {