@php /* ── Precompute chart data ── */ $proposals = $data['proposals']; $statusColors = [ 'draft' => '#94a3b8', 'internal_review' => '#60a5fa', 'client_review' => '#38bdf8', 'final' => '#fb923c', 'submitted' => '#34d399', 'won' => '#16a34a', 'lost' => '#ef4444', 'cancelled' => '#c084fc', ]; $statusLabels = [ 'draft' => 'Draft', 'internal_review' => 'Internal Review', 'client_review' => 'Client Review', 'final' => 'Final', 'submitted' => 'Submitted', 'won' => 'Won', 'lost' => 'Lost', 'cancelled' => 'Cancelled', ]; $statusDist = []; foreach ($proposals as $p) { $k = $p->status?->value ?? 'unknown'; $statusDist[$k] = ($statusDist[$k] ?? 0) + 1; } arsort($statusDist); $totalForPct = array_sum($statusDist) ?: 1; $barMax = max(array_values($statusDist) ?: [1]); /* Client distribution (top 6) */ $clientDist = []; foreach ($proposals as $p) { $name = $p->tender?->client?->name ?? 'Tidak diketahui'; $clientDist[$name] = ($clientDist[$name] ?? 0) + 1; } arsort($clientDist); $clientDist = array_slice($clientDist, 0, 6, true); $clientMax = max(array_values($clientDist) ?: [1]); $clientColors = ['#465fff','#38bdf8','#34d399','#fb923c','#a78bfa','#fbbf24']; /* SVG donut */ function donutSlicesP(array $dist, array $colors, int $cx, int $cy, int $r, int $innerR): string { $total = array_sum($dist) ?: 1; $angle = -90; $svg = ''; $i = 0; foreach ($dist as $key => $val) { $pct = $val / $total; $sweep = 360 * $pct; if ($sweep >= 359.9) $sweep = 359.9; $r1 = deg2rad($angle); $r2 = deg2rad($angle + $sweep); $x1 = $cx + $r * cos($r1); $y1 = $cy + $r * sin($r1); $x2 = $cx + $r * cos($r2); $y2 = $cy + $r * sin($r2); $xi1 = $cx + $innerR * cos($r1); $yi1 = $cy + $innerR * sin($r1); $xi2 = $cx + $innerR * cos($r2); $yi2 = $cy + $innerR * sin($r2); $large = $sweep > 180 ? 1 : 0; $color = $colors[$i % count($colors)]; $svg .= ""; $angle += $sweep; $i++; } return $svg; } @endphp {{-- ── HEADER ── --}}
Raya Tender
Laporan Proposal
PT. Raya Konstruksi Internasional · Dicetak: {{ now()->format('d F Y, H:i') }} @if(!empty($filters['start_date'])) · Periode: {{ $filters['start_date'] }} s/d {{ $filters['end_date'] ?? now()->format('Y-m-d') }} @endif @if(!empty($filters['status'])) · Status: {{ strtoupper($filters['status']) }} @endif
{{-- ── TABLE ── --}}
Daftar Proposal
@forelse($data['proposals'] as $p) @php $sk = 's-' . ($p->status?->value ?? 'default'); @endphp @empty @endforelse
Kode Judul Proposal Tender Klien PIC Status Versi Deadline
{{ $p->code }} {{ $p->title }} {{ $p->tender?->code ?? '—' }} {{ $p->tender?->client?->name ?? '—' }} {{ $p->pic?->name ?? '—' }} {{ $p->status?->label() }} v{{ $p->current_version }} {{ $p->deadline?->format('d/m/Y') ?? '—' }}
Tidak ada data proposal

{{-- ── STATS ── --}}
{{ $data['total'] }}
Total
{{ $data['draft'] }}
Draft
{{ $data['internal_review'] }}
Review
{{ $data['submitted'] }}
Submitted
{{ $data['final'] ?? 0 }}
Final
{{-- ── CHARTS ── --}}
{{-- Bar chart: Status Distribution --}}
Distribusi Status Proposal
@foreach($statusDist as $key => $cnt) @php $pct = $barMax > 0 ? round(($cnt / $barMax) * 100) : 0; $color = $statusColors[$key] ?? '#94a3b8'; @endphp
{{ $statusLabels[$key] ?? ucfirst($key) }}
{{ $cnt }}
@endforeach
{{-- Donut: Top Clients --}}
Top Klien
@php $svgSize = 110; $cx = 55; $cy = 55; $r = 46; $innerR = 28; $totalC = array_sum($clientDist) ?: 1; $donutSvg = donutSlicesP($clientDist, $clientColors, $cx, $cy, $r, $innerR); @endphp
{!! $donutSvg !!} {{ $totalC }} proposal
@foreach($clientDist as $name => $cnt) @php $color = $clientColors[array_search($name, array_keys($clientDist)) % count($clientColors)]; @endphp
{{ Str::limit($name, 20) }}
{{ $cnt }} ({{ round($cnt/$totalC*100) }}%)
@endforeach
{{-- ── FOOTER ── --}}