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

194 lines
11 KiB
HTML

{% load i18n static inspections_tags %}
{# Inspections et contrôles liés à l'asset #}
<div class="card mb-3" id="asset-inspections-card">
<div class="card-header bg-light d-flex align-items-center justify-content-between">
<h5 class="mb-0 fs-6 fw-bold">
<i class="bi bi-patch-check me-2 text-primary"></i>{% translate "Inspections et contrôles terrain" %}
{% if inspections %}
<span class="badge bg-secondary rounded-pill ms-1">{{ total_count }}</span>
{% endif %}
</h5>
{% if can_inspect %}
<button type="button"
class="btn btn-outline-primary btn-sm btn-trigger-asset-inspection"
data-bs-toggle="modal"
data-bs-target="#quickInspectionModal"
data-content-type-id="{{ asset_ct_id }}"
data-object-id="{{ asset_pk }}"
data-target-code="{{ asset.code|default:asset.pk }}"
data-target-name="{{ asset.name_fr|default:asset.name_nl|default:asset }}"
data-target-type="{{ asset.category.name_fr|default:'Asset' }}"
data-target-status="{{ asset.get_status_display|default:asset.inspection_status|default:'-' }}">
<i class="bi bi-plus-lg me-1"></i>{% translate "Nouvelle inspection" %}
</button>
{% endif %}
</div>
<div class="card-body p-0">
{% if inspections %}
<div class="table-responsive">
<table class="table table-hover table-sm mb-0 align-middle">
<thead class="table-light">
<tr>
<th style="width: 15%;" class="ps-3">{% translate "Date & Heure" %}</th>
<th style="width: 18%;">{% translate "Statut du contrôle" %}</th>
<th style="width: 15%;">{% translate "Nature" %}</th>
<th style="width: 20%;">{% translate "Inspecteur" %}</th>
<th style="width: 22%;">{% translate "Remarques" %}</th>
<th style="width: 10%;" class="pe-3 text-end">{% translate "Action" %}</th>
</tr>
</thead>
<tbody>
{% for insp in inspections %}
<tr>
<td class="ps-3 fw-semibold">
{{ insp.inspection_date|date:"d/m/Y H:i" }}
</td>
<td>
<span class="badge {{ insp.status_badge_class }}">
<i class="bi {{ insp.status_icon }} me-1"></i>{{ insp.get_result_status_display }}
</span>
</td>
<td>
<span class="badge bg-light text-dark border">{{ insp.get_nature_display }}</span>
</td>
<td>
<i class="bi bi-person me-1 text-muted"></i>{{ insp.inspector.get_full_name|default:insp.inspector.username|default:"-" }}
</td>
<td>
<span class="small text-muted text-truncate d-inline-block" style="max-width: 220px;" title="{{ insp.details_summary }}">
{{ insp.details_summary }}
</span>
</td>
<td class="pe-3 text-end">
<button type="button" class="btn btn-xs btn-outline-primary px-2 py-1 rounded" data-bs-toggle="modal" data-bs-target="#assetInspectionDetailModal{{ insp.id }}">
<i class="bi bi-eye me-1"></i>{% translate "Détail" %}
</button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<div class="p-3 text-center text-muted small">
<i class="bi bi-info-circle fs-5 d-block mb-1 text-secondary"></i>
{% translate "Aucune inspection ni vérification enregistrée pour cet équipement." %}
</div>
{% endif %}
</div>
</div>
{% for insp in inspections %}
<!-- Modale de détail de l'inspection pour l'asset -->
<div class="modal fade" id="assetInspectionDetailModal{{ insp.id }}" tabindex="-1" aria-labelledby="assetInspectionDetailModalLabel{{ insp.id }}" aria-hidden="true">
<div class="modal-dialog modal-lg modal-dialog-centered">
<div class="modal-content border-0 shadow">
<div class="modal-header bg-light py-2.5">
<h5 class="modal-title fs-6 fw-bold" id="assetInspectionDetailModalLabel{{ insp.id }}">
<i class="bi bi-patch-check me-2 text-primary"></i>{% translate "Détail du contrôle" %} - {{ insp.inspection_date|date:"d/m/Y H:i" }}
</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body p-3">
<ul class="list-group list-group-flush mb-3">
<li class="list-group-item d-flex justify-content-between align-items-center px-0">
<span class="text-muted"><i class="bi bi-geo-alt me-1"></i>{% translate "Équipement cible" %}</span>
<span class="fw-bold text-end ms-2">{{ insp.target_display }}</span>
</li>
<li class="list-group-item d-flex justify-content-between align-items-center px-0">
<span class="text-muted"><i class="bi bi-calendar-event me-1"></i>{% translate "Date & Heure" %}</span>
<span class="fw-semibold">{{ insp.inspection_date|date:"d/m/Y H:i" }}</span>
</li>
<li class="list-group-item d-flex justify-content-between align-items-center px-0">
<span class="text-muted"><i class="bi bi-shield-check me-1"></i>{% translate "Résultat du contrôle" %}</span>
<span class="badge {{ insp.status_badge_class }}"><i class="bi {{ insp.status_icon }} me-1"></i>{{ insp.get_result_status_display }}</span>
</li>
<li class="list-group-item d-flex justify-content-between align-items-center px-0">
<span class="text-muted"><i class="bi bi-eye me-1"></i>{% translate "Nature" %}</span>
<span class="badge bg-light text-dark border">{{ insp.get_nature_display }}</span>
</li>
<li class="list-group-item d-flex justify-content-between align-items-center px-0">
<span class="text-muted"><i class="bi bi-person me-1"></i>{% translate "Inspecteur" %}</span>
<span class="fw-semibold">{{ insp.inspector.get_full_name|default:insp.inspector.username|default:"-" }}</span>
</li>
{% get_inspection_detail_template insp as detail_template %}
{% if detail_template %}
{% include detail_template with insp=insp %}
{% endif %}
</ul>
{% if insp.notes %}
<div class="mb-3">
<label class="form-label text-muted small fw-semibold"><i class="bi bi-journal-text me-1"></i>{% translate "Remarques / Observations" %}:</label>
<div class="p-2 bg-light rounded border text-secondary small">
{{ insp.notes|linebreaksbr }}
</div>
</div>
{% endif %}
{% if insp.documents.all %}
<div>
<label class="form-label text-muted small fw-semibold mb-2"><i class="bi bi-camera me-1"></i>{% translate "Photos & Documents joints" %} ({{ insp.documents.count }}):</label>
<div class="d-flex flex-wrap gap-2">
{% for doc in insp.documents.all %}
<a href="{{ doc.file_url }}" target="_blank" class="d-inline-block border rounded p-1 bg-light">
<img data-src="{{ doc.file_url }}" src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1 1'%3E%3C/svg%3E" loading="lazy" alt="Photo" class="rounded" style="width: 75px; height: 75px; object-fit: cover;">
</a>
{% endfor %}
</div>
</div>
{% endif %}
</div>
<div class="modal-footer py-2 bg-light">
<button type="button" class="btn btn-secondary btn-sm" data-bs-dismiss="modal">{% translate "Fermer" %}</button>
</div>
</div>
</div>
</div>
{% endfor %}
{% if can_inspect %}
{% include "inspections/components/inspection_form_modal.html" %}
<script>
document.addEventListener('DOMContentLoaded', function() {
const triggerBtns = document.querySelectorAll('.btn-trigger-asset-inspection');
triggerBtns.forEach(btn => {
btn.addEventListener('click', function() {
const ctId = this.getAttribute('data-content-type-id');
const objId = this.getAttribute('data-object-id');
const code = this.getAttribute('data-target-code');
const name = this.getAttribute('data-target-name');
const type = this.getAttribute('data-target-type');
const status = this.getAttribute('data-target-status');
const modalCtInput = document.getElementById('insp_content_type_id');
const modalObjInput = document.getElementById('insp_object_id');
const modalTypeCode = document.getElementById('insp_target_code');
const modalTypeName = document.getElementById('insp_target_name');
const modalTypeBadge = document.getElementById('insp_target_type');
const modalStatusBadge = document.getElementById('insp_target_status');
if (modalCtInput) modalCtInput.value = ctId;
if (modalObjInput) modalObjInput.value = objId;
if (modalTypeCode) modalTypeCode.textContent = code;
if (modalTypeName) modalTypeName.textContent = name;
if (modalTypeBadge) modalTypeBadge.textContent = type;
if (modalStatusBadge) modalStatusBadge.textContent = status;
});
});
const form = document.getElementById('quickInspectionForm');
if (form && !form.dataset.reloadHandlerAttached) {
form.dataset.reloadHandlerAttached = 'true';
form.addEventListener('submit', function() {
setTimeout(function() {
window.location.reload();
}, 600);
});
}
});
</script>
{% endif %}