loko/streetup/assets/templates/assets/components/inspection_form_modal.html

194 lines
13 KiB
HTML

{% load i18n %}
<!-- Modale de Saisie Rapide d'Inspection -->
<div class="modal fade" id="quickInspectionModal" tabindex="-1" aria-labelledby="quickInspectionModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg modal-dialog-centered">
<div class="modal-content shadow">
<div class="modal-header bg-light">
<h5 class="modal-title fw-bold" id="quickInspectionModalLabel">
<i class="bi bi-search text-primary me-2"></i>{% translate "Nouvelle inspection" %}
</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="{% translate 'Fermer' %}"></button>
</div>
<form id="quickInspectionForm" action="{% url 'assets:create_inspection_api' %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
<input type="hidden" name="content_type_id" id="insp_content_type_id">
<input type="hidden" name="object_id" id="insp_object_id">
<input type="hidden" name="nature" value="visual">
<input type="hidden" name="inspector_role" value="observer">
<div class="modal-body">
<!-- Target Card Preview -->
<div class="card mb-3 bg-light border-0">
<div class="card-body p-2 d-flex align-items-center justify-content-between">
<div>
<span class="badge bg-secondary mb-1" id="insp_target_type">Asset</span>
<h6 class="mb-0 fw-bold" id="insp_target_code">#12345</h6>
<small class="text-muted" id="insp_target_name">-</small>
</div>
<div class="text-end">
<span class="small text-muted d-block">{% translate "Statut actuel" %}</span>
<span class="badge bg-info text-dark" id="insp_target_status">-</span>
</div>
</div>
</div>
<div id="quickInspectionAlert" class="alert alert-danger d-none mb-3"></div>
<!-- Résultat de contrôle avec boutons colorés -->
<div class="mb-3">
<label class="form-label fw-semibold d-block">{% translate "Résultat du contrôle" %} <span class="text-danger">*</span></label>
<div class="d-flex flex-column gap-2" role="group" aria-label="{% translate 'Résultat' %}">
<div class="row g-2">
<div class="col-6">
<input type="radio" class="btn-check" name="result_status" id="res_compliant" value="compliant" checked>
<label class="btn btn-outline-success w-100 py-2 d-flex align-items-center justify-content-center gap-1" for="res_compliant">
<i class="bi bi-check-circle-fill"></i>
<span>{% translate "Conforme" %}</span>
</label>
</div>
<div class="col-6">
<input type="radio" class="btn-check" name="result_status" id="res_non_compliant" value="non_compliant">
<label class="btn btn-outline-warning text-dark w-100 py-2 d-flex align-items-center justify-content-center gap-1" for="res_non_compliant">
<i class="bi bi-exclamation-triangle-fill"></i>
<span>{% translate "Non conforme" %}</span>
</label>
</div>
</div>
<div class="row g-2">
<div class="col-4">
<input type="radio" class="btn-check" name="result_status" id="res_damaged" value="damaged">
<label class="btn btn-outline-danger w-100 py-2 d-flex align-items-center justify-content-center gap-1 small" for="res_damaged">
<i class="bi bi-x-circle-fill"></i>
<span>{% translate "Endommagé" %}</span>
</label>
</div>
<div class="col-4">
<input type="radio" class="btn-check" name="result_status" id="res_missing" value="missing">
<label class="btn btn-outline-dark w-100 py-2 d-flex align-items-center justify-content-center gap-1 small" for="res_missing">
<i class="bi bi-dash-circle-fill"></i>
<span>{% translate "Absent" %}</span>
</label>
</div>
<div class="col-4">
<input type="radio" class="btn-check" name="result_status" id="res_updated" value="updated">
<label class="btn btn-outline-info text-dark w-100 py-2 d-flex align-items-center justify-content-center gap-1 small" for="res_updated">
<i class="bi bi-pencil-square"></i>
<span>{% translate "Corrigé" %}</span>
</label>
</div>
</div>
</div>
</div>
<!-- Section Photos (Mode continu & Fichiers) -->
<div class="card border border-success-subtle mb-3" style="background-color: #e8f6f3;">
<div class="card-header bg-transparent border-0 pb-0 pt-2 px-3">
<span class="fw-bold text-dark small"><i class="bi bi-camera me-1 text-teal"></i>{% translate "Photos & Fichiers" %}</span>
</div>
<div class="card-body p-3">
<div class="d-grid gap-2">
<button type="button" id="insp_btn_continuous_camera" class="btn btn-outline-secondary bg-white text-dark py-2 d-flex align-items-center justify-content-center gap-2 shadow-sm" style="border-color: #ced4da;">
<i class="bi bi-camera me-1"></i>
<span>{% translate "Prendre des photos (mode continu)" %}</span>
</button>
<button type="button" id="insp_btn_gallery_files" class="btn btn-outline-secondary bg-white text-dark py-2 d-flex align-items-center justify-content-center gap-2 shadow-sm" style="border-color: #ced4da;">
<i class="bi bi-folder2-open me-1"></i>
<span>{% translate "Photos, vidéos, fichiers" %}</span>
</button>
</div>
<!-- Inputs masqués -->
<input type="file" id="insp_camera_input" accept="image/*" capture="environment" class="d-none">
<input type="file" id="insp_gallery_input" accept="image/*,.pdf,.doc,.docx,.xls,.xlsx" multiple class="d-none">
<!-- Grille de prévisualisation des photos/fichiers accumulés -->
<div id="insp_photos_preview_container" class="row g-2 mt-2"></div>
</div>
</div>
<!-- Champs spécifiques au type d'asset -->
<div id="assetSpecificFieldsContainer">
{% if inspection_template %}
{% include inspection_template %}
{% endif %}
</div>
<!-- Option Création automatique d'une intervention -->
<div class="form-check form-switch mb-3 bg-light p-2 rounded ps-4" id="createInterventionSwitchContainer">
<input class="form-check-input ms-0 me-2" type="checkbox" name="create_intervention" value="true" id="createInterventionSwitch">
<label class="form-check-label small fw-semibold" for="createInterventionSwitch">
{% translate "Créer automatiquement une intervention en cas d'anomalie / dégât" %}
</label>
</div>
<!-- Remarques -->
<div class="mb-3">
<label class="form-label fw-semibold mb-1">{% translate "Remarques / Remarques du constat" %}</label>
<textarea name="notes" id="insp_notes" class="form-control" rows="2" placeholder="{% translate 'Saisir vos remarques ou détails...' %}"></textarea>
</div>
</div>
<div class="modal-footer bg-light">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{% translate "Annuler" %}</button>
<button type="submit" class="btn btn-primary" id="submitQuickInspectionBtn">
<span class="spinner-border spinner-border-sm me-1 d-none" id="submitQuickInspectionSpinner"></span>
<i class="bi bi-check-lg me-1" id="submitQuickInspectionIcon"></i>
{% translate "Valider l'inspection" %}
</button>
</div>
</form>
</div>
</div>
</div>
<!-- Modal caméra Canvas (mode continu pour inspection) -->
<div class="modal fade" id="inspCameraModal" tabindex="-1" aria-labelledby="inspCameraModalLabel" aria-hidden="true" style="z-index: 1060;">
<div class="modal-dialog modal-fullscreen-sm-down d-flex m-0 h-100 mx-auto">
<div class="modal-content bg-dark text-white d-flex flex-column">
<div class="modal-header border-0 flex-shrink-0 py-2">
<h5 class="modal-title fw-bold" id="inspCameraModalLabel">
<i class="bi bi-camera-video me-1"></i>{% translate "Caméra (Mode continu)" %}
</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="{% translate 'Fermer' %}" id="inspCameraModalCloseBtn"></button>
</div>
<div class="modal-body d-flex flex-column p-2 flex-grow-1" style="overflow: hidden; min-height: 0;">
<div class="flex-grow-1 d-flex align-items-center justify-content-center" style="min-height: 0; overflow: hidden;">
<div class="position-relative w-100 h-100 d-flex align-items-center justify-content-center" style="border-radius: 0.5rem; overflow: hidden;">
<video id="inspCameraPreview" playsinline autoplay style="max-width: 100%; max-height: 100%; object-fit: contain;"></video>
<div id="inspCameraFlashOverlay" style="position: absolute; inset: 0; background: rgba(255, 255, 255, 0.9); opacity: 0; pointer-events: none; transition: opacity 120ms ease-out; z-index: 2;"></div>
<canvas id="inspCameraCanvas" class="d-none"></canvas>
</div>
</div>
<div id="inspCameraStatus" class="small text-center text-muted my-2 flex-shrink-0"></div>
<div class="d-flex justify-content-between align-items-center gap-2 mb-2 flex-shrink-0">
<button type="button" class="btn btn-outline-light flex-fill py-2" id="inspCameraStopBtn">
<i class="bi bi-x-circle me-1"></i>{% translate "Terminer" %}
</button>
<button type="button" class="btn btn-primary flex-fill py-2 fw-semibold" id="inspCameraCaptureBtn">
<i class="bi bi-camera-fill me-1"></i>{% translate "Capturer" %}
</button>
</div>
</div>
</div>
</div>
</div>
<!-- Modale de Choix d'Asset (Zone dense / Sélection multiple) -->
<div class="modal fade" id="targetChooserModal" tabindex="-1" aria-labelledby="targetChooserModalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content shadow">
<div class="modal-header bg-light">
<h5 class="modal-title fw-bold" id="targetChooserModalLabel">
<i class="bi bi-geo-fill text-primary me-2"></i>{% translate "Choisir un équipement à inspecter" %}
</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="{% translate 'Fermer' %}"></button>
</div>
<div class="modal-body p-2">
<p class="text-muted small px-2 mb-2">{% translate "Plusieurs équipements ont été détectés à cet emplacement. Veuillez sélectionner celui à inspecter :" %}</p>
<div class="list-group" id="targetChooserList"></div>
</div>
</div>
</div>
</div>