From 7ffb802f3e7302a53aa2c8bef97b22ccff84c727 Mon Sep 17 00:00:00 2001 From: JokoPrasetio Date: Wed, 20 May 2026 14:53:14 +0700 Subject: [PATCH] fixing persentase data in datatable ghost --- app/Http/Controllers/PitStopController.php | 139 +++++++-------------- storage/.gitignore | 1 + 2 files changed, 48 insertions(+), 92 deletions(-) create mode 100644 storage/.gitignore diff --git a/app/Http/Controllers/PitStopController.php b/app/Http/Controllers/PitStopController.php index 93b752b..1458128 100644 --- a/app/Http/Controllers/PitStopController.php +++ b/app/Http/Controllers/PitStopController.php @@ -2058,53 +2058,32 @@ class PitStopController extends Controller $totalSteps = (int) MasterPitStopPraAkre::where('statusenabled', true)->count(); - // ---------------------------------------------------------------- - // Subquery: belum_count & belum_steps dihitung SEKALI via CTE - // Hindari correlated subquery per-baris - // ---------------------------------------------------------------- - $belumCte = DB::connection('pgsql') - ->table('public.masterpitstop as ms') - ->where('ms.statusenabled', true) - ->select([ - 'ms.id as ms_id', - 'ms.nama as ms_nama', - ]); - - // ---------------------------------------------------------------- - // Internal query — ganti correlated subquery dengan LEFT JOIN agregasi - // ---------------------------------------------------------------- + // ── Internal ──────────────────────────────────────────────────── $internal = DB::connection('pgsql') ->table('public.mappegawaijabatantounitkerja_m as mp') - ->join('public.pegawai_m as pg', 'pg.id', '=', 'mp.objectpegawaifk') - ->join('public.unitkerjapegawai_m as ukp', 'ukp.id', '=', 'mp.objectunitkerjapegawaifk') - ->leftJoin('public.praakre as p', function ($join) { - $join->on('p.pegawai_id', '=', 'pg.id') - ->where('p.tipe_karyawan', '!=', 'luar'); // pastikan hanya internal - }) + ->join('public.pegawai_m as pg', 'pg.id', '=', 'mp.objectpegawaifk') + ->join('public.unitkerjapegawai_m as ukp', 'ukp.id', '=', 'mp.objectunitkerjapegawaifk') + ->leftJoin('public.praakre as p', 'p.pegawai_id', '=', 'pg.id') ->leftJoin('public.masterpitstop as m', function ($join) { $join->on(DB::raw('m.id::text'), '=', 'p.masterpitstop_id') ->where('m.statusenabled', true); }) - ->where('mp.statusenabled', true) - ->where('mp.isprimary', true) - ->where('pg.statusenabled', true) - ->where('pg.kedudukanfk', 1) + ->where('mp.statusenabled', true) + ->where('mp.isprimary', true) + ->where('pg.statusenabled', true) + ->where('pg.kedudukanfk', 1) ->where('ukp.statusenabled', true) ->select([ DB::raw("'internal' as tipe_karyawan"), 'pg.id', DB::raw("coalesce(pg.namalengkap, '-') as nama"), + DB::raw("coalesce(pg.nip_pns, '-') as identitas"), DB::raw("coalesce(ukp.name, '-') as unit_name"), DB::raw("count(distinct m.id) as lulus_count"), - // belum_count = totalSteps - lulus (dihitung di PHP, bukan subquery) - DB::raw("0 as belum_count"), // placeholder, dihitung di PHP - DB::raw("'' as belum_steps"), // placeholder, isi jika memang dibutuhkan ]) ->groupBy('pg.id', 'pg.namalengkap', 'pg.nip_pns', 'ukp.name'); - // ---------------------------------------------------------------- - // External query - // ---------------------------------------------------------------- + // ── External ──────────────────────────────────────────────────── $external = DB::connection('pgsql') ->table('public.pegawai_luar_pl as pl') ->leftJoin('public.praakre as p', function ($join) { @@ -2119,45 +2098,31 @@ class PitStopController extends Controller DB::raw("'luar' as tipe_karyawan"), 'pl.id', DB::raw("coalesce(pl.nama, '-') as nama"), + DB::raw("coalesce(pl.nik, '-') as identitas"), DB::raw("coalesce(nullif(btrim(pl.tipe), ''), '-') as unit_name"), DB::raw("count(distinct m.id) as lulus_count"), - DB::raw("0 as belum_count"), - DB::raw("'' as belum_steps"), ]) ->groupBy('pl.id', 'pl.nama', 'pl.nik', DB::raw("coalesce(nullif(btrim(pl.tipe), ''), '-')")); - // ---------------------------------------------------------------- - // Union & base query — hanya SATU kali wrap - // ---------------------------------------------------------------- - $union = $internal->unionAll($external); - $base = DB::connection('pgsql') - ->query() - ->fromSub($union, 'u'); + // ── Union & Base ───────────────────────────────────────────────── + $union = $internal->unionAll($external); + $base = DB::connection('pgsql')->query()->fromSub($union, 'u'); if ($search !== '') { $base->where(function ($q) use ($search) { - $q->where('u.nama', 'ILIKE', "%{$search}%") - ->orWhere('u.unit_name', 'ILIKE', "%{$search}%") + $q->where('u.nama', 'ILIKE', "%{$search}%") + ->orWhere('u.identitas', 'ILIKE', "%{$search}%") + ->orWhere('u.unit_name', 'ILIKE', "%{$search}%") ->orWhere('u.tipe_karyawan','ILIKE', "%{$search}%"); }); } - // ---------------------------------------------------------------- - // Hitung total SEKALI dengan conditional aggregate - // Hindari eksekusi query count dua kali - // ---------------------------------------------------------------- - $counts = (clone $base) - ->selectRaw('count(*) as total') - ->first(); + // ── Count — eksekusi SEKALI ────────────────────────────────────── + $recordsFiltered = (clone $base)->count(); + $recordsTotal = $search === '' ? $recordsFiltered + : DB::connection('pgsql')->query()->fromSub($union, 'u')->count(); - $recordsFiltered = (int) ($counts->total ?? 0); - $recordsTotal = $search === '' - ? $recordsFiltered - : (int) DB::connection('pgsql')->query()->fromSub($union, 'u')->count(); - - // ---------------------------------------------------------------- - // Ambil data dengan pagination - // ---------------------------------------------------------------- + // ── Fetch halaman ini saja ─────────────────────────────────────── $rows = (clone $base) ->select('u.*') ->orderByDesc('lulus_count') @@ -2166,22 +2131,25 @@ class PitStopController extends Controller ->limit($length) ->get(); - // ---------------------------------------------------------------- - // belum_steps: hanya ambil untuk baris yang ditampilkan saja (bukan semua) - // Jauh lebih efisien daripada subquery per-baris - // ---------------------------------------------------------------- - $pegawaiIds = $rows->where('tipe_karyawan', 'internal')->pluck('id')->toArray(); - $luarIds = $rows->where('tipe_karyawan', 'luar')->pluck('id')->toArray(); + // ── Batch query belum_steps (hanya untuk baris di halaman ini) ─── + $allSteps = DB::connection('pgsql') + ->table('public.masterpitstop') + ->where('statusenabled', true) + ->orderBy('id') + ->pluck('nama', 'id'); // [id => nama] - // Ambil step yang sudah lulus per pegawai (hanya untuk baris di halaman ini) + $internalIds = $rows->where('tipe_karyawan', 'internal')->pluck('id')->toArray(); + $luarIds = $rows->where('tipe_karyawan', 'luar')->pluck('id')->toArray(); + + // Step yang sudah lulus, di-group per pegawai_id $lulusInternal = collect(); $lulusLuar = collect(); - if (!empty($pegawaiIds)) { + if (!empty($internalIds)) { $lulusInternal = DB::connection('pgsql') ->table('public.praakre as p') ->join('public.masterpitstop as ms', DB::raw('ms.id::text'), '=', 'p.masterpitstop_id') - ->whereIn('p.pegawai_id', $pegawaiIds) + ->whereIn('p.pegawai_id', $internalIds) ->where('ms.statusenabled', true) ->select('p.pegawai_id', 'ms.id as step_id') ->get() @@ -2200,42 +2168,29 @@ class PitStopController extends Controller ->groupBy('pegawai_id'); } - // Semua step aktif - $allSteps = DB::connection('pgsql') - ->table('public.masterpitstop') - ->where('statusenabled', true) - ->orderBy('id') - ->pluck('nama', 'id'); - - // ---------------------------------------------------------------- - // Map hasil - // ---------------------------------------------------------------- + // ── Map hasil ──────────────────────────────────────────────────── $data = $rows->map(function ($r) use ($totalSteps, $lulusInternal, $lulusLuar, $allSteps) { - $isLuar = $r->tipe_karyawan === 'luar'; - $lulusMap = $isLuar - ? ($lulusLuar->get($r->id) ?? collect()) - : ($lulusInternal->get($r->id) ?? collect()); + $isLuar = $r->tipe_karyawan === 'luar'; + $lulusMap = $isLuar ? ($lulusLuar->get($r->id) ?? collect()) + : ($lulusInternal->get($r->id) ?? collect()); + $lulusIds = $lulusMap->pluck('step_id')->toArray(); - $lulusStepIds = $lulusMap->pluck('step_id')->toArray(); - - $belumSteps = $allSteps - ->filter(fn($nama, $id) => !in_array($id, $lulusStepIds)) - ->values() + $belumSteps = $allSteps + ->filter(fn($nama, $id) => !in_array($id, $lulusIds)) ->implode(', '); - $lulus = (int) ($r->lulus_count ?? 0); - $belum = $totalSteps - $lulus; - $pct = $totalSteps > 0 ? round(($lulus / $totalSteps) * 100, 1) : 0; + $lulus = (int) ($r->lulus_count ?? 0); + $belum = max(0, $totalSteps - $lulus); return [ 'tipe_karyawan' => (string) ($r->tipe_karyawan ?? 'internal'), - 'id' => (int) ($r->id ?? 0), + 'id' => (int) ($r->id ?? 0), 'nama' => (string) ($r->nama ?? '-'), 'unit_name' => (string) ($r->unit_name ?? '-'), 'lulus_count' => $lulus, - 'pct' => $pct, - 'selesai' => $totalSteps > 0 ? ($lulus >= $totalSteps ? 1 : 0) : 0, - 'belum_count' => max(0, $belum), + 'pct' => $totalSteps > 0 ? round(($lulus / $totalSteps) * 100, 1) : 0, + 'selesai' => $totalSteps > 0 && $lulus >= $totalSteps ? 1 : 0, + 'belum_count' => $belum, 'belum_steps' => $belumSteps, ]; })->values(); diff --git a/storage/.gitignore b/storage/.gitignore new file mode 100644 index 0000000..e01eaa9 --- /dev/null +++ b/storage/.gitignore @@ -0,0 +1 @@ +/debugbar