Detailing fungsi semua modul dari bugs error

This commit is contained in:
Iwit
2026-06-05 13:39:13 +07:00
parent 1089f60a3d
commit 6a79bc3464
31 changed files with 1927 additions and 228 deletions
@@ -9,32 +9,159 @@ use App\Models\Sop;
use App\Models\ExamResult;
use Illuminate\View\View;
use Illuminate\Support\Facades\DB;
use App\Models\Department;
use Carbon\Carbon;
class DashboardController extends Controller
{
/**
* 1. Fungsi Dashboard Utama Admin
*/
public function index(Request $request): View
public function index(Request $request)
{
$statistics = [
// PENTING: Menggunakan whereHas() untuk mengecek relasi Role di tabel pivot
'total_karyawan' => User::whereHas('roles', function ($query) {
$query->where('name', 'trainee'); // Atau 'karyawan', sesuaikan dengan nama role di database Anda
})->count(),
// 1. FILTER TAHUN & BULAN
$selectedYear = $request->input('year', Carbon::now()->year);
$selectedMonth = $request->input('month', Carbon::now()->month);
'total_trainer' => User::whereHas('roles', function ($query) {
// Menghitung admin dan trainer
$query->whereIn('name', ['trainer', 'admin']);
})->count(),
// 2. STATISTIK OVERDUE (Training Terlewat)
// Mengambil penugasan yang deadlinenya sudah lewat dan belum lulus
$overdueTrainings = DB::table('exam_assignments')
->join('users', 'exam_assignments.user_id', '=', 'users.id')
->join('exams', 'exam_assignments.exam_id', '=', 'exams.id')
->join('departments', 'users.department_id', '=', 'departments.id')
->whereMonth('exam_assignments.deadline_date', $selectedMonth)
->whereYear('exam_assignments.deadline_date', $selectedYear)
->where('exam_assignments.deadline_date', '<', Carbon::now())
->where('exam_assignments.status', '!=', 'passed')
->select('users.first_name', 'users.last_name', 'exams.title', 'departments.name as dept_name', 'exam_assignments.deadline_date')
->orderBy('exam_assignments.deadline_date', 'asc')
->take(5) // Ambil 5 teratas untuk list ringkas
->get();
'total_sop' => Sop::where('status', 'Active')->count(),
$totalOverdue = DB::table('exam_assignments')
->whereMonth('deadline_date', $selectedMonth)
->whereYear('deadline_date', $selectedYear)
->where('deadline_date', '<', Carbon::now())
->where('status', '!=', 'passed')
->count();
// 3. PERSENTASE PEMENUHAN TRAINING PER DEPARTEMEN
// Menghitung (Total Lulus / Total Ditugaskan) * 100 per departemen
$departments = Department::all();
$deptFulfillment = [];
foreach ($departments as $dept) {
$totalAssigned = DB::table('exam_assignments')
->join('users', 'exam_assignments.user_id', '=', 'users.id')
->where('users.department_id', $dept->id)
->whereMonth('exam_assignments.created_at', $selectedMonth)
->whereYear('exam_assignments.created_at', $selectedYear)
->count();
$totalPassed = DB::table('exam_assignments')
->join('users', 'exam_assignments.user_id', '=', 'users.id')
->where('users.department_id', $dept->id)
->where('exam_assignments.status', 'passed')
->whereMonth('exam_assignments.created_at', $selectedMonth)
->whereYear('exam_assignments.created_at', $selectedYear)
->count();
$percentage = $totalAssigned > 0 ? round(($totalPassed / $totalAssigned) * 100) : 0;
'lulus_ujian' => ExamResult::where('is_passed', true)->count(),
];
$deptFulfillment[] = [
'id' => $dept->id,
'name' => $dept->name,
'assigned' => $totalAssigned,
'passed' => $totalPassed,
'percentage' => $percentage
];
}
// Pastikan path view ini benar-benar ada di resources/views/pages/admin/dashboard/dashboard.blade.php
return view('pages.admin.dashboard.dashboard', compact('statistics'));
// Urutkan dari persentase terkecil (yang butuh perhatian) ke terbesar
usort($deptFulfillment, function($a, $b) {
return $a['percentage'] <=> $b['percentage'];
});
// 4. DATA ACTIVE / ONGOING EXAM (Untuk injeksi awal Realtime)
// Kita tarik data awal, selanjutnya Alpine.js akan melakukan polling AJAX
$activeExamsCount = DB::table('exam_attempts')->where('status', 'ongoing')->count();
// -------------------------------------------------------------------
// 5. DATA UNTUK KALENDER TRAINING (Berdasarkan Role)
// -------------------------------------------------------------------
$user = \Illuminate\Support\Facades\Auth::user();
$calendarQuery = DB::table('exam_assignments')
->join('users', 'exam_assignments.user_id', '=', 'users.id')
->join('exams', 'exam_assignments.exam_id', '=', 'exams.id')
->select(
'exam_assignments.id',
'exams.title as exam_title',
'users.first_name',
'exam_assignments.created_at',
'exam_assignments.deadline_date',
'exam_assignments.status'
);
// LOGIKA ROLE: Jika BUKAN superadmin, batasi hanya melihat departemennya sendiri
if (!$user->hasRole('superadmin')) {
$calendarQuery->where('users.department_id', $user->department_id);
}
$calendarData = $calendarQuery->get()->map(function($assign) {
// Menentukan warna event di kalender berdasarkan status
$color = '#f59e0b'; // Amber (Pending)
if ($assign->status === 'passed') $color = '#10b981'; // Emerald (Lulus)
if ($assign->status === 'ongoing') $color = '#3b82f6'; // Blue (Sedang dikerjakan)
if ($assign->status != 'passed' && Carbon::parse($assign->deadline_date)->isPast()) {
$color = '#ef4444'; // Red (Overdue)
}
return [
'id' => $assign->id,
'title' => $assign->first_name . ' - ' . $assign->exam_title,
'start' => Carbon::parse($assign->created_at)->format('Y-m-d'), // Tanggal ditugaskan
'end' => Carbon::parse($assign->deadline_date)->addDay()->format('Y-m-d'), // Tanggal deadline (+1 agar FullCalendar merender sampai hari H penuh)
'color' => $color,
'allDay'=> true
];
});
return view('pages.admin.dashboard.dashboard', compact(
'selectedYear', 'selectedMonth', 'overdueTrainings', 'totalOverdue', 'deptFulfillment', 'activeExamsCount', 'calendarData' // <--- Tambahkan ini
));
}
// ==========================================================
// FUNGSI API UNTUK REAL-TIME MONITORING (AJAX Polling)
// ==========================================================
public function getLiveExams()
{
$liveExams = DB::table('exam_attempts')
->join('exam_assignments', 'exam_attempts.exam_assignment_id', '=', 'exam_assignments.id')
->join('users', 'exam_assignments.user_id', '=', 'users.id')
->join('exams', 'exam_assignments.exam_id', '=', 'exams.id')
->join('departments', 'users.department_id', '=', 'departments.id')
->where('exam_attempts.status', 'ongoing')
->select(
'exam_attempts.id as attempt_id',
'users.first_name',
'users.last_name',
'departments.name as dept_name',
'exams.title as exam_title',
'exam_attempts.started_at',
'exams.duration_minutes'
)
->get()
->map(function ($exam) {
// Kalkulasi sisa waktu secara server-side
$started = Carbon::parse($exam->started_at);
$endsAt = $started->copy()->addMinutes($exam->duration_minutes);
$exam->time_left_seconds = Carbon::now()->diffInSeconds($endsAt, false); // Minus jika kelebihan
return $exam;
});
return response()->json($liveExams);
}
/**
@@ -234,4 +361,31 @@ class DashboardController extends Controller
return response()->stream($callback, 200, $headers);
}
// ==========================================================
// FUNGSI UNTUK HALAMAN DETAIL PEMENUHAN DEPARTEMEN
// ==========================================================
public function departmentFulfillment($id, Request $request)
{
$department = Department::findOrFail($id);
$selectedMonth = $request->input('month', Carbon::now()->month);
$selectedYear = $request->input('year', Carbon::now()->year);
// Ambil detail penugasan ujian khusus departemen ini di bulan/tahun yang dipilih
$assignments = DB::table('exam_assignments')
->join('users', 'exam_assignments.user_id', '=', 'users.id')
->join('exams', 'exam_assignments.exam_id', '=', 'exams.id')
->where('users.department_id', $id)
->whereMonth('exam_assignments.created_at', $selectedMonth)
->whereYear('exam_assignments.created_at', $selectedYear)
->select(
'users.first_name', 'users.last_name', 'users.nik',
'exams.title', 'exam_assignments.status',
'exam_assignments.deadline_date', 'exam_assignments.created_at'
)
->orderBy('exam_assignments.created_at', 'desc')
->paginate(20);
return view('pages.admin.dashboard.department-detail', compact('department', 'assignments', 'selectedMonth', 'selectedYear'));
}
}