project = $project; // Cargar fases con sus capas y los features de esas capas (para mostrarlos en el mapa) $this->phases = $project->phases()->with(['layers.features'])->get(); // Por defecto mostrar todas las capas activas (todas las fases que tengan alguna capa con features) $this->activeLayers = $this->phases->pluck('id')->toArray(); $this->loadTemplates(); } public function loadTemplates() { $this->templates = InspectionTemplate::where('project_id', $this->project->id)->get(); } public function toggleLayer($phaseId) { if (in_array($phaseId, $this->activeLayers)) { $this->activeLayers = array_diff($this->activeLayers, [$phaseId]); } else { $this->activeLayers[] = $phaseId; } $this->dispatch('layersUpdated', $this->activeLayers); } /** * Actualizar el progreso de un Feature y recalcular el progreso de la fase. */ public function updateProgress($featureId, $newProgress, $comment = null) { $feature = Feature::findOrFail($featureId); $user = Auth::user(); if (!$user->can('update progress') && !$user->hasRole('Admin')) { $this->dispatch('notify', 'Sin permisos'); return; } $oldProgress = $feature->progress; $feature->progress = min(100, max(0, $newProgress)); $feature->save(); // Recalcular el progreso de la fase (promedio de todos sus features) $phase = Phase::find($feature->layer->phase_id); $phase->progress_percent = $phase->features()->avg('progress') ?: 0; $phase->save(); // Registrar la actualización en progress_updates $phase->progressUpdates()->create([ 'user_id' => $user->id, 'progress_percent' => $phase->progress_percent, 'comment' => $comment, ]); $this->dispatch('progressUpdated', $featureId, $feature->progress); $this->dispatch('notify', 'Progreso actualizado'); // Si el feature seleccionado es el mismo, actualizar la propiedad local if ($this->selectedFeature && $this->selectedFeature->id == $featureId) { $this->selectedFeature->progress = $feature->progress; $this->editProgress = $feature->progress; } } /** * Seleccionar un Feature al hacer clic en el mapa. */ public function selectFeature($featureId) { $feature = Feature::with('template')->find($featureId); if (!$feature) return; $this->selectedFeature = $feature; $this->selectedPhaseId = $feature->layer->phase_id; $this->editProgress = $feature->progress; $this->editResponsible = $feature->responsible ?? ''; $this->editPhotos = $feature->properties['photos'] ?? []; $this->selectedTemplateId = $feature->template_id; $this->loadInspectionHistory(); $this->resetInspectionForm(); $this->dispatch('featureSelected', $featureId); } /** * Cargar el historial de inspecciones del feature seleccionado. */ public function loadInspectionHistory() { if (!$this->selectedFeature) { $this->inspectionHistory = []; return; } $this->inspectionHistory = Inspection::where('feature_id', $this->selectedFeature->id) ->with('user', 'template') ->orderBy('created_at', 'desc') ->get(); } /** * Reiniciar el formulario de inspección según el template seleccionado. */ public function resetInspectionForm() { $this->inspectionFormData = []; if ($this->selectedTemplateId) { $template = InspectionTemplate::find($this->selectedTemplateId); if ($template) { foreach ($template->fields as $field) { $this->inspectionFormData[$field['name']] = ''; } } } } /** * Guardar una nueva inspección. */ public function saveInspection() { if (!$this->selectedFeature || !$this->selectedTemplateId) { $this->dispatch('notify', 'Selecciona un elemento y un template.'); return; } $this->validate([ 'selectedTemplateId' => 'required|exists:inspection_templates,id', ]); $template = InspectionTemplate::find($this->selectedTemplateId); foreach ($template->fields as $field) { if (($field['required'] ?? false) && empty($this->inspectionFormData[$field['name']])) { $this->dispatch('notify', "El campo {$field['label']} es obligatorio."); return; } } $inspection = Inspection::create([ 'project_id' => $this->project->id, 'layer_id' => $this->selectedFeature->layer_id, 'feature_id' => $this->selectedFeature->id, 'template_id' => $this->selectedTemplateId, 'user_id' => auth()->id(), 'data' => $this->inspectionFormData, ]); // Si el template tiene un campo llamado 'progress', actualizar el progreso del feature if (isset($this->inspectionFormData['progress'])) { $this->updateProgress($this->selectedFeature->id, (int)$this->inspectionFormData['progress'], 'Inspección registrada'); } $this->loadInspectionHistory(); $this->resetInspectionForm(); $this->dispatch('notify', 'Inspección guardada correctamente'); } /** * Asignar un template al feature seleccionado. */ public function assignTemplateToFeature($templateId) { if (!$this->selectedFeature) return; $this->selectedFeature->template_id = $templateId; $this->selectedFeature->save(); $this->selectedTemplateId = $templateId; $this->resetInspectionForm(); $this->dispatch('notify', 'Template asignado al elemento'); } public function toggleFullscreen() { $this->formFullscreen = !$this->formFullscreen; if (!$this->formFullscreen) { $this->dispatch('mapResize'); } } public function render() { return view('livewire.projects.project-map', [ 'project' => $this->project, 'phases' => $this->phases, ]); } }