2026-08-14 18:02:25 +02:00
{% extends "base.html" %}
{% block title %}{{ equipment.name }} — GMAO Collège{% endblock %}
{% block content %}
< div class = "d-flex justify-content-between align-items-center mb-4" >
< h1 >
< i class = "bi bi-pc-display" > < / i > {{ equipment.name }}
{% if equipment.code %}< small class = "text-muted" > ({{ equipment.code }})< / small > {% endif %}
< / h1 >
< div >
{% if equipment.status != 'jete' %}
< a href = "{{ url_for('equipments.edit', id=equipment.id) }}" class = "btn btn-outline-primary" >
< i class = "bi bi-pencil" > < / i > Modifier
< / a >
< a href = "{{ url_for('interventions.create') }}?equipment_id={{ equipment.id }}" class = "btn btn-danger" >
< i class = "bi bi-wrench" > < / i > Nouvelle intervention
< / a >
{% if equipment.status != 'a_jeter' %}
< form action = "{{ url_for('equipments.mark_as_trash', id=equipment.id) }}" method = "POST" style = "display:inline;" >
< button type = "submit" class = "btn btn-outline-danger" onclick = "return confirm('Marquer cet équipement comme à jeter ?')" >
< i class = "bi bi-trash" > < / i > À jeter
< / button >
< / form >
{% endif %}
{% endif %}
< / div >
< / div >
{% if equipment.status == 'a_jeter' %}
< div class = "alert alert-danger" >
< i class = "bi bi-exclamation-triangle" > < / i >
< strong > Cet équipement est marqué comme à jeter.< / strong >
< form action = "{{ url_for('equipments.confirm_trashed', id=equipment.id) }}" method = "POST" style = "display:inline;" >
< button type = "submit" class = "btn btn-danger btn-sm" onclick = "return confirm('Confirmer que cet équipement a été jeté ? Il ne sera plus visible dans les listings normaux.')" >
< i class = "bi bi-trash" > < / i > Confirmer la mise au rebut
< / button >
< / form >
< form action = "{{ url_for('equipments.cancel_trash', id=equipment.id) }}" method = "POST" style = "display:inline;" >
< button type = "submit" class = "btn btn-success btn-sm" >
< i class = "bi bi-arrow-counterclockwise" > < / i > Annuler (remettre en service)
< / button >
< / form >
< / div >
{% elif equipment.status == 'jete' %}
< div class = "alert alert-dark" >
< i class = "bi bi-archive" > < / i >
< strong > Cet équipement a été mis au rebut.< / strong >
< span class = "text-muted" > Il n'est plus visible dans les listings normaux mais son historique reste consultable.< / span >
< / div >
{% endif %}
{% if equipment.needs_deep_work %}
< div class = "alert alert-warning" >
< i class = "bi bi-exclamation-octagon" > < / i >
< strong > Alerte récurrence :< / strong > Cet équipement a {{ equipment.curative_count }} interventions curatives.
Des travaux profonds sont recommandés.
< / div >
{% endif %}
< div class = "row" >
< div class = "col-md-6" >
< div class = "card mb-3" >
< div class = "card-header" > < i class = "bi bi-info-circle" > < / i > Informations< / div >
< div class = "card-body" >
< table class = "table table-sm mb-0" >
< tr > < th > Statut< / th > < td > < span class = "badge {{ equipment.status|status_badge }}" > {{ equipment.status|format_status }}< / span > < / td > < / tr >
{# Affichage pour un groupe #}
{% if equipment.is_group %}
< tr > < th > Type< / th > < td > < span class = "badge bg-info" > Groupe ({{ equipment.quantity }} unités déclarées)< / span > < / td > < / tr >
< tr > < th > Suivi individuel< / th > < td >
{% if equipment.tracked_individually %}
< span class = "badge bg-success" > Obligatoire< / span >
{% else %}
< span class = "badge bg-secondary" > Optionnel< / span >
{% endif %}
< / td > < / tr >
< tr > < th>Éléments< / th > < td >
< strong > {{ equipment.children_count }} actifs< / strong > / {{ equipment.total_children }} dans le groupe
{% if equipment.total_children < equipment.quantity % }
< small class = "text-muted" > ({{ equipment.quantity }} déclarés initialement)< / small >
{% endif %}
< / td > < / tr >
{% elif equipment.is_individual %}
< tr > < th > Type< / th > < td >
< span class = "badge bg-warning text-dark" > Élément individuel< / span >
{% if equipment.individual_number %}
< small class = "text-muted" > n°{{ equipment.individual_number }}< / small >
{% endif %}
< / td > < / tr >
< tr > < th > Groupe parent< / th > < td >
< a href = "{{ url_for('equipments.detail', id=equipment.parent_id) }}" > {{ equipment.parent.name }}< / a >
< small class = "text-muted" > ({{ equipment.parent.quantity }} unités)< / small >
< / td > < / tr >
{% if equipment.position %}
< tr > < th > Position< / th > < td > {{ equipment.position }}< / td > < / tr >
{% endif %}
{% endif %}
< tr > < th > Catégorie< / th > < td > {{ equipment.category.name if equipment.category else '—' }}< / td > < / tr >
< tr > < th > Localisation< / th > < td >
{{ equipment.effective_room.building.name if equipment.effective_room and equipment.effective_room.building else '' }}
{% if equipment.effective_room %} > {{ equipment.effective_room.name }}{% endif %}
{% if equipment.position %}< br > < small class = "text-muted" > {{ equipment.position }}< / small > {% endif %}
< / td > < / tr >
{% if equipment.install_date %}< tr > < th > Installation< / th > < td > {{ equipment.install_date|date_fmt }}< / td > < / tr > {% endif %}
{% if equipment.warranty_end %}< tr > < th > Garantie< / th > < td > {{ equipment.warranty_end|date_fmt }}< / td > < / tr > {% endif %}
{% if equipment.parent %}< tr > < th > Groupe parent< / th > < td > < a href = "{{ url_for('equipments.detail', id=equipment.parent_id) }}" > {{ equipment.parent.name }}< / a > < / td > < / tr > {% endif %}
< / table >
< / div >
< / div >
{# Boutons d'action pour les groupes #}
{% if equipment.is_group and equipment.status not in ['a_jeter', 'jete'] %}
< div class = "card mb-3" >
< div class = "card-header" > < i class = "bi bi-gear" > < / i > Actions de groupe< / div >
< div class = "card-body" >
{% if not equipment.tracked_individually %}
< a href = "{{ url_for('equipments.individualize', id=equipment.id) }}" class = "btn btn-sm btn-outline-primary mb-2" >
< i class = "bi bi-box-arrow-up-right" > < / i > Individualiser un élément
< / a >
< br >
{% endif %}
< a href = "{{ url_for('equipments.add_elements', id=equipment.id) }}" class = "btn btn-sm btn-outline-success mb-2" >
< i class = "bi bi-plus" > < / i > Ajouter des éléments
< / a >
< br >
< a href = "{{ url_for('interventions.create_for_group', equipment_id=equipment.id) }}" class = "btn btn-sm btn-outline-danger mb-2" >
< i class = "bi bi-wrench" > < / i > Intervention sur le groupe
< / a >
< / div >
< / div >
{% endif %}
{# Boutons d'action pour les éléments individuels #}
{% if equipment.is_individual and equipment.status not in ['a_jeter', 'jete'] %}
< div class = "card mb-3" >
< div class = "card-header" > < i class = "bi bi-gear" > < / i > Actions< / div >
< div class = "card-body" >
< a href = "{{ url_for('equipments.move_to_room', id=equipment.id) }}" class = "btn btn-sm btn-outline-primary mb-2" >
< i class = "bi bi-arrow-left-right" > < / i > Déplacer vers une autre salle
< / a >
< / div >
< / div >
{% endif %}
< / div >
< div class = "col-md-6" >
{% if equipment.description %}
< div class = "card mb-3" >
< div class = "card-header" > < i class = "bi bi-file-text" > < / i > Description< / div >
< div class = "card-body" > {{ equipment.description }}< / div >
< / div >
{% endif %}
{# Résumé des statuts pour les groupes avec suivi individuel #}
{% if equipment.is_group and equipment.tracked_individually %}
< div class = "card mb-3" >
< div class = "card-header" > < i class = "bi bi-bar-chart" > < / i > Résumé des statuts< / div >
< div class = "card-body" >
{% set stats = equipment.get_status_summary() %}
< div class = "d-flex flex-wrap gap-2" >
{% if stats.get('en_service', 0) > 0 %}
< span class = "badge bg-success" > En service : {{ stats.get('en_service', 0) }}< / span >
{% endif %}
{% if stats.get('en_maintenance', 0) > 0 %}
< span class = "badge bg-warning" > En maintenance : {{ stats.get('en_maintenance', 0) }}< / span >
{% endif %}
{% if stats.get('hors_service', 0) > 0 %}
< span class = "badge bg-danger" > Hors service : {{ stats.get('hors_service', 0) }}< / span >
{% endif %}
{% if stats.get('a_jeter', 0) > 0 %}
< span class = "badge bg-warning text-dark" > À jeter : {{ stats.get('a_jeter', 0) }}< / span >
{% endif %}
{% if stats.get('jete', 0) > 0 %}
< span class = "badge bg-secondary" > Jetés : {{ stats.get('jete', 0) }}< / span >
{% endif %}
< / div >
< / div >
< / div >
{% endif %}
< / div >
< / div >
{# Liste des enfants pour les groupes avec suivi individuel #}
{% if equipment.is_group and equipment.children.count() > 0 %}
< div class = "card mb-3" >
< div class = "card-header d-flex justify-content-between align-items-center" >
< span > < i class = "bi bi-list-ul" > < / i > Éléments du groupe ({{ equipment.children.count() }})< / span >
{% if equipment.children.count() < equipment.quantity and not equipment . tracked_individually % }
< button class = "btn btn-sm btn-outline-primary" data-bs-toggle = "modal" data-bs-target = "#addElementModal" >
< i class = "bi bi-plus" > < / i > Ajouter un élément
< / button >
{% endif %}
< / div >
< div class = "card-body" >
< div class = "table-responsive" >
< table class = "table table-sm table-hover mb-0" >
< thead >
< tr >
< th > N°< / th >
< th > Code< / th >
< th > Position< / th >
< th > Statut< / th >
< th > Interventions< / th >
< th > Actions< / th >
< / tr >
< / thead >
< tbody >
{% for child in equipment.children|sort(attribute='individual_number') %}
< tr >
< td > {{ child.individual_number }}< / td >
< td > < a href = "{{ url_for('equipments.detail', id=child.id) }}" > {{ child.code or '—' }}< / a > < / td >
< td > {{ child.position or '—' }}< / td >
< td > < span class = "badge {{ child.status|status_badge }}" > {{ child.status|format_status }}< / span > < / td >
< td >
{{ child.interventions.count() }}
{% if child.has_active_curative %}
< span class = "badge bg-warning text-dark ms-1" title = "Intervention curative en cours" >
< i class = "bi bi-wrench" > < / i > En cours
< / span >
{% endif %}
< / td >
< td >
< a href = "{{ url_for('equipments.detail', id=child.id) }}" class = "btn btn-sm btn-outline-primary" title = "Voir" >
< i class = "bi bi-eye" > < / i >
< / a >
< a href = "{{ url_for('equipments.edit', id=child.id) }}" class = "btn btn-sm btn-outline-secondary" title = "Modifier" >
< i class = "bi bi-pencil" > < / i >
< / a >
< / td >
< / tr >
{% endfor %}
< / tbody >
< / table >
< / div >
< / div >
< / div >
{% endif %}
< div class = "row" >
< div class = "col-md-6" >
< div class = "card mb-3" >
< div class = "card-header" > < i class = "bi bi-geo-alt" > < / i > Historique des déplacements< / div >
< div class = "card-body" >
{% if equipment.room_history %}
< table class = "table table-sm mb-0" >
< thead > < tr > < th > Date< / th > < th > Ancienne salle< / th > < th > Nouvelle salle< / th > < th > Par< / th > < / tr > < / thead >
< tbody >
{% for h in equipment.room_history %}
< tr >
< td > {{ h.changed_at|date_fmt }}< / td >
< td > {{ h.old_room.name if h.old_room else '—' }}< / td >
< td > {{ h.new_room.name if h.new_room else '—' }}< / td >
< td > {{ h.changed_by.full_name if h.changed_by else '—' }}< / td >
< / tr >
{% endfor %}
< / tbody >
< / table >
{% else %}
< p class = "text-muted mb-0" > Aucun déplacement enregistré.< / p >
{% endif %}
< / div >
< / div >
< / div >
< / div >
<!-- Historique des interventions -->
< div class = "card" >
< div class = "card-header d-flex justify-content-between align-items-center" >
< span > < i class = "bi bi-clock-history" > < / i > Historique des interventions< / span >
< a href = "{{ url_for('interventions.index') }}?equipment_id={{ equipment.id }}" class = "btn btn-sm btn-outline-secondary" > Voir tout< / a >
< / div >
< div class = "card-body" >
{% if interventions %}
< div class = "table-responsive" >
< table class = "table table-sm table-hover mb-0" >
< thead > < tr > < th > #< / th > < th > Titre< / th > < th > Type< / th > < th > Statut< / th > < th > Date< / th > < / tr > < / thead >
< tbody >
{% for interv in interventions %}
< tr >
< td > < a href = "{{ url_for('interventions.detail', id=interv.id) }}" > #{{ interv.id }}< / a > < / td >
< td > {{ interv.title }}< / td >
< td > {% if interv.type == 'curatif' %}< span class = "badge bg-danger" > Curatif< / span > {% else %}< span class = "badge bg-info" > Préventif< / span > {% endif %}< / td >
< td > < span class = "badge {{ interv.status|status_badge }}" > {{ interv.status|format_status }}< / span > < / td >
< td > {{ interv.requested_at|date_fmt }}< / td >
< / tr >
{% endfor %}
< / tbody >
< / table >
< / div >
{% else %}
< p class = "text-muted" > Aucune intervention enregistrée pour cet équipement.< / p >
{% endif %}
< / div >
< / div >
<!-- Documents -->
< div class = "card mt-3" >
< div class = "card-header d-flex justify-content-between align-items-center" >
< span > < i class = "bi bi-file-earmark" > < / i > Documents ({{ equipment.documents.count() }})< / span >
< button class = "btn btn-sm btn-outline-primary" data-bs-toggle = "modal" data-bs-target = "#uploadDocumentModal" >
< i class = "bi bi-upload" > < / i > Ajouter
< / button >
< / div >
< div class = "card-body" >
{% if equipment.documents.all() %}
< div class = "table-responsive" >
< table class = "table table-sm table-hover mb-0" >
< thead > < tr > < th > Fichier< / th > < th > Description< / th > < th > Date< / th > < th > Actions< / th > < / tr > < / thead >
< tbody >
{% for doc in equipment.documents %}
< tr >
< td >
{% set ext = doc.filename|lower %}
< i class = "bi bi-file-earmark-{% if '.pdf' in ext %}pdf{% elif '.png' in ext or '.jpg' in ext or '.jpeg' in ext or '.gif' in ext %}image{% else %}text{% endif %}" > < / i >
{{ doc.filename }}
< / td >
< td > {{ doc.description or '—' }}< / td >
2026-08-15 00:47:55 +02:00
< td > {{ doc.uploaded_at|datetime_fmt if doc.uploaded_at else '—' }}< / td >
2026-08-14 18:02:25 +02:00
< td >
< a href = "{{ url_for('documents.download_equipment', doc_id=doc.id) }}" class = "btn btn-sm btn-outline-secondary" title = "Télécharger" >
< i class = "bi bi-download" > < / i >
< / a >
< button type = "button" class = "btn btn-sm btn-outline-primary" title = "Modifier la description" data-bs-toggle = "modal" data-bs-target = "#editDocumentModal{{ doc.id }}" >
< i class = "bi bi-pencil" > < / i >
< / button >
< form method = "POST" action = "{{ url_for('documents.delete_equipment', doc_id=doc.id) }}" style = "display:inline;" onsubmit = "return confirm('Supprimer ce document ?')" >
< button type = "submit" class = "btn btn-sm btn-outline-danger" title = "Supprimer" >
< i class = "bi bi-trash" > < / i >
< / button >
< / form >
< / td >
< / tr >
{% endfor %}
< / tbody >
< / table >
< / div >
{% else %}
< p class = "text-muted mb-0" > Aucun document attaché.< / p >
{% endif %}
< / div >
< / div >
<!-- Modal Upload Document -->
< div class = "modal fade" id = "uploadDocumentModal" tabindex = "-1" >
< div class = "modal-dialog" >
< div class = "modal-content" >
< div class = "modal-header" >
< h5 class = "modal-title" > Ajouter un document< / h5 >
< button type = "button" class = "btn-close" data-bs-dismiss = "modal" > < / button >
< / div >
< form method = "POST" action = "{{ url_for('documents.upload_equipment', equipment_id=equipment.id) }}" enctype = "multipart/form-data" >
< div class = "modal-body" >
< div class = "mb-3" >
< label class = "form-label" > Fichier< / label >
< input type = "file" name = "file" class = "form-control" required >
< div class = "form-text" > PDF, images, documents Office autorisés.< / div >
< / div >
< div class = "mb-3" >
< label class = "form-label" > Description< / label >
< textarea name = "description" class = "form-control" rows = "2" placeholder = "Description optionnelle..." > < / textarea >
< / div >
< / div >
< div class = "modal-footer" >
< button type = "button" class = "btn btn-secondary" data-bs-dismiss = "modal" > Annuler< / button >
< button type = "submit" class = "btn btn-primary" > Uploader< / button >
< / div >
< / form >
< / div >
< / div >
< / div >
<!-- Modals Edit Documents -->
{% for doc in equipment.documents %}
< div class = "modal fade" id = "editDocumentModal{{ doc.id }}" tabindex = "-1" >
< div class = "modal-dialog" >
< div class = "modal-content" >
< div class = "modal-header" >
< h5 class = "modal-title" > Modifier la description< / h5 >
< button type = "button" class = "btn-close" data-bs-dismiss = "modal" > < / button >
< / div >
< form method = "POST" action = "{{ url_for('documents.edit_equipment', doc_id=doc.id) }}" >
< div class = "modal-body" >
< p > < strong > Fichier :< / strong > {{ doc.filename }}< / p >
< div class = "mb-3" >
< label class = "form-label" > Description< / label >
< textarea name = "description" class = "form-control" rows = "3" > {{ doc.description or '' }}< / textarea >
< / div >
< / div >
< div class = "modal-footer" >
< button type = "button" class = "btn btn-secondary" data-bs-dismiss = "modal" > Annuler< / button >
< button type = "submit" class = "btn btn-primary" > Enregistrer< / button >
< / div >
< / form >
< / div >
< / div >
< / div >
{% endfor %}
{% endblock %}