batch 1 update style & dahsboard for rec.nurinda.co.id
This commit is contained in:
1 parent
9107ffb158
commit
f39aa60384
18485 files changed
+843
-2881869
No files matched your search
@@ -0,0 +1,36 @@
|
||||
<?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(); ?>
|
||||
Reference in new issue
Block a user