848 lines
49 KiB
PHP
848 lines
49 KiB
PHP
|
||
|
||
<?php $__env->startSection('content'); ?>
|
||
|
||
<style>
|
||
/* ── Tab Navigation ── */
|
||
.laporan-tabs { display: flex; gap: 0; border-bottom: 2px solid #e2e8f0; margin-bottom: 0; flex-wrap: wrap; }
|
||
.laporan-tab { padding: 12px 20px; cursor: pointer; border: none; background: none; font-size: 0.9rem; color: var(--text-light); transition: all 0.3s; border-bottom: 3px solid transparent; white-space: nowrap; }
|
||
.laporan-tab:hover { color: var(--primary-color); background: rgba(16,185,129,0.05); }
|
||
.laporan-tab.active { color: var(--primary-color); border-bottom: 3px solid var(--primary-color); font-weight: 600; }
|
||
.laporan-tab i { margin-right: 6px; }
|
||
.tab-pane { display: none; padding: 20px 0; }
|
||
.tab-pane.active { display: block; }
|
||
|
||
/* ── KPI Cards ── */
|
||
.kpi-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 16px; margin-bottom: 24px; }
|
||
.kpi-card { padding: 20px; border-radius: 12px; background: #fff; box-shadow: 0 2px 8px rgba(0,0,0,0.06); position: relative; overflow: hidden; }
|
||
.kpi-card::before { content:''; position:absolute; top:0; left:0; right:0; height:4px; }
|
||
.kpi-card.kpi-blue::before { background: linear-gradient(90deg,#3B82F6,#60A5FA); }
|
||
.kpi-card.kpi-green::before { background: linear-gradient(90deg,#10B981,#34D399); }
|
||
.kpi-card.kpi-gold::before { background: linear-gradient(90deg,#F59E0B,#FBBF24); }
|
||
.kpi-card.kpi-red::before { background: linear-gradient(90deg,#EF4444,#F87171); }
|
||
.kpi-label { font-size: 0.82rem; color: var(--text-light); margin-bottom: 6px; }
|
||
.kpi-value { font-size: 1.8rem; font-weight: 700; color: var(--primary-dark); }
|
||
.kpi-sub { font-size: 0.78rem; margin-top: 6px; }
|
||
.kpi-sub.up { color: #10B981; }
|
||
.kpi-sub.down { color: #EF4444; }
|
||
.kpi-sub.neutral { color: #6B7280; }
|
||
.kpi-icon { position:absolute; top:18px; right:18px; font-size:2rem; opacity:0.12; }
|
||
|
||
/* ── Period Selector ── */
|
||
.period-bar { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-bottom: 20px; }
|
||
.period-btn { padding: 6px 14px; border-radius: 20px; border: 1px solid #e2e8f0; background: #fff; cursor: pointer; font-size: 0.82rem; transition: all 0.2s; }
|
||
.period-btn:hover, .period-btn.active { background: var(--primary-color); color: #fff; border-color: var(--primary-color); }
|
||
.custom-range { display: none; align-items: center; gap: 8px; }
|
||
.custom-range.show { display: flex; }
|
||
.custom-range input[type=date] { padding: 5px 10px; border: 1px solid #e2e8f0; border-radius: 6px; font-size: 0.82rem; }
|
||
|
||
/* ── Charts ── */
|
||
.chart-box { background: #fff; border-radius: 12px; padding: 20px; box-shadow: 0 2px 8px rgba(0,0,0,0.06); margin-bottom: 20px; }
|
||
.chart-box h4 { margin: 0 0 16px 0; color: var(--primary-dark); font-size: 1rem; }
|
||
.chart-container { position: relative; width: 100%; }
|
||
.chart-container canvas { max-width: 100%; }
|
||
|
||
/* ── Heatmap ── */
|
||
.heatmap-table { width: 100%; border-collapse: collapse; font-size: 0.82rem; }
|
||
.heatmap-table th { padding: 10px 8px; background: #f8fafc; color: var(--text-light); font-weight: 600; text-align: center; border: 1px solid #e2e8f0; }
|
||
.heatmap-table td { padding: 0; border: 1px solid #e2e8f0; }
|
||
.heatmap-cell { padding: 10px 8px; text-align: center; cursor: pointer; transition: all 0.2s; font-weight: 600; font-size: 0.8rem; }
|
||
.heatmap-cell:hover { transform: scale(1.08); box-shadow: 0 2px 8px rgba(0,0,0,0.15); position: relative; z-index: 2; }
|
||
.heatmap-90 { background: #10B981; color: #fff; }
|
||
.heatmap-80 { background: #34D399; color: #fff; }
|
||
.heatmap-70 { background: #FBBF24; color: #333; }
|
||
.heatmap-low { background: #EF4444; color: #fff; }
|
||
.heatmap-na { background: #F3F4F6; color: #9CA3AF; cursor: not-allowed; }
|
||
.heatmap-table .row-label { text-align: left; padding: 10px 12px; font-weight: 600; background: #fff; white-space: nowrap; }
|
||
|
||
/* ── Top/Bottom Cards ── */
|
||
.rank-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; }
|
||
@media(max-width:768px){ .rank-grid { grid-template-columns: 1fr; } }
|
||
.rank-card { padding: 14px 16px; border-radius: 10px; background: #fff; border-left: 4px solid; display: flex; align-items: center; gap: 14px; box-shadow: 0 1px 4px rgba(0,0,0,0.05); }
|
||
.rank-card.top { border-color: #10B981; }
|
||
.rank-card.bottom { border-color: #EF4444; }
|
||
.rank-num { font-size: 1.4rem; font-weight: 700; min-width: 30px; text-align: center; }
|
||
.rank-card.top .rank-num { color: #10B981; }
|
||
.rank-card.bottom .rank-num { color: #EF4444; }
|
||
.rank-info { flex: 1; }
|
||
.rank-info .name { font-weight: 600; font-size: 0.9rem; }
|
||
.rank-info .meta { font-size: 0.78rem; color: var(--text-light); }
|
||
.rank-persen { font-weight: 700; font-size: 1.1rem; }
|
||
|
||
/* ── Leaderboard ── */
|
||
.leaderboard-table { width: 100%; }
|
||
.leaderboard-table .medal { font-size: 1.3rem; }
|
||
.streak-badge { background: linear-gradient(135deg,#F59E0B,#FBBF24); color:#fff; padding: 2px 8px; border-radius: 12px; font-size: 0.75rem; font-weight: 600; }
|
||
|
||
/* ── Progress bar inline ── */
|
||
.progress-inline { display: flex; align-items: center; gap: 8px; }
|
||
.progress-bar-mini { flex: 1; background: #e9ecef; border-radius: 8px; height: 8px; overflow: hidden; max-width: 120px; }
|
||
.progress-bar-mini .fill { height: 100%; border-radius: 8px; transition: width 0.4s ease; }
|
||
|
||
/* ── Pattern Cards ── */
|
||
.pattern-card { padding: 16px; border-radius: 10px; border-left: 4px solid; margin-bottom: 12px; background: #fff; box-shadow: 0 1px 4px rgba(0,0,0,0.05); }
|
||
.pattern-card.p-danger { border-color: #EF4444; background: #FEF2F2; }
|
||
.pattern-card.p-warning { border-color: #F59E0B; background: #FFFBEB; }
|
||
.pattern-card.p-info { border-color: #3B82F6; background: #EFF6FF; }
|
||
.pattern-card.p-success { border-color: #10B981; background: #ECFDF5; }
|
||
.pattern-title { font-weight: 600; font-size: 0.92rem; margin-bottom: 4px; }
|
||
.pattern-desc { font-size: 0.82rem; color: #4B5563; }
|
||
.pattern-category { display: inline-block; font-size: 0.72rem; padding: 2px 8px; border-radius: 10px; background: rgba(0,0,0,0.06); margin-bottom: 6px; }
|
||
|
||
/* ── Export Section ── */
|
||
.export-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 20px; }
|
||
.export-card { padding: 24px; border-radius: 12px; background: #fff; box-shadow: 0 2px 8px rgba(0,0,0,0.06); }
|
||
.export-card h4 { margin: 0 0 16px; color: var(--primary-dark); }
|
||
.checkbox-group { display: flex; flex-direction: column; gap: 8px; margin: 12px 0; }
|
||
.checkbox-group label { display: flex; align-items: center; gap: 8px; font-size: 0.88rem; cursor: pointer; }
|
||
.checkbox-group input[type=checkbox] { accent-color: var(--primary-color); }
|
||
|
||
/* ── Accordion ── */
|
||
.accordion-item { border: 1px solid #e2e8f0; border-radius: 8px; margin-bottom: 8px; overflow: hidden; }
|
||
.accordion-header { padding: 14px 16px; background: #f8fafc; cursor: pointer; display: flex; justify-content: space-between; align-items: center; font-weight: 600; font-size:0.9rem; transition: background 0.2s; }
|
||
.accordion-header:hover { background: #eef2f7; }
|
||
.accordion-header .arrow { transition: transform 0.3s; }
|
||
.accordion-header.open .arrow { transform: rotate(180deg); }
|
||
.accordion-body { padding: 0 16px; max-height: 0; overflow: hidden; transition: max-height 0.4s ease, padding 0.3s; }
|
||
.accordion-body.open { max-height: 2000px; padding: 16px; }
|
||
|
||
/* ── Insight Box ── */
|
||
.insight-box { padding: 12px 16px; border-radius: 8px; margin-bottom: 8px; display: flex; align-items: flex-start; gap: 10px; font-size: 0.85rem; }
|
||
.insight-box.i-success { background: #ECFDF5; color: #065F46; }
|
||
.insight-box.i-warning { background: #FFFBEB; color: #92400E; }
|
||
.insight-box.i-danger { background: #FEF2F2; color: #991B1B; }
|
||
.insight-box.i-info { background: #EFF6FF; color: #1E40AF; }
|
||
.insight-box i { margin-top: 2px; }
|
||
|
||
/* ── Misc ── */
|
||
.section-title { font-size: 1.05rem; font-weight: 600; color: var(--primary-dark); margin: 0 0 16px; display: flex; align-items: center; gap: 8px; }
|
||
.text-center { text-align: center; }
|
||
.text-right { text-align: right; }
|
||
.two-col { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; }
|
||
@media(max-width:768px){ .two-col { grid-template-columns: 1fr; } }
|
||
</style>
|
||
|
||
|
||
<div class="page-header">
|
||
<h2><i class="fas fa-chart-line"></i> Laporan & Statistik Kegiatan</h2>
|
||
<div style="display: flex; gap: 8px;">
|
||
<a href="<?php echo e(route('admin.riwayat-kegiatan.index')); ?>" class="btn btn-info btn-sm">
|
||
<i class="fas fa-history"></i> Riwayat Kegiatan
|
||
</a>
|
||
<a href="<?php echo e(route('admin.laporan-kegiatan.export-pdf', request()->query())); ?>" class="btn btn-danger btn-sm" target="_blank">
|
||
<i class="fas fa-file-pdf"></i> PDF
|
||
</a>
|
||
<button onclick="exportExcel()" class="btn btn-success btn-sm">
|
||
<i class="fas fa-file-excel"></i> Excel
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
<div class="content-box" style="margin-bottom: 20px;">
|
||
<form method="GET" id="periodForm" action="<?php echo e(route('admin.laporan-kegiatan.index')); ?>">
|
||
<div class="period-bar">
|
||
<span style="font-size:0.85rem; color:var(--text-light);"><i class="fas fa-calendar-alt"></i> Periode:</span>
|
||
<?php $__currentLoopData = ['hari_ini'=>'Hari Ini','minggu_ini'=>'Minggu Ini','bulan_ini'=>'Bulan Ini','semester_ini'=>'Semester','custom'=>'Custom']; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $key=>$label): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
|
||
<button type="button" class="period-btn <?php echo e($periode === $key ? 'active' : ''); ?>" data-periode="<?php echo e($key); ?>" onclick="setPeriode('<?php echo e($key); ?>')"><?php echo e($label); ?></button>
|
||
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
|
||
<div class="custom-range <?php echo e($periode === 'custom' ? 'show' : ''); ?>" id="customRange">
|
||
<input type="date" name="tanggal_dari" value="<?php echo e(request('tanggal_dari', $startDate->format('Y-m-d'))); ?>">
|
||
<span>—</span>
|
||
<input type="date" name="tanggal_sampai" value="<?php echo e(request('tanggal_sampai', $endDate->format('Y-m-d'))); ?>">
|
||
</div>
|
||
<input type="hidden" name="periode" id="periodeInput" value="<?php echo e($periode); ?>">
|
||
<button type="submit" class="btn btn-primary btn-sm"><i class="fas fa-sync-alt"></i> Terapkan</button>
|
||
</div>
|
||
</form>
|
||
<p style="margin: 8px 0 0; font-size: 0.82rem; color: var(--text-light);">
|
||
<i class="fas fa-info-circle"></i> Menampilkan data: <strong><?php echo e($periodeLabel); ?></strong>
|
||
</p>
|
||
</div>
|
||
|
||
|
||
<div class="kpi-grid">
|
||
<div class="kpi-card kpi-blue">
|
||
<div class="kpi-label">Total Kegiatan</div>
|
||
<div class="kpi-value"><?php echo e($kpi['total_kegiatan']); ?></div>
|
||
<div class="kpi-sub <?php echo e($kpiComparison['total_kegiatan'] >= 0 ? 'up' : 'down'); ?>">
|
||
<i class="fas fa-<?php echo e($kpiComparison['total_kegiatan'] >= 0 ? 'arrow-up' : 'arrow-down'); ?>"></i>
|
||
<?php echo e(abs($kpiComparison['total_kegiatan'])); ?> vs periode lalu
|
||
</div>
|
||
<i class="fas fa-calendar-check kpi-icon"></i>
|
||
</div>
|
||
<div class="kpi-card kpi-green">
|
||
<div class="kpi-label">Rata-rata Kehadiran</div>
|
||
<div class="kpi-value"><?php echo e($kpi['avg_kehadiran']); ?>%</div>
|
||
<div class="kpi-sub <?php echo e($kpiComparison['avg_kehadiran'] >= 0 ? 'up' : 'down'); ?>">
|
||
<i class="fas fa-<?php echo e($kpiComparison['avg_kehadiran'] >= 0 ? 'arrow-up' : 'arrow-down'); ?>"></i>
|
||
<?php echo e(abs($kpiComparison['avg_kehadiran'])); ?>% vs periode lalu
|
||
</div>
|
||
<i class="fas fa-percentage kpi-icon"></i>
|
||
</div>
|
||
<div class="kpi-card kpi-gold">
|
||
<div class="kpi-label">Kegiatan Terbaik</div>
|
||
<div class="kpi-value" style="font-size:1.2rem;"><?php echo e($kpi['kegiatan_terbaik']['nama']); ?></div>
|
||
<div class="kpi-sub up">
|
||
<i class="fas fa-trophy"></i> <?php echo e($kpi['kegiatan_terbaik']['persen']); ?>% kehadiran
|
||
</div>
|
||
<i class="fas fa-award kpi-icon"></i>
|
||
</div>
|
||
<div class="kpi-card kpi-red">
|
||
<div class="kpi-label">Santri Perlu Perhatian</div>
|
||
<div class="kpi-value"><?php echo e($kpi['santri_perlu_perhatian']); ?></div>
|
||
<div class="kpi-sub <?php echo e($kpiComparison['santri_perlu_perhatian'] <= 0 ? 'up' : 'down'); ?>">
|
||
<i class="fas fa-<?php echo e($kpiComparison['santri_perlu_perhatian'] <= 0 ? 'arrow-down' : 'arrow-up'); ?>"></i>
|
||
<?php echo e(abs($kpiComparison['santri_perlu_perhatian'])); ?> vs periode lalu
|
||
</div>
|
||
<i class="fas fa-user-clock kpi-icon"></i>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
<div class="content-box" style="padding:0;">
|
||
<div class="laporan-tabs" id="laporanTabs">
|
||
<button class="laporan-tab active" data-tab="overview"><i class="fas fa-tachometer-alt"></i> Overview</button>
|
||
<button class="laporan-tab" data-tab="kelas"><i class="fas fa-school"></i> Analisis Kelas</button>
|
||
<button class="laporan-tab" data-tab="santri"><i class="fas fa-users"></i> Analisis Santri</button>
|
||
<button class="laporan-tab" data-tab="kegiatan"><i class="fas fa-tasks"></i> Analisis Kegiatan</button>
|
||
<button class="laporan-tab" data-tab="pattern"><i class="fas fa-brain"></i> Pola & Anomali</button>
|
||
<button class="laporan-tab" data-tab="export"><i class="fas fa-download"></i> Export</button>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
<div class="tab-pane active" id="tab-overview">
|
||
|
||
<div class="chart-box">
|
||
<h4><i class="fas fa-chart-line"></i> Trend Kehadiran Per Kategori</h4>
|
||
<div class="chart-container" style="height:320px;">
|
||
<canvas id="trendChart"></canvas>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="two-col">
|
||
|
||
<div class="chart-box">
|
||
<h4><i class="fas fa-chart-bar"></i> Distribusi Kehadiran Santri</h4>
|
||
<div class="chart-container" style="height:280px;">
|
||
<canvas id="distribusiChart"></canvas>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
<div class="chart-box">
|
||
<h4><i class="fas fa-lightbulb"></i> Insight Otomatis</h4>
|
||
<?php if($kpi['avg_kehadiran'] >= 85): ?>
|
||
<div class="insight-box i-success"><i class="fas fa-check-circle"></i> Rata-rata kehadiran sangat baik (<?php echo e($kpi['avg_kehadiran']); ?>%). Pertahankan!</div>
|
||
<?php elseif($kpi['avg_kehadiran'] >= 70): ?>
|
||
<div class="insight-box i-warning"><i class="fas fa-exclamation-triangle"></i> Rata-rata kehadiran cukup (<?php echo e($kpi['avg_kehadiran']); ?>%). Ada ruang untuk peningkatan.</div>
|
||
<?php else: ?>
|
||
<div class="insight-box i-danger"><i class="fas fa-times-circle"></i> Rata-rata kehadiran rendah (<?php echo e($kpi['avg_kehadiran']); ?>%). Perlu evaluasi serius.</div>
|
||
<?php endif; ?>
|
||
|
||
<?php if($kpi['santri_perlu_perhatian'] > 0): ?>
|
||
<div class="insight-box i-danger"><i class="fas fa-user-clock"></i> <?php echo e($kpi['santri_perlu_perhatian']); ?> santri memiliki kehadiran <70%. <a href="#" onclick="switchTab('santri')">Lihat daftar →</a></div>
|
||
<?php endif; ?>
|
||
|
||
<?php if(!empty($bottomKegiatan)): ?>
|
||
<?php $worst = $bottomKegiatan[0] ?? null; ?>
|
||
<?php if($worst && $worst['persen'] < 70): ?>
|
||
<div class="insight-box i-warning"><i class="fas fa-arrow-down"></i> <?php echo e($worst['nama_kegiatan']); ?> memiliki kehadiran terendah (<?php echo e($worst['persen']); ?>%). <a href="<?php echo e(route('admin.laporan-kegiatan.analisis-kegiatan', $worst['kegiatan_id'])); ?>">Analisis →</a></div>
|
||
<?php endif; ?>
|
||
<?php endif; ?>
|
||
|
||
<?php if($kpiComparison['avg_kehadiran'] > 5): ?>
|
||
<div class="insight-box i-success"><i class="fas fa-arrow-up"></i> Kehadiran meningkat <?php echo e($kpiComparison['avg_kehadiran']); ?>% dibanding periode lalu.</div>
|
||
<?php elseif($kpiComparison['avg_kehadiran'] < -5): ?>
|
||
<div class="insight-box i-danger"><i class="fas fa-arrow-down"></i> Kehadiran menurun <?php echo e(abs($kpiComparison['avg_kehadiran'])); ?>% dibanding periode lalu.</div>
|
||
<?php endif; ?>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
<div class="two-col">
|
||
<div class="chart-box">
|
||
<h4><i class="fas fa-trophy" style="color:#10B981;"></i> Top 5 Kegiatan Terbaik</h4>
|
||
<?php $__empty_1 = true; $__currentLoopData = $topKegiatan; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $i => $kg): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); $__empty_1 = false; ?>
|
||
<div class="rank-card top" style="margin-bottom: 8px;">
|
||
<div class="rank-num"><?php echo e($i + 1); ?></div>
|
||
<div class="rank-info">
|
||
<div class="name"><?php echo e($kg['nama_kegiatan']); ?></div>
|
||
<div class="meta"><?php echo e($kg['nama_kategori'] ?? '-'); ?></div>
|
||
</div>
|
||
<div class="progress-inline">
|
||
<div class="progress-bar-mini"><div class="fill" style="width:<?php echo e($kg['persen']); ?>%; background:#10B981;"></div></div>
|
||
<span class="rank-persen" style="color:#10B981;"><?php echo e($kg['persen']); ?>%</span>
|
||
</div>
|
||
</div>
|
||
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); if ($__empty_1): ?>
|
||
<p style="color:var(--text-light); font-size:0.85rem;">Belum ada data</p>
|
||
<?php endif; ?>
|
||
</div>
|
||
<div class="chart-box">
|
||
<h4><i class="fas fa-exclamation-triangle" style="color:#EF4444;"></i> 5 Kegiatan Perlu Evaluasi</h4>
|
||
<?php $__empty_1 = true; $__currentLoopData = $bottomKegiatan; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $i => $kg): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); $__empty_1 = false; ?>
|
||
<div class="rank-card bottom" style="margin-bottom: 8px;">
|
||
<div class="rank-num"><?php echo e($i + 1); ?></div>
|
||
<div class="rank-info">
|
||
<div class="name"><?php echo e($kg['nama_kegiatan']); ?></div>
|
||
<div class="meta"><?php echo e($kg['nama_kategori'] ?? '-'); ?></div>
|
||
</div>
|
||
<div class="progress-inline">
|
||
<div class="progress-bar-mini"><div class="fill" style="width:<?php echo e($kg['persen']); ?>%; background:#EF4444;"></div></div>
|
||
<span class="rank-persen" style="color:#EF4444;"><?php echo e($kg['persen']); ?>%</span>
|
||
</div>
|
||
</div>
|
||
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); if ($__empty_1): ?>
|
||
<p style="color:var(--text-light); font-size:0.85rem;">Belum ada data</p>
|
||
<?php endif; ?>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
<div class="tab-pane" id="tab-kelas">
|
||
|
||
<div class="chart-box">
|
||
<h4><i class="fas fa-chart-bar"></i> Kehadiran Per Kelompok Kelas</h4>
|
||
<div class="chart-container" style="height:300px;">
|
||
<canvas id="kelasBarChart"></canvas>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
<div class="chart-box">
|
||
<h4><i class="fas fa-th"></i> Heatmap: Kelas vs Kategori Kegiatan</h4>
|
||
<div style="overflow-x:auto;">
|
||
<table class="heatmap-table">
|
||
<thead>
|
||
<tr>
|
||
<th style="text-align:left; min-width:140px;">Kelas</th>
|
||
<?php $__currentLoopData = $heatmapData['columns']; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $col): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
|
||
<th><?php echo e($col); ?></th>
|
||
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
|
||
<th>Rata-rata</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<?php $__currentLoopData = $heatmapData['rows']; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $row): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
|
||
<tr>
|
||
<td class="row-label">
|
||
<span style="font-size:0.72rem; color:var(--text-light);"><?php echo e($row['kelompok']); ?></span><br>
|
||
<?php echo e($row['kelas']); ?>
|
||
|
||
</td>
|
||
<?php $rowVals = []; ?>
|
||
<?php $__currentLoopData = $heatmapData['columns']; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $col): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
|
||
<?php
|
||
$val = $row['data'][$col] ?? null;
|
||
if ($val !== null) $rowVals[] = $val;
|
||
$cls = $val === null ? 'heatmap-na' : ($val >= 90 ? 'heatmap-90' : ($val >= 80 ? 'heatmap-80' : ($val >= 70 ? 'heatmap-70' : 'heatmap-low')));
|
||
?>
|
||
<td><div class="heatmap-cell <?php echo e($cls); ?>" title="<?php echo e($row['kelas']); ?> — <?php echo e($col); ?>: <?php echo e($val !== null ? $val.'%' : 'N/A'); ?>"><?php echo e($val !== null ? $val.'%' : '-'); ?></div></td>
|
||
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
|
||
<?php $avg = count($rowVals) > 0 ? round(array_sum($rowVals)/count($rowVals),1) : null; ?>
|
||
<td><div class="heatmap-cell <?php echo e($avg === null ? 'heatmap-na' : ($avg >= 90 ? 'heatmap-90' : ($avg >= 80 ? 'heatmap-80' : ($avg >= 70 ? 'heatmap-70' : 'heatmap-low')))); ?>"><strong><?php echo e($avg !== null ? $avg.'%' : '-'); ?></strong></div></td>
|
||
</tr>
|
||
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
<div style="margin-top:12px; display:flex; gap:16px; font-size:0.78rem; flex-wrap:wrap;">
|
||
<span><span style="display:inline-block;width:14px;height:14px;border-radius:3px;background:#10B981;vertical-align:middle;"></span> ≥90%</span>
|
||
<span><span style="display:inline-block;width:14px;height:14px;border-radius:3px;background:#34D399;vertical-align:middle;"></span> 80-89%</span>
|
||
<span><span style="display:inline-block;width:14px;height:14px;border-radius:3px;background:#FBBF24;vertical-align:middle;"></span> 70-79%</span>
|
||
<span><span style="display:inline-block;width:14px;height:14px;border-radius:3px;background:#EF4444;vertical-align:middle;"></span> <70%</span>
|
||
<span><span style="display:inline-block;width:14px;height:14px;border-radius:3px;background:#F3F4F6;vertical-align:middle;"></span> N/A</span>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
<div class="chart-box">
|
||
<h4><i class="fas fa-layer-group"></i> Detail Per Kelas</h4>
|
||
<?php $__currentLoopData = $kehadiranPerKelas; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $kelompok): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
|
||
<div class="accordion-item">
|
||
<div class="accordion-header" onclick="toggleAccordion(this)">
|
||
<span><i class="fas fa-folder-open" style="color:var(--primary-color);margin-right:8px;"></i> <?php echo e($kelompok['nama_kelompok']); ?> (<?php echo e(count($kelompok['kelas'])); ?> kelas)</span>
|
||
<i class="fas fa-chevron-down arrow"></i>
|
||
</div>
|
||
<div class="accordion-body">
|
||
<table class="data-table" style="font-size:0.85rem;">
|
||
<thead>
|
||
<tr>
|
||
<th>Kelas</th><th class="text-center">Santri</th><th class="text-center">Hadir</th><th class="text-center">Izin</th><th class="text-center">Sakit</th><th class="text-center">Alpa</th><th class="text-center">% Kehadiran</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<?php $__currentLoopData = $kelompok['kelas']; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $k): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
|
||
<tr>
|
||
<td><strong><?php echo e($k['nama_kelas']); ?></strong></td>
|
||
<td class="text-center"><?php echo e($k['jumlah_santri']); ?></td>
|
||
<td class="text-center"><span class="badge badge-success"><?php echo e($k['hadir']); ?></span></td>
|
||
<td class="text-center"><span class="badge badge-warning"><?php echo e($k['izin']); ?></span></td>
|
||
<td class="text-center"><span class="badge badge-info"><?php echo e($k['sakit']); ?></span></td>
|
||
<td class="text-center"><span class="badge badge-danger"><?php echo e($k['alpa']); ?></span></td>
|
||
<td class="text-center">
|
||
<div class="progress-inline" style="justify-content:center;">
|
||
<div class="progress-bar-mini"><div class="fill" style="width:<?php echo e($k['persen']); ?>%; background:<?php echo e($k['persen'] >= 85 ? '#10B981' : ($k['persen'] >= 70 ? '#FBBF24' : '#EF4444')); ?>;"></div></div>
|
||
<strong><?php echo e($k['persen']); ?>%</strong>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
<div class="tab-pane" id="tab-santri">
|
||
<div class="two-col">
|
||
|
||
<div class="chart-box">
|
||
<h4><i class="fas fa-user-clock" style="color:#EF4444;"></i> Santri Perlu Perhatian (<70%)</h4>
|
||
<?php if($santriPerluPerhatianList && $santriPerluPerhatianList->count() > 0): ?>
|
||
<table class="data-table" style="font-size:0.85rem;">
|
||
<thead><tr><th>No</th><th>Nama</th><th class="text-center">Alpa</th><th class="text-center">Kehadiran</th><th>Aksi</th></tr></thead>
|
||
<tbody>
|
||
<?php $__currentLoopData = $santriPerluPerhatianList; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $i => $s): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
|
||
<tr>
|
||
<td><?php echo e($i + 1); ?></td>
|
||
<td><strong><?php echo e($s->nama_lengkap); ?></strong></td>
|
||
<td class="text-center"><span class="badge badge-danger"><?php echo e($s->alpa); ?>x</span></td>
|
||
<td class="text-center">
|
||
<div class="progress-inline" style="justify-content:center;">
|
||
<div class="progress-bar-mini"><div class="fill" style="width:<?php echo e($s->persen); ?>%; background:#EF4444;"></div></div>
|
||
<strong style="color:#EF4444;"><?php echo e($s->persen); ?>%</strong>
|
||
</div>
|
||
</td>
|
||
<td><a href="<?php echo e(route('admin.laporan-kegiatan.detail-santri', $s->id_santri)); ?>" class="btn btn-sm btn-info" title="Detail"><i class="fas fa-eye"></i></a></td>
|
||
</tr>
|
||
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
|
||
</tbody>
|
||
</table>
|
||
<a href="<?php echo e(route('admin.laporan-kegiatan.santri-perlu-perhatian', request()->query())); ?>" class="btn btn-sm btn-secondary" style="margin-top:12px;">
|
||
<i class="fas fa-list"></i> Lihat Semua
|
||
</a>
|
||
<?php else: ?>
|
||
<div class="insight-box i-success"><i class="fas fa-check-circle"></i> Tidak ada santri dengan kehadiran di bawah 70%. Alhamdulillah!</div>
|
||
<?php endif; ?>
|
||
</div>
|
||
|
||
|
||
<div class="chart-box">
|
||
<h4><i class="fas fa-medal" style="color:#F59E0B;"></i> Leaderboard Kehadiran Terbaik</h4>
|
||
<?php if($leaderboard && $leaderboard->count() > 0): ?>
|
||
<table class="data-table leaderboard-table" style="font-size:0.85rem;">
|
||
<thead><tr><th style="width:40px;">#</th><th>Nama</th><th class="text-center">Kehadiran</th><th class="text-center">Streak</th></tr></thead>
|
||
<tbody>
|
||
<?php $__currentLoopData = $leaderboard; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $i => $s): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
|
||
<tr>
|
||
<td class="text-center">
|
||
<?php if($i === 0): ?> <span class="medal">🥇</span>
|
||
<?php elseif($i === 1): ?> <span class="medal">🥈</span>
|
||
<?php elseif($i === 2): ?> <span class="medal">🥉</span>
|
||
<?php else: ?> <?php echo e($i + 1); ?>
|
||
|
||
<?php endif; ?>
|
||
</td>
|
||
<td>
|
||
<a href="<?php echo e(route('admin.laporan-kegiatan.detail-santri', $s->id_santri)); ?>" style="color:inherit;text-decoration:none;">
|
||
<strong><?php echo e($s->nama_lengkap); ?></strong>
|
||
</a>
|
||
</td>
|
||
<td class="text-center">
|
||
<strong style="color:#10B981;"><?php echo e($s->persen); ?>%</strong>
|
||
</td>
|
||
<td class="text-center">
|
||
<?php if($s->streak > 0): ?>
|
||
<span class="streak-badge">🔥 <?php echo e($s->streak); ?></span>
|
||
<?php else: ?>
|
||
-
|
||
<?php endif; ?>
|
||
</td>
|
||
</tr>
|
||
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
|
||
</tbody>
|
||
</table>
|
||
<?php else: ?>
|
||
<p style="color:var(--text-light); font-size:0.85rem;">Belum ada data kehadiran.</p>
|
||
<?php endif; ?>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
<div class="chart-box">
|
||
<h4><i class="fas fa-chart-pie"></i> Distribusi Kehadiran Santri</h4>
|
||
<div class="chart-container" style="height:280px;">
|
||
<canvas id="distribusiChart2"></canvas>
|
||
</div>
|
||
<div style="margin-top:12px;">
|
||
<?php $__currentLoopData = $distribusiSantri; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $d): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
|
||
<div style="display:flex; align-items:center; gap:10px; margin-bottom:6px; font-size:0.85rem;">
|
||
<div style="flex:1;"><strong><?php echo e($d['label']); ?></strong></div>
|
||
<div style="width:60px; text-align:right;"><?php echo e($d['count']); ?> santri</div>
|
||
<div style="width:60px; text-align:right; color:var(--text-light);">(<?php echo e($d['percentage']); ?>%)</div>
|
||
</div>
|
||
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
<div class="tab-pane" id="tab-kegiatan">
|
||
<div class="chart-box">
|
||
<h4><i class="fas fa-tasks"></i> Performa Semua Kegiatan</h4>
|
||
<div style="overflow-x:auto;">
|
||
<table class="data-table" style="font-size:0.85rem;">
|
||
<thead>
|
||
<tr>
|
||
<th>No</th>
|
||
<th>Kegiatan</th>
|
||
<th>Kategori</th>
|
||
<th>Hari</th>
|
||
<th class="text-center">Total Absensi</th>
|
||
<th class="text-center">Hadir</th>
|
||
<th class="text-center" style="min-width:180px;">% Kehadiran</th>
|
||
<th>Aksi</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<?php $__empty_1 = true; $__currentLoopData = $kegiatanPerformance; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $i => $kg): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); $__empty_1 = false; ?>
|
||
<tr>
|
||
<td><?php echo e($i + 1); ?></td>
|
||
<td><strong><?php echo e($kg->nama_kegiatan); ?></strong></td>
|
||
<td><span class="badge badge-info"><?php echo e($kg->nama_kategori ?? '-'); ?></span></td>
|
||
<td><?php echo e($kg->hari ?? '-'); ?></td>
|
||
<td class="text-center"><?php echo e($kg->total); ?></td>
|
||
<td class="text-center"><span class="badge badge-success"><?php echo e($kg->hadir); ?></span></td>
|
||
<td class="text-center">
|
||
<div class="progress-inline" style="justify-content:center;">
|
||
<div class="progress-bar-mini"><div class="fill" style="width:<?php echo e($kg->persen); ?>%; background:<?php echo e($kg->persen >= 85 ? '#10B981' : ($kg->persen >= 70 ? '#FBBF24' : '#EF4444')); ?>;"></div></div>
|
||
<strong style="color:<?php echo e($kg->persen >= 85 ? '#10B981' : ($kg->persen >= 70 ? '#92400E' : '#EF4444')); ?>;"><?php echo e($kg->persen); ?>%</strong>
|
||
</div>
|
||
</td>
|
||
<td>
|
||
<a href="<?php echo e(route('admin.laporan-kegiatan.analisis-kegiatan', $kg->kegiatan_id)); ?>" class="btn btn-sm btn-primary" title="Analisis Detail">
|
||
<i class="fas fa-search-plus"></i>
|
||
</a>
|
||
</td>
|
||
</tr>
|
||
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); if ($__empty_1): ?>
|
||
<tr><td colspan="8" class="text-center" style="color:var(--text-light);">Belum ada data kegiatan</td></tr>
|
||
<?php endif; ?>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
<div class="tab-pane" id="tab-pattern">
|
||
<div class="chart-box">
|
||
<h4><i class="fas fa-brain"></i> Pola & Anomali Terdeteksi</h4>
|
||
<p style="font-size:0.82rem; color:var(--text-light); margin-bottom:16px;">Sistem secara otomatis mendeteksi pola kehadiran dan anomali berdasarkan data 3 minggu terakhir.</p>
|
||
|
||
<?php if(!empty($patterns) && count($patterns) > 0): ?>
|
||
<?php $__currentLoopData = $patterns; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $p): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
|
||
<div class="pattern-card p-<?php echo e($p['type']); ?>">
|
||
<div class="pattern-category"><?php echo e($p['category']); ?></div>
|
||
<div class="pattern-title"><?php echo e($p['title']); ?></div>
|
||
<div class="pattern-desc"><?php echo e($p['description']); ?></div>
|
||
<?php if(!empty($p['action_url'])): ?>
|
||
<a href="<?php echo e($p['action_url']); ?>" class="btn btn-sm btn-<?php echo e($p['type'] === 'danger' ? 'danger' : ($p['type'] === 'warning' ? 'warning' : 'info')); ?>" style="margin-top:8px;">
|
||
<i class="fas fa-arrow-right"></i> <?php echo e($p['action_text']); ?>
|
||
|
||
</a>
|
||
<?php endif; ?>
|
||
</div>
|
||
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
|
||
<?php else: ?>
|
||
<div class="insight-box i-success">
|
||
<i class="fas fa-check-circle"></i>
|
||
Tidak ada anomali terdeteksi. Pola kehadiran dalam kondisi normal.
|
||
</div>
|
||
<?php endif; ?>
|
||
</div>
|
||
|
||
|
||
<div class="chart-box">
|
||
<h4><i class="fas fa-chart-line"></i> Prediksi Trend Minggu Depan</h4>
|
||
<div class="chart-container" style="height:250px;">
|
||
<canvas id="prediksiChart"></canvas>
|
||
</div>
|
||
<div class="insight-box i-info" style="margin-top:12px;">
|
||
<i class="fas fa-robot"></i>
|
||
Prediksi ini berdasarkan tren 4 minggu terakhir menggunakan regresi linear sederhana. Akurasi bervariasi.
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
<div class="tab-pane" id="tab-export">
|
||
<div class="export-grid">
|
||
|
||
<div class="export-card">
|
||
<h4><i class="fas fa-file-download"></i> Download Laporan</h4>
|
||
<form id="exportForm">
|
||
<input type="hidden" name="periode" value="<?php echo e($periode); ?>">
|
||
<input type="hidden" name="tanggal_dari" value="<?php echo e($startDate->format('Y-m-d')); ?>">
|
||
<input type="hidden" name="tanggal_sampai" value="<?php echo e($endDate->format('Y-m-d')); ?>">
|
||
|
||
<label style="font-size:0.85rem; font-weight:600; margin-bottom:8px; display:block;">Pilih Konten:</label>
|
||
<div class="checkbox-group">
|
||
<label><input type="checkbox" name="content[]" value="summary" checked> Executive Summary (KPI)</label>
|
||
<label><input type="checkbox" name="content[]" value="per_kelas"> Analisis Per Kelas</label>
|
||
<label><input type="checkbox" name="content[]" value="per_santri"> Detail Per Santri <small style="color:var(--text-light);">(file besar)</small></label>
|
||
<label><input type="checkbox" name="content[]" value="top_bottom"> Top & Bottom Kegiatan</label>
|
||
<label><input type="checkbox" name="content[]" value="patterns"> Pola & Anomali</label>
|
||
</div>
|
||
|
||
<div style="display:flex; gap:8px; margin-top:16px;">
|
||
<button type="button" onclick="exportExcel()" class="btn btn-success"><i class="fas fa-file-excel"></i> Download Excel (CSV)</button>
|
||
<a href="<?php echo e(route('admin.laporan-kegiatan.export-pdf', request()->query())); ?>" class="btn btn-danger" target="_blank"><i class="fas fa-file-pdf"></i> Download PDF</a>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
|
||
|
||
<div class="export-card">
|
||
<h4><i class="fas fa-file-alt"></i> Template Laporan Cepat</h4>
|
||
<div style="display:flex; flex-direction:column; gap:10px;">
|
||
<a href="<?php echo e(route('admin.laporan-kegiatan.export-pdf', ['periode'=>'minggu_ini'])); ?>" class="btn btn-secondary" target="_blank" style="text-align:left;">
|
||
<i class="fas fa-calendar-week"></i> Laporan Mingguan untuk Pimpinan
|
||
</a>
|
||
<a href="<?php echo e(route('admin.laporan-kegiatan.export-pdf', ['periode'=>'bulan_ini'])); ?>" class="btn btn-secondary" target="_blank" style="text-align:left;">
|
||
<i class="fas fa-calendar-alt"></i> Laporan Bulanan untuk Yayasan
|
||
</a>
|
||
<a href="<?php echo e(route('admin.laporan-kegiatan.export-excel', ['periode'=>'bulan_ini','content'=>['summary','per_kelas','per_santri']])); ?>" class="btn btn-secondary" target="_blank" style="text-align:left;">
|
||
<i class="fas fa-table"></i> Data Lengkap (CSV) - Bulan Ini
|
||
</a>
|
||
</div>
|
||
|
||
<h4 style="margin-top:24px;"><i class="fas fa-print"></i> Cetak Langsung</h4>
|
||
<button onclick="window.print()" class="btn btn-primary">
|
||
<i class="fas fa-print"></i> Cetak Halaman Ini
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.1/dist/chart.umd.min.js"></script>
|
||
|
||
<script>
|
||
// ── Tab Management ──
|
||
document.querySelectorAll('.laporan-tab').forEach(tab => {
|
||
tab.addEventListener('click', () => switchTab(tab.dataset.tab));
|
||
});
|
||
|
||
function switchTab(tabId) {
|
||
document.querySelectorAll('.laporan-tab').forEach(t => t.classList.remove('active'));
|
||
document.querySelectorAll('.tab-pane').forEach(p => p.classList.remove('active'));
|
||
document.querySelector(`[data-tab="${tabId}"]`).classList.add('active');
|
||
document.getElementById('tab-' + tabId).classList.add('active');
|
||
|
||
// Lazy-load charts
|
||
if (tabId === 'kelas' && !window._kelasChartInited) initKelasChart();
|
||
if (tabId === 'santri' && !window._distribusi2Inited) initDistribusi2();
|
||
if (tabId === 'pattern' && !window._prediksiInited) initPrediksiChart();
|
||
}
|
||
|
||
// ── Period Selector ──
|
||
function setPeriode(p) {
|
||
document.getElementById('periodeInput').value = p;
|
||
document.querySelectorAll('.period-btn').forEach(b => b.classList.remove('active'));
|
||
event.target.classList.add('active');
|
||
document.getElementById('customRange').classList.toggle('show', p === 'custom');
|
||
if (p !== 'custom') document.getElementById('periodForm').submit();
|
||
}
|
||
|
||
// ── Accordion ──
|
||
function toggleAccordion(el) {
|
||
el.classList.toggle('open');
|
||
el.nextElementSibling.classList.toggle('open');
|
||
}
|
||
|
||
// ═══ Chart Colors ═══
|
||
const chartColors = ['#10B981','#3B82F6','#F59E0B','#EF4444','#8B5CF6','#EC4899','#06B6D4','#84CC16'];
|
||
|
||
// ═══ TREND CHART (Tab 1) ═══
|
||
const trendData = <?php echo json_encode($trendData, 15, 512) ?>;
|
||
new Chart(document.getElementById('trendChart'), {
|
||
type: 'line',
|
||
data: {
|
||
labels: trendData.labels,
|
||
datasets: trendData.datasets.map((ds, i) => ({
|
||
label: ds.kategori,
|
||
data: ds.data,
|
||
borderColor: chartColors[i % chartColors.length],
|
||
backgroundColor: chartColors[i % chartColors.length] + '20',
|
||
tension: 0.4,
|
||
fill: false,
|
||
pointRadius: 4,
|
||
pointHoverRadius: 6,
|
||
spanGaps: true,
|
||
}))
|
||
},
|
||
options: {
|
||
responsive: true, maintainAspectRatio: false,
|
||
plugins: {
|
||
legend: { position: 'top', labels: { usePointStyle: true, padding: 16 } },
|
||
tooltip: { callbacks: { label: ctx => ctx.dataset.label + ': ' + (ctx.parsed.y ?? '-') + '%' } }
|
||
},
|
||
scales: {
|
||
y: { min: 0, max: 100, ticks: { callback: v => v + '%' }, grid: { color: '#f1f5f9' } },
|
||
x: { grid: { display: false } }
|
||
}
|
||
}
|
||
});
|
||
|
||
// ═══ DISTRIBUSI CHART (Tab 1) ═══
|
||
const distribusi = <?php echo json_encode($distribusiSantri, 15, 512) ?>;
|
||
const distribusiColors = ['#10B981','#34D399','#60A5FA','#FBBF24','#EF4444'];
|
||
new Chart(document.getElementById('distribusiChart'), {
|
||
type: 'bar',
|
||
data: {
|
||
labels: distribusi.map(d => d.label),
|
||
datasets: [{
|
||
data: distribusi.map(d => d.count),
|
||
backgroundColor: distribusiColors,
|
||
borderRadius: 6,
|
||
barThickness: 28,
|
||
}]
|
||
},
|
||
options: {
|
||
indexAxis: 'y', responsive: true, maintainAspectRatio: false,
|
||
plugins: {
|
||
legend: { display: false },
|
||
tooltip: { callbacks: { label: ctx => ctx.raw + ' santri (' + distribusi[ctx.dataIndex].percentage + '%)' } }
|
||
},
|
||
scales: {
|
||
x: { grid: { color: '#f1f5f9' }, ticks: { stepSize: 1 } },
|
||
y: { grid: { display: false } }
|
||
}
|
||
}
|
||
});
|
||
|
||
// ═══ KELAS BAR CHART (Tab 2 - lazy) ═══
|
||
function initKelasChart() {
|
||
window._kelasChartInited = true;
|
||
const kelasData = <?php echo json_encode($kehadiranPerKelas, 15, 512) ?>;
|
||
const labels = [];
|
||
const data = [];
|
||
const bgColors = [];
|
||
kelasData.forEach((kelompok, ki) => {
|
||
kelompok.kelas.forEach(k => {
|
||
labels.push(k.nama_kelas);
|
||
data.push(k.persen);
|
||
bgColors.push(chartColors[ki % chartColors.length]);
|
||
});
|
||
});
|
||
new Chart(document.getElementById('kelasBarChart'), {
|
||
type: 'bar',
|
||
data: { labels, datasets: [{ label: '% Kehadiran', data, backgroundColor: bgColors, borderRadius: 6 }] },
|
||
options: {
|
||
responsive: true, maintainAspectRatio: false,
|
||
plugins: { legend: { display: false }, tooltip: { callbacks: { label: ctx => ctx.raw + '%' } } },
|
||
scales: { y: { min: 0, max: 100, ticks: { callback: v => v + '%' } }, x: { grid: { display: false } } }
|
||
}
|
||
});
|
||
}
|
||
|
||
// ═══ DISTRIBUSI 2 (Tab 3 - lazy) ═══
|
||
function initDistribusi2() {
|
||
window._distribusi2Inited = true;
|
||
new Chart(document.getElementById('distribusiChart2'), {
|
||
type: 'doughnut',
|
||
data: {
|
||
labels: distribusi.map(d => d.label),
|
||
datasets: [{ data: distribusi.map(d => d.count), backgroundColor: distribusiColors, borderWidth: 2, hoverOffset: 8 }]
|
||
},
|
||
options: {
|
||
responsive: true, maintainAspectRatio: false,
|
||
plugins: { legend: { position: 'bottom', labels: { usePointStyle: true, padding: 12 } } }
|
||
}
|
||
});
|
||
}
|
||
|
||
// ═══ PREDIKSI CHART (Tab 5 - lazy) ═══
|
||
function initPrediksiChart() {
|
||
window._prediksiInited = true;
|
||
const t = trendData.datasets[0] ? trendData.datasets[0].data.filter(v => v !== null) : [];
|
||
const prediksi = t.length >= 2 ? Math.max(0, Math.min(100, Math.round(t[t.length-1] + (t[t.length-1] - t[t.length-2]) * 0.5))) : null;
|
||
const allLabels = [...trendData.labels];
|
||
const histData = t.length > 0 ? [...t] : [];
|
||
const predData = new Array(histData.length).fill(null);
|
||
if (prediksi !== null) {
|
||
allLabels.push('Prediksi');
|
||
histData.push(null);
|
||
predData.push(prediksi);
|
||
predData[predData.length-2] = t[t.length-1]; // connect line
|
||
}
|
||
new Chart(document.getElementById('prediksiChart'), {
|
||
type: 'line',
|
||
data: {
|
||
labels: allLabels,
|
||
datasets: [
|
||
{ label: 'Aktual', data: histData, borderColor: '#3B82F6', tension: 0.4, pointRadius: 4, spanGaps: false },
|
||
{ label: 'Prediksi', data: predData, borderColor: '#F59E0B', borderDash: [6,4], tension: 0.4, pointRadius: 6, spanGaps: false, pointStyle: 'star' }
|
||
]
|
||
},
|
||
options: {
|
||
responsive: true, maintainAspectRatio: false,
|
||
plugins: { legend: { position: 'top' } },
|
||
scales: { y: { min: 0, max: 100, ticks: { callback: v => v + '%' } } }
|
||
}
|
||
});
|
||
}
|
||
|
||
// ═══ Export Functions ═══
|
||
function exportExcel() {
|
||
const form = document.getElementById('exportForm');
|
||
const formData = new FormData(form);
|
||
const params = new URLSearchParams();
|
||
formData.forEach((v, k) => params.append(k, v));
|
||
window.open('<?php echo e(route("admin.laporan-kegiatan.export-excel")); ?>?' + params.toString(), '_blank');
|
||
}
|
||
|
||
// ═══ Auto Refresh KPI (every 5 min) ═══
|
||
setInterval(() => {
|
||
fetch('<?php echo e(route("admin.laporan-kegiatan.refresh-kpi")); ?>?periode=<?php echo e($periode); ?>&tanggal_dari=<?php echo e($startDate->format("Y-m-d")); ?>&tanggal_sampai=<?php echo e($endDate->format("Y-m-d")); ?>')
|
||
.then(r => r.json())
|
||
.then(data => {
|
||
// Silently update – could update DOM elements if needed
|
||
console.log('KPI refreshed', data);
|
||
})
|
||
.catch(() => {});
|
||
}, 300000);
|
||
|
||
// ═══ Print Styles ═══
|
||
window.addEventListener('beforeprint', () => {
|
||
document.querySelectorAll('.tab-pane').forEach(p => p.style.display = 'block');
|
||
});
|
||
window.addEventListener('afterprint', () => {
|
||
document.querySelectorAll('.tab-pane').forEach(p => {
|
||
p.style.display = p.classList.contains('active') ? 'block' : 'none';
|
||
});
|
||
});
|
||
</script>
|
||
|
||
|
||
<style>
|
||
@media print {
|
||
.page-header .btn, .period-bar, .laporan-tabs, .btn, button, .export-card, .accordion-header .arrow,
|
||
#tab-export { display: none !important; }
|
||
.tab-pane { display: block !important; page-break-inside: avoid; }
|
||
.content-box { box-shadow: none !important; border: 1px solid #e2e8f0; }
|
||
.chart-box { box-shadow: none !important; border: 1px solid #e2e8f0; page-break-inside: avoid; }
|
||
.kpi-card { box-shadow: none !important; border: 1px solid #e2e8f0; }
|
||
}
|
||
</style>
|
||
<?php $__env->stopSection(); ?>
|
||
|
||
<?php echo $__env->make('layouts.app', \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->render(); ?><?php /**PATH C:\xampp\htdocs\TugasAkhir\sim-pkpps\resources\views/admin/kegiatan/laporan/index.blade.php ENDPATH**/ ?>
|