329 lines
14 KiB
HTML
329 lines
14 KiB
HTML
{% load i18n %}
|
|
|
|
<!-- Modal for adding repair intervention (structures only) -->
|
|
<div class="modal fade" id="addRepairInterventionModal" tabindex="-1" aria-labelledby="addRepairInterventionModalLabel" aria-hidden="true">
|
|
<div class="modal-dialog modal-dialog-centered modal-lg">
|
|
<div class="modal-content">
|
|
|
|
<div class="modal-header">
|
|
<h5 class="modal-title" id="addRepairInterventionModalLabel">{% translate "Nouvelle intervention de réparation" %}</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="{% translate 'Fermer' %}"></button>
|
|
</div>
|
|
|
|
<div class="modal-body">
|
|
<form id="addRepairInterventionForm">
|
|
{% csrf_token %}
|
|
|
|
<!-- Localisation -->
|
|
<div class="mb-3">
|
|
<label for="locationSearchDesktop" class="form-label required">{% translate "Localisation" %}</label>
|
|
<input type="text"
|
|
class="form-control"
|
|
id="locationSearchDesktop"
|
|
placeholder="{% translate 'Rechercher une localisation...' %}"
|
|
autocomplete="off">
|
|
<div id="locationResultsDesktop" class="border rounded mt-1 p-2" style="max-height: 250px; overflow-y: auto; display: none;">
|
|
</div>
|
|
<div id="selectedLocationDesktop" class="alert alert-info mt-2" style="display: none;">
|
|
<span id="selectedLocationTextDesktop"></span>
|
|
<button type="button" class="btn btn-sm btn-outline-danger float-end" onclick="clearLocationDesktop()">
|
|
<i class="bi bi-x-lg"></i>
|
|
</button>
|
|
</div>
|
|
<input type="hidden" name="location_id" id="locationIdDesktop" value="">
|
|
</div>
|
|
|
|
<!-- Catégorie -->
|
|
<div class="mb-3">
|
|
<label for="categorySelectDesktop" class="form-label required">{% translate "Catégorie" %}</label>
|
|
<select class="form-select" name="category_id" id="categorySelectDesktop" required>
|
|
<option value="">{% translate "Sélectionner une catégorie" %}</option>
|
|
{% for category in categories %}
|
|
<option value="{{ category.id }}">{{ category.get_name }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
</div>
|
|
|
|
<!-- Équipement (optionnel) -->
|
|
<div class="mb-3">
|
|
<label for="assetSearchDesktop" class="form-label">{% translate "Équipement" %} <small class="text-muted">({% translate "optionnel" %})</small></label>
|
|
<input type="text"
|
|
class="form-control"
|
|
id="assetSearchDesktop"
|
|
placeholder="{% translate 'Rechercher un équipement...' %}"
|
|
autocomplete="off"
|
|
disabled>
|
|
<small class="text-muted" id="assetSearchHintDesktop">{% translate "Sélectionnez d'abord une localisation" %}</small>
|
|
<div id="assetResultsDesktop" class="border rounded mt-1 p-2" style="max-height: 250px; overflow-y: auto; display: none;">
|
|
</div>
|
|
<div id="selectedAssetDesktop" class="alert alert-info mt-2" style="display: none;">
|
|
<span id="selectedAssetTextDesktop"></span>
|
|
<button type="button" class="btn btn-sm btn-outline-danger float-end" onclick="clearAssetDesktop()">
|
|
<i class="bi bi-x-lg"></i>
|
|
</button>
|
|
</div>
|
|
<input type="hidden" name="asset_id" id="assetIdDesktop" value="">
|
|
</div>
|
|
|
|
<!-- Titre -->
|
|
<div class="mb-3">
|
|
<label for="titleInputDesktop" class="form-label required">{% translate "Titre" %}</label>
|
|
<input type="text"
|
|
class="form-control"
|
|
name="title"
|
|
id="titleInputDesktop"
|
|
placeholder="{% translate 'Titre de l\'intervention' %}"
|
|
required>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{% translate "Annuler" %}</button>
|
|
<button type="button" class="btn btn-success" onclick="submitRepairInterventionForm()">
|
|
<i class="bi bi-check-lg me-2"></i>{% translate "Créer l'intervention" %}
|
|
</button>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
(function() {
|
|
const locationSearch = document.getElementById('locationSearchDesktop');
|
|
const locationResults = document.getElementById('locationResultsDesktop');
|
|
const locationId = document.getElementById('locationIdDesktop');
|
|
const selectedLocation = document.getElementById('selectedLocationDesktop');
|
|
const selectedLocationText = document.getElementById('selectedLocationTextDesktop');
|
|
|
|
const assetSearch = document.getElementById('assetSearchDesktop');
|
|
const assetResults = document.getElementById('assetResultsDesktop');
|
|
const assetId = document.getElementById('assetIdDesktop');
|
|
const selectedAsset = document.getElementById('selectedAssetDesktop');
|
|
const selectedAssetText = document.getElementById('selectedAssetTextDesktop');
|
|
const assetSearchHint = document.getElementById('assetSearchHintDesktop');
|
|
|
|
const categorySelect = document.getElementById('categorySelectDesktop');
|
|
const titleInput = document.getElementById('titleInputDesktop');
|
|
|
|
let searchTimeout = null;
|
|
|
|
// Location search
|
|
locationSearch.addEventListener('input', function() {
|
|
clearTimeout(searchTimeout);
|
|
const query = this.value.trim();
|
|
|
|
if (query.length < 2) {
|
|
locationResults.style.display = 'none';
|
|
return;
|
|
}
|
|
|
|
searchTimeout = setTimeout(() => {
|
|
searchLocations(query);
|
|
}, 300);
|
|
});
|
|
|
|
async function searchLocations(query) {
|
|
try {
|
|
const response = await fetch(`{% url 'assets:locations_autocomplete' %}?q=${encodeURIComponent(query)}&thematic=structures`);
|
|
const data = await response.json();
|
|
|
|
locationResults.innerHTML = '';
|
|
if (data.length > 0) {
|
|
data.forEach(item => {
|
|
const div = document.createElement('div');
|
|
div.className = 'p-2 border-bottom cursor-pointer';
|
|
div.style.cursor = 'pointer';
|
|
div.innerHTML = `<strong>${item.code}</strong> - ${item.name}`;
|
|
div.addEventListener('click', () => selectLocationDesktop(item.value.obj, item.code, item.name));
|
|
locationResults.appendChild(div);
|
|
});
|
|
locationResults.style.display = 'block';
|
|
} else {
|
|
locationResults.innerHTML = '<div class="p-2 text-muted">{% translate "Aucun résultat" %}</div>';
|
|
locationResults.style.display = 'block';
|
|
}
|
|
} catch (error) {
|
|
console.error('Error searching locations:', error);
|
|
}
|
|
}
|
|
|
|
window.selectLocationDesktop = function(objId, code, name) {
|
|
locationId.value = objId;
|
|
selectedLocationText.textContent = `${code} - ${name}`;
|
|
selectedLocation.style.display = 'block';
|
|
locationSearch.value = '';
|
|
locationResults.style.display = 'none';
|
|
|
|
// Enable asset search
|
|
assetSearch.disabled = false;
|
|
assetSearchHint.style.display = 'none';
|
|
|
|
// Update title suggestion
|
|
updateTitleSuggestionDesktop();
|
|
};
|
|
|
|
window.clearLocationDesktop = function() {
|
|
locationId.value = '';
|
|
selectedLocation.style.display = 'none';
|
|
selectedLocationText.textContent = '';
|
|
|
|
// Clear and disable asset search
|
|
clearAssetDesktop();
|
|
assetSearch.disabled = true;
|
|
assetSearchHint.style.display = 'block';
|
|
};
|
|
|
|
// Asset search
|
|
assetSearch.addEventListener('input', function() {
|
|
clearTimeout(searchTimeout);
|
|
const query = this.value.trim();
|
|
|
|
if (query.length < 2 || !locationId.value) {
|
|
assetResults.style.display = 'none';
|
|
return;
|
|
}
|
|
|
|
searchTimeout = setTimeout(() => {
|
|
searchAssets(query);
|
|
}, 300);
|
|
});
|
|
|
|
async function searchAssets(query) {
|
|
try {
|
|
const categoryId = categorySelect.value;
|
|
let url = `{% url 'assets:structures_autocomplete_assets' %}?q=${encodeURIComponent(query)}&location_id=${locationId.value}`;
|
|
if (categoryId) {
|
|
url += `&asset_category=${categoryId}`;
|
|
}
|
|
|
|
const response = await fetch(url);
|
|
const data = await response.json();
|
|
|
|
assetResults.innerHTML = '';
|
|
if (data.length > 0) {
|
|
data.forEach(item => {
|
|
const div = document.createElement('div');
|
|
div.className = 'p-2 border-bottom cursor-pointer';
|
|
div.style.cursor = 'pointer';
|
|
div.innerHTML = item.label;
|
|
div.addEventListener('click', () => selectAssetDesktop(item.id, item.label));
|
|
assetResults.appendChild(div);
|
|
});
|
|
assetResults.style.display = 'block';
|
|
} else {
|
|
assetResults.innerHTML = '<div class="p-2 text-muted">{% translate "Aucun résultat" %}</div>';
|
|
assetResults.style.display = 'block';
|
|
}
|
|
} catch (error) {
|
|
console.error('Error searching assets:', error);
|
|
}
|
|
}
|
|
|
|
window.selectAssetDesktop = function(id, label) {
|
|
assetId.value = id;
|
|
selectedAssetText.textContent = label;
|
|
selectedAsset.style.display = 'block';
|
|
assetSearch.value = '';
|
|
assetResults.style.display = 'none';
|
|
|
|
// Update title suggestion with asset
|
|
updateTitleSuggestionDesktop();
|
|
};
|
|
|
|
window.clearAssetDesktop = function() {
|
|
assetId.value = '';
|
|
selectedAsset.style.display = 'none';
|
|
selectedAssetText.textContent = '';
|
|
};
|
|
|
|
// Title suggestion
|
|
function updateTitleSuggestionDesktop() {
|
|
if (titleInput.value.trim() === '') {
|
|
let suggestion = '';
|
|
const categoryText = categorySelect.options[categorySelect.selectedIndex]?.text;
|
|
const locationText = selectedLocationText.textContent;
|
|
|
|
if (categoryText && categoryText !== categorySelect.options[0].text) {
|
|
suggestion = categoryText;
|
|
}
|
|
if (locationText) {
|
|
const locationCode = locationText.split(' - ')[0];
|
|
suggestion = suggestion ? `${suggestion} - ${locationCode}` : locationCode;
|
|
}
|
|
|
|
if (suggestion) {
|
|
titleInput.value = suggestion;
|
|
}
|
|
}
|
|
}
|
|
|
|
categorySelect.addEventListener('change', updateTitleSuggestionDesktop);
|
|
|
|
// Close results on click outside
|
|
document.addEventListener('click', function(e) {
|
|
if (!locationSearch.contains(e.target) && !locationResults.contains(e.target)) {
|
|
locationResults.style.display = 'none';
|
|
}
|
|
if (!assetSearch.contains(e.target) && !assetResults.contains(e.target)) {
|
|
assetResults.style.display = 'none';
|
|
}
|
|
});
|
|
})();
|
|
|
|
async function submitRepairInterventionForm() {
|
|
const form = document.getElementById('addRepairInterventionForm');
|
|
const formData = new FormData(form);
|
|
|
|
// Validation basique
|
|
const locationId = document.getElementById('locationIdDesktop').value;
|
|
const categoryId = document.getElementById('categorySelectDesktop').value;
|
|
const title = document.getElementById('titleInputDesktop').value.trim();
|
|
|
|
if (!locationId) {
|
|
alert('{% translate "La localisation est obligatoire." %}');
|
|
return;
|
|
}
|
|
if (!categoryId) {
|
|
alert('{% translate "La catégorie est obligatoire." %}');
|
|
return;
|
|
}
|
|
if (!title) {
|
|
alert('{% translate "Le titre est obligatoire." %}');
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const response = await fetch('{% url "interventions:add_repair_intervention_modal" %}', {
|
|
method: 'POST',
|
|
body: formData,
|
|
headers: {
|
|
'X-Requested-With': 'XMLHttpRequest'
|
|
}
|
|
});
|
|
|
|
if (response.ok) {
|
|
const data = await response.json();
|
|
if (data.success) {
|
|
// Close modal
|
|
const modal = bootstrap.Modal.getInstance(document.getElementById('addRepairInterventionModal'));
|
|
modal.hide();
|
|
|
|
// Show success message
|
|
alert(`{% translate "L'intervention" %} ${data.code} {% translate "a été créée avec succès." %}`);
|
|
|
|
// Reload page or redirect
|
|
window.location.href = '{% url "interventions:interventions_index" %}';
|
|
} else {
|
|
alert(data.error || '{% translate "Une erreur est survenue." %}');
|
|
}
|
|
} else {
|
|
alert('{% translate "Une erreur est survenue." %}');
|
|
}
|
|
} catch (error) {
|
|
console.error('Error:', error);
|
|
alert('{% translate "Une erreur est survenue." %}');
|
|
}
|
|
}
|
|
</script>
|