239 lines
14 KiB
HTML
239 lines
14 KiB
HTML
{% extends "base.html" %}
|
||
|
||
{% block title %}{{ lot.name }} — GMAO{% endblock %}
|
||
|
||
{% block content %}
|
||
<div class="container-fluid">
|
||
<div class="row mb-4">
|
||
<div class="col">
|
||
<nav aria-label="breadcrumb">
|
||
<ol class="breadcrumb">
|
||
<li class="breadcrumb-item"><a href="{{ url_for('lots.index') }}">Lots</a></li>
|
||
<li class="breadcrumb-item active">{{ lot.name }}</li>
|
||
</ol>
|
||
</nav>
|
||
<h1 class="h3">
|
||
<i class="fas fa-layer-group me-2"></i>{{ lot.name }}
|
||
</h1>
|
||
{% if lot.company %}
|
||
<p class="text-muted">
|
||
<i class="fas fa-building me-1"></i>{{ lot.company.trade_name or lot.company.specialty }}
|
||
</p>
|
||
{% endif %}
|
||
</div>
|
||
<div class="col-auto">
|
||
<a href="{{ url_for('lots.edit', id=lot.id) }}" class="btn btn-outline-primary">
|
||
<i class="fas fa-edit me-1"></i>Modifier
|
||
</a>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="row">
|
||
<div class="col-lg-8">
|
||
{% if lot.needs_equipment_attention %}
|
||
<div class="alert alert-warning">
|
||
<i class="bi bi-exclamation-triangle me-1"></i>
|
||
<strong>Lot présent sans équipement.</strong> Rattachez au moins un équipement ou marquez ce lot comme non présent.
|
||
</div>
|
||
{% elif not lot.is_present %}
|
||
<div class="alert alert-secondary">
|
||
<i class="bi bi-dash-circle me-1"></i>
|
||
<strong>Ce lot n’est pas présent dans l’établissement.</strong>
|
||
{% if lot.absence_reason %}<div class="mt-1">{{ lot.absence_reason }}</div>{% endif %}
|
||
</div>
|
||
{% endif %}
|
||
<div class="card mb-4">
|
||
<div class="card-header">
|
||
<h5 class="mb-0">Informations</h5>
|
||
</div>
|
||
<div class="card-body">
|
||
<dl class="row">
|
||
<dt class="col-sm-4">Nom</dt>
|
||
<dd class="col-sm-8">{{ lot.name }}</dd>
|
||
|
||
<dt class="col-sm-4">Présence</dt>
|
||
<dd class="col-sm-8">
|
||
{% if lot.is_present %}<span class="badge bg-success">Présent</span>
|
||
{% else %}<span class="badge bg-secondary">Non présent</span>{% endif %}
|
||
</dd>
|
||
|
||
{% if lot.description %}
|
||
<dt class="col-sm-4">Description</dt>
|
||
<dd class="col-sm-8">{{ lot.description }}</dd>
|
||
{% endif %}
|
||
|
||
{% if lot.company %}
|
||
<dt class="col-sm-4">Entreprise</dt>
|
||
<dd class="col-sm-8">
|
||
<a href="{{ url_for('companies.detail', id=lot.company.id) }}">
|
||
{{ lot.company.trade_name or lot.company.specialty }}
|
||
</a>
|
||
</dd>
|
||
{% endif %}
|
||
|
||
<dt class="col-sm-4">Catégorie</dt>
|
||
<dd class="col-sm-8">
|
||
{% if lot.category %}
|
||
<a href="{{ url_for('equipments.category_detail', id=lot.category.id) }}">
|
||
{{ lot.category.name }}
|
||
</a>
|
||
{% else %}
|
||
<span class="text-muted">Non assignée</span>
|
||
{% endif %}
|
||
</dd>
|
||
</dl>
|
||
</div>
|
||
</div>
|
||
|
||
{% if not lot.active_equipment_count %}
|
||
<div class="card mb-4">
|
||
<div class="card-header">Statut du lot</div>
|
||
<div class="card-body">
|
||
<form method="POST" action="{{ url_for('lots.set_presence', id=lot.id) }}">
|
||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||
{% if lot.is_present %}
|
||
<input type="hidden" name="action" value="absent">
|
||
<div class="mb-3">
|
||
<label class="form-label" for="absence_reason">Raison facultative</label>
|
||
<input class="form-control" id="absence_reason" name="absence_reason" placeholder="Ex. aucun ascenseur dans l’établissement">
|
||
</div>
|
||
<button class="btn btn-outline-secondary">Marquer le lot comme non présent</button>
|
||
{% else %}
|
||
<input type="hidden" name="action" value="present">
|
||
<button class="btn btn-outline-success">Marquer le lot comme présent</button>
|
||
{% endif %}
|
||
</form>
|
||
</div>
|
||
</div>
|
||
{% endif %}
|
||
|
||
<div class="card mb-4">
|
||
<div class="card-header d-flex justify-content-between align-items-center">
|
||
<div><h5 class="mb-0"><i class="bi bi-calendar2-check me-2"></i>Maintenance préventive</h5><small class="text-muted">Le lot définit les règles héritées par ses équipements.</small></div>
|
||
<a class="btn btn-sm btn-primary" href="{{ url_for('lots.task_create', lot_id=lot.id) }}"><i class="bi bi-plus-lg"></i> Ajouter une tâche</a>
|
||
</div>
|
||
<div class="card-body border-bottom">
|
||
<div class="row text-center g-2">
|
||
<div class="col"><div class="fw-bold fs-4">{{ lot.tasks|length }}</div><small class="text-muted">règles</small></div>
|
||
<div class="col"><div class="fw-bold fs-4 text-primary">{{ task_counts.planned }}</div><small class="text-muted">planifiées</small></div>
|
||
<div class="col"><div class="fw-bold fs-4 text-warning">{{ task_counts.suspended }}</div><small class="text-muted">suspendues</small></div>
|
||
<div class="col"><div class="fw-bold fs-4 text-danger">{{ task_counts.overdue }}</div><small class="text-muted">en retard</small></div>
|
||
</div>
|
||
</div>
|
||
{% if lot.tasks %}<div class="table-responsive"><table class="table table-sm align-middle mb-0"><thead><tr><th>N°</th><th>Tâche</th><th>Déclenchement</th><th>Portée</th><th>Indisponibilité</th><th></th></tr></thead><tbody>
|
||
{% for task in lot.tasks %}<tr class="{{ 'table-secondary' if not task.is_active }}"><td>{{ task.num_tache or '—' }}</td><td><strong>{{ task.tache or 'Tâche sans nom' }}</strong><div class="small text-muted">{{ task.periodicite or (task.jours_entre_interventions|string + ' jours' if task.jours_entre_interventions else 'Périodicité à définir') }}</div>{% if task.is_safety_critical %}<span class="badge bg-danger">Sécurité</span>{% endif %}</td><td>{{ task.trigger_type|replace('calendar','calendrier')|replace('season','saison')|replace('event','événement')|replace('weather','météo')|replace('meter','compteur')|title }}</td><td>{{ {'auto':'Automatique','group':'Groupe / salle','unit':'Par unité'}.get(task.application_scope, task.application_scope) }}</td><td>{{ {'suspend':'Suspendre','keep':'Maintenir','postpone':'Reporter'}.get(task.unavailable_policy, task.unavailable_policy) }}</td><td><a class="btn btn-sm btn-outline-primary" href="{{ url_for('lots.task_edit', lot_id=lot.id, task_id=task.id) }}"><i class="bi bi-pencil"></i></a></td></tr>{% endfor %}
|
||
</tbody></table></div>{% else %}<div class="card-body text-muted">Aucune règle préventive. Ajoutez-en une pour générer les échéances.</div>{% endif %}
|
||
<div class="card-footer"><form method="post" action="{{ url_for('lots.generate_tasks', lot_id=lot.id) }}"><input type="hidden" name="csrf_token" value="{{ csrf_token() }}"><button class="btn btn-success" {% if not lot.is_present %}disabled{% endif %}><i class="bi bi-magic"></i> Générer les échéances maintenant</button></form></div>
|
||
</div>
|
||
|
||
{# Équipements du lot #}
|
||
{% if equipments %}
|
||
<div class="card mb-4">
|
||
<div class="card-header d-flex justify-content-between align-items-center">
|
||
<h5 class="mb-0"><i class="bi bi-hdd-stack me-2"></i>Équipements ({{ equipments|length }})</h5>
|
||
</div>
|
||
<div class="card-body p-0">
|
||
<div class="table-responsive">
|
||
<table class="table table-sm table-hover mb-0">
|
||
<thead>
|
||
<tr>
|
||
<th>Nom</th>
|
||
<th>Localisation</th>
|
||
<th>Statut</th>
|
||
<th>Compteurs</th>
|
||
<th></th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
{% for eq in equipments %}
|
||
<tr>
|
||
<td>
|
||
<a href="{{ url_for('equipments.detail', id=eq.id) }}">
|
||
{{ eq.name }}
|
||
</a>
|
||
</td>
|
||
<td>
|
||
{% if eq.room %}
|
||
<a href="{{ url_for('rooms.detail', id=eq.room.id) }}">
|
||
{{ eq.room.name }}
|
||
</a>
|
||
{% elif eq.location %}
|
||
{{ eq.location }}
|
||
{% else %}
|
||
<span class="text-muted">—</span>
|
||
{% endif %}
|
||
</td>
|
||
<td>
|
||
{% if eq.status == 'active' %}
|
||
<span class="badge bg-success">En service</span>
|
||
{% elif eq.status == 'inactive' %}
|
||
<span class="badge bg-secondary">Inactif</span>
|
||
{% elif eq.status == 'maintenance' %}
|
||
<span class="badge bg-warning text-dark">Maintenance</span>
|
||
{% elif eq.status == 'retired' %}
|
||
<span class="badge bg-danger">Retiré</span>
|
||
{% else %}
|
||
<span class="badge bg-secondary">{{ eq.status }}</span>
|
||
{% endif %}
|
||
</td>
|
||
<td>
|
||
{% if eq.meters %}
|
||
{% for meter in eq.meters %}
|
||
<a href="{{ url_for('meters.detail', meter_id=meter.id) }}"
|
||
class="badge bg-info text-dark text-decoration-none me-1">
|
||
{{ meter.name }}: {{ meter.current_value }} {{ meter.unit }}
|
||
</a>
|
||
{% endfor %}
|
||
{% else %}
|
||
<span class="text-muted">—</span>
|
||
{% endif %}
|
||
</td>
|
||
<td>
|
||
<a href="{{ url_for('equipments.detail', id=eq.id) }}"
|
||
class="btn btn-sm btn-outline-primary">
|
||
<i class="bi bi-eye"></i>
|
||
</a>
|
||
</td>
|
||
</tr>
|
||
{% endfor %}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
{% else %}
|
||
<div class="card mb-4">
|
||
<div class="card-body text-muted">
|
||
<i class="bi bi-info-circle me-2"></i>Aucun équipement dans ce lot.
|
||
<a href="{{ url_for('equipments.index') }}">Rechercher un équipement</a> pour l'ajouter à ce lot.
|
||
</div>
|
||
</div>
|
||
{% endif %}
|
||
</div>
|
||
|
||
<div class="col-lg-4">
|
||
<div class="card">
|
||
<div class="card-header">
|
||
<h5 class="mb-0">Actions</h5>
|
||
</div>
|
||
<div class="card-body">
|
||
<div class="d-grid gap-2">
|
||
<a href="{{ url_for('lots.edit', id=lot.id) }}" class="btn btn-outline-primary">
|
||
<i class="fas fa-edit me-1"></i>Modifier le lot
|
||
</a>
|
||
<a href="{{ url_for('equipments.lifecycle_dashboard', status='all') }}" class="btn btn-outline-secondary"><i class="bi bi-activity"></i> Cycle de vie</a>
|
||
|
||
<form method="POST" action="{{ url_for('lots.delete', id=lot.id) }}"
|
||
onsubmit="return confirm('Confirmer la suppression ?');">
|
||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||
<button type="submit" class="btn btn-outline-danger w-100">
|
||
<i class="fas fa-trash me-1"></i>Supprimer
|
||
</button>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
{% endblock %}
|