849 lines
26 KiB
PHP
849 lines
26 KiB
PHP
<?php $role = $this->session->userdata('role'); ?>
|
|
|
|
<style>
|
|
/* ======================================================
|
|
DASHBOARD CLEAN - Orange Theme (Minimal & Elegant)
|
|
====================================================== */
|
|
:root {
|
|
/* Orange Theme Colors */
|
|
--orange-primary: #ff8c00;
|
|
--orange-light: #ffd4a3;
|
|
--orange-dark: #e67700;
|
|
--orange-gradient: linear-gradient(135deg, #ff8c00 0%, #ff7b00 50%, #e67700 100%);
|
|
|
|
/* Neutral Colors */
|
|
--white: #ffffff;
|
|
--light-bg: #f8fafc;
|
|
--border-light: #e2e8f0;
|
|
--text-dark: #1e293b;
|
|
--text-muted: #64748b;
|
|
|
|
/* Shadows - Subtle */
|
|
--shadow-sm: 0 2px 8px rgba(0,0,0,0.06);
|
|
--shadow-md: 0 8px 24px rgba(0,0,0,0.08);
|
|
--shadow-lg: 0 16px 40px rgba(0,0,0,0.10);
|
|
}
|
|
|
|
/* Modern Card - Clean & Minimal */
|
|
.modern-card {
|
|
background: var(--white);
|
|
border: 1px solid var(--border-light);
|
|
border-radius: 16px;
|
|
box-shadow: var(--shadow-sm);
|
|
transition: all 0.3s ease;
|
|
position: relative;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.modern-card::before {
|
|
content: '';
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
height: 3px;
|
|
background: var(--orange-gradient);
|
|
transform: scaleX(0);
|
|
transition: transform 0.3s ease;
|
|
}
|
|
|
|
.modern-card:hover {
|
|
box-shadow: var(--shadow-lg);
|
|
transform: translateY(-2px);
|
|
}
|
|
|
|
.modern-card:hover::before {
|
|
transform: scaleX(1);
|
|
}
|
|
|
|
/* ======================================================
|
|
SUMMARY CARDS - Orange Accents
|
|
====================================================== */
|
|
.summary-card {
|
|
background: var(--white);
|
|
border: 1px solid var(--border-light);
|
|
border-radius: 16px;
|
|
padding: 24px;
|
|
transition: all 0.3s ease;
|
|
cursor: pointer;
|
|
position: relative;
|
|
}
|
|
|
|
.summary-card:hover {
|
|
box-shadow: var(--shadow-md);
|
|
transform: translateY(-4px);
|
|
}
|
|
|
|
.summary-icon {
|
|
width: 60px;
|
|
height: 60px;
|
|
border-radius: 12px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-size: 22px;
|
|
color: var(--white);
|
|
flex-shrink: 0;
|
|
box-shadow: 0 6px 20px rgba(255,140,0,0.3);
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
/* Orange-based icon colors - subtle variations */
|
|
.summary-card:nth-child(1) .summary-icon { background: var(--orange-gradient); }
|
|
.summary-card:nth-child(2) .summary-icon {
|
|
background: linear-gradient(135deg, var(--orange-light) 0%, var(--orange-primary) 100%);
|
|
}
|
|
.summary-card:nth-child(3) .summary-icon {
|
|
background: linear-gradient(135deg, #ff9500 0%, var(--orange-primary) 100%);
|
|
}
|
|
.summary-card:nth-child(4) .summary-icon {
|
|
background: linear-gradient(135deg, var(--orange-dark) 0%, #d66a00 100%);
|
|
}
|
|
.summary-card:nth-child(5) .summary-icon {
|
|
background: linear-gradient(135deg, #ffb366 0%, var(--orange-primary) 100%);
|
|
}
|
|
.summary-card:nth-child(6) .summary-icon {
|
|
background: linear-gradient(135deg, #ffcc80 0%, #ffad42 100%);
|
|
}
|
|
.summary-card:nth-child(7) .summary-icon {
|
|
background: linear-gradient(135deg, #ffd180 0%, #ffab40 100%);
|
|
}
|
|
|
|
/* Quick Action Cards */
|
|
.quick-action .summary-card {
|
|
text-decoration: none;
|
|
color: inherit;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.quick-action .summary-card:hover .summary-icon {
|
|
transform: scale(1.1);
|
|
box-shadow: 0 10px 30px rgba(255,140,0,0.4);
|
|
}
|
|
|
|
/* ======================================================
|
|
AI INSIGHT - Clean Cards
|
|
====================================================== */
|
|
.ai-box {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 12px;
|
|
max-height: 340px;
|
|
overflow-y: auto;
|
|
}
|
|
|
|
.ai-box::-webkit-scrollbar {
|
|
width: 4px;
|
|
}
|
|
|
|
.ai-box::-webkit-scrollbar-track {
|
|
background: #f1f5f9;
|
|
border-radius: 10px;
|
|
}
|
|
|
|
.ai-box::-webkit-scrollbar-thumb {
|
|
background: var(--orange-light);
|
|
border-radius: 10px;
|
|
}
|
|
|
|
.ai-item {
|
|
padding: 16px 20px;
|
|
border-radius: 12px;
|
|
font-size: 14px;
|
|
line-height: 1.6;
|
|
border-left: 4px solid var(--orange-primary);
|
|
background: #fef7ee;
|
|
box-shadow: var(--shadow-sm);
|
|
transition: all 0.2s ease;
|
|
border: 1px solid #fee2c7;
|
|
}
|
|
|
|
.ai-item:hover {
|
|
box-shadow: var(--shadow-md);
|
|
transform: translateX(4px);
|
|
}
|
|
|
|
.ai-item i {
|
|
font-size: 16px;
|
|
margin-top: 1px;
|
|
flex-shrink: 0;
|
|
opacity: 0.9;
|
|
color: var(--orange-primary);
|
|
margin-right: 12px;
|
|
}
|
|
|
|
.ai-success {
|
|
border-left-color: #10b981;
|
|
background: #f0fdf4;
|
|
border-color: #bbf7d0;
|
|
}
|
|
|
|
.ai-success i {
|
|
color: #10b981;
|
|
}
|
|
|
|
.ai-warning {
|
|
border-left-color: #f59e0b;
|
|
background: #fef3c7;
|
|
border-color: #fed7aa;
|
|
}
|
|
|
|
.ai-warning i {
|
|
color: #f59e0b;
|
|
}
|
|
|
|
.ai-info {
|
|
border-left-color: #3b82f6;
|
|
background: #eff6ff;
|
|
border-color: #bfdbfe;
|
|
}
|
|
|
|
.ai-info i {
|
|
color: #3b82f6;
|
|
}
|
|
|
|
/* ======================================================
|
|
TABLE CLEAN & MODERN
|
|
====================================================== */
|
|
.modern-table-dashboard {
|
|
border-radius: 12px;
|
|
overflow: hidden;
|
|
box-shadow: var(--shadow-sm);
|
|
border: none;
|
|
background: var(--white);
|
|
}
|
|
|
|
.modern-table-dashboard thead th {
|
|
background: linear-gradient(135deg, #fef7ee 0%, #fff8f0 100%);
|
|
border: none;
|
|
padding: 18px 16px;
|
|
font-weight: 600;
|
|
color: var(--text-dark);
|
|
font-size: 0.95rem;
|
|
}
|
|
|
|
.modern-table-dashboard tbody tr {
|
|
transition: all 0.2s ease;
|
|
border: none;
|
|
}
|
|
|
|
.modern-table-dashboard tbody tr:hover {
|
|
background: rgba(255,140,0,0.04);
|
|
}
|
|
|
|
.modern-table-dashboard td {
|
|
padding: 18px 16px;
|
|
border-color: #f8fafc;
|
|
vertical-align: middle;
|
|
}
|
|
|
|
/* Modern Badges */
|
|
.badge {
|
|
padding: 8px 16px;
|
|
border-radius: 20px;
|
|
font-weight: 600;
|
|
font-size: 0.8rem;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.3px;
|
|
box-shadow: var(--shadow-sm);
|
|
}
|
|
|
|
/* ======================================================
|
|
SUBTLE ANIMATIONS
|
|
====================================================== */
|
|
@keyframes fadeInUp {
|
|
from {
|
|
opacity: 0;
|
|
transform: translateY(20px);
|
|
}
|
|
to {
|
|
opacity: 1;
|
|
transform: translateY(0);
|
|
}
|
|
}
|
|
|
|
.modern-card,
|
|
.summary-card {
|
|
animation: fadeInUp 0.6s ease forwards;
|
|
}
|
|
|
|
.modern-card:nth-child(1) { animation-delay: 0.1s; }
|
|
.modern-card:nth-child(2) { animation-delay: 0.15s; }
|
|
.modern-card:nth-child(3) { animation-delay: 0.2s; }
|
|
.modern-card:nth-child(4) { animation-delay: 0.25s; }
|
|
|
|
/* ======================================================
|
|
RESPONSIVE - Clean Mobile
|
|
====================================================== */
|
|
@media (max-width: 768px) {
|
|
.summary-card {
|
|
padding: 20px;
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
.summary-icon {
|
|
width: 52px;
|
|
height: 52px;
|
|
font-size: 20px;
|
|
}
|
|
|
|
.ai-item {
|
|
padding: 14px 16px;
|
|
font-size: 13.5px;
|
|
}
|
|
|
|
.modern-table-dashboard thead th,
|
|
.modern-table-dashboard td {
|
|
padding: 14px 12px;
|
|
font-size: 0.9rem;
|
|
}
|
|
|
|
.modern-card,
|
|
.summary-card {
|
|
margin-bottom: 16px;
|
|
}
|
|
}
|
|
|
|
/* Button enhancements */
|
|
.btn-outline-primary {
|
|
border-color: var(--orange-primary);
|
|
color: var(--orange-primary);
|
|
}
|
|
|
|
.btn-outline-primary:hover {
|
|
background: var(--orange-primary);
|
|
border-color: var(--orange-primary);
|
|
color: white;
|
|
}
|
|
|
|
/* Chart container */
|
|
.chart-container {
|
|
height: 300px;
|
|
position: relative;
|
|
}
|
|
</style>
|
|
|
|
<!-- ───────────────────────── DASHBOARD CONTENT ───────────────────────── -->
|
|
<div class="container mt-4 px-3 px-md-4">
|
|
|
|
<?php if($role == 'Admin'): ?>
|
|
<!-- ================= SUMMARY CARDS ================= -->
|
|
<div class="row g-4 mb-3">
|
|
<div class="col-12 col-md-4">
|
|
<div class="summary-card h-100">
|
|
<div class="d-flex align-items-center h-100">
|
|
<div class="summary-icon"><i class="bi bi-cash-stack"></i></div>
|
|
<div class="ms-3 flex-grow-1">
|
|
<div class="fw-bold fs-4 lh-1 text-dark">Rp <?= number_format($summary['total_revenue']); ?></div>
|
|
<small class="text-muted fw-medium">Total Pemasukan</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-12 col-md-4">
|
|
<div class="summary-card h-100">
|
|
<div class="d-flex align-items-center h-100">
|
|
<div class="summary-icon"><i class="bi bi-arrow-down-circle"></i></div>
|
|
<div class="ms-3 flex-grow-1">
|
|
<div class="fw-bold fs-4 lh-1 text-danger">Rp <?= number_format($summary['total_expense']); ?></div>
|
|
<small class="text-muted fw-medium">Total Pengeluaran</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-12 col-md-4">
|
|
<div class="summary-card h-100">
|
|
<div class="d-flex align-items-center h-100">
|
|
<div class="summary-icon"><i class="bi bi-graph-up-arrow"></i></div>
|
|
<div class="ms-3 flex-grow-1">
|
|
<div class="fw-bold fs-4 lh-1 text-success">Rp <?= number_format($summary['net_profit']); ?></div>
|
|
<small class="text-muted fw-medium">Keuntungan Bersih</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<!-- ================= SECOND ROW ================= -->
|
|
<div class="row g-4 mb-3">
|
|
|
|
<!-- ================= NERACA ================= -->
|
|
<div class="col-12 col-md-6">
|
|
<a href="<?= base_url('neraca'); ?>" class="text-decoration-none">
|
|
<div class="summary-card h-100">
|
|
<div class="d-flex align-items-center h-100">
|
|
|
|
<div class="summary-icon">
|
|
<i class="bi bi-bar-chart-line-fill"></i>
|
|
</div>
|
|
|
|
<div class="ms-3 flex-grow-1 position-relative">
|
|
|
|
<div class="fw-bold fs-4 lh-1 text-primary">
|
|
Neraca
|
|
</div>
|
|
|
|
<small class="text-muted fw-medium">
|
|
Laporan posisi keuangan perusahaan
|
|
</small>
|
|
|
|
<div class="position-absolute bottom-0 end-0 p-3">
|
|
<i class="bi bi-arrow-right fs-5 text-secondary opacity-75"></i>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
</a>
|
|
</div>
|
|
|
|
<!-- ================= LABA RUGI ================= -->
|
|
<div class="col-12 col-md-6">
|
|
<a href="<?= base_url('labarugi'); ?>" class="text-decoration-none">
|
|
<div class="summary-card h-100">
|
|
<div class="d-flex align-items-center h-100">
|
|
|
|
<div class="summary-icon">
|
|
<i class="bi bi-graph-up-arrow"></i>
|
|
</div>
|
|
|
|
<div class="ms-3 flex-grow-1 position-relative">
|
|
|
|
<div class="fw-bold fs-4 lh-1 text-success">
|
|
Laba Rugi
|
|
</div>
|
|
|
|
<small class="text-muted fw-medium">
|
|
Analisis pendapatan dan beban usaha
|
|
</small>
|
|
|
|
<div class="position-absolute bottom-0 end-0 p-3">
|
|
<i class="bi bi-arrow-right fs-5 text-secondary opacity-75"></i>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
</a>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<!-- ================= QUICK ACTIONS ================= -->
|
|
<div class="row g-4 mb-3 quick-action">
|
|
|
|
<!-- ================= INVOICE ================= -->
|
|
<div class="col-md-6 col-sm-6">
|
|
<a href="<?= base_url('invoices/draft'); ?>" class="text-decoration-none">
|
|
<div class="summary-card h-100 text-center p-4 position-relative overflow-hidden">
|
|
|
|
<div class="summary-icon mx-auto mb-3 d-inline-block">
|
|
<i class="bi bi-receipt"></i>
|
|
</div>
|
|
|
|
<h6 class="mb-2 fw-bold text-dark">Invoice</h6>
|
|
|
|
<small class="text-muted fw-medium d-block">
|
|
Kelola penjualan & penagihan pelanggan
|
|
</small>
|
|
|
|
<div class="position-absolute bottom-0 end-0 p-3">
|
|
<i class="bi bi-arrow-right fs-5 text-secondary opacity-75"></i>
|
|
</div>
|
|
|
|
</div>
|
|
</a>
|
|
</div>
|
|
|
|
<!-- ================= GUDANG / ITEMS ================= -->
|
|
<div class="col-md-6 col-sm-6">
|
|
<a href="<?= base_url('items'); ?>" class="text-decoration-none">
|
|
<div class="summary-card h-100 text-center p-4 position-relative overflow-hidden">
|
|
|
|
<div class="summary-icon mx-auto mb-3 d-inline-block">
|
|
<i class="bi bi-box-seam"></i>
|
|
</div>
|
|
|
|
<h6 class="mb-2 fw-bold text-dark">Persediaan</h6>
|
|
|
|
<small class="text-muted fw-medium d-block">
|
|
Kelola stok & barang gudang
|
|
</small>
|
|
|
|
<div class="position-absolute bottom-0 end-0 p-3">
|
|
<i class="bi bi-arrow-right fs-5 text-secondary opacity-75"></i>
|
|
</div>
|
|
|
|
</div>
|
|
</a>
|
|
</div>
|
|
|
|
</div>
|
|
<!-- ================= MAIN CONTENT ================= -->
|
|
<div class="row g-4">
|
|
<!-- Chart -->
|
|
<div class="col-xl-8">
|
|
<div class="modern-card h-100">
|
|
<div class="p-5">
|
|
<div class="d-flex justify-content-between align-items-start mb-4">
|
|
<div>
|
|
<h4 class="mb-1 fw-bold text-dark">Ringkasan Keuangan</h4>
|
|
<small class="text-muted">Performa keuangan</small>
|
|
</div>
|
|
<div class="btn-group" role="group">
|
|
<select id="yearFilter" class="form-select form-select-sm">
|
|
<option value="">Semua Tahun</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div class="chart-container">
|
|
<canvas id="financeChart" height="140"></canvas>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- AI INSIGHT -->
|
|
<div class="col-xl-4">
|
|
<div class="modern-card h-100 shadow-sm border-0 rounded-4">
|
|
<div class="p-4">
|
|
|
|
<!-- HEADER -->
|
|
<div class="d-flex align-items-center mb-4">
|
|
<div class="bg-primary rounded-circle p-3 me-3 shadow-sm">
|
|
<i class="bi bi-robot text-white fs-5"></i>
|
|
</div>
|
|
<div>
|
|
<h5 class="mb-0 fw-bold text-dark">AI Insight</h5>
|
|
<small class="text-muted">Rekomendasi otomatis sistem</small>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- CONTENT -->
|
|
<div class="ai-box d-flex flex-column gap-2">
|
|
|
|
<?php if(empty($ai_insight)): ?>
|
|
|
|
<div class="text-center text-muted py-4">
|
|
<i class="bi bi-lightbulb-off" style="font-size:28px;"></i>
|
|
<div class="mt-2 small">Belum ada insight hari ini</div>
|
|
</div>
|
|
|
|
<?php else: ?>
|
|
|
|
<?php foreach($ai_insight as $ai): ?>
|
|
|
|
<?php
|
|
// =========================
|
|
// mapping icon & color
|
|
// =========================
|
|
$icon = 'bi-info-circle-fill';
|
|
$colorClass = 'ai-info';
|
|
|
|
if($ai->severity == 'critical'){
|
|
$icon = 'bi-x-octagon-fill';
|
|
$colorClass = 'ai-danger';
|
|
} elseif($ai->severity == 'warning'){
|
|
$icon = 'bi-exclamation-triangle-fill';
|
|
$colorClass = 'ai-warning';
|
|
} elseif($ai->severity == 'info'){
|
|
$icon = 'bi-info-circle-fill';
|
|
$colorClass = 'ai-info';
|
|
} elseif($ai->type == 'stock'){
|
|
$icon = 'bi-box-seam-fill';
|
|
$colorClass = 'ai-stock';
|
|
} elseif($ai->type == 'finance'){
|
|
$icon = 'bi-cash-coin';
|
|
$colorClass = 'ai-finance';
|
|
}
|
|
?>
|
|
|
|
<div class="ai-item <?= $colorClass ?>">
|
|
|
|
<div class="d-flex align-items-start gap-2">
|
|
|
|
<i class="bi <?= $icon ?> fs-5 mt-1"></i>
|
|
|
|
<div class="flex-grow-1">
|
|
<div class="small text-dark">
|
|
<?= $ai->message; ?>
|
|
</div>
|
|
|
|
<?php if(!empty($ai->meta)): ?>
|
|
<div class="text-muted small mt-1">
|
|
<i class="bi bi-info-circle"></i>
|
|
detail tambahan tersedia
|
|
</div>
|
|
<?php endif; ?>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<?php endforeach; ?>
|
|
|
|
<?php endif; ?>
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<?php endif; ?>
|
|
|
|
<!-- ================= ACTIVITY FEED ================= -->
|
|
<div class="row mt-4">
|
|
<div class="col-12">
|
|
<div class="modern-card">
|
|
<div class="p-5">
|
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
|
<div>
|
|
<h4 class="mb-1 fw-bold text-dark">Aktivitas Terbaru</h4>
|
|
<small class="text-muted">Aktivitas terakhir di sistem</small>
|
|
</div>
|
|
<a href="<?= base_url('dashboard/log_activity') ?>" class="btn btn-outline-primary btn-sm px-4 rounded-pill">
|
|
Lihat Semua <i class="bi bi-arrow-right ms-1"></i>
|
|
</a>
|
|
</div>
|
|
|
|
<div class="table-responsive">
|
|
<table class="table modern-table-dashboard table-hover align-middle mb-0">
|
|
<thead>
|
|
<tr>
|
|
<th class="rounded-start">Waktu</th>
|
|
<th>Modul</th>
|
|
<th>Keterangan</th>
|
|
<th>Pengguna</th>
|
|
<th class="rounded-end">Status</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="activityBody"></tbody>
|
|
</table>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div> <!-- End Container -->
|
|
|
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
|
|
|
<script>
|
|
$(document).ready(function () {
|
|
|
|
let chartInstance = null;
|
|
|
|
// ================= INIT =================
|
|
const currentYear = new Date().getFullYear();
|
|
|
|
loadYearOptions();
|
|
loadChart(currentYear);
|
|
|
|
// set default dropdown setelah load
|
|
setTimeout(() => {
|
|
$('#yearFilter').val(currentYear);
|
|
}, 500);
|
|
|
|
// ================= LOAD YEAR =================
|
|
function loadYearOptions() {
|
|
$.get("<?= base_url('dashboard/get_years'); ?>", function (res) {
|
|
|
|
let html = ``;
|
|
|
|
res.forEach(y => {
|
|
html += `<option value="${y.year}">${y.year}</option>`;
|
|
});
|
|
|
|
$('#yearFilter').html(html);
|
|
|
|
}, 'json');
|
|
}
|
|
|
|
// ================= LOAD CHART =================
|
|
function loadChart(year = '') {
|
|
|
|
$.get("<?= base_url('dashboard/get_chart'); ?>", { year: year }, function (res) {
|
|
|
|
const ctx = document.getElementById('financeChart');
|
|
if (!ctx) return;
|
|
|
|
if (chartInstance) chartInstance.destroy();
|
|
|
|
const g1 = ctx.getContext('2d').createLinearGradient(0, 0, 0, 250);
|
|
g1.addColorStop(0, 'rgba(25, 135, 84, 0.18)');
|
|
g1.addColorStop(1, 'rgba(25, 135, 84, 0.02)');
|
|
|
|
const g2 = ctx.getContext('2d').createLinearGradient(0, 0, 0, 250);
|
|
g2.addColorStop(0, 'rgba(220, 53, 69, 0.18)');
|
|
g2.addColorStop(1, 'rgba(220, 53, 69, 0.02)');
|
|
|
|
chartInstance = new Chart(ctx, {
|
|
type: 'line',
|
|
data: {
|
|
labels: res.labels || [],
|
|
datasets: [
|
|
{
|
|
label: 'Revenue',
|
|
data: res.revenue || [],
|
|
borderColor: '#198754',
|
|
backgroundColor: g1,
|
|
borderWidth: 2,
|
|
tension: 0.35,
|
|
fill: true,
|
|
pointRadius: 2,
|
|
pointHoverRadius: 5
|
|
},
|
|
{
|
|
label: 'Expense',
|
|
data: res.expense || [],
|
|
borderColor: '#dc3545',
|
|
backgroundColor: g2,
|
|
borderWidth: 2,
|
|
tension: 0.35,
|
|
fill: true,
|
|
pointRadius: 2,
|
|
pointHoverRadius: 5
|
|
}
|
|
]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
maintainAspectRatio: false,
|
|
|
|
interaction: {
|
|
mode: 'index',
|
|
intersect: false
|
|
},
|
|
|
|
plugins: {
|
|
legend: {
|
|
position: 'bottom',
|
|
labels: {
|
|
usePointStyle: true,
|
|
pointStyle: 'circle',
|
|
padding: 18,
|
|
font: {
|
|
size: 12,
|
|
weight: '500'
|
|
}
|
|
}
|
|
},
|
|
|
|
tooltip: {
|
|
backgroundColor: 'rgba(33,33,33,0.9)',
|
|
padding: 10,
|
|
displayColors: false
|
|
}
|
|
},
|
|
|
|
scales: {
|
|
|
|
x: {
|
|
grid: {
|
|
display: false
|
|
},
|
|
ticks: {
|
|
font: {
|
|
size: 11
|
|
}
|
|
}
|
|
},
|
|
|
|
y: {
|
|
beginAtZero: true,
|
|
grid: {
|
|
color: 'rgba(0,0,0,0.05)'
|
|
},
|
|
ticks: {
|
|
font: {
|
|
size: 11
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
}, 'json');
|
|
}
|
|
|
|
// ================= FILTER =================
|
|
$('#yearFilter').on('change', function () {
|
|
loadChart($(this).val());
|
|
});
|
|
|
|
});
|
|
</script>
|
|
|
|
<script>
|
|
document.addEventListener("DOMContentLoaded", function () {
|
|
loadActivity();
|
|
});
|
|
|
|
function loadActivity() {
|
|
fetch("<?= base_url('dashboard/get_activity') ?>")
|
|
.then(res => res.json())
|
|
.then(data => {
|
|
|
|
let html = "";
|
|
|
|
if (!data || data.length === 0) {
|
|
html = `
|
|
<tr>
|
|
<td colspan="5" class="text-center text-muted py-2">
|
|
Tidak ada aktivitas
|
|
</td>
|
|
</tr>
|
|
`;
|
|
document.getElementById("activityBody").innerHTML = html;
|
|
return;
|
|
}
|
|
|
|
data.forEach(item => {
|
|
|
|
let time = new Date(item.created_at);
|
|
let jam = time.getHours().toString().padStart(2,'0') + ":" +
|
|
time.getMinutes().toString().padStart(2,'0');
|
|
|
|
html += `
|
|
<tr>
|
|
<td class="fw-semibold text-primary">${jam}</td>
|
|
<td>${item.module ?? '-'}</td>
|
|
<td>${item.description ?? '-'}</td>
|
|
<td class="fw-medium">${item.nama ?? 'System'}</td>
|
|
<td>${getStatusBadge(item.status)}</td>
|
|
</tr>
|
|
`;
|
|
});
|
|
|
|
document.getElementById("activityBody").innerHTML = html;
|
|
})
|
|
.catch(err => console.error(err));
|
|
}
|
|
|
|
|
|
// ================= STATUS BADGE (SIMPLE CLEAN) =================
|
|
function getStatusBadge(status) {
|
|
|
|
if (!status) status = 'success';
|
|
|
|
const map = {
|
|
success: "success",
|
|
failed: "danger",
|
|
pending: "warning"
|
|
};
|
|
|
|
let cls = map[status] || "secondary";
|
|
|
|
return `<span class="badge bg-${cls}">${status}</span>`;
|
|
}
|
|
</script>
|