This commit is contained in:
Saufi
2026-06-02 17:35:45 +08:00
commit 4ef99b1f81
148 changed files with 21134 additions and 0 deletions

View File

@@ -0,0 +1,254 @@
@extends('layouts.admin')
@section('title', 'Dashboard')
@section('content')
<div class="d-flex justify-content-between align-items-center mb-4">
<h4 class="fw-bold mb-0"><i class="bi bi-speedometer2 me-2 text-primary"></i>Dashboard Pentadbir</h4>
<span class="text-muted small">{{ now()->format('d M Y, H:i') }}</span>
</div>
{{-- Baris 1: Pengguna & Projek --}}
<div class="row g-3 mb-3">
<div class="col-md-3">
<div class="card stat-card bg-success text-white h-100">
<div class="card-body">
<div class="d-flex justify-content-between align-items-start">
<div>
<div class="fs-1 fw-bold">{{ $stats['users_active'] }}</div>
<div class="opacity-75 small">Pengguna Aktif</div>
<div class="mt-1 opacity-60" style="font-size:0.78rem">
{{ $stats['users_total'] }} jumlah &bull;
{{ $stats['users_inactive'] }} dinyahaktif
</div>
</div>
<i class="bi bi-people-fill fs-2 opacity-50"></i>
</div>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card stat-card bg-primary text-white h-100">
<div class="card-body">
<div class="d-flex justify-content-between align-items-start">
<div>
<div class="fs-1 fw-bold">{{ $stats['projects_total'] }}</div>
<div class="opacity-75 small">Jumlah Projek</div>
<div class="mt-1 opacity-60" style="font-size:0.78rem">
+{{ $stats['projects_last_7'] }} (7 hari) &bull;
+{{ $stats['projects_last_30'] }} (30 hari)
</div>
</div>
<i class="bi bi-folder-fill fs-2 opacity-50"></i>
</div>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card stat-card bg-info text-white h-100">
<div class="card-body">
<div class="d-flex justify-content-between align-items-start">
<div>
<div class="fs-1 fw-bold">{{ $stats['projects_completed'] }}</div>
<div class="opacity-75 small">Transkripsi Selesai</div>
@php
$pct = $stats['projects_total'] > 0
? round($stats['projects_completed'] / $stats['projects_total'] * 100)
: 0;
@endphp
<div class="mt-1 opacity-60" style="font-size:0.78rem">
{{ $pct }}% kadar kejayaan
</div>
</div>
<i class="bi bi-check-circle-fill fs-2 opacity-50"></i>
</div>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card stat-card bg-warning text-dark h-100">
<div class="card-body">
<div class="d-flex justify-content-between align-items-start">
<div>
@php
$totalBytes = $stats['storage_bytes'];
if ($totalBytes >= 1073741824) {
$storageLabel = number_format($totalBytes / 1073741824, 2) . ' GB';
} elseif ($totalBytes >= 1048576) {
$storageLabel = number_format($totalBytes / 1048576, 1) . ' MB';
} else {
$storageLabel = number_format($totalBytes / 1024, 0) . ' KB';
}
$durationH = intdiv($stats['duration_total_seconds'], 3600);
$durationM = intdiv($stats['duration_total_seconds'] % 3600, 60);
@endphp
<div class="fs-3 fw-bold">{{ $storageLabel }}</div>
<div class="small" style="opacity:0.8">Storan Digunakan</div>
<div class="mt-1" style="font-size:0.78rem; opacity:0.7">
{{ $durationH }}j {{ $durationM }}m jumlah audio
</div>
</div>
<i class="bi bi-hdd-fill fs-2 opacity-50"></i>
</div>
</div>
</div>
</div>
</div>
{{-- Baris 2: Status + Trend --}}
<div class="row g-3 mb-3">
<div class="col-md-4">
<div class="card h-100">
<div class="card-header bg-white fw-semibold">
<i class="bi bi-pie-chart me-2 text-primary"></i>Status Transkripsi
</div>
<div class="card-body pb-2">
<table class="table table-sm mb-0">
<tbody>
@php
$statusRows = [
['bg-secondary', 'Menunggu', $stats['projects_pending']],
['bg-warning text-dark', 'Sedang Diproses', $stats['projects_processing']],
['bg-success', 'Selesai', $stats['projects_completed']],
['bg-danger', 'Gagal', $stats['projects_failed']],
['bg-light text-muted border', 'Dipadam (soft)', $stats['projects_deleted']],
];
@endphp
@foreach($statusRows as [$cls, $label, $count])
<tr>
<td><span class="badge {{ $cls }}">{{ $label }}</span></td>
<td class="fw-bold">{{ $count }}</td>
<td class="text-muted small">
@if($stats['projects_total'] > 0)
{{ round($count / ($stats['projects_total'] ?: 1) * 100) }}%
@endif
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card h-100">
<div class="card-header bg-white fw-semibold">
<i class="bi bi-bar-chart me-2 text-success"></i>Trend 30 Hari Lepas
</div>
<div class="card-body p-0">
@if($trendRaw->isEmpty())
<div class="text-muted small text-center py-4">Tiada data projek dalam 30 hari lepas.</div>
@else
<div class="table-responsive" style="max-height:220px; overflow-y:auto">
<table class="table table-sm table-hover mb-0">
<thead class="table-light sticky-top">
<tr>
<th>Tarikh</th>
<th class="text-center">Baru</th>
<th class="text-center text-success">Selesai</th>
<th class="text-center text-danger">Gagal</th>
</tr>
</thead>
<tbody>
@foreach($trendRaw->sortByDesc('date') as $row)
<tr>
<td class="small">{{ \Carbon\Carbon::parse($row->date)->format('d/m') }}</td>
<td class="text-center">{{ $row->total }}</td>
<td class="text-center text-success">{{ $row->completed }}</td>
<td class="text-center text-danger">{{ $row->failed }}</td>
</tr>
@endforeach
</tbody>
</table>
</div>
@endif
</div>
</div>
</div>
<div class="col-md-4">
<div class="card h-100">
<div class="card-header bg-white fw-semibold">
<i class="bi bi-trophy me-2 text-warning"></i>Pengguna Paling Aktif
</div>
<div class="card-body p-0">
@if($topUsers->isEmpty())
<div class="text-muted small text-center py-4">Tiada data pengguna.</div>
@else
<table class="table table-sm mb-0">
<tbody>
@foreach($topUsers as $i => $u)
<tr>
<td style="width:28px" class="text-center text-muted small">{{ $i + 1 }}</td>
<td>
<div class="small fw-semibold">{{ $u->name }}</div>
<div class="text-muted" style="font-size:0.72rem">{{ $u->email }}</div>
</td>
<td class="text-end fw-bold small">{{ $u->owned_projects_count }}</td>
</tr>
@endforeach
</tbody>
</table>
@endif
</div>
</div>
</div>
</div>
{{-- Baris 3: Jabatan + Tindakan Pantas --}}
<div class="row g-3">
<div class="col-md-6">
<div class="card h-100">
<div class="card-header bg-white fw-semibold">
<i class="bi bi-building me-2 text-secondary"></i>Projek Mengikut Jabatan
</div>
<div class="card-body p-0">
@if($deptStats->isEmpty())
<div class="text-muted small text-center py-4">Tiada data jabatan.</div>
@else
<table class="table table-sm mb-0">
<tbody>
@foreach($deptStats as $dept)
<tr>
<td class="small">{{ $dept->name }}</td>
<td class="text-end">
<span class="badge bg-primary">{{ $dept->project_count }}</span>
</td>
</tr>
@endforeach
</tbody>
</table>
@endif
</div>
</div>
</div>
<div class="col-md-6">
<div class="card h-100">
<div class="card-header bg-white fw-semibold">
<i class="bi bi-lightning me-2 text-warning"></i>Tindakan Pantas
</div>
<div class="card-body d-flex flex-column gap-2">
<a href="{{ route('admin.users.index') }}" class="btn btn-outline-primary">
<i class="bi bi-people me-2"></i>Urus Pengguna
<span class="badge bg-primary ms-1">{{ $stats['users_total'] }}</span>
</a>
<a href="{{ route('admin.users.create') }}" class="btn btn-outline-success">
<i class="bi bi-person-plus me-2"></i>Daftar Pengguna Baru
</a>
<a href="{{ route('admin.projects.index') }}" class="btn btn-outline-secondary">
<i class="bi bi-folder2 me-2"></i>Senarai Projek (Metadata)
<span class="badge bg-secondary ms-1">{{ $stats['projects_total'] }}</span>
</a>
<a href="{{ route('admin.audit-logs.index') }}" class="btn btn-outline-dark">
<i class="bi bi-journal-text me-2"></i>Log Audit
</a>
</div>
</div>
</div>
</div>
@endsection