Files
Recruitment-HC/dashboard/idap_jawab.php
T

37 lines
7.9 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
require __DIR__ . '/bootstrap.php'; require_admin();
require_once __DIR__.'/../includes/exam-service.php';
$id=(int)($_GET['id']??0); exam_expire_due($id); $p=one('SELECT * FROM in_daper WHERE id=?','i',[$id]);
if(!$p) { http_response_code(404); page_start('Peserta tidak ditemukan','participants'); echo '<p>Peserta tidak ditemukan.</p>'; page_end(); exit; }
$error='';
if($_SERVER['REQUEST_METHOD']==='POST') {
verify_csrf(); $action=$_POST['action']??'';
if($action==='stage' && array_key_exists((string)($_POST['kode']??''),STAGES)) {
query('UPDATE in_daper SET kode=? WHERE id=?','ii',[(int)$_POST['kode'],$id]); $_SESSION['flash']='Tahap seleksi diperbarui.'; redirect('idap_jawab.php?id='.$id);
}
if($action==='grade') {
db()->begin_transaction();
try {
$locked=one('SELECT level FROM in_daper WHERE id=? FOR UPDATE','i',[$id]);
$answers=rows('SELECT j.id,j.cek FROM in_jawab j JOIN in_soal s ON s.id=j.isoal WHERE j.idap=? AND s.kat BETWEEN 1 AND 4 FOR UPDATE','i',[$id]);
$grades=$_POST['grade']??[];
if((int)$locked['level']<4 || !$answers || !is_array($grades)) throw new InvalidArgumentException('Penilaian dapat disimpan setelah peserta menyelesaikan seluruh fase tes.');
foreach($answers as $answer) {
$grade=$grades[$answer['id']]??'';
if(!in_array($grade,['0','10'],true)) throw new InvalidArgumentException('Nilai semua jawaban fase 1–3 sebelum menyimpan.');
query('UPDATE in_jawab SET cek=? WHERE id=? AND idap=?','sii',[$grade,(int)$answer['id'],$id]);
}
$orphans=one('SELECT COUNT(*) n FROM in_jawab j LEFT JOIN in_soal s ON s.id=j.isoal WHERE j.idap=? AND s.id IS NULL','i',[$id]);
if((int)$orphans['n']>0) throw new InvalidArgumentException('Ada jawaban yang kehilangan referensi soal. Pulihkan soal sebelum menyelesaikan penilaian.');
query('UPDATE in_daper SET cek=1 WHERE id=?','i',[$id]); db()->commit(); $_SESSION['flash']='Penilaian berhasil disimpan.'; redirect('idap_jawab.php?id='.$id);
} catch(InvalidArgumentException $ex) { db()->rollback(); $error=$ex->getMessage(); } catch(Throwable $ex) { db()->rollback(); throw $ex; }
}
}
$answers=rows('SELECT j.id,j.jawab,j.cek,s.id question_id,s.kat,s.soal,s.soal1,s.kunci FROM in_jawab j LEFT JOIN in_soal s ON s.id=j.isoal WHERE j.idap=? ORDER BY s.kat,j.id','i',[$id]);
$score=0; $ungraded=0; $orphans=0;
foreach($answers as $a) { if(!$a['question_id']) $orphans++; if((int)$a['kat']>=1 && (int)$a['kat']<=4) { if($a['cek']==='10') $score+=10; if(!in_array($a['cek'],['0','10'],true)) $ungraded++; } }
$attemptLog=rows('SELECT a.phase,a.status,a.deadline,a.started_at,a.submitted_at,COUNT(e.id) event_count FROM rec_exam_attempt a LEFT JOIN rec_exam_event e ON e.attempt_id=a.id WHERE a.participant_id=? GROUP BY a.id ORDER BY a.phase','i',[$id]);
$activityLog=rows('SELECT a.phase,e.event_type,e.created_at FROM rec_exam_event e JOIN rec_exam_attempt a ON a.id=e.attempt_id WHERE a.participant_id=? ORDER BY e.id DESC LIMIT 50','i',[$id]);
page_start('Hasil Psikotest', 'participants');
?><a class="text-link back" href="idap.php">← Daftar peserta</a><section class="card participant-card"><div class="person"><span class="avatar large"><?=e(substr($p['nama'],0,1))?></span><div><h2><?=e($p['nama'])?></h2><p><?=e($p['posisi'])?> · <?=e($p['jk'])?></p><small><?=e($p['email'])?> · <?=e($p['nowa'])?></small></div></div><div><span class="muted">Skor fase 1–3</span><div class="score"><?=$score?><small> / ambang <?=threshold()?></small></div><span class="badge <?=(int)$p['cek']===1?'success':''?>"><?=(int)$p['cek']!==1?'Belum difinalkan':($score>=threshold()?'Lulus skor':'Di bawah ambang')?></span></div></section><section class="card stage-card"><div><h2>Tahap seleksi</h2><p>Progres tes: <?=min(4,max(0,(int)$p['level']))?> / 4 fase · <?=e(STAGES[(int)$p['kode']]??'Lainnya')?></p></div><form method="post" class="inline-form"><?php csrf_field(); ?><input type="hidden" name="action" value="stage"><select name="kode" aria-label="Tahap seleksi"><?php foreach(STAGES as $k=>$v): ?><option value="<?=$k?>" <?=(int)$p['kode']===$k?'selected':''?>><?=e($v)?></option><?php endforeach; ?></select><button class="button secondary">Simpan tahap</button></form></section><?php if($error): ?><div class="notice error"><?=e($error)?></div><?php endif; ?><?php if($orphans): ?><div class="notice error"><?=$orphans?> jawaban tidak memiliki referensi soal. Penilaian belum dapat difinalkan.</div><?php endif; ?><section class="card"><div class="card-heading"><div><h2>Catatan integritas sesi tes</h2><p>Aktivitas browser adalah laporan dari perangkat peserta, dapat tidak lengkap, dan bukan bukti kecurangan atau keputusan seleksi otomatis.</p></div></div><div class="table-wrap"><table><thead><tr><th>Fase</th><th>Mulai</th><th>Deadline server</th><th>Status</th><th>Catatan aktivitas</th></tr></thead><tbody><?php foreach($attemptLog as $log): ?><tr><td><?=(int)$log['phase']?></td><td><?=e($log['started_at'])?></td><td><?=e(date('Y-m-d H:i:s',(int)$log['deadline']))?></td><td><?=e(['active'=>'Berjalan','expired'=>'Waktu habis','submitted'=>'Dikirim'][$log['status']]??$log['status'])?></td><td><?=(int)$log['event_count']?></td></tr><?php endforeach; if(!$attemptLog): ?><tr><td colspan="5" class="empty">Data historis: belum ada catatan sesi tes.</td></tr><?php endif; ?></tbody></table></div><?php if($activityLog): ?><details class="integrity-details"><summary>Lihat 50 aktivitas terbaru</summary><div class="table-wrap"><table><thead><tr><th>Waktu</th><th>Fase</th><th>Aktivitas</th></tr></thead><tbody><?php foreach($activityLog as $log): ?><tr><td><?=e($log['created_at'])?></td><td><?=(int)$log['phase']?></td><td><?=e(['tab_hidden'=>'Halaman tidak terlihat','window_blur'=>'Jendela kehilangan fokus','copy'=>'Copy','cut'=>'Cut','paste'=>'Paste','contextmenu'=>'Menu konteks','page_resumed'=>'Kembali ke halaman','relogin'=>'Login ulang','stale_tab'=>'Permintaan dari tab/sesi yang sudah digantikan'][$log['event_type']]??$log['event_type'])?></td></tr><?php endforeach; ?></tbody></table></div></details><?php endif; ?></section><form method="post"><?php csrf_field(); ?><input type="hidden" name="action" value="grade"><?php foreach(CATEGORIES as $category=>$label): ?><section class="card answer-section"><div class="card-heading"><div><span class="eyebrow">KATEGORI 0<?=$category?></span><h2><?=e($label)?></h2></div><span class="badge"><?=$category===5?'Deskriptif · tanpa skor':'Benar 10 · Salah 0'?></span></div><div class="table-wrap"><table><thead><tr><th>Soal<?=$category===5?' / Pilihan L':''?></th><?php if($category===5): ?><th>Pilihan R</th><?php endif; ?><th>Jawaban peserta</th><?php if($category!==5): ?><th>Kunci jawaban</th><th>Penilaian</th><?php endif; ?></tr></thead><tbody><?php $count=0; foreach($answers as $a): if((int)$a['kat']!==$category) continue; $count++; ?><tr><td class="question-text"><?=nl2br(e($a['soal']))?></td><?php if($category===5): ?><td class="question-text"><?=nl2br(e($a['soal1']))?></td><?php endif; ?><td><?=nl2br(e($a['jawab']))?></td><?php if($category!==5): ?><td><?=nl2br(e($a['kunci']))?></td><td><select name="grade[<?=(int)$a['id']?>]" aria-label="Nilai jawaban <?=(int)$a['id']?>" required><option value="">Pilih nilai</option><?php foreach(['10'=>'Benar (+10)','0'=>'Salah (0)'] as $value=>$text): ?><option value="<?=$value?>" <?=(string)($_POST['grade'][$a['id']]??$a['cek'])===(string)$value?'selected':''?>><?=$text?></option><?php endforeach; ?></select></td><?php endif; ?></tr><?php endforeach; if(!$count): ?><tr><td colspan="4" class="empty">Belum ada jawaban untuk kategori ini.</td></tr><?php endif; ?></tbody></table></div></section><?php endforeach; ?><div class="save-bar"><div><strong>Penilaian manual</strong><small><?=$ungraded?> jawaban belum dinilai. Kepribadian ditinjau secara deskriptif.</small></div><button class="button" <?=(int)$p['level']<4 || !$answers || $orphans?'disabled':''?>>Simpan penilaian</button></div></form><?php page_end(); ?>