Detailing fungsi semua modul dari bugs error
This commit is contained in:
@@ -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'));
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user