gmao/app_new/equipments/templates/detail.html

399 lines
No EOL
20 KiB
HTML

{% 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></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>
<td>{{ doc.uploaded_at|datetime_fmt if doc.uploaded_at else '—' }}</td>
<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 %}