339 lines
No EOL
18 KiB
HTML
339 lines
No EOL
18 KiB
HTML
{% extends "base.html" %}
|
|
|
|
{% block title %}{{ 'Nouvel équipement' if not equipment else 'Modifier l\'équipement' }} — GMAO{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="container-fluid">
|
|
<div class="row mb-4">
|
|
<div class="col">
|
|
<h1 class="h3">
|
|
<i class="fas fa-tools me-2"></i>
|
|
{{ 'Nouvel équipement' if not equipment else 'Modifier l\'équipement' }}
|
|
</h1>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-lg-8">
|
|
<div class="card">
|
|
<div class="card-body">
|
|
<!-- Étape 1: Choix du type (uniquement pour création) -->
|
|
{% if not equipment %}
|
|
<div class="mb-4" id="type-selector">
|
|
<label class="form-label fw-bold">Type d'équipement</label>
|
|
<div class="row g-3">
|
|
<div class="col-md-4">
|
|
<div class="card h-100 type-card" data-type="parent" style="cursor: pointer; transition: all 0.2s;">
|
|
<div class="card-body text-center">
|
|
<i class="bi bi-collection fs-1 text-primary"></i>
|
|
<h5 class="mt-2">Groupe parent</h5>
|
|
<small class="text-muted">Ex: Lot de 60 chaises</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div class="card h-100 type-card" data-type="child" style="cursor: pointer; transition: all 0.2s;">
|
|
<div class="card-body text-center">
|
|
<i class="bi bi-diagram-3 fs-1 text-success"></i>
|
|
<h5 class="mt-2">Groupe enfant</h5>
|
|
<small class="text-muted">Ex: 30 chaises salle B101</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div class="card h-100 type-card" data-type="individual" style="cursor: pointer; transition: all 0.2s;">
|
|
<div class="card-body text-center">
|
|
<i class="bi bi-box fs-1 text-warning"></i>
|
|
<h5 class="mt-2">Individuel</h5>
|
|
<small class="text-muted">Ex: Vidéo-projecteur #1</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<form method="POST" id="equipment-form">
|
|
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
|
<input type="hidden" name="is_group" id="is_group_input" value="{{ '1' if equipment and equipment.is_group else '0' }}">
|
|
<input type="hidden" name="parent_id" id="parent_id_input" value="{{ equipment.parent_id if equipment else '' }}">
|
|
|
|
<!-- Champs communs -->
|
|
<div class="row mb-3">
|
|
<div class="col-md-6">
|
|
<label for="name" class="form-label">Nom *</label>
|
|
<input type="text" class="form-control" id="name" name="name"
|
|
value="{{ equipment.name if equipment else '' }}" required>
|
|
</div>
|
|
<div class="col-md-6" id="code_field">
|
|
{% if not equipment or equipment.is_individual %}
|
|
<label for="code" class="form-label">Code / Numéro de série</label>
|
|
<input type="text" class="form-control" id="code" name="code"
|
|
value="{{ equipment.code if equipment else '' }}"
|
|
placeholder="Ex: CHAISE-001">
|
|
<small class="text-muted">Uniquement pour les éléments individuels</small>
|
|
{% else %}
|
|
<label class="form-label">Code</label>
|
|
<input type="text" class="form-control" value="Non applicable (groupe)" disabled>
|
|
<small class="text-muted">Les groupes n'ont pas de numéro de série</small>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row mb-3">
|
|
<div class="col-md-6">
|
|
<label for="category_id" class="form-label">Catégorie</label>
|
|
<select class="form-select" id="category_id" name="category_id">
|
|
<option value="">-- Sélectionner --</option>
|
|
{% for cat in categories %}
|
|
<option value="{{ cat.id }}" {{ 'selected' if equipment and equipment.category_id == cat.id else '' }}>
|
|
{{ cat.name }}
|
|
</option>
|
|
{% endfor %}
|
|
</select>
|
|
</div>
|
|
<div class="col-md-6" id="room_field">
|
|
<label for="room_id" class="form-label">Salle <span id="room_required">*</span></label>
|
|
<select class="form-select" id="room_id" name="room_id">
|
|
<option value="">-- Sélectionner --</option>
|
|
{% for building in buildings %}
|
|
<optgroup label="{{ building.name }}">
|
|
{% for room in building.rooms %}
|
|
<option value="{{ room.id }}" {{ 'selected' if equipment and equipment.room_id == room.id else '' }}>
|
|
{{ room.name }}
|
|
</option>
|
|
{% endfor %}
|
|
</optgroup>
|
|
{% endfor %}
|
|
</select>
|
|
<small class="text-muted" id="room_hint">Obligatoire pour les éléments individuels</small>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row mb-3">
|
|
<div class="col-md-6">
|
|
<label for="lot_id" class="form-label">Lot</label>
|
|
<select class="form-select" id="lot_id" name="lot_id">
|
|
<option value="">-- Aucun lot --</option>
|
|
{% for lot in lots %}
|
|
<option value="{{ lot.id }}" {{ 'selected' if equipment and equipment.lot_id == lot.id else '' }}>
|
|
{{ lot.name }}
|
|
</option>
|
|
{% endfor %}
|
|
</select>
|
|
<small class="text-muted">Associe les tâches préventives du lot à l'équipement</small>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label for="status" class="form-label">Statut</label>
|
|
<select class="form-select" id="status" name="status">
|
|
<option value="en_service" {{ 'selected' if equipment and equipment.status == 'en_service' else '' }}>En service</option>
|
|
<option value="en_panne" {{ 'selected' if equipment and equipment.status == 'en_panne' else '' }}>En panne</option>
|
|
<option value="en_maintenance" {{ 'selected' if equipment and equipment.status == 'en_maintenance' else '' }}>En maintenance</option>
|
|
<option value="hs" {{ 'selected' if equipment and equipment.status == 'hs' else '' }}>Hors service</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-6" id="quantity_field">
|
|
<label for="quantity" class="form-label">Quantité</label>
|
|
<input type="number" class="form-control" id="quantity" name="quantity"
|
|
value="{{ equipment.quantity if equipment else 1 }}" min="1">
|
|
<small class="text-muted">Nombre d'unités dans le groupe</small>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row mb-3" id="parent_selector" style="display: none;">
|
|
<div class="col-md-12">
|
|
<label for="parent_select" class="form-label">Équipement parent *</label>
|
|
<select class="form-select" id="parent_select" name="parent_select">
|
|
<option value="">-- Sélectionner un parent --</option>
|
|
{% for eq in parent_equipments %}
|
|
<option value="{{ eq.id }}" data-quantity="{{ eq.quantity }}" data-category="{{ eq.category_id }}" {{ 'selected' if preselected_parent_id == eq.id|string else '' }}>
|
|
{{ eq.name }} ({{ eq.quantity }} unités)
|
|
</option>
|
|
{% endfor %}
|
|
</select>
|
|
<small class="text-muted">L'enfant héritera de la catégorie du parent</small>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label for="description" class="form-label">Description</label>
|
|
<textarea class="form-control" id="description" name="description" rows="3">{{ equipment.description if equipment else '' }}</textarea>
|
|
</div>
|
|
|
|
<div class="d-flex justify-content-between">
|
|
<a href="{{ url_for('equipments.index') }}" class="btn btn-outline-secondary">
|
|
<i class="fas fa-arrow-left me-1"></i>Retour
|
|
</a>
|
|
<button type="submit" class="btn btn-primary">
|
|
<i class="fas fa-save me-1"></i>Enregistrer
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-lg-4">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="mb-0">Aide</h5>
|
|
</div>
|
|
<div class="card-body" id="help-panel">
|
|
<p class="text-muted">Sélectionnez un type d'équipement pour voir les détails.</p>
|
|
|
|
<div id="help-parent" style="display:none;">
|
|
<h6><i class="bi bi-collection text-primary me-2"></i>Groupe parent</h6>
|
|
<ul class="small">
|
|
<li>Équipement principal (ex: Lot de 60 chaises)</li>
|
|
<li>Pas de salle assignée</li>
|
|
<li>Peut contenir des enfants</li>
|
|
<li>Quantité déclarée</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div id="help-child" style="display:none;">
|
|
<h6><i class="bi bi-diagram-3 text-success me-2"></i>Groupe enfant</h6>
|
|
<ul class="small">
|
|
<li>Sous-ensemble localisé (ex: 30 chaises salle B101)</li>
|
|
<li>Salle optionnelle</li>
|
|
<li>Lié à un parent</li>
|
|
<li>Hérite de la catégorie du parent</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div id="help-individual" style="display:none;">
|
|
<h6><i class="bi bi-box text-warning me-2"></i>Individuel</h6>
|
|
<ul class="small">
|
|
<li>Unité unique suivie individuellement</li>
|
|
<li>Numéro de série requis</li>
|
|
<li>Salle obligatoire</li>
|
|
<li>Peut être déplacé entre salles</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<style>
|
|
.type-card {
|
|
border: 2px solid #dee2e6;
|
|
}
|
|
.type-card:hover {
|
|
border-color: #0d6efd;
|
|
transform: translateY(-2px);
|
|
}
|
|
.type-card.selected {
|
|
border-color: #0d6efd;
|
|
background-color: #f8f9fa;
|
|
}
|
|
</style>
|
|
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
const typeCards = document.querySelectorAll('.type-card');
|
|
const isGroupInput = document.getElementById('is_group_input');
|
|
const parentIdInput = document.getElementById('parent_id_input');
|
|
const parentSelector = document.getElementById('parent_selector');
|
|
const quantityField = document.getElementById('quantity_field');
|
|
const roomField = document.getElementById('room_field');
|
|
const codeField = document.getElementById('code_field');
|
|
const roomRequired = document.getElementById('room_required');
|
|
const roomHint = document.getElementById('room_hint');
|
|
|
|
// Vérifier si on a un parent_id dans l'URL (via template)
|
|
const preselectedParentId = "{{ preselected_parent_id or '' }}";
|
|
|
|
// Masquer les champs conditionnels au départ (création uniquement)
|
|
{% if not equipment %}
|
|
parentSelector.style.display = 'none';
|
|
quantityField.style.display = 'none';
|
|
{% endif %}
|
|
|
|
// Gestion du changement de parent
|
|
const parentSelect = document.getElementById('parent_select');
|
|
if (parentSelect) {
|
|
parentSelect.addEventListener('change', function() {
|
|
parentIdInput.value = this.value;
|
|
|
|
// Hériter de la catégorie du parent
|
|
if (this.selectedOptions[0]) {
|
|
const categoryId = this.selectedOptions[0].dataset.category;
|
|
document.getElementById('category_id').value = categoryId;
|
|
}
|
|
});
|
|
}
|
|
|
|
// Fonction pour sélectionner un type
|
|
function selectType(type) {
|
|
// Retirer la sélection précédente
|
|
typeCards.forEach(c => c.classList.remove('selected'));
|
|
|
|
// Trouver et ajouter la classe selected
|
|
const card = document.querySelector('.type-card[data-type="' + type + '"]');
|
|
if (card) {
|
|
card.classList.add('selected');
|
|
}
|
|
|
|
// Masquer tous les panneaux d'aide
|
|
document.getElementById('help-parent').style.display = 'none';
|
|
document.getElementById('help-child').style.display = 'none';
|
|
document.getElementById('help-individual').style.display = 'none';
|
|
|
|
// Afficher le panneau d'aide correspondant
|
|
document.getElementById('help-' + type).style.display = 'block';
|
|
|
|
// Ajuster les champs selon le type
|
|
if (type === 'parent') {
|
|
isGroupInput.value = '1';
|
|
parentIdInput.value = '';
|
|
parentSelector.style.display = 'none';
|
|
quantityField.style.display = 'block';
|
|
roomField.style.display = 'block';
|
|
roomRequired.textContent = '';
|
|
roomHint.textContent = 'Optionnel pour un groupe parent';
|
|
codeField.querySelector('input').disabled = true;
|
|
codeField.querySelector('input').value = '';
|
|
codeField.querySelector('small').textContent = 'Les groupes n\'ont pas de numéro de série';
|
|
} else if (type === 'child') {
|
|
isGroupInput.value = '1';
|
|
parentSelector.style.display = 'block';
|
|
quantityField.style.display = 'block';
|
|
roomField.style.display = 'block';
|
|
roomRequired.textContent = '';
|
|
roomHint.textContent = 'Optionnel pour un groupe enfant';
|
|
codeField.querySelector('input').disabled = true;
|
|
codeField.querySelector('small').textContent = 'Les groupes n\'ont pas de numéro de série';
|
|
} else if (type === 'individual') {
|
|
isGroupInput.value = '0';
|
|
parentIdInput.value = '';
|
|
parentSelector.style.display = 'none';
|
|
quantityField.style.display = 'none';
|
|
roomField.style.display = 'block';
|
|
roomRequired.textContent = '*';
|
|
roomHint.textContent = 'Obligatoire pour un élément individuel';
|
|
codeField.querySelector('input').disabled = false;
|
|
codeField.querySelector('input').placeholder = 'Ex: CHAISE-001';
|
|
codeField.querySelector('small').textContent = 'Uniquement pour les éléments individuels';
|
|
}
|
|
}
|
|
|
|
// Gestion du clic sur les cartes de type
|
|
typeCards.forEach(card => {
|
|
card.addEventListener('click', function() {
|
|
selectType(this.dataset.type);
|
|
});
|
|
});
|
|
|
|
// Si parent_id pré-sélectionné, activer le mode "enfant"
|
|
{% if preselected_parent_id %}
|
|
selectType('child');
|
|
if (parentSelect) {
|
|
parentSelect.value = '{{ preselected_parent_id }}';
|
|
parentSelect.dispatchEvent(new Event('change'));
|
|
}
|
|
{% endif %}
|
|
});
|
|
</script>
|
|
{% endblock %} |