fixing persentase data in datatable ghost

This commit is contained in:
JokoPrasetio 2026-05-20 14:53:14 +07:00
parent e13f9d458e
commit 7ffb802f3e
2 changed files with 48 additions and 92 deletions

View File

@ -2058,53 +2058,32 @@ class PitStopController extends Controller
$totalSteps = (int) MasterPitStopPraAkre::where('statusenabled', true)->count(); $totalSteps = (int) MasterPitStopPraAkre::where('statusenabled', true)->count();
// ---------------------------------------------------------------- // ── Internal ────────────────────────────────────────────────────
// 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 = DB::connection('pgsql') $internal = DB::connection('pgsql')
->table('public.mappegawaijabatantounitkerja_m as mp') ->table('public.mappegawaijabatantounitkerja_m as mp')
->join('public.pegawai_m as pg', 'pg.id', '=', 'mp.objectpegawaifk') ->join('public.pegawai_m as pg', 'pg.id', '=', 'mp.objectpegawaifk')
->join('public.unitkerjapegawai_m as ukp', 'ukp.id', '=', 'mp.objectunitkerjapegawaifk') ->join('public.unitkerjapegawai_m as ukp', 'ukp.id', '=', 'mp.objectunitkerjapegawaifk')
->leftJoin('public.praakre as p', function ($join) { ->leftJoin('public.praakre as p', 'p.pegawai_id', '=', 'pg.id')
$join->on('p.pegawai_id', '=', 'pg.id')
->where('p.tipe_karyawan', '!=', 'luar'); // pastikan hanya internal
})
->leftJoin('public.masterpitstop as m', function ($join) { ->leftJoin('public.masterpitstop as m', function ($join) {
$join->on(DB::raw('m.id::text'), '=', 'p.masterpitstop_id') $join->on(DB::raw('m.id::text'), '=', 'p.masterpitstop_id')
->where('m.statusenabled', true); ->where('m.statusenabled', true);
}) })
->where('mp.statusenabled', true) ->where('mp.statusenabled', true)
->where('mp.isprimary', true) ->where('mp.isprimary', true)
->where('pg.statusenabled', true) ->where('pg.statusenabled', true)
->where('pg.kedudukanfk', 1) ->where('pg.kedudukanfk', 1)
->where('ukp.statusenabled', true) ->where('ukp.statusenabled', true)
->select([ ->select([
DB::raw("'internal' as tipe_karyawan"), DB::raw("'internal' as tipe_karyawan"),
'pg.id', 'pg.id',
DB::raw("coalesce(pg.namalengkap, '-') as nama"), 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("coalesce(ukp.name, '-') as unit_name"),
DB::raw("count(distinct m.id) as lulus_count"), 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'); ->groupBy('pg.id', 'pg.namalengkap', 'pg.nip_pns', 'ukp.name');
// ---------------------------------------------------------------- // ── External ────────────────────────────────────────────────────
// External query
// ----------------------------------------------------------------
$external = DB::connection('pgsql') $external = DB::connection('pgsql')
->table('public.pegawai_luar_pl as pl') ->table('public.pegawai_luar_pl as pl')
->leftJoin('public.praakre as p', function ($join) { ->leftJoin('public.praakre as p', function ($join) {
@ -2119,45 +2098,31 @@ class PitStopController extends Controller
DB::raw("'luar' as tipe_karyawan"), DB::raw("'luar' as tipe_karyawan"),
'pl.id', 'pl.id',
DB::raw("coalesce(pl.nama, '-') as nama"), 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("coalesce(nullif(btrim(pl.tipe), ''), '-') as unit_name"),
DB::raw("count(distinct m.id) as lulus_count"), 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), ''), '-')")); ->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') // ── Union & Base ─────────────────────────────────────────────────
->query() $union = $internal->unionAll($external);
->fromSub($union, 'u'); $base = DB::connection('pgsql')->query()->fromSub($union, 'u');
if ($search !== '') { if ($search !== '') {
$base->where(function ($q) use ($search) { $base->where(function ($q) use ($search) {
$q->where('u.nama', 'ILIKE', "%{$search}%") $q->where('u.nama', 'ILIKE', "%{$search}%")
->orWhere('u.unit_name', 'ILIKE', "%{$search}%") ->orWhere('u.identitas', 'ILIKE', "%{$search}%")
->orWhere('u.unit_name', 'ILIKE', "%{$search}%")
->orWhere('u.tipe_karyawan','ILIKE', "%{$search}%"); ->orWhere('u.tipe_karyawan','ILIKE', "%{$search}%");
}); });
} }
// ---------------------------------------------------------------- // ── Count — eksekusi SEKALI ──────────────────────────────────────
// Hitung total SEKALI dengan conditional aggregate $recordsFiltered = (clone $base)->count();
// Hindari eksekusi query count dua kali $recordsTotal = $search === '' ? $recordsFiltered
// ---------------------------------------------------------------- : DB::connection('pgsql')->query()->fromSub($union, 'u')->count();
$counts = (clone $base)
->selectRaw('count(*) as total')
->first();
$recordsFiltered = (int) ($counts->total ?? 0); // ── Fetch halaman ini saja ───────────────────────────────────────
$recordsTotal = $search === ''
? $recordsFiltered
: (int) DB::connection('pgsql')->query()->fromSub($union, 'u')->count();
// ----------------------------------------------------------------
// Ambil data dengan pagination
// ----------------------------------------------------------------
$rows = (clone $base) $rows = (clone $base)
->select('u.*') ->select('u.*')
->orderByDesc('lulus_count') ->orderByDesc('lulus_count')
@ -2166,22 +2131,25 @@ class PitStopController extends Controller
->limit($length) ->limit($length)
->get(); ->get();
// ---------------------------------------------------------------- // ── Batch query belum_steps (hanya untuk baris di halaman ini) ───
// belum_steps: hanya ambil untuk baris yang ditampilkan saja (bukan semua) $allSteps = DB::connection('pgsql')
// Jauh lebih efisien daripada subquery per-baris ->table('public.masterpitstop')
// ---------------------------------------------------------------- ->where('statusenabled', true)
$pegawaiIds = $rows->where('tipe_karyawan', 'internal')->pluck('id')->toArray(); ->orderBy('id')
$luarIds = $rows->where('tipe_karyawan', 'luar')->pluck('id')->toArray(); ->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(); $lulusInternal = collect();
$lulusLuar = collect(); $lulusLuar = collect();
if (!empty($pegawaiIds)) { if (!empty($internalIds)) {
$lulusInternal = DB::connection('pgsql') $lulusInternal = DB::connection('pgsql')
->table('public.praakre as p') ->table('public.praakre as p')
->join('public.masterpitstop as ms', DB::raw('ms.id::text'), '=', 'p.masterpitstop_id') ->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) ->where('ms.statusenabled', true)
->select('p.pegawai_id', 'ms.id as step_id') ->select('p.pegawai_id', 'ms.id as step_id')
->get() ->get()
@ -2200,42 +2168,29 @@ class PitStopController extends Controller
->groupBy('pegawai_id'); ->groupBy('pegawai_id');
} }
// Semua step aktif // ── Map hasil ────────────────────────────────────────────────────
$allSteps = DB::connection('pgsql')
->table('public.masterpitstop')
->where('statusenabled', true)
->orderBy('id')
->pluck('nama', 'id');
// ----------------------------------------------------------------
// Map hasil
// ----------------------------------------------------------------
$data = $rows->map(function ($r) use ($totalSteps, $lulusInternal, $lulusLuar, $allSteps) { $data = $rows->map(function ($r) use ($totalSteps, $lulusInternal, $lulusLuar, $allSteps) {
$isLuar = $r->tipe_karyawan === 'luar'; $isLuar = $r->tipe_karyawan === 'luar';
$lulusMap = $isLuar $lulusMap = $isLuar ? ($lulusLuar->get($r->id) ?? collect())
? ($lulusLuar->get($r->id) ?? collect()) : ($lulusInternal->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, $lulusIds))
$belumSteps = $allSteps
->filter(fn($nama, $id) => !in_array($id, $lulusStepIds))
->values()
->implode(', '); ->implode(', ');
$lulus = (int) ($r->lulus_count ?? 0); $lulus = (int) ($r->lulus_count ?? 0);
$belum = $totalSteps - $lulus; $belum = max(0, $totalSteps - $lulus);
$pct = $totalSteps > 0 ? round(($lulus / $totalSteps) * 100, 1) : 0;
return [ return [
'tipe_karyawan' => (string) ($r->tipe_karyawan ?? 'internal'), 'tipe_karyawan' => (string) ($r->tipe_karyawan ?? 'internal'),
'id' => (int) ($r->id ?? 0), 'id' => (int) ($r->id ?? 0),
'nama' => (string) ($r->nama ?? '-'), 'nama' => (string) ($r->nama ?? '-'),
'unit_name' => (string) ($r->unit_name ?? '-'), 'unit_name' => (string) ($r->unit_name ?? '-'),
'lulus_count' => $lulus, 'lulus_count' => $lulus,
'pct' => $pct, 'pct' => $totalSteps > 0 ? round(($lulus / $totalSteps) * 100, 1) : 0,
'selesai' => $totalSteps > 0 ? ($lulus >= $totalSteps ? 1 : 0) : 0, 'selesai' => $totalSteps > 0 && $lulus >= $totalSteps ? 1 : 0,
'belum_count' => max(0, $belum), 'belum_count' => $belum,
'belum_steps' => $belumSteps, 'belum_steps' => $belumSteps,
]; ];
})->values(); })->values();

1
storage/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/debugbar