feat: Plan 5 — Ekspor PDF + Ekspor per Radius + Cetak Laporan

- Add ExportController: allMiskinPDF (all data) + radiusMiskinPDF
  (server-side Haversine filtering per ibadah radius)
- Add two table-based PDF Blade views (dompdf-compatible, no flexbox/grid)
- Add export routes (/export/pdf, /export/pdf/radius/{id}/{radius})
  with numeric route constraints
- Add "Ekspor PDF" button to data tabular view
- Add CSV + PDF radius export buttons to map analysis panel;
  exportRadiusCSV() reuses existing isInside(); PDF href synced on
  ibadah click and radius slider change
- 5 new tests: access control, PDF content-type, 404 + param validation
- Mark K-04 and Section 5 (Cetak & Ekspor) complete in missing_features.md
- Update README with export features

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
GuavaPopper
2026-06-03 20:44:10 +07:00
parent 4649a983ef
commit 1fcad7d9b2
9 changed files with 327 additions and 9 deletions
+51
View File
@@ -0,0 +1,51 @@
<?php
namespace App\Http\Controllers;
use App\Models\RumahIbadah;
use App\Models\RumahMiskin;
use Barryvdh\DomPDF\Facade\Pdf;
use Illuminate\Support\Str;
class ExportController extends Controller
{
public function allMiskinPDF()
{
$miskin = RumahMiskin::orderBy('kondisi_rumah')->get();
$ibadahCount = RumahIbadah::count();
$totalJiwa = $miskin->sum('jumlah_orang');
$totalKK = $miskin->sum('jumlah_kk');
$pdf = Pdf::loadView('exports.laporan-miskin', compact('miskin', 'ibadahCount', 'totalJiwa', 'totalKK'));
$pdf->setPaper('a4', 'landscape');
return $pdf->download('laporan-keluarga-miskin.pdf');
}
public function radiusMiskinPDF(int $ibadahId, int $radius)
{
$ibadah = RumahIbadah::findOrFail($ibadahId);
$allMiskin = RumahMiskin::all();
$miskin = $allMiskin->filter(fn($m) => $this->haversineDistance(
$ibadah->latitude, $ibadah->longitude,
$m->latitude, $m->longitude
) <= $radius);
$totalJiwa = $miskin->sum('jumlah_orang');
$totalKK = $miskin->sum('jumlah_kk');
$pdf = Pdf::loadView('exports.laporan-radius', compact('ibadah', 'miskin', 'radius', 'totalJiwa', 'totalKK'));
$pdf->setPaper('a4', 'portrait');
$filename = 'laporan-radius-' . Str::slug($ibadah->nama) . '-' . $radius . 'm.pdf';
return $pdf->download($filename);
}
private function haversineDistance(float $lat1, float $lon1, float $lat2, float $lon2): float
{
$R = 6371000;
$dLat = deg2rad($lat2 - $lat1);
$dLon = deg2rad($lon2 - $lon1);
$a = sin($dLat / 2) ** 2 + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * sin($dLon / 2) ** 2;
return 2 * $R * asin(sqrt($a));
}
}