2026-08-14 18:02:25 +02:00
{% extends "base.html" %}
{% block title %}Équipements — GMAO Collège{% endblock %}
{% block content %}
< div class = "d-flex justify-content-between align-items-center mb-3" >
< h2 class = "mb-0 h5" > < i class = "bi bi-pc-display" > < / i > Équipements< / h2 >
< a href = "{{ url_for('equipments.create') }}" class = "btn btn-primary btn-sm" >
< i class = "bi bi-plus-lg" > < / i > < span class = "d-none d-sm-inline" > Nouvel< / span > < span class = "d-sm-none" > +< / span >
< / a >
2026-08-17 01:54:23 +02:00
< div class = "btn-group btn-group-sm ms-2" >
< a class = "btn {{ 'btn-primary' if view != 'zones' else 'btn-outline-primary' }}" href = "{{ url_for('equipments.index', view='families') }}" > < i class = "bi bi-diagram-3" > < / i > Par familles< / a >
< a class = "btn {{ 'btn-primary' if view == 'zones' else 'btn-outline-primary' }}" href = "{{ url_for('equipments.index', view='zones') }}" > < i class = "bi bi-signpost-split" > < / i > Par zones et salles< / a >
< / div >
2026-08-14 18:02:25 +02:00
< / div >
2026-08-17 01:54:23 +02:00
{% if view == 'zones' %}
< div class = "alert alert-info py-2" > < i class = "bi bi-info-circle" > < / i > Les quantités sont regroupées par zone, salle et type d’ équipement. Les groupes parents sont exclus pour éviter les doublons.< / div >
{% for building in zone_tree %}
< div class = "card border-0 shadow-sm mb-3" > < div class = "card-header fw-semibold" > < i class = "bi bi-building" > < / i > {{ building.name }}< / div > < div class = "card-body" >
{% for zone in building.zones %}< div class = "ms-2 mb-3" > < h6 > < i class = "bi bi-signpost-split" > < / i > {{ zone.name }}< / h6 >
{% for room in zone.rooms %}< div class = "border rounded p-2 mb-2 ms-3" > < strong > < i class = "bi bi-door-open" > < / i > {{ room.name }}< / strong > < div class = "table-responsive" > < table class = "table table-sm mb-0 mt-1" > < tbody > {% for item in room.types %}< tr > < td > {{ item.name }}< / td > < td class = "text-muted" > {{ item.category }}< / td > < td class = "text-end" > < span class = "badge bg-primary" > {{ item.quantity }}< / span > < / td > < / tr > {% endfor %}< / tbody > < / table > < / div > < / div > {% endfor %}
< / div > {% endfor %}< / div > < / div >
{% else %}< div class = "text-center text-muted py-4" > Aucun équipement localisé ne correspond aux filtres.< / div > {% endfor %}
{% else %}
2026-08-14 18:02:25 +02:00
<!-- Filtres -->
< div class = "card border-0 shadow-sm mb-3" >
< div class = "card-body py-2" >
< form method = "GET" class = "row g-2 g-md-3 align-items-end" >
< div class = "col-6 col-md-3" >
< input type = "text" name = "search" class = "form-control form-control-sm" placeholder = "Rechercher..." value = "{{ filters.search }}" >
< / div >
< div class = "col-6 col-md-2" >
< select name = "category" class = "form-select form-select-sm" >
< option value = "" > — Catégorie —< / option >
{% for cat in categories %}
< option value = "{{ cat.id }}" > {{ cat.name }}< / option >
{% endfor %}
< / select >
< / div >
< div class = "col-6 col-md-2" >
< select name = "building" class = "form-select form-select-sm" >
< option value = "" > — Bâtiment —< / option >
{% for b in buildings %}
< option value = "{{ b.id }}" > {{ b.name }}< / option >
{% endfor %}
< / select >
< / div >
< div class = "col-6 col-md-2" >
< select name = "status" class = "form-select form-select-sm" >
< option value = "" > — Statut —< / option >
< option value = "en_service" > En service< / option >
< option value = "hors_service" > Hors service< / option >
< option value = "en_reparation" > En réparation< / option >
< option value = "remplace" > Remplacé< / option >
< / select >
< / div >
< div class = "col-12 col-md-2" >
< button type = "submit" class = "btn btn-sm btn-outline-primary" > < i class = "bi bi-funnel" > < / i > Filtrer< / button >
< a href = "{{ url_for('equipments.index') }}" class = "btn btn-sm btn-outline-secondary" > < i class = "bi bi-x-circle" > < / i > < / a >
< / div >
< / form >
< / div >
< / div >
<!-- Liste -->
{% if equipments.items %}
<!-- Desktop : table -->
< div class = "card border-0 shadow-sm d-none d-md-block" >
< div class = "card-body p-0" >
< div class = "table-responsive" >
< table class = "table table-hover table-sm mb-0" >
< thead > < tr > < th > Code< / th > < th > Nom< / th > < th > Catégorie< / th > < th > Localisation< / th > < th > Statut< / th > < th > Curatif< / th > < / tr > < / thead >
< tbody >
{% for eq in equipments.items %}
< tr { % if eq . needs_deep_work % } class = "table-danger" { % endif % } >
< td > < code > {{ eq.code or '—' }}< / code > < / td >
< td >
< a href = "{{ url_for('equipments.detail', id=eq.id) }}" > {{ eq.name }}< / a >
{% if eq.is_group %}
< span class = "badge bg-info ms-1" > {{ eq.children_count }}/{{ eq.total_children }}< / span >
{% if eq.tracked_individually %}
< span class = "badge bg-success ms-1" > Suivi indiv.< / span >
{% endif %}
{% endif %}
< / td >
< td > {{ eq.category.name if eq.category else '—' }}< / td >
< td > {{ eq.full_path }}< / td >
< td > < span class = "badge {{ eq.status|status_badge }}" > {{ eq.status|format_status }}< / span > < / td >
< td >
{% if eq.curative_count > 0 %}
< span class = "badge {% if eq.needs_deep_work %}bg-danger{% else %}bg-warning text-dark{% endif %}" > {{ eq.curative_count }}< / span >
{% else %}
< span class = "text-muted" > 0< / span >
{% endif %}
< / td >
< / tr >
{% endfor %}
< / tbody >
< / table >
< / div >
< / div >
< / div >
<!-- Mobile : cards -->
< div class = "d-md-none" >
{% for eq in equipments.items %}
< a href = "{{ url_for('equipments.detail', id=eq.id) }}" class = "text-decoration-none" >
< div class = "card border-0 shadow-sm mb-2" >
< div class = "card-body py-2 px-3" >
< div class = "d-flex justify-content-between align-items-start" >
< div style = "min-width:0;" >
< strong class = "text-truncate d-block" > {{ eq.name }}< / strong >
< small class = "text-muted" >
< code > {{ eq.code or '—' }}< / code > · {{ eq.category.name if eq.category else '—' }}
< / small >
< / div >
< div class = "d-flex gap-1 align-items-center flex-shrink-0 ms-1" >
< span class = "badge {{ eq.status|status_badge }}" style = "font-size:0.7rem;" > {{ eq.status|format_status }}< / span >
{% if eq.curative_count > 0 %}
< span class = "badge {% if eq.needs_deep_work %}bg-danger{% else %}bg-warning text-dark{% endif %}" style = "font-size:0.7rem;" > {{ eq.curative_count }}< / span >
{% endif %}
< / div >
< / div >
< / div >
< / div >
< / a >
{% endfor %}
< / div >
<!-- Pagination -->
{% if equipments.pages > 1 %}
< nav class = "mt-2" > < ul class = "pagination pagination-sm justify-content-center mb-0" >
{% if equipments.has_prev %}
< li class = "page-item" > < a class = "page-link" href = "{{ url_for('equipments.index', page=equipments.prev_num) }}" > « < / a > < / li >
{% endif %}
{% for p in equipments.iter_pages() %}
< li class = "page-item {% if p == equipments.page %}active{% endif %}" > < a class = "page-link" href = "{{ url_for('equipments.index', page=p) }}" > {{ p }}< / a > < / li >
{% endfor %}
{% if equipments.has_next %}
< li class = "page-item" > < a class = "page-link" href = "{{ url_for('equipments.index', page=equipments.next_num) }}" > » < / a > < / li >
{% endif %}
< / ul > < / nav >
{% endif %}
{% else %}
< div class = "text-center py-5 text-muted" >
< i class = "bi bi-inbox" style = "font-size:3rem;" > < / i >
< p class = "mt-2" > Aucun équipement< / p >
< / div >
{% endif %}
2026-08-17 01:54:23 +02:00
{% endif %}
{% endblock %}