Files
construprogress/resources/views/emails/scheduled-report.blade.php
T

157 lines
9.5 KiB
PHP
Raw Normal View History

2026-09-01 13:23:20 +02:00
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Informe Programado - {{ $project->name }}</title>
<style>
body { font-family: 'Segoe UI', Arial, sans-serif; font-size: 14px; color: #1f2937; line-height: 1.6; margin: 0; padding: 20px; background: #f8fafc; }
.container { max-width: 700px; margin: 0 auto; background: #fff; border-radius: 8px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); overflow: hidden; }
.header { background: #1e3a8a; color: #fff; padding: 24px; }
.header h1 { margin: 0; font-size: 24px; font-weight: 700; }
.header p { margin: 8px 0 0; opacity: 0.9; font-size: 14px; }
.content { padding: 24px; }
.stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; margin-bottom: 24px; }
.stat { background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 8px; padding: 16px; text-align: center; }
.stat-value { font-size: 28px; font-weight: 700; color: #2563eb; line-height: 1; }
.stat-label { font-size: 12px; color: #6b7280; margin-top: 4px; text-transform: uppercase; letter-spacing: 0.03em; }
.stat-value.completed { color: #22c55e; }
.stat-value.issues { color: #ef4444; }
.section { margin-bottom: 24px; }
.section-title { font-size: 16px; font-weight: 700; color: #1e3a8a; border-bottom: 2px solid #e5e7eb; padding-bottom: 8px; margin-bottom: 16px; }
.phase { border: 1px solid #e5e7eb; border-radius: 8px; margin-bottom: 12px; overflow: hidden; }
.phase-header { background: #f8fafc; padding: 12px 16px; border-left: 4px solid #3b82f6; display: flex; justify-content: space-between; align-items: center; }
.phase-name { font-weight: 700; color: #1e3a8a; font-size: 14px; }
.phase-progress { font-weight: 700; color: #3b82f6; }
.phase-table { width: 100%; border-collapse: collapse; font-size: 13px; }
.phase-table th { background: #f1f5f9; padding: 8px 12px; text-align: left; font-weight: 600; color: #374151; border-bottom: 1px solid #cbd5e1; }
.phase-table td { padding: 8px 12px; border-bottom: 1px solid #e5e7eb; }
.badge { display: inline-block; padding: 2px 8px; border-radius: 9999px; font-size: 10px; font-weight: 600; text-transform: uppercase; }
.badge-planned { background: #f3f4f6; color: #6b7280; }
.badge-in_progress { background: #fef3c7; color: #92400e; }
.badge-completed { background: #d1fae5; color: #065f46; }
.badge-verified { background: #ede9fe; color: #5b21b6; }
.progress-bar { background: #e5e7eb; border-radius: 4px; height: 6px; width: 80px; overflow: hidden; }
.progress-bar-fill { height: 100%; border-radius: 4px; background: #22c55e; }
.footer { background: #f8fafc; border-top: 1px solid #e5e7eb; padding: 16px 24px; font-size: 12px; color: #9ca3af; text-align: center; }
@media print { .container { box-shadow: none; } }
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>{{ $project->name }}</h1>
<p>Informe programado generado el {{ now()->format('d/m/Y H:i') }}</p>
</div>
<div class="content">
<div class="stats">
<div class="stat">
<div class="stat-value">{{ $data['stats']['total_features'] ?? 0 }}</div>
<div class="stat-label">Total elementos</div>
</div>
<div class="stat">
<div class="stat-value completed">{{ $data['stats']['completed_features'] ?? 0 }}</div>
<div class="stat-label">Completados</div>
</div>
<div class="stat">
<div class="stat-value">{{ round($data['stats']['avg_progress'] ?? 0) }}%</div>
<div class="stat-label">Progreso medio</div>
</div>
</div>
<div class="section">
<div class="section-title">Detalle por Fase</div>
@forelse($data['phases'] as $phase)
@php
$phaseFeatures = $phase->layers->flatMap(fn($l) => $l->features);
$phaseColor = $phase->color ?? '#3b82f6';
@endphp
<div class="phase" style="border-left-color:{{ $phaseColor }};">
<div class="phase-header" style="border-left-color:{{ $phaseColor }};">
<div>
<div class="phase-name">{{ $phase->name }}</div>
<div style="font-size:12px;color:#6b7280;">
@if($phase->planned_start)
{{ $phase->planned_start->format('d/m/Y') }} {{ $phase->planned_end?->format('d/m/Y') ?? 'Sin fecha fin' }}
@else
Sin fechas planificadas
@endif
&nbsp;&bull;&nbsp; {{ $phaseFeatures->count() }} elementos
</div>
</div>
<div style="text-align:right;">
<div style="font-size:16px;font-weight:700;color:{{ $phaseColor }};">{{ $phase->progress_percent ?? 0 }}%</div>
<div class="progress-bar" style="margin-top:4px;">
<div class="progress-bar-fill" style="width:{{ min(100, $phase->progress_percent ?? 0) }}%;background:{{ $phaseColor }};"></div>
</div>
</div>
</div>
@if($phaseFeatures->count() > 0)
<table class="phase-table">
<thead>
<tr>
<th>Elemento</th>
<th>Estado</th>
<th>Progreso</th>
<th>Responsable</th>
</tr>
</thead>
<tbody>
@foreach($phaseFeatures as $feature)
<tr>
<td>{{ $feature->name ?? 'Sin nombre' }}</td>
<td>
<span class="badge badge-{{ $feature->status ?? 'planned' }}">
{{ match($feature->status) {
'planned' => 'Planificado',
'started' => 'Iniciado',
'in_progress' => 'En progreso',
'completed' => 'Completado',
'verified' => 'Verificado',
default => ($feature->status ?? 'N/A'),
} }}
</span>
</td>
<td>
<div style="display:flex;align-items:center;gap:6px;">
<div style="flex:1;background:#e5e7eb;border-radius:4px;height:6px;min-width:60px;">
<div class="progress-bar-fill" style="width:{{ min(100, $feature->progress ?? 0) }}%;background:{{ $phaseColor }};"></div>
</div>
<span style="font-size:11px;color:#6b7280;white-space:nowrap;">{{ $feature->progress ?? 0 }}%</span>
</div>
</td>
<td>{{ $feature->responsible ?? ($feature->responsibleUser?->name ?? '—') }}</td>
</tr>
@endforeach
</tbody>
</table>
@else
<div style="padding:12px 16px;color:#9ca3af;font-style:italic;font-size:12px;">
Sin elementos registrados en esta fase.
</div>
@endif
</div>
@empty
<div style="padding:16px;color:#9ca3af;text-align:center;font-style:italic;">
No hay fases registradas en este proyecto.
</div>
@endforelse
</div>
<div class="section">
<div class="section-title">Parámetros del Informe</div>
<p><strong>Rango de fechas:</strong> {{ $filters->date_from ? $filters->date_from->format('d/m/Y') : 'Sin fecha desde' }} {{ $filters->date_to ? $filters->date_to->format('d/m/Y') : 'Sin fecha hasta' }}</p>
<p><strong>Secciones:</strong> {{ implode(', ', collect($filters->entity_types)->map(fn ($k) => ucfirst(str_replace('_', ' ', $k)))->toArray()) }}</p>
<p><strong>Incluir fotos:</strong> {{ $filters->include_photos ? 'Sí' : 'No' }}</p>
<p><strong>Incluir gráficos:</strong> {{ $filters->include_charts ? 'Sí' : 'No' }}</p>
</div>
</div>
<div class="footer">
ConstruProgress Sistema de Gestión de Obras<br>
Informe generado automáticamente el {{ now()->format('d/m/Y H:i') }}
</div>
</div>
</body>
</html>