@extends('layouts.app', ['class' => 'g-sidenav-show bg-gray-100', 'title_menu' => 'Dashboard HRD']) @section('content') @include('layouts.navbars.auth.topnav', ['title' => 'Dashboard', 'title_group' => 'HRD', 'title_menu' => 'Dashboard'])
@php $filterMonth = request()->input('bulan', now()->format('m')); $filterYear = request()->input('tahun', now()->format('Y')); $monthNames = [ '01' => 'Januari', '02' => 'Februari', '03' => 'Maret', '04' => 'April', '05' => 'Mei', '06' => 'Juni', '07' => 'Juli', '08' => 'Agustus', '09' => 'September', '10' => 'Oktober', '11' => 'November', '12' => 'Desember', ]; @endphp

Dashboard HRD

@php $selectedMonthLabel = $monthNames[$filterMonth] ?? now()->translatedFormat('F'); $selectedPeriodLabel = $selectedMonthLabel . ' ' . $filterYear; $monthScope = function ($query) use ($filterMonth, $filterYear) { $query->where(function ($q) { $q->where('is_active', 1)->orWhereNull('is_active'); }); $query->whereMonth('created_at', $filterMonth) ->whereYear('created_at', $filterYear); }; // 1. APPROVAL STATISTICS (scoped) $totalApprovalNeeded = \Illuminate\Support\Facades\DB::table('tr_non_periodic') ->where($monthScope) ->whereIn('request_status', ['review', 'pending', 'approved']) ->whereNotNull('head_approval_date') ->whereNull('hrd_approval_date') ->count(); $approvedRequests = \Illuminate\Support\Facades\DB::table('tr_non_periodic') ->where($monthScope) ->whereIn('request_status', ['pengadaan', 'pengerjaan']) ->count(); $rejectedRequests = \Illuminate\Support\Facades\DB::table('tr_non_periodic') ->where($monthScope) ->where('request_status', 'LIKE', '%reject%') ->count(); $completedRequests = \Illuminate\Support\Facades\DB::table('tr_non_periodic') ->where($monthScope) ->where('request_status', 'completed') ->count(); // 2. PERIODIC SCHEDULE STATS $periodicHeaders = \Illuminate\Support\Facades\DB::table('tr_periodic_header') ->count(); $periodicDetails = \Illuminate\Support\Facades\DB::table('tr_periodic_detail') ->count(); $generatedItems = \Illuminate\Support\Facades\DB::table('tr_periodic_items') ->count(); $unrealizedItems = \Illuminate\Support\Facades\DB::table('tr_periodic_items') ->whereNull('realization_date') ->count(); // 3. DAILY TASK STATS $totalDailyTasks = \Illuminate\Support\Facades\DB::table('ms_daily') ->where('is_active', 1) ->count(); $todayLoggedTasks = \Illuminate\Support\Facades\DB::table('rp_daily_log') ->whereDate('work_date', \Illuminate\Support\Carbon::today()->toDateString()) ->distinct() ->count('daily_task_id'); $todayCompleted = \Illuminate\Support\Facades\DB::table('rp_daily_log') ->whereDate('work_date', \Illuminate\Support\Carbon::today()->toDateString()) ->whereRaw('LOWER(COALESCE(job_status, \'\')) = ?', ['completed']) ->distinct() ->count('daily_task_id'); $dailyTarget = $totalDailyTasks; $completionRate = $dailyTarget > 0 ? round(($todayCompleted / $dailyTarget) * 100) : 0; $dailyRateLabels = []; $dailyRateData = []; $dailyCompletedData = []; $dailyTargetData = []; $dailyStartDate = \Illuminate\Support\Carbon::createFromDate((int) $filterYear, (int) $filterMonth, 1)->startOfMonth(); $dailyEndDate = $dailyStartDate->copy()->endOfMonth(); $dailyCompletedRows = \Illuminate\Support\Facades\DB::table('rp_daily_log') ->whereBetween('work_date', [$dailyStartDate->toDateString(), $dailyEndDate->toDateString()]) ->whereRaw('LOWER(COALESCE(job_status, \'\')) = ?', ['completed']) ->select( 'work_date', \Illuminate\Support\Facades\DB::raw('COUNT(DISTINCT daily_task_id) as completed_count') ) ->groupBy('work_date') ->get() ->keyBy('work_date'); $dailyCursorDate = $dailyStartDate->copy(); while ($dailyCursorDate->lte($dailyEndDate)) { $dailyDate = $dailyCursorDate->toDateString(); $dailyCompletedCount = isset($dailyCompletedRows[$dailyDate]) ? (int) $dailyCompletedRows[$dailyDate]->completed_count : 0; $dailyRateLabels[] = $dailyCursorDate->format('d M'); $dailyCompletedData[] = $dailyCompletedCount; $dailyTargetData[] = $dailyTarget; $dailyRateData[] = $dailyTarget > 0 ? round(($dailyCompletedCount / $dailyTarget) * 100, 1) : 0; $dailyCursorDate->addDay(); } $dailyMonthlyAverage = count($dailyRateData) > 0 ? round(array_sum($dailyRateData) / count($dailyRateData), 1) : 0; // 4. AREA & WORKERS $totalAreas = \Illuminate\Support\Facades\DB::table('ms_area')->count(); $totalWorkers = \Illuminate\Support\Facades\DB::table('users') ->whereRaw("FIND_IN_SET('ptgoff', REPLACE(idroles, ' ', '')) OR FIND_IN_SET('ptgspu', REPLACE(idroles, ' ', ''))") ->count(); // 5. TOP AREAS by Requests $topAreas = \Illuminate\Support\Facades\DB::table('tr_non_periodic') ->where($monthScope) ->select('area_id', \Illuminate\Support\Facades\DB::raw('COUNT(*) as count')) ->groupBy('area_id') ->orderBy('count', 'desc') ->limit(5) ->get(); $selectedRequests = \Illuminate\Support\Facades\DB::table('tr_non_periodic') ->where($monthScope) ->select('user_id') ->get(); $selectedUserIds = $selectedRequests->pluck('user_id')->filter()->unique()->values()->all(); $departmentMap = []; if (!empty($selectedUserIds)) { $departmentMap = \Illuminate\Support\Facades\DB::table('ms_employee') ->whereIn('user_id', $selectedUserIds) ->join('ms_department', 'ms_employee.departemen_id', '=', 'ms_department.id') ->pluck('ms_department.nama_departemen', 'ms_employee.user_id') ->toArray(); } $allDepartments = \Illuminate\Support\Facades\DB::table('ms_department') ->where(fn ($q) => $q->where('is_active', '1')->orWhereNull('is_active')) ->orderBy('nama_departemen') ->pluck('nama_departemen') ->toArray(); $deptCounts = array_fill_keys($allDepartments, 0); $deptCounts['Tidak Diketahui'] = 0; foreach ($selectedRequests as $requestRow) { if (isset($requestRow->user_id) && isset($departmentMap[$requestRow->user_id])) { $deptName = $departmentMap[$requestRow->user_id]; if (!array_key_exists($deptName, $deptCounts)) { $deptCounts[$deptName] = 0; } $deptCounts[$deptName]++; } else { $deptCounts['Tidak Diketahui']++; } } $deptLabels = array_keys($deptCounts); $deptData = array_values($deptCounts); $chartColors = [ 'rgba(15,98,254,0.75)', 'rgba(66,190,101,0.75)', 'rgba(255,131,43,0.75)', 'rgba(250,77,86,0.75)', 'rgba(138,63,252,0.75)', 'rgba(51,177,255,0.75)', 'rgba(255,193,7,0.75)', 'rgba(233,30,99,0.75)', 'rgba(0,150,136,0.75)', 'rgba(121,85,72,0.75)', ]; $deptBgColors = []; foreach ($deptLabels as $idx => $label) { $deptBgColors[] = $label === 'Tidak Diketahui' ? 'rgba(158,158,158,0.4)' : $chartColors[$idx % count($chartColors)]; } $periodicYearLabels = []; $periodicYearTotalData = []; $periodicYearDoneData = []; $periodicYearPendingData = []; $periodicYearRateData = []; $periodicYearSummary = []; for ($month = 1; $month <= 12; $month++) { $monthKey = str_pad((string) $month, 2, '0', STR_PAD_LEFT); $periodicYearLabels[] = $monthNames[$monthKey] ?? $monthKey; $periodicYearSummary[$monthKey] = [ 'total' => 0, 'done' => 0, 'pending' => 0, ]; } $periodicYearRows = \Illuminate\Support\Facades\DB::table('tr_periodic_items') ->where(function ($query) { $query->where('is_active', 1)->orWhereNull('is_active'); }) ->whereNotNull('planned_date') ->whereYear('planned_date', $filterYear) ->select( \Illuminate\Support\Facades\DB::raw('MONTH(planned_date) as month_number'), \Illuminate\Support\Facades\DB::raw('COUNT(*) as total_count'), \Illuminate\Support\Facades\DB::raw('SUM(CASE WHEN realization_date IS NOT NULL THEN 1 ELSE 0 END) as done_count') ) ->groupBy(\Illuminate\Support\Facades\DB::raw('MONTH(planned_date)')) ->get(); foreach ($periodicYearRows as $row) { $monthKey = str_pad((string) $row->month_number, 2, '0', STR_PAD_LEFT); $totalCount = (int) $row->total_count; $doneCount = (int) $row->done_count; $periodicYearSummary[$monthKey] = [ 'total' => $totalCount, 'done' => $doneCount, 'pending' => max(0, $totalCount - $doneCount), ]; } foreach ($periodicYearSummary as $summary) { $periodicYearTotalData[] = $summary['total']; $periodicYearDoneData[] = $summary['done']; $periodicYearPendingData[] = $summary['pending']; $periodicYearRateData[] = $summary['total'] > 0 ? round(($summary['done'] / $summary['total']) * 100, 1) : 0; } $periodicYearTotal = array_sum($periodicYearTotalData); $periodicYearDone = array_sum($periodicYearDoneData); $periodicYearRate = $periodicYearTotal > 0 ? round(($periodicYearDone / $periodicYearTotal) * 100, 1) : 0; @endphp @php $approvalUrl = url('pengajuan-hrd') . '#list_hrd_approval'; $approvedUrl = url('pengajuan-hrd') . '#list_hrd_pending'; $rejectedUrl = url('pengajuan-hrd') . '?status=rejected#list_hrd_history'; $completedUrl = url('pengajuan-hrd') . '?status=completed#list_hrd_history'; @endphp @if (($overdue_estimation_alerts ?? collect())->isNotEmpty())
Pengajuan Melewati Estimasi

{{ $overdue_estimation_alerts->count() }} pengajuan masih aktif tetapi tanggal estimasinya sudah lewat.

Lihat Daftar HRD
@foreach ($overdue_estimation_alerts as $alert) @endforeach
Pekerjaan Area Tahap Estimasi Selesai Aksi
{{ $alert->job_description ?? '-' }} {{ $alert->area_name ?? '-' }} {{ $alert->overdue_stage ?? '-' }} {{ $alert->overdue_date ? \Illuminate\Support\Carbon::parse($alert->overdue_date)->format('d-m-Y') : '-' }} Detail
@endif
Jadwal Periodic

Template Aktif

{{ $periodicDetails }}

Item Generated

{{ $generatedItems }}
{{ $unrealizedItems }} item belum direalisasikan
Daily Checklist - {{ now()->format('d M Y') }}
Progress Completion {{ $completionRate }}%

{{ $todayCompleted }} dari {{ $dailyTarget }} task hari ini

@if ($todayLoggedTasks < $dailyTarget)

{{ $todayLoggedTasks }} task sudah diinput hari ini

@endif
Realisasi Periodic - {{ $filterYear }}
Total: {{ $periodicYearTotal }} | Terlaksana: {{ $periodicYearDone }} | Rate: {{ $periodicYearRate }}%
Completion Rate Daily - {{ $selectedPeriodLabel }}
Rata-rata: {{ $dailyMonthlyAverage }}% | Target harian: {{ $dailyTarget }} task
Permintaan Departemen - {{ $selectedPeriodLabel }}
Trend Permintaan Non-Periodic - {{ $selectedPeriodLabel }}
Area dengan Permintaan Terbanyak
@if($topAreas->count() > 0)
@foreach($topAreas as $area) @php $areaName = \Illuminate\Support\Facades\DB::table('ms_area') ->where('id', $area->area_id) ->value('nama_area') ?? 'Area ' . $area->area_id; @endphp
{{ $areaName }} {{ $area->count }}
@endforeach
@else

Tidak ada data permintaan

@endif
Ringkasan Sumber Daya

Petugas Aktif

{{ $totalWorkers }}

Area Kerja

{{ $totalAreas }}

Daily Task Master

{{ $totalDailyTasks }}
@php $startDate = \Illuminate\Support\Carbon::createFromDate((int) $filterYear, (int) $filterMonth, 1)->startOfMonth(); $endDate = (clone $startDate)->endOfMonth(); $range = []; $cursor = $startDate->copy(); while ($cursor->lte($endDate)) { $d = $cursor->copy(); $range[] = $d->toDateString(); $cursor->addDay(); } $raw = \Illuminate\Support\Facades\DB::table('tr_non_periodic') ->where($monthScope) ->select(\Illuminate\Support\Facades\DB::raw('DATE(created_at) as date'), \Illuminate\Support\Facades\DB::raw('COUNT(*) as count')) ->groupBy(\Illuminate\Support\Facades\DB::raw('DATE(created_at)')) ->orderBy('date') ->get() ->keyBy('date'); $trendLabels = []; $trendData = []; foreach ($range as $d) { $trendLabels[] = \Illuminate\Support\Carbon::parse($d)->format('d M'); $trendData[] = isset($raw[$d]) ? (int) $raw[$d]->count : 0; } @endphp
@endsection @push('js') @endpush