gmao/app_new/interventions/templates/detail.html
root a81b3ed4fa
Some checks are pending
CI - Tests et Syntax / lint-and-test (push) Waiting to run
Filtrer les types d'équipement par salle
2026-08-21 10:49:58 +00:00

699 lines
36 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{% extends "base.html" %}
{% block title %}{{ intervention.title }} — GMAO{% endblock %}
{% block content %}
<div class="py-2 py-md-4">
{% if intervention.is_deleted %}
<div class="alert alert-danger mb-3">
<i class="bi bi-trash3"></i> <strong>Cette intervention est dans la corbeille.</strong>
Supprimée le {{ intervention.deleted_at|datetime_fmt if intervention.deleted_at else '—' }}.
</div>
{% endif %}
{% if intervention.equipment and intervention.equipment.status in ['a_jeter', 'jete'] %}
<div class="alert alert-{% if intervention.equipment.status == 'a_jeter' %}danger{% else %}dark{% endif %} mb-3">
{% if intervention.equipment.status == 'a_jeter' %}
<i class="bi bi-exclamation-triangle"></i>
<strong>Équipement à jeter :</strong>
L'équipement « {{ intervention.equipment.name }} » est marqué pour mise au rebut.
{% else %}
<i class="bi bi-archive"></i>
<strong>Équipement mis au rebut :</strong>
L'équipement « {{ intervention.equipment.name }} » a été définitivement mis au rebut. L'historique reste consultable.
{% endif %}
</div>
{% endif %}
<!-- En-tête -->
<div class="d-flex flex-column flex-md-row justify-content-between align-items-start mb-3 gap-2">
<div>
<h2 class="mb-1 h5">
<span class="badge bg-{% if intervention.type == 'curatif' %}danger{% else %}info{% endif %}">
{% if intervention.type == 'curatif' %}🔧 Curatif{% else %}🛡️ Préventif{% endif %}
</span>
{{ intervention.title }}
</h2>
<span class="text-muted" style="font-size:0.85rem;">Intervention #{{ intervention.id }} — {{ intervention.created_at|datetime_fmt if intervention.created_at else '—' }}</span>
</div>
<div class="d-flex gap-2 align-items-center">
<span class="badge bg-{{ intervention.status_color }}" style="font-size:1rem;">
{{ intervention.status_label }}
</span>
<span class="badge bg-{{ intervention.priority_color }}">
{{ intervention.priority_label }}
</span>
</div>
</div>
<!-- ═══ Barre de workflow ═══ -->
<div class="card border-0 shadow-sm mb-3 mb-md-4 bg-white">
<div class="card-body py-2 py-md-3">
<h6 class="text-muted mb-2" style="font-size:0.85rem;"><i class="bi bi-diagram-3"></i> Workflow</h6>
<form method="POST" action="{{ url_for('interventions.save_work_details', id=intervention.id) }}" class="d-flex flex-wrap gap-2 align-items-center mb-2">
<label class="small text-muted mb-0">Parcours :</label>
<select name="execution_mode" class="form-select form-select-sm" style="max-width:280px;">
{% for value, label in [('interne', 'Intervention interne'), ('chef', 'Validation du chef'), ('departement', 'Demande au Département'), ('entreprise', 'Entreprise extérieure')] %}
<option value="{{ value }}" {% if intervention.execution_mode == value %}selected{% endif %}>{{ label }}</option>
{% endfor %}
</select>
<button class="btn btn-outline-primary btn-sm" type="submit"><i class="bi bi-arrow-repeat"></i> Appliquer</button>
</form>
<div class="d-flex flex-wrap align-items-center gap-1" style="font-size:0.75rem;">
{% set workflow_order = workflow_status_order %}
<div class="mb-2"><span class="badge bg-secondary">Workflow {{ intervention.workflow_label }}</span></div>
{% for step in workflow_order %}
{% if step in statuses %}
{% set is_current = (step == intervention.status) %}
{% set is_past = workflow_order.index(step) < workflow_order.index(intervention.status) if intervention.status in workflow_order else false %}
{% set bg_class = 'bg-' + statuses[step]['color'] if is_current else ('bg-success' if is_past else 'bg-light') %}
{% set text_class = 'text-white' if is_current or is_past else 'text-muted' %}
<span class="badge {{ bg_class }} {{ text_class }} py-1 px-2" {% if is_current %}style="box-shadow: 0 0 0 3px rgba(13,110,253,0.3);"{% endif %}>
{% if is_past %}<i class="bi bi-check2 me-1"></i>{% endif %}
{{ statuses[step]['label'] }}
</span>
{% if not loop.last %}<i class="bi bi-chevron-right text-muted d-none d-md-inline mx-1"></i><i class="bi bi-chevron-down text-muted d-md-none"></i>{% endif %}
{% endif %}
{% endfor %}
</div>
</div>
</div>
<!-- ═══ Actions rapides ═══ -->
{% if transitions %}
<div class="card border-0 shadow-sm mb-3 mb-md-4 border-start border-primary border-4">
<div class="card-body">
<h6 class="mb-3"><i class="bi bi-lightning-fill text-warning"></i> Actions rapides</h6>
<form method="POST" action="{{ url_for('interventions.change_status', id=intervention.id) }}">
<div class="mb-2">
<label class="form-label small text-muted">Changer le statut vers :</label>
<div class="d-flex flex-wrap gap-2">
{% for status, label in transitions %}
<button type="submit" name="to_status" value="{{ status }}" class="btn btn-outline-primary btn-sm">
{{ label }}
</button>
{% endfor %}
</div>
</div>
<div class="d-flex gap-2 align-items-center">
<input type="text" name="comment" class="form-control form-control-sm" placeholder="Commentaire (optionnel)...">
<button type="submit" class="btn btn-primary btn-sm">
<i class="bi bi-check-circle"></i> Confirmer
</button>
</div>
</form>
{% if intervention.status not in ['terminee', 'cloturee', 'refusee', 'annulee'] %}
<hr class="my-3">
<form method="POST" action="{{ url_for('interventions.refuse', id=intervention.id) }}" onsubmit="return confirm('Refuser cette intervention ? Le motif sera conservé dans l\'historique.')">
<label class="form-label small text-muted">Refuser la demande</label>
<div class="input-group input-group-sm">
<input type="text" name="refusal_reason" class="form-control" required minlength="3" placeholder="Motif obligatoire (ex. demande non pertinente)...">
<button type="submit" class="btn btn-outline-danger"><i class="bi bi-ban"></i> Refuser</button>
</div>
</form>
{% endif %}
{% if intervention.equipment and intervention.equipment.status not in ['a_jeter', 'jete'] %}
<hr class="my-3">
<form method="POST" action="{{ url_for('equipments.mark_as_trash', id=intervention.equipment.id) }}">
<div class="mb-2">
<label class="form-label small text-muted">Action spéciale :</label>
</div>
<div class="d-flex gap-2 align-items-center">
<button type="submit" class="btn btn-danger btn-sm" onclick="return confirm('Proposer cet équipement pour mise au rebut ?')">
<i class="bi bi-trash"></i> Proposer l'équipement pour mise au rebut
</button>
</div>
</form>
{% endif %}
{% if intervention.status == 'refusee' %}
<div class="alert alert-danger mb-3">
<h6 class="alert-heading"><i class="bi bi-ban"></i> Intervention refusée</h6>
<div>{{ intervention.refusal_reason or 'Motif non renseigné' }}</div>
<small>Le {{ intervention.refused_at|datetime_fmt if intervention.refused_at else '—' }}{% if intervention.refused_by %} par {{ intervention.refused_by.full_name }}{% endif %}</small>
</div>
{% endif %}
</div>
</div>
{% else %}
<div class="alert alert-secondary mb-3 mb-md-4">
<i class="bi bi-lock"></i> Aucune transition possible depuis le statut actuel avec votre rôle.
</div>
{% endif %}
<div class="row g-4">
<!-- ═══ Colonne gauche : infos principales ═══ -->
<div class="col-lg-8">
<!-- Responsable actuel -->
<div class="card border-0 shadow-sm mb-3">
<div class="card-body">
<h6 class="card-title"><i class="bi bi-person-badge text-primary"></i> Responsable actuel</h6>
{% if intervention.assigned_to %}
<div class="d-flex align-items-center">
<span class="avatar-placeholder bg-primary text-white rounded-circle d-flex align-items-center justify-content-center me-2" style="width:40px;height:40px;font-size:1.1rem;">
{{ intervention.assigned_to.full_name[0]|upper }}
</span>
<div>
<strong>{{ intervention.assigned_to.full_name }}</strong><br>
<span class="badge bg-secondary">{{ intervention.assigned_to.role_label }}</span>
</div>
</div>
{% elif intervention.status == 'brouillon' %}
<span class="text-muted"><i class="bi bi-pencil"></i> Brouillon — pas encore de responsable assigné</span>
{% else %}
<span class="text-muted"><i class="bi bi-question-circle"></i> Non assigné</span>
{% endif %}
</div>
</div>
<!-- Technicien assigné -->
{% if intervention.technician %}
<div class="card border-0 shadow-sm mb-3">
<div class="card-body">
<h6 class="card-title"><i class="bi bi-wrench text-success"></i> Technicien assigné</h6>
<strong>{{ intervention.technician.full_name }}</strong>
<span class="badge bg-success ms-2">{{ intervention.technician.role_label }}</span>
</div>
</div>
{% endif %}
<!-- Description -->
<div class="card border-0 shadow-sm mb-3">
<div class="card-body">
<h6 class="card-title"><i class="bi bi-file-text text-info"></i> Description</h6>
{% if intervention.description %}
<p class="mb-0" style="white-space: pre-wrap;">{{ intervention.description }}</p>
{% else %}
<p class="text-muted mb-0 fst-italic">Aucune description</p>
{% endif %}
</div>
</div>
<!-- GIMA & Budget -->
{% if intervention.gima_number or intervention.needs_budget %}
<div class="card border-0 shadow-sm mb-3 border-start border-info border-4">
<div class="card-body">
<h6 class="card-title"><i class="bi bi-building text-info"></i> GIMA & Budget</h6>
<div class="row">
{% if intervention.gima_number %}
<div class="col-sm-6">
<strong>N° demande GIMA :</strong> {{ intervention.gima_number }}<br>
<strong>Service :</strong>
{% if intervention.gima_service == 'entretien' %}
Service Entretien
{% elif intervention.gima_service == 'securite' %}
Service Sécurité
{% else %}
{{ intervention.gima_service or '—' }}
{% endif %}
</div>
{% endif %}
{% if intervention.needs_budget %}
<div class="col-sm-6">
<span class="badge bg-purple"><i class="bi bi-cash-coin"></i> Budget prévisionnel requis</span><br>
{% if intervention.budget_amount %}
<strong>Montant :</strong> {{ "%.2f"|format(intervention.budget_amount) }} €
{% endif %}
{% if intervention.budget_approved %}
<span class="badge bg-success ms-1">Approuvé</span>
{% else %}
<span class="badge bg-warning text-dark ms-1">En attente</span>
{% endif %}
</div>
{% endif %}
</div>
</div>
</div>
{% endif %}
<!-- Workflow travaux intégré -->
<div class="card border-0 shadow-sm mb-3 border-start border-warning border-4">
<div class="card-header bg-light d-flex justify-content-between align-items-center">
<h6 class="mb-0"><i class="bi bi-hammer text-warning"></i> Suivi des travaux</h6>
<span class="badge bg-secondary">Dans cette intervention</span>
</div>
<div class="card-body">
<form method="POST" action="{{ url_for('interventions.save_work_details', id=intervention.id) }}">
<div class="row g-2">
<div class="col-md-4">
<label class="form-label small">Mode de réalisation</label>
<select name="execution_mode" class="form-select form-select-sm">
{% for value, label in [('interne', 'Travaux réalisés par moi-même'), ('chef', 'Validation de mon chef'), ('departement', 'Demande au Département'), ('entreprise', 'Entreprise extérieure')] %}
<option value="{{ value }}" {% if intervention.execution_mode == value %}selected{% endif %}>{{ label }}</option>
{% endfor %}
</select>
</div>
<div class="col-md-4">
<label class="form-label small">Service du Département</label>
<select name="department_service_id" class="form-select form-select-sm">
<option value="">— Non concerné —</option>
{% for service in services %}<option value="{{ service.id }}" {% if intervention.department_service_id == service.id %}selected{% endif %}>{{ service.name }}</option>{% endfor %}
</select>
</div>
<div class="col-md-4">
<label class="form-label small">Entreprise mandatée</label>
<select name="company_id" class="form-select form-select-sm">
<option value="">— Aucune —</option>
{% for company in companies %}<option value="{{ company.id }}" {% if intervention.company_id == company.id %}selected{% endif %}>{{ company.name }}</option>{% endfor %}
</select>
</div>
<div class="col-md-4"><label class="form-label small">État du devis</label><select name="quote_status" class="form-select form-select-sm">{% for value,label in [('non_requis','Non requis'),('attendu','Attendu'),('recu','Reçu'),('valide_chef','Validé par le chef'),('valide_departement','Validé par le Département'),('refuse','Refusé')] %}<option value="{{ value }}" {% if intervention.quote_status == value %}selected{% endif %}>{{ label }}</option>{% endfor %}</select></div>
<div class="col-md-4"><label class="form-label small">Référence devis</label><input name="quote_reference" class="form-control form-control-sm" value="{{ intervention.quote_reference or '' }}"></div>
<div class="col-md-2"><label class="form-label small">Montant HT</label><input type="number" step="0.01" name="quote_amount_ht" class="form-control form-control-sm" value="{{ intervention.quote_amount_ht or '' }}"></div>
<div class="col-md-2"><label class="form-label small">Montant TTC</label><input type="number" step="0.01" name="quote_amount_ttc" class="form-control form-control-sm" value="{{ intervention.quote_amount_ttc or '' }}"></div>
<div class="col-md-4"><label class="form-label small">Date demande Département</label><input type="date" name="department_request_date" class="form-control form-control-sm" value="{{ intervention.department_request_date or '' }}"></div>
<div class="col-md-4"><label class="form-label small">Date validation chef</label><input type="date" name="chief_validation_date" class="form-control form-control-sm" value="{{ intervention.chief_validation_date or '' }}"></div>
<div class="col-md-4"><label class="form-label small">Date validation Département</label><input type="date" name="department_validation_date" class="form-control form-control-sm" value="{{ intervention.department_validation_date or '' }}"></div>
<div class="col-12"><label class="form-label small">Notes de suivi</label><textarea name="work_notes" class="form-control form-control-sm" rows="2">{{ intervention.work_notes or '' }}</textarea></div>
</div>
<button class="btn btn-warning btn-sm mt-3"><i class="bi bi-save"></i> Enregistrer le suivi</button>
</form>
</div>
</div>
<!-- Équipement -->
<div class="card border-0 shadow-sm mb-3">
<div class="card-body">
<h6 class="card-title"><i class="bi bi-hdd text-warning"></i> Équipement</h6>
<div class="mb-2"><strong>Salle :</strong> {% if intervention.room %}{{ intervention.room.full_name }}{% elif intervention.equipment and intervention.equipment.room %}{{ intervention.equipment.room.full_name }}{% else %}<span class="text-muted">Non renseignée</span>{% endif %}</div>
{% if intervention.is_group_intervention %}
<div class="mb-2">
<span class="badge bg-info">Groupe d'équipements</span>
<span class="badge bg-secondary ms-1">{{ intervention.quantity_affected }} unité(s) concernée(s)</span>
</div>
{% endif %}
{% if intervention.equipment %}
<a href="{{ url_for('equipments.detail', id=intervention.equipment.id) }}" class="text-decoration-none">
{{ intervention.equipment.code or intervention.equipment.name }}
</a>
<br><span class="text-muted small">{{ intervention.equipment.full_path }}</span>
{% else %}
<span class="text-muted">Aucun équipement précis associé</span>
{% endif %}
</div>
</div>
<!-- Localisation modifiable en cascade -->
<div class="card border-0 shadow-sm mb-3 border-start border-success border-4">
<div class="card-body">
<h6 class="card-title"><i class="bi bi-geo-alt text-success"></i> Salle et équipement concernés</h6>
<form method="POST" action="{{ url_for('interventions.update_location', id=intervention.id) }}" id="intervention-location-form">
<div class="row g-2">
<div class="col-md-4">
<label class="form-label small">1. Salle</label>
<select name="room_id" id="intervention-room" class="form-select form-select-sm">
<option value="">— Aucune salle —</option>
{% for room in rooms %}<option value="{{ room.id }}" {% if intervention.room_id == room.id %}selected{% endif %}>{{ room.full_name }}</option>{% endfor %}
</select>
</div>
<div class="col-md-4">
<label class="form-label small">2. Type déquipement</label>
<select name="category_id" id="intervention-category" class="form-select form-select-sm">
<option value="">— Toutes les catégories —</option>
{% for category in categories %}<option value="{{ category.id }}" {% if intervention.equipment and intervention.equipment.effective_category_id == category.id %}selected{% endif %}>{{ category.name }}</option>{% endfor %}
</select>
</div>
<div class="col-md-4">
<label class="form-label small">3. Équipement précis</label>
<select name="equipment_id" id="intervention-equipment" class="form-select form-select-sm">
<option value="">— Aucun équipement précis —</option>
{% for equipment in equipment_choices %}<option value="{{ equipment.id }}" data-room="{{ equipment.room_id or '' }}" data-category="{{ equipment.effective_category_id or '' }}" {% if intervention.equipment_id == equipment.id %}selected{% endif %}>{{ equipment.name }}{% if equipment.code %} ({{ equipment.code }}){% endif %}</option>{% endfor %}
</select>
</div>
</div>
<button type="submit" class="btn btn-outline-success btn-sm mt-3"><i class="bi bi-save"></i> Enregistrer la localisation</button>
</form>
</div>
</div>
<!-- Éléments du groupe concernés -->
{% if intervention.is_group_intervention %}
{% set affected_units = intervention.get_affected_units() %}
{% if affected_units %}
<div class="card border-0 shadow-sm mb-3 border-start border-warning border-4">
<div class="card-body">
<h6 class="card-title"><i class="bi bi-list-check text-warning"></i> Éléments concernés ({{ affected_units|length }})</h6>
<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>Actions</th>
</tr>
</thead>
<tbody>
{% for unit in affected_units %}
<tr>
<td>{{ unit.individual_number }}</td>
<td><a href="{{ url_for('equipments.detail', id=unit.id) }}">{{ unit.code or '—' }}</a></td>
<td>{{ unit.position or '—' }}</td>
<td>
<span class="badge {{ unit.status|status_badge }}">{{ unit.status|format_status }}</span>
{% if unit.has_active_curative and unit.id != intervention.equipment_id %}
<span class="badge bg-warning text-dark ms-1" title="Intervention curative en cours">
<i class="bi bi-wrench"></i>
</span>
{% endif %}
</td>
<td>
{% if intervention.status not in ['cloturee', 'terminee'] %}
<div class="btn-group btn-group-sm">
<button type="button" class="btn btn-outline-secondary dropdown-toggle" data-bs-toggle="dropdown">
Statut
</button>
<ul class="dropdown-menu">
{% for value, label in [('en_service', 'En service'), ('hs', 'Hors service'), ('a_jeter', 'À jeter')] %}
<li><form method="post" action="{{ url_for('equipments.change_status', id=unit.id, status=value) }}"><button class="dropdown-item" type="submit">{{ label }}</button></form></li>
{% endfor %}
</ul>
</div>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
{% endif %}
{% endif %}
<!-- Entreprise extérieure -->
{% if intervention.company %}
<div class="card border-0 shadow-sm mb-3">
<div class="card-body">
<h6 class="card-title"><i class="bi bi-truck text-orange"></i> Entreprise extérieure</h6>
<a href="{{ url_for('companies.detail', id=intervention.company.id) }}" class="text-decoration-none">
{{ intervention.company.name }}
</a>
{% if intervention.company.specialty %}
<span class="badge bg-secondary ms-1">{{ intervention.company.specialty }}</span>
{% endif %}
</div>
</div>
{% endif %}
<!-- Historique des changements de statut -->
{% if history %}
<div class="card border-0 shadow-sm mb-3">
<div class="card-body">
<h6 class="card-title"><i class="bi bi-clock-history text-secondary"></i> Historique des statuts</h6>
<div class="timeline">
{% for change in history %}
<div class="d-flex align-items-start mb-2 pb-2 border-bottom">
<div class="me-3 text-center" style="min-width:50px;">
<span class="badge bg-{{ change.to_color }}">
<i class="bi bi-{{ statuses[change.to_status]['icon'] }}"></i>
</span>
</div>
<div class="flex-grow-1">
<strong>{{ change.to_label }}</strong>
<span class="text-muted small">(de {{ change.from_label }})</span>
<br>
<span class="text-muted small">
Par <strong>{{ change.changed_by.full_name if change.changed_by else 'Utilisateur supprimé' }}</strong> — {{ change.created_at|datetime_fmt if change.created_at else '—' }}
</span>
{% if change.comment %}
<br><em class="small">{{ change.comment }}</em>
{% endif %}
</div>
</div>
{% endfor %}
</div>
</div>
</div>
{% endif %}
<!-- Commentaires -->
<div class="card border-0 shadow-sm mb-3">
<div class="card-body">
<h6 class="card-title"><i class="bi bi-chat-dots text-primary"></i> Commentaires</h6>
{% for comment in intervention.comments %}
<div class="d-flex mb-3 pb-2 border-bottom">
<div class="me-3">
<div class="avatar-placeholder bg-secondary text-white rounded-circle d-flex align-items-center justify-content-center" style="width:36px;height:36px;font-size:0.9rem;">
{{ comment.author.full_name[0]|upper }}
</div>
</div>
<div class="flex-grow-1">
<strong>{{ comment.author.full_name }}</strong>
<span class="text-muted small ms-2">{{ comment.created_at|datetime_fmt if comment.created_at else '—' }}</span>
<p class="mb-0 mt-1" style="white-space: pre-wrap;">{{ comment.content }}</p>
</div>
</div>
{% endfor %}
<form method="POST" action="{{ url_for('interventions.add_comment', id=intervention.id) }}">
<div class="input-group">
<textarea name="content" class="form-control" placeholder="Ajouter un commentaire..." rows="2" required></textarea>
<button class="btn btn-outline-primary" type="submit"><i class="bi bi-send"></i></button>
</div>
</form>
</div>
</div>
</div>
<!-- ═══ Colonne droite : infos synthétiques ═══ -->
<div class="col-lg-4">
<!-- Actions -->
<div class="d-grid gap-2 mb-3">
{% if intervention.is_deleted %}
<form method="POST" action="{{ url_for('interventions.restore', id=intervention.id) }}">
<button type="submit" class="btn btn-outline-success w-100" onclick="return confirm('Restaurer cette intervention ?')">
<i class="bi bi-arrow-counterclockwise"></i> Restaurer
</button>
</form>
{% else %}
<a href="{{ url_for('interventions.edit', id=intervention.id) }}" class="btn btn-outline-primary">
<i class="bi bi-pencil"></i> Modifier l'intervention
</a>
<form method="POST" action="{{ url_for('interventions.soft_delete', id=intervention.id) }}">
<button type="submit" class="btn btn-outline-danger w-100" onclick="return confirm('Mettre cette intervention en corbeille ?')">
<i class="bi bi-trash3"></i> Mettre en corbeille
</button>
</form>
{% endif %}
</div>
<!-- Infos clés -->
<div class="card border-0 shadow-sm mb-3">
<div class="card-body">
<h6 class="card-title"><i class="bi bi-info-circle text-primary"></i> Résumé</h6>
<table class="table table-sm table-borderless mb-0">
<tr><td class="text-muted">Type</td><td class="fw-bold">
{% if intervention.type == 'curatif' %}🔧 Curatif{% else %}🛡️ Préventif{% endif %}
</td></tr>
<tr><td class="text-muted">Priorité</td><td><span class="badge bg-{{ intervention.priority_color }}">{{ intervention.priority_label }}</span></td></tr>
<tr><td class="text-muted">Statut</td><td><span class="badge bg-{{ intervention.status_color }}">{{ intervention.status_label }}</span></td></tr>
{% if intervention.recurrence_month %}
<tr><td class="text-muted">Récurrence</td><td>Tous les {{ intervention.recurrence_month }} mois</td></tr>
{% endif %}
{% if intervention.cost %}
<tr><td class="text-muted">Coût</td><td>{{ "%.2f"|format(intervention.cost) }} €</td></tr>
{% endif %}
{% if intervention.time_spent %}
<tr><td class="text-muted">Temps passé</td><td>{{ intervention.time_spent }} min</td></tr>
{% endif %}
<tr><td class="text-muted">Demandé le</td><td>{{ intervention.requested_at.strftime('%d/%m/%Y') if intervention.requested_at else '—' }}</td></tr>
{% if intervention.started_at %}
<tr><td class="text-muted">Débuté le</td><td>{{ intervention.started_at.strftime('%d/%m/%Y') }}</td></tr>
{% endif %}
{% if intervention.completed_at %}
<tr><td class="text-muted">Terminé le</td><td>{{ intervention.completed_at.strftime('%d/%m/%Y') }}</td></tr>
{% endif %}
</table>
</div>
</div>
<!-- Demandeur -->
{% if intervention.requester_name %}
<div class="card border-0 shadow-sm mb-3">
<div class="card-body">
<h6 class="card-title"><i class="bi bi-person text-secondary"></i> Demandeur</h6>
<strong>{{ intervention.requester_name }}</strong>
{% if intervention.requester_contact %}
<br><span class="text-muted small">{{ intervention.requester_contact }}</span>
{% endif %}
</div>
</div>
{% endif %}
<!-- Détails préventif -->
{% if intervention.type == 'preventif' and intervention.preventive_type %}
<div class="card border-0 shadow-sm mb-3">
<div class="card-body">
<h6 class="card-title"><i class="bi bi-calendar-check text-success"></i> Détails préventif</h6>
<strong>Type :</strong> {{ intervention.preventive_type }}
{% if intervention.recurrence_month %}
<br><strong>Récurrence :</strong> Tous les {{ intervention.recurrence_month }} mois
{% endif %}
</div>
</div>
{% endif %}
<!-- Documents -->
<div class="card border-0 shadow-sm mb-3">
<div class="card-header d-flex justify-content-between align-items-center py-2">
<span><i class="bi bi-file-earmark"></i> Documents</span>
<button class="btn btn-sm btn-outline-primary" data-bs-toggle="modal" data-bs-target="#uploadInterventionDocumentModal">
<i class="bi bi-upload"></i>
</button>
</div>
<div class="card-body">
{% if intervention.documents.all() %}
<div class="list-group list-group-flush">
{% for doc in intervention.documents %}
<div class="list-group-item d-flex justify-content-between align-items-center px-0">
<div>
{% 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 }}
{% if doc.description %}
<br><small class="text-muted">{{ doc.description }}</small>
{% endif %}
<br><small class="text-muted">{{ doc.uploaded_at.strftime('%d/%m/%Y') if doc.uploaded_at else '—' }}</small>
</div>
<div>
<a href="{{ url_for('documents.download_intervention', 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="#editInterventionDocumentModal{{ doc.id }}">
<i class="bi bi-pencil"></i>
</button>
<form method="POST" action="{{ url_for('documents.delete_intervention', 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>
</div>
</div>
{% endfor %}
</div>
{% else %}
<p class="text-muted mb-0"><i class="bi bi-inbox"></i> Aucun document</p>
{% endif %}
</div>
</div>
</div>
</div>
</div>
<script>
(() => {
const room = document.getElementById('intervention-room');
const category = document.getElementById('intervention-category');
const equipment = document.getElementById('intervention-equipment');
if (!room || !category || !equipment) return;
const equipmentOptions = [...equipment.options].filter(option => option.value);
const filterCategories = () => {
const roomId = room.value;
const presentCategories = new Set(
equipmentOptions
.filter(option => roomId && option.dataset.room === roomId)
.map(option => option.dataset.category)
.filter(Boolean)
);
[...category.options].forEach(option => {
if (!option.value) {
option.hidden = false;
option.textContent = roomId ? '— Choisir un type présent —' : '— Sélectionnez dabord une salle —';
return;
}
option.hidden = !roomId || !presentCategories.has(option.value);
if (option.hidden && option.selected) category.value = '';
});
category.disabled = !roomId || presentCategories.size === 0;
};
const filter = () => {
const roomId = room.value;
const categoryId = category.value;
[...equipment.options].forEach(option => {
if (!option.value) { option.hidden = false; return; }
const matchesRoom = !roomId || option.dataset.room === roomId;
const matchesCategory = !categoryId || option.dataset.category === categoryId;
option.hidden = !(matchesRoom && matchesCategory);
if (option.hidden && option.selected) equipment.value = '';
});
};
room.addEventListener('change', () => { filterCategories(); filter(); });
category.addEventListener('change', filter);
filterCategories();
filter();
})();
</script>
<!-- Modal Upload Document Intervention -->
<div class="modal fade" id="uploadInterventionDocumentModal" 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_intervention', intervention_id=intervention.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 Intervention -->
{% for doc in intervention.documents %}
<div class="modal fade" id="editInterventionDocumentModal{{ 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_intervention', 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 %}
<!-- Styles custom pour le workflow -->
<style>
.bg-purple { background-color: #6f42c1 !important; }
.bg-orange { background-color: #fd7e14 !important; }
.avatar-placeholder { font-weight: 600; }
</style>
{% endblock %}