1240 lines
71 KiB
HTML
1240 lines
71 KiB
HTML
{% load i18n static %}
|
|
|
|
<!-- Component Formulaire d'Inspection GIEP Natif Mobile-First (Recommandations avec 5 choix) -->
|
|
<div id="giepSpecificFields" class="border rounded-4 p-3 mb-3 bg-white shadow-sm">
|
|
|
|
<!-- En-tête -->
|
|
<div class="d-flex align-items-center justify-content-between mb-3 border-bottom pb-2">
|
|
<div class="d-flex align-items-center gap-2">
|
|
<i class="bi bi-droplet-fill text-primary fs-5"></i>
|
|
<h6 class="fw-bold mb-0 text-primary">{% translate "Formulaire d'inspection GIEP" %}</h6>
|
|
</div>
|
|
<span class="badge bg-info text-white px-2.5 py-1 rounded-pill">{% translate "Eaux Pluviales" %}</span>
|
|
</div>
|
|
|
|
<!-- Hidden Field pour la sérialisation JSON -->
|
|
<input type="hidden" name="giep_data" id="giep_data_serialized" value="{}">
|
|
|
|
<!-- 1. Conditions météorologiques -->
|
|
<div class="card border-primary-subtle bg-light-subtle mb-3 rounded-4 shadow-sm">
|
|
<div class="card-body p-3">
|
|
<h6 class="fw-bold mb-3 small text-uppercase text-primary border-bottom pb-2">
|
|
<i class="bi bi-cloud-sun-fill me-2"></i>{% translate "Conditions météorologiques" %}
|
|
</h6>
|
|
<div class="row g-3">
|
|
<div class="col-12 col-md-6">
|
|
<label class="form-label small fw-semibold mb-1">
|
|
<i class="bi bi-cloud-rain me-1 text-primary"></i>{% translate "Date de la dernière pluie" %}
|
|
</label>
|
|
<select name="date_derniere_pluie" id="giep_date_derniere_pluie" class="form-select form-select-sm giep-input rounded-pill">
|
|
<option value="null" selected>-- {% translate "Non renseigné" %} --</option>
|
|
<option value="aujourdhui">{% translate "Aujourd'hui" %}</option>
|
|
<option value="moins_24h">{% translate "Moins de 24h" %}</option>
|
|
<option value="plus_24h">{% translate "Plus de 24h" %}</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-12 col-md-6">
|
|
<label class="form-label small fw-semibold mb-1">
|
|
<i class="bi bi-lightning-charge me-1 text-danger"></i>{% translate "Orage récent (-1h)" %}
|
|
</label>
|
|
<select name="orage_moins_une_heure" id="giep_orage_moins_une_heure" class="form-select form-select-sm giep-input rounded-pill">
|
|
<option value="null" selected>-- {% translate "Non renseigné" %} --</option>
|
|
<option value="true">{% translate "Oui" %}</option>
|
|
<option value="false">{% translate "Non" %}</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 2. Ouvrages de la zone -->
|
|
<div class="mb-2">
|
|
<div class="d-flex align-items-center justify-content-between mb-2">
|
|
<h6 class="fw-bold mb-0 small text-uppercase text-secondary">
|
|
<i class="bi bi-list-check me-2"></i>{% translate "Ouvrages inspectés" %}
|
|
</h6>
|
|
<button type="button" class="btn btn-outline-success btn-sm py-1.5 px-3 fw-semibold rounded-pill shadow-sm" id="giep_add_ouvrage_btn">
|
|
<i class="bi bi-plus-circle me-1"></i>{% translate "Ajouter un ouvrage" %}
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Dynamic Container for Ouvrages -->
|
|
<div id="giep_ouvrages_container" class="d-flex flex-column gap-3"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Modal pour Sélection des Équipements GIEP sur Carte -->
|
|
<div class="modal fade" id="giepAssetMapModal" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1" aria-labelledby="giepAssetMapModalLabel" aria-hidden="true" style="z-index: 1060;">
|
|
<div class="modal-dialog modal-lg modal-dialog-centered modal-dialog-scrollable">
|
|
<div class="modal-content rounded-4 shadow-lg border-0">
|
|
<div class="modal-header bg-primary text-white py-2.5 px-3 rounded-top-4">
|
|
<h6 class="modal-title fw-bold mb-0" id="giepAssetMapModalLabel">
|
|
<i class="bi bi-droplet-fill me-2"></i>{% translate "Sélectionner un équipement GIEP sur la carte" %}
|
|
</h6>
|
|
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="{% translate 'Fermer' %}"></button>
|
|
</div>
|
|
<div class="modal-body p-3">
|
|
<div class="row g-2 mb-3">
|
|
<div class="col-12 col-md-7">
|
|
<div class="input-group input-group-sm">
|
|
<span class="input-group-text bg-white"><i class="bi bi-search text-muted"></i></span>
|
|
<input type="text" id="giep_modal_search_input" class="form-control" placeholder="{% translate 'Filtrer par code (ex: BI-01...) ou par type...' %}">
|
|
</div>
|
|
</div>
|
|
<div class="col-12 col-md-5">
|
|
<select id="giep_modal_type_filter" class="form-select form-select-sm">
|
|
<option value="">{% translate "Tous les types d'équipements" %}</option>
|
|
<option value="evc">{% translate "Espace vert creux (EVC)" %}</option>
|
|
<option value="oed">{% translate "Massif drainant (OED)" %}</option>
|
|
<option value="ta">{% translate "Technique alternative (TA)" %}</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<!-- Conteneur Carte Agrandie -->
|
|
<div id="giep_modal_map_container" class="rounded-3 border overflow-hidden" style="height: 480px; max-height: 68vh; position: relative;">
|
|
<div id="giepModalMap" style="width: 100%; height: 100%;"></div>
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer py-2 px-3 bg-light">
|
|
<button type="button" class="btn btn-secondary btn-sm rounded-pill" data-bs-dismiss="modal">{% translate "Fermer" %}</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<style>
|
|
.device-select-btn {
|
|
border: 2px solid #dee2e6;
|
|
border-radius: 16px;
|
|
background: #ffffff;
|
|
padding: 0.6rem 0.4rem;
|
|
text-align: center;
|
|
cursor: pointer;
|
|
transition: all 0.2s ease;
|
|
}
|
|
.device-select-btn:hover {
|
|
border-color: #adb5bd;
|
|
}
|
|
.device-select-btn.active[data-device="evc"] {
|
|
border-color: #2e7d32;
|
|
background-color: #e8f5e9;
|
|
box-shadow: 0 3px 8px rgba(46,125,50,0.18);
|
|
}
|
|
.device-select-btn.active[data-device="oed"] {
|
|
border-color: #0277bd;
|
|
background-color: #e1f5fe;
|
|
box-shadow: 0 3px 8px rgba(2,119,189,0.18);
|
|
}
|
|
.device-select-btn.active[data-device="ta"] {
|
|
border-color: #00796b;
|
|
background-color: #e0f2f1;
|
|
box-shadow: 0 3px 8px rgba(0,121,107,0.18);
|
|
}
|
|
.btn-seg {
|
|
border-radius: 50rem !important;
|
|
touch-action: manipulation;
|
|
user-select: none;
|
|
transition: all 0.2s ease;
|
|
flex: 1 1 0px !important;
|
|
width: 0 !important;
|
|
font-size: 0.72rem !important;
|
|
padding: 0.35rem 0.2rem !important;
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
text-align: center;
|
|
line-height: 1.1;
|
|
min-height: 36px;
|
|
}
|
|
.btn-seg:hover {
|
|
transform: translateY(-1px);
|
|
}
|
|
</style>
|
|
|
|
<script>
|
|
(function() {
|
|
function createEmptyOuvrage(idx, deviceType = "evc", asset = null) {
|
|
return {
|
|
local_id: String(idx),
|
|
device_type: deviceType,
|
|
name: asset ? (asset.code + (asset.structure_type ? ' (' + asset.structure_type + ')' : '')) : `Ouvrage #${idx + 1}`,
|
|
asset_id: asset ? asset.id : null,
|
|
asset_code: asset ? asset.code : null,
|
|
asset_name: asset ? (asset.structure_type || asset.name || '') : null,
|
|
questions: {
|
|
// EVC
|
|
evc_pe_ok: null,
|
|
evc_pe_feuilles: null,
|
|
evc_pe_detritus: null,
|
|
evc_empierrement_present: false,
|
|
evc_empierrement_ok: null,
|
|
evc_empierrement_colmate: false,
|
|
evc_empierrement_emporte: false,
|
|
evc_empierrement_envahi: false,
|
|
evc_ev_veg_etat: null,
|
|
evc_ev_plantes_mortes: null,
|
|
evc_ev_chenaux_erosion: null,
|
|
evc_ev_flaques: null,
|
|
evc_ev_sediments: null,
|
|
evc_ev_croute_sediments: null,
|
|
evc_ev_envahissantes: null,
|
|
evc_surverse_presente: false,
|
|
evc_sv_grille_propre: null,
|
|
evc_sv_decantation_vide: null,
|
|
evc_sv_haute: null,
|
|
|
|
// OED
|
|
oed_revetement_ok: null,
|
|
oed_revetement_ornieres: false,
|
|
oed_revetement_fissures: false,
|
|
oed_revetement_trous: false,
|
|
oed_injection_presente: false,
|
|
oed_bi_niveaux_ok: null,
|
|
oed_bi_grille_propre: null,
|
|
oed_bi_decantation_vide: null,
|
|
oed_bi_filtre_present: null,
|
|
oed_bi_filtre_propre: null,
|
|
oed_bi_filtre_bon: null,
|
|
oed_bi_drain_colmate: null,
|
|
oed_rhm_presente: false,
|
|
oed_rhm_stagne: null,
|
|
oed_rhm_stagne_plus_2h: null,
|
|
oed_rhm_joints_ok: null,
|
|
oed_rhm_joints_fines: null,
|
|
oed_rhm_joints_remplissage: null,
|
|
oed_rp_presente: false,
|
|
oed_rp_stagne: null,
|
|
oed_rp_stagne_plus_2h: null,
|
|
oed_rp_depots: null,
|
|
oed_rp_test_permeabilite: null,
|
|
oed_rna_presente: false,
|
|
oed_rna_stagne: null,
|
|
oed_rna_stagne_plus_2h: null,
|
|
oed_rna_matiere_ok: null,
|
|
oed_rna_geotextile_visible: null,
|
|
|
|
// TA
|
|
ta_pe_ok: null,
|
|
ta_pe_conduits_ok: null,
|
|
ta_pe_grilles: null,
|
|
ta_pe_feuilles: null,
|
|
ta_pe_detritus: null,
|
|
ta_bo_vegetation_etat: null,
|
|
ta_bo_plantes_mortes: null,
|
|
ta_bo_chenaux: null,
|
|
ta_bo_flaques: null,
|
|
ta_sediments: null,
|
|
ta_sediments_rempli: null,
|
|
ta_bo_detritus: null,
|
|
ta_bo_envahissantes: null
|
|
},
|
|
actions: {}
|
|
};
|
|
}
|
|
|
|
// Formulaire initialement à VIDE (0 ouvrages)
|
|
let giepOuvrages = [];
|
|
let locationGiepAssets = [];
|
|
let activeOuvrageIdxForMap = null;
|
|
let modalMapInstance = null;
|
|
let modalMapMarkers = [];
|
|
|
|
const container = document.getElementById('giep_ouvrages_container');
|
|
const serializedInput = document.getElementById('giep_data_serialized');
|
|
const addBtn = document.getElementById('giep_add_ouvrage_btn');
|
|
|
|
function extendBoundsFromGeom(bounds, geom) {
|
|
if (!bounds || !geom || !geom.coordinates) return;
|
|
const type = geom.type;
|
|
if (type === 'Point') {
|
|
bounds.extend(geom.coordinates);
|
|
} else if (type === 'LineString' || type === 'MultiPoint') {
|
|
geom.coordinates.forEach(c => bounds.extend(c));
|
|
} else if (type === 'Polygon' || type === 'MultiLineString') {
|
|
geom.coordinates.forEach(ring => ring.forEach(c => bounds.extend(c)));
|
|
} else if (type === 'MultiPolygon') {
|
|
geom.coordinates.forEach(poly => poly.forEach(ring => ring.forEach(c => bounds.extend(c))));
|
|
}
|
|
}
|
|
|
|
function fetchLocationAssets() {
|
|
if (locationGiepAssets.length > 0) return Promise.resolve(locationGiepAssets);
|
|
let locationId = null;
|
|
const modalTrigger = document.querySelector('[data-object-id]');
|
|
if (modalTrigger) {
|
|
locationId = modalTrigger.getAttribute('data-object-id');
|
|
} else {
|
|
const urlMatch = window.location.pathname.match(/\/zirw\/(\d+)\//);
|
|
if (urlMatch) locationId = urlMatch[1];
|
|
}
|
|
if (!locationId) return Promise.resolve([]);
|
|
|
|
return fetch("{% url 'assets:water_assets_geojson' %}?location=" + locationId)
|
|
.then(r => r.json())
|
|
.then(data => {
|
|
if (data && data.features) {
|
|
locationGiepAssets = data.features.map(f => {
|
|
const props = f.properties || {};
|
|
let lon = props.lon;
|
|
let lat = props.lat;
|
|
if ((lon === null || lon === undefined || lat === null || lat === undefined) && f.geometry) {
|
|
if (f.geometry.type === 'Point' && Array.isArray(f.geometry.coordinates)) {
|
|
lon = f.geometry.coordinates[0];
|
|
lat = f.geometry.coordinates[1];
|
|
}
|
|
}
|
|
return {
|
|
id: f.id,
|
|
code: props.code || `Asset #${f.id}`,
|
|
name: props.name || props.structure_type || props.category || props.code || `Asset #${f.id}`,
|
|
structure_type: props.structure_type || '',
|
|
category: props.category || '',
|
|
lon: (lon !== null && lon !== undefined) ? parseFloat(lon) : null,
|
|
lat: (lat !== null && lat !== undefined) ? parseFloat(lat) : null,
|
|
geometry: f.geometry,
|
|
rawFeature: f
|
|
};
|
|
});
|
|
}
|
|
return locationGiepAssets;
|
|
})
|
|
.catch(err => {
|
|
console.warn("Erreur de chargement des équipements GIEP :", err);
|
|
return [];
|
|
});
|
|
}
|
|
|
|
function inferDeviceType(asset) {
|
|
if (!asset) return null;
|
|
const text = ((asset.structure_type || '') + ' ' + (asset.name || '') + ' ' + (asset.category || '')).toLowerCase();
|
|
|
|
// Avaloirs, Bouches d'injection, Regards, Grilles : équipements d'accès non associés à l'un des 3 types
|
|
if (text.includes('avaloir') || text.includes('injection') || text.includes('regard') || text.includes('grille')) {
|
|
return null;
|
|
}
|
|
|
|
// EVC (Espace Vert Creux, Noue, Jardin de pluie, Zone végétalisée creuse)
|
|
if (text.includes('espace vert') || text.includes('creux') || text.includes('evc') || text.includes('noue') || text.includes('gazon') || text.includes('jardin') || text.includes('végétalis')) {
|
|
return 'evc';
|
|
}
|
|
|
|
// TA (Technique Alternative, Bassin d'orage, Surverse, Trop-plein, Marre)
|
|
if (text.includes('bassin') || text.includes('orage') || text.includes('technique alternative') || text.includes('ta') || text.includes('surverse') || text.includes('trop plein') || text.includes('marre')) {
|
|
return 'ta';
|
|
}
|
|
|
|
// OED (Massif drainant, Chaussée réservoir, Dalles, Tranchée drainante, Revêtement poreux)
|
|
if (text.includes('massif') || text.includes('drainant') || text.includes('oed') || text.includes('chaussée') || text.includes('revêtement') || text.includes('dalle') || text.includes('tranchée')) {
|
|
return 'oed';
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
let currentMapPopup = null;
|
|
|
|
function showAssetPopup(asset, lngLat) {
|
|
if (!modalMapInstance) return;
|
|
if (currentMapPopup) {
|
|
currentMapPopup.remove();
|
|
currentMapPopup = null;
|
|
}
|
|
|
|
const devType = inferDeviceType(asset);
|
|
let badgeHtml = '';
|
|
if (devType === 'evc') badgeHtml = '<span class="badge bg-success-subtle text-success text-uppercase me-1">EVC</span>';
|
|
else if (devType === 'oed') badgeHtml = '<span class="badge bg-info-subtle text-info text-uppercase me-1">OED</span>';
|
|
else if (devType === 'ta') badgeHtml = '<span class="badge bg-teal-subtle text-teal text-uppercase me-1">TA</span>';
|
|
else badgeHtml = '<span class="badge bg-secondary-subtle text-secondary text-uppercase me-1">Équipement</span>';
|
|
|
|
const popupNode = document.createElement('div');
|
|
popupNode.className = 'p-1';
|
|
popupNode.innerHTML = `
|
|
<div class="d-flex align-items-center gap-1.5 mb-1">
|
|
<i class="bi bi-droplet-fill text-primary"></i>
|
|
<strong class="fw-bold text-dark fs-6">${asset.code}</strong>
|
|
</div>
|
|
<div class="small text-dark fw-semibold mb-1">${asset.name || asset.structure_type || ''}</div>
|
|
<div class="extra-small text-muted mb-2">
|
|
${badgeHtml}
|
|
<span>${asset.structure_type || ''}</span>
|
|
</div>
|
|
<button type="button" class="btn btn-primary btn-sm w-100 rounded-pill py-1.5 px-3 fw-semibold select-popup-btn">
|
|
<i class="bi bi-check-circle me-1"></i>{% filter escapejs %}{% translate "Sélectionner" %}{% endfilter %}
|
|
</button>
|
|
`;
|
|
|
|
popupNode.querySelector('.select-popup-btn').addEventListener('click', () => {
|
|
selectAssetForOuvrage(activeOuvrageIdxForMap, asset);
|
|
const modalEl = document.getElementById('giepAssetMapModal');
|
|
const modalInstance = bootstrap.Modal.getInstance(modalEl);
|
|
if (modalInstance) modalInstance.hide();
|
|
});
|
|
|
|
currentMapPopup = new maplibregl.Popup({ offset: 15, closeButton: true, maxWidth: '250px' })
|
|
.setLngLat(lngLat)
|
|
.setDOMContent(popupNode)
|
|
.addTo(modalMapInstance);
|
|
}
|
|
|
|
function selectAssetForOuvrage(idx, asset) {
|
|
if (typeof idx !== 'number' || !giepOuvrages[idx]) return;
|
|
giepOuvrages[idx].asset_id = asset.id;
|
|
giepOuvrages[idx].asset_code = asset.code;
|
|
giepOuvrages[idx].asset_name = asset.structure_type || asset.name || asset.code;
|
|
const inferred = inferDeviceType(asset);
|
|
if (inferred) {
|
|
giepOuvrages[idx].device_type = inferred;
|
|
}
|
|
renderOuvrages();
|
|
}
|
|
|
|
function updateSerializedGiepData() {
|
|
const pluieVal = document.getElementById('giep_date_derniere_pluie')?.value || 'null';
|
|
const orageVal = document.getElementById('giep_orage_moins_une_heure')?.value || 'null';
|
|
|
|
const payload = {
|
|
ouvrages: giepOuvrages,
|
|
date_derniere_pluie: pluieVal,
|
|
orage_moins_une_heure: orageVal === 'true' ? true : (orageVal === 'false' ? false : null)
|
|
};
|
|
if (serializedInput) {
|
|
serializedInput.value = JSON.stringify(payload);
|
|
}
|
|
}
|
|
|
|
// Helper pour générer des boutons segmentés
|
|
function renderSegGroup(idx, qKey, label, currentVal, options) {
|
|
const opts = options || [
|
|
{val: 'true', text: '{% filter escapejs %}{% translate "Oui" %}{% endfilter %}', activeClass: 'btn-success', inactiveClass: 'btn-outline-success'},
|
|
{val: 'false', text: '{% filter escapejs %}{% translate "Non" %}{% endfilter %}', activeClass: 'btn-danger', inactiveClass: 'btn-outline-danger'},
|
|
{val: 'null', text: '{% filter escapejs %}{% translate "Non vérifié" %}{% endfilter %}', activeClass: 'btn-secondary', inactiveClass: 'btn-outline-secondary'}
|
|
];
|
|
|
|
let btnsHtml = opts.map(opt => {
|
|
const isSelected = (currentVal === opt.val);
|
|
const btnClass = isSelected ? opt.activeClass : opt.inactiveClass;
|
|
return `<button type="button" class="btn ${btnClass} btn-seg fw-semibold shadow-sm" data-idx="${idx}" data-q="${qKey}" data-val="${opt.val}">${opt.text}</button>`;
|
|
}).join('');
|
|
|
|
return `
|
|
<div class="mb-3">
|
|
<label class="form-label small fw-semibold text-dark mb-1.5 d-block">${label}</label>
|
|
<div class="d-flex gap-2 w-100" role="group">
|
|
${btnsHtml}
|
|
</div>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
function populateModalAssetsList(filterText = '', filterType = '') {
|
|
// Obsolete list, filtering operates directly on map layers
|
|
}
|
|
|
|
function renderModalMapFeatures(isInitialFit = false) {
|
|
if (!modalMapInstance) return;
|
|
|
|
if (modalMapMarkers) {
|
|
modalMapMarkers.forEach(m => m.remove());
|
|
modalMapMarkers = [];
|
|
}
|
|
|
|
const filterText = (document.getElementById('giep_modal_search_input')?.value || '').toLowerCase().trim();
|
|
const filterType = document.getElementById('giep_modal_type_filter')?.value || '';
|
|
|
|
const filteredFeatures = [];
|
|
const bounds = (typeof maplibregl !== 'undefined') ? new maplibregl.LngLatBounds() : null;
|
|
let hasCoords = false;
|
|
|
|
locationGiepAssets.forEach(asset => {
|
|
const matchText = !filterText || asset.code.toLowerCase().includes(filterText) || (asset.structure_type && asset.structure_type.toLowerCase().includes(filterText)) || (asset.name && asset.name.toLowerCase().includes(filterText));
|
|
const devType = inferDeviceType(asset);
|
|
const matchType = !filterType || devType === filterType;
|
|
|
|
if (matchText && matchType && asset.rawFeature && asset.rawFeature.geometry && typeof maplibregl !== 'undefined') {
|
|
const geom = asset.rawFeature.geometry;
|
|
let color = '#0277bd'; // Bleu GIEP (naturerwiasset)
|
|
if (devType === 'evc') color = '#2e7d32'; // Vert EVC
|
|
if (devType === 'oed') color = '#0277bd'; // Bleu OED
|
|
if (devType === 'ta') color = '#00796b'; // Turquoise TA
|
|
|
|
const featureClone = {
|
|
type: 'Feature',
|
|
id: asset.id,
|
|
geometry: geom,
|
|
properties: {
|
|
...(asset.rawFeature.properties || {}),
|
|
id: asset.id,
|
|
code: asset.code,
|
|
name: asset.name,
|
|
structure_type: asset.structure_type,
|
|
device_type: devType,
|
|
color: color
|
|
}
|
|
};
|
|
|
|
filteredFeatures.push(featureClone);
|
|
if (isInitialFit) {
|
|
extendBoundsFromGeom(bounds, geom);
|
|
}
|
|
hasCoords = true;
|
|
|
|
// Marqueurs ronds pour les géométries de type Point
|
|
if (geom.type === 'Point' && Array.isArray(geom.coordinates)) {
|
|
const lon = geom.coordinates[0];
|
|
const lat = geom.coordinates[1];
|
|
if (!isNaN(lon) && !isNaN(lat)) {
|
|
const el = document.createElement('div');
|
|
el.className = 'giep-map-marker';
|
|
el.style.width = '28px';
|
|
el.style.height = '28px';
|
|
el.style.borderRadius = '50%';
|
|
el.style.backgroundColor = color;
|
|
el.style.border = '2.5px solid white';
|
|
el.style.boxShadow = '0 3px 8px rgba(0,0,0,0.4)';
|
|
el.style.cursor = 'pointer';
|
|
el.style.display = 'flex';
|
|
el.style.alignItems = 'center';
|
|
el.style.justifyContent = 'center';
|
|
el.innerHTML = '<i class="bi bi-droplet-fill text-white" style="font-size: 14px;"></i>';
|
|
el.title = `${asset.code} - ${asset.structure_type || asset.name}`;
|
|
|
|
const marker = new maplibregl.Marker({ element: el })
|
|
.setLngLat([lon, lat])
|
|
.addTo(modalMapInstance);
|
|
|
|
el.addEventListener('click', (e) => {
|
|
e.stopPropagation();
|
|
showAssetPopup(asset, [lon, lat]);
|
|
});
|
|
|
|
modalMapMarkers.push(marker);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
const geojsonPayload = {
|
|
type: 'FeatureCollection',
|
|
features: filteredFeatures
|
|
};
|
|
|
|
const source = modalMapInstance.getSource('giep-assets-src');
|
|
if (source) {
|
|
source.setData(geojsonPayload);
|
|
} else {
|
|
modalMapInstance.addSource('giep-assets-src', {
|
|
type: 'geojson',
|
|
data: geojsonPayload
|
|
});
|
|
|
|
// 1. Couche de remplissage (Polygones) — EN-DESSOUS
|
|
modalMapInstance.addLayer({
|
|
id: 'giep-assets-fill',
|
|
type: 'fill',
|
|
source: 'giep-assets-src',
|
|
filter: ['match', ['geometry-type'], ['Polygon', 'MultiPolygon'], true, false],
|
|
paint: {
|
|
'fill-color': ['get', 'color'],
|
|
'fill-opacity': 0.45
|
|
}
|
|
});
|
|
|
|
// 2. Couche de lignes (Lignes et contours) — AU MILIEU
|
|
modalMapInstance.addLayer({
|
|
id: 'giep-assets-line',
|
|
type: 'line',
|
|
source: 'giep-assets-src',
|
|
filter: ['match', ['geometry-type'], ['LineString', 'MultiLineString', 'Polygon', 'MultiPolygon'], true, false],
|
|
paint: {
|
|
'line-color': ['get', 'color'],
|
|
'line-width': 3.5
|
|
}
|
|
});
|
|
|
|
// 3. Couche de cercles (Points) — AU-DESSUS
|
|
modalMapInstance.addLayer({
|
|
id: 'giep-assets-circle',
|
|
type: 'circle',
|
|
source: 'giep-assets-src',
|
|
filter: ['match', ['geometry-type'], ['Point', 'MultiPoint'], true, false],
|
|
paint: {
|
|
'circle-color': ['get', 'color'],
|
|
'circle-radius': 8,
|
|
'circle-stroke-width': 2.5,
|
|
'circle-stroke-color': '#ffffff'
|
|
}
|
|
});
|
|
|
|
// Un seul handler de clic sur la carte avec priorité stricte de géométrie (Points > Lignes > Polygones)
|
|
modalMapInstance.on('click', (e) => {
|
|
const layers = ['giep-assets-circle', 'giep-assets-line', 'giep-assets-fill'];
|
|
const features = modalMapInstance.queryRenderedFeatures(e.point, { layers: layers });
|
|
if (!features || features.length === 0) return;
|
|
|
|
const priorityOrder = { 'Point': 1, 'MultiPoint': 1, 'LineString': 2, 'MultiLineString': 2, 'Polygon': 3, 'MultiPolygon': 3 };
|
|
features.sort((a, b) => {
|
|
const typeA = a.geometry ? a.geometry.type : '';
|
|
const typeB = b.geometry ? b.geometry.type : '';
|
|
const pA = priorityOrder[typeA] || 99;
|
|
const pB = priorityOrder[typeB] || 99;
|
|
return pA - pB;
|
|
});
|
|
|
|
const topFeature = features[0];
|
|
const props = topFeature.properties;
|
|
const targetAsset = locationGiepAssets.find(a => String(a.id) === String(props.id));
|
|
if (targetAsset) {
|
|
showAssetPopup(targetAsset, e.lngLat);
|
|
}
|
|
});
|
|
|
|
['giep-assets-circle', 'giep-assets-line', 'giep-assets-fill'].forEach(layerId => {
|
|
modalMapInstance.on('mouseenter', layerId, () => {
|
|
modalMapInstance.getCanvas().style.cursor = 'pointer';
|
|
});
|
|
modalMapInstance.on('mouseleave', layerId, () => {
|
|
modalMapInstance.getCanvas().style.cursor = '';
|
|
});
|
|
});
|
|
}
|
|
|
|
// Seul le chargement initial modifie le zoom et cadrage de la carte
|
|
if (isInitialFit && hasCoords && bounds && !bounds.isEmpty()) {
|
|
modalMapInstance.fitBounds(bounds, { padding: 50, maxZoom: 18 });
|
|
}
|
|
}
|
|
|
|
function initOrUpdateModalMap() {
|
|
const containerEl = document.getElementById('giepModalMap');
|
|
if (!containerEl || typeof maplibregl === 'undefined') return;
|
|
|
|
const style = window.MAP_STYLE_LIGHT || 'https://basemaps.cartocdn.com/gl/positron-gl-style/style.json';
|
|
|
|
if (!modalMapInstance) {
|
|
modalMapInstance = new maplibregl.Map({
|
|
container: 'giepModalMap',
|
|
style: style,
|
|
center: [4.3517, 50.8503],
|
|
zoom: 15,
|
|
antialias: true
|
|
});
|
|
|
|
// Contrôles de navigation et de géolocalisation
|
|
modalMapInstance.addControl(new maplibregl.NavigationControl(), 'top-right');
|
|
|
|
const geolocate = new maplibregl.GeolocateControl({
|
|
positionOptions: { enableHighAccuracy: true },
|
|
trackUserLocation: true,
|
|
showUserLocation: true
|
|
});
|
|
modalMapInstance.addControl(geolocate, 'top-right');
|
|
|
|
modalMapInstance.on('load', () => {
|
|
renderModalMapFeatures(true);
|
|
geolocate.trigger();
|
|
});
|
|
} else {
|
|
setTimeout(() => {
|
|
modalMapInstance.resize();
|
|
renderModalMapFeatures(true);
|
|
}, 150);
|
|
}
|
|
|
|
// Tentative de géolocalisation de l'utilisateur si navigateur supporté
|
|
if (navigator.geolocation) {
|
|
navigator.geolocation.getCurrentPosition(
|
|
(pos) => {
|
|
const uLon = pos.coords.longitude;
|
|
const uLat = pos.coords.latitude;
|
|
if (modalMapInstance) {
|
|
modalMapInstance.flyTo({ center: [uLon, uLat], zoom: 16 });
|
|
}
|
|
},
|
|
(err) => {
|
|
console.log("Géolocalisation utilisateur non disponible:", err);
|
|
},
|
|
{ enableHighAccuracy: true, timeout: 6000 }
|
|
);
|
|
}
|
|
}
|
|
|
|
function openMapModal(idx) {
|
|
activeOuvrageIdxForMap = idx;
|
|
fetchLocationAssets().then(assets => {
|
|
populateModalAssetsList();
|
|
const modalEl = document.getElementById('giepAssetMapModal');
|
|
let modalInstance = bootstrap.Modal.getInstance(modalEl);
|
|
if (!modalInstance) {
|
|
modalInstance = new bootstrap.Modal(modalEl);
|
|
}
|
|
modalInstance.show();
|
|
});
|
|
}
|
|
|
|
function renderOuvrages() {
|
|
if (!container) return;
|
|
container.innerHTML = '';
|
|
|
|
if (giepOuvrages.length === 0) {
|
|
container.innerHTML = `
|
|
<div class="text-center p-4 border border-dashed rounded-4 bg-light shadow-sm my-2" id="giep_empty_state">
|
|
<i class="bi bi-inbox fs-2 text-primary opacity-50 d-block mb-2"></i>
|
|
<h6 class="fw-bold text-secondary mb-1">{% filter escapejs %}{% translate "Aucun ouvrage dans cette inspection" %}{% endfilter %}</h6>
|
|
<p class="small text-muted mb-3">{% filter escapejs %}{% translate "Cliquez ci-dessous pour ajouter un ouvrage à inspecter." %}{% endfilter %}</p>
|
|
<button type="button" class="btn btn-success btn-sm px-3.5 py-2 rounded-pill fw-semibold shadow-sm" id="giep_add_first_ouvrage_btn">
|
|
<i class="bi bi-plus-circle me-1"></i>{% filter escapejs %}{% translate "Ajouter un ouvrage" %}{% endfilter %}
|
|
</button>
|
|
</div>
|
|
`;
|
|
document.getElementById('giep_add_first_ouvrage_btn')?.addEventListener('click', () => {
|
|
giepOuvrages.push(createEmptyOuvrage(0, "evc"));
|
|
renderOuvrages();
|
|
});
|
|
updateSerializedGiepData();
|
|
return;
|
|
}
|
|
|
|
giepOuvrages.forEach((ouv, idx) => {
|
|
const card = document.createElement('div');
|
|
card.className = 'card border p-3 bg-light rounded-4 shadow-sm';
|
|
|
|
let deviceBorder = 'border-start: 4px solid #2e7d32;';
|
|
if (ouv.device_type === 'oed') deviceBorder = 'border-start: 4px solid #0277bd;';
|
|
if (ouv.device_type === 'ta') deviceBorder = 'border-start: 4px solid #00796b;';
|
|
card.style = deviceBorder;
|
|
|
|
const q = ouv.questions || {};
|
|
const act = ouv.actions || {};
|
|
|
|
let dynamicQuestionsHtml = '';
|
|
|
|
// ── 1. EVC (Espace Vert Creux) ──
|
|
if (ouv.device_type === 'evc') {
|
|
dynamicQuestionsHtml = `
|
|
<!-- EVC: Point d'entrée -->
|
|
<div class="border rounded-3 p-3 mb-3 bg-white border-success-subtle shadow-sm">
|
|
<h6 class="fw-bold mb-3 small text-success text-uppercase border-bottom pb-1"><i class="bi bi-box-arrow-in-right me-1"></i>{% translate "Point d'entrée dans l'ouvrage" %}</h6>
|
|
${renderSegGroup(idx, 'evc_pe_ok', '{% filter escapejs %}{% translate "L'eau peut-elle facilement entrer dans l'EVC ?" %}{% endfilter %}', q.evc_pe_ok)}
|
|
|
|
<div class="ps-3 border-start border-2 border-danger-subtle mt-2 ${q.evc_pe_ok === 'false' ? '' : 'd-none'}">
|
|
${renderSegGroup(idx, 'evc_pe_feuilles', '{% filter escapejs %}{% translate "Des feuilles ou branches bloquent-elles l'eau ?" %}{% endfilter %}', q.evc_pe_feuilles)}
|
|
${renderSegGroup(idx, 'evc_pe_detritus', '{% filter escapejs %}{% translate "Un amas de détritus bloque-t-il l'eau ?" %}{% endfilter %}', q.evc_pe_detritus)}
|
|
</div>
|
|
|
|
<!-- Empierrement switch -->
|
|
<div class="form-check form-switch mt-3 pt-2 border-top">
|
|
<input class="form-check-input q-check-dyn" type="checkbox" data-idx="${idx}" data-q="evc_empierrement_present" id="emp_pres_${idx}" ${q.evc_empierrement_present ? 'checked' : ''}>
|
|
<label class="form-check-label small fw-semibold" for="emp_pres_${idx}">
|
|
{% translate "L'ouvrage dispose-t-il d'un empierrement ?" %}
|
|
<span class="extra-small text-muted d-block font-italic">{% translate "Activer pour compléter l'état de l'empierrement" %}</span>
|
|
</label>
|
|
</div>
|
|
|
|
<div class="ps-3 border-start border-2 border-success-subtle mt-2 ${q.evc_empierrement_present ? '' : 'd-none'}">
|
|
${renderSegGroup(idx, 'evc_empierrement_ok', '{% filter escapejs %}{% translate "L'empierrement est-il en bon état ?" %}{% endfilter %}', q.evc_empierrement_ok)}
|
|
|
|
<div class="${q.evc_empierrement_ok === 'false' ? '' : 'd-none'}">
|
|
<div class="form-check mb-1">
|
|
<input class="form-check-input q-check-dyn" type="checkbox" data-idx="${idx}" data-q="evc_empierrement_colmate" id="emp_col_${idx}" ${q.evc_empierrement_colmate ? 'checked' : ''}>
|
|
<label class="form-check-label extra-small" for="emp_col_${idx}">{% translate "Colmaté par les sédiments" %}</label>
|
|
</div>
|
|
<div class="form-check mb-1">
|
|
<input class="form-check-input q-check-dyn" type="checkbox" data-idx="${idx}" data-q="evc_empierrement_emporte" id="emp_emp_${idx}" ${q.evc_empierrement_emporte ? 'checked' : ''}>
|
|
<label class="form-check-label extra-small" for="emp_emp_${idx}">{% translate "Emporté par l'eau" %}</label>
|
|
</div>
|
|
<div class="form-check">
|
|
<input class="form-check-input q-check-dyn" type="checkbox" data-idx="${idx}" data-q="evc_empierrement_envahi" id="emp_env_${idx}" ${q.evc_empierrement_envahi ? 'checked' : ''}>
|
|
<label class="form-check-label extra-small" for="emp_env_${idx}">{% translate "Envahi d'adventices" %}</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- EVC: Espace Vert -->
|
|
<div class="border rounded-3 p-3 mb-3 bg-white border-success-subtle shadow-sm">
|
|
<h6 class="fw-bold mb-3 small text-success text-uppercase border-bottom pb-1"><i class="bi bi-flower1 me-1"></i>{% translate "Espace vert" %}</h6>
|
|
|
|
${renderSegGroup(idx, 'evc_ev_veg_etat', '{% filter escapejs %}{% translate "Quel est l'état de la végétation ?" %}{% endfilter %}', q.evc_ev_veg_etat, [
|
|
{val: 'bon', text: '{% filter escapejs %}{% translate "Bon" %}{% endfilter %}', activeClass: 'btn-success', inactiveClass: 'btn-outline-success'},
|
|
{val: 'mauvais', text: '{% filter escapejs %}{% translate "Mauvais" %}{% endfilter %}', activeClass: 'btn-danger', inactiveClass: 'btn-outline-danger'},
|
|
{val: 'null', text: '{% filter escapejs %}{% translate "Non vérifié" %}{% endfilter %}', activeClass: 'btn-secondary', inactiveClass: 'btn-outline-secondary'}
|
|
])}
|
|
|
|
<div class="ps-3 border-start border-2 border-danger-subtle mb-3 ${q.evc_ev_veg_etat === 'mauvais' ? '' : 'd-none'}">
|
|
${renderSegGroup(idx, 'evc_ev_plantes_mortes', '{% filter escapejs %}{% translate "Présence de plantes mortes ou absentes :" %}{% endfilter %}', q.evc_ev_plantes_mortes, [
|
|
{val: 'plus_10', text: '{% filter escapejs %}{% translate "+ de 10%" %}{% endfilter %}', activeClass: 'btn-danger', inactiveClass: 'btn-outline-danger'},
|
|
{val: 'moins_10', text: '{% filter escapejs %}{% translate "- de 10%" %}{% endfilter %}', activeClass: 'btn-success', inactiveClass: 'btn-outline-success'},
|
|
{val: 'null', text: '{% filter escapejs %}{% translate "Non vérifié" %}{% endfilter %}', activeClass: 'btn-secondary', inactiveClass: 'btn-outline-secondary'}
|
|
])}
|
|
</div>
|
|
|
|
${renderSegGroup(idx, 'evc_ev_chenaux_erosion', '{% filter escapejs %}{% translate "Présence de chenaux d'érosion ?" %}{% endfilter %}', q.evc_ev_chenaux_erosion)}
|
|
${renderSegGroup(idx, 'evc_ev_flaques', '{% filter escapejs %}{% translate "Présence de flaques d'eau persistantes ?" %}{% endfilter %}', q.evc_ev_flaques)}
|
|
${renderSegGroup(idx, 'evc_ev_sediments', '{% filter escapejs %}{% translate "Présence de sédiments dans l'ouvrage ?" %}{% endfilter %}', q.evc_ev_sediments)}
|
|
|
|
<div class="ps-3 border-start border-2 border-danger-subtle mb-3 ${q.evc_ev_sediments === 'true' ? '' : 'd-none'}">
|
|
${renderSegGroup(idx, 'evc_ev_croute_sediments', '{% filter escapejs %}{% translate "La croûte de sédimentation est-elle supérieure à 5 cm ?" %}{% endfilter %}', q.evc_ev_croute_sediments)}
|
|
</div>
|
|
|
|
${renderSegGroup(idx, 'evc_ev_envahissantes', '{% filter escapejs %}{% translate "Présence d'espèces exotiques envahissantes ?" %}{% endfilter %}', q.evc_ev_envahissantes)}
|
|
</div>
|
|
|
|
<!-- EVC: Surverse / Trop-plein -->
|
|
<div class="border rounded-3 p-3 mb-3 bg-white border-success-subtle shadow-sm">
|
|
<div class="form-check form-switch mb-0">
|
|
<input class="form-check-input q-check-dyn" type="checkbox" data-idx="${idx}" data-q="evc_surverse_presente" id="sv_pres_${idx}" ${q.evc_surverse_presente ? 'checked' : ''}>
|
|
<label class="form-check-label small fw-semibold text-success" for="sv_pres_${idx}">
|
|
<i class="bi bi-water me-1"></i>{% translate "Une surverse est-elle présente ?" %}
|
|
<span class="extra-small text-muted d-block font-italic">{% translate "Activer si le système dispose d'une évacuation de trop-plein" %}</span>
|
|
</label>
|
|
</div>
|
|
|
|
<div class="ps-3 border-start border-2 border-success-subtle mt-3 ${q.evc_surverse_presente ? '' : 'd-none'}">
|
|
${renderSegGroup(idx, 'evc_sv_grille_propre', '{% filter escapejs %}{% translate "La grille de surverse est propre et dégagée ?" %}{% endfilter %}', q.evc_sv_grille_propre)}
|
|
${renderSegGroup(idx, 'evc_sv_decantation_vide', '{% filter escapejs %}{% translate "La décantation est vide ou peu remplie ?" %}{% endfilter %}', q.evc_sv_decantation_vide)}
|
|
${renderSegGroup(idx, 'evc_sv_haute', '{% filter escapejs %}{% translate "La surverse est-elle plus haute que le fond de l'ouvrage ?" %}{% endfilter %}', q.evc_sv_haute)}
|
|
</div>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
// ── 2. OED (Massif Drainant) ──
|
|
else if (ouv.device_type === 'oed') {
|
|
dynamicQuestionsHtml = `
|
|
<!-- OED: État général du revêtement -->
|
|
<div class="border rounded-3 p-3 mb-3 bg-white border-info-subtle shadow-sm">
|
|
<h6 class="fw-bold mb-3 small text-info text-uppercase border-bottom pb-1"><i class="bi bi-road-perspective me-1"></i>{% translate "État général du revêtement / chaussée" %}</h6>
|
|
${renderSegGroup(idx, 'oed_revetement_ok', '{% filter escapejs %}{% translate "La surface au-dessus du massif drainant est en bon état ?" %}{% endfilter %}', q.oed_revetement_ok)}
|
|
|
|
<div class="ps-3 border-start border-2 border-danger-subtle mt-2 ${q.oed_revetement_ok === 'false' ? '' : 'd-none'}">
|
|
<div class="form-check mb-1">
|
|
<input class="form-check-input q-check-dyn" type="checkbox" data-idx="${idx}" data-q="oed_revetement_ornieres" id="orn_${idx}" ${q.oed_revetement_ornieres ? 'checked' : ''}>
|
|
<label class="form-check-label extra-small" for="orn_${idx}">{% translate "Présence d'ornières" %}</label>
|
|
</div>
|
|
<div class="form-check mb-1">
|
|
<input class="form-check-input q-check-dyn" type="checkbox" data-idx="${idx}" data-q="oed_revetement_fissures" id="fis_${idx}" ${q.oed_revetement_fissures ? 'checked' : ''}>
|
|
<label class="form-check-label extra-small" for="fis_${idx}">{% translate "Présence de fissures" %}</label>
|
|
</div>
|
|
<div class="form-check">
|
|
<input class="form-check-input q-check-dyn" type="checkbox" data-idx="${idx}" data-q="oed_revetement_trous" id="tro_${idx}" ${q.oed_revetement_trous ? 'checked' : ''}>
|
|
<label class="form-check-label extra-small" for="tro_${idx}">{% translate "Présence de trous" %}</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- OED: Bouche d'injection & Drainage -->
|
|
<div class="border rounded-3 p-3 mb-3 bg-white border-info-subtle shadow-sm">
|
|
<div class="form-check form-switch mb-0">
|
|
<input class="form-check-input q-check-dyn" type="checkbox" data-idx="${idx}" data-q="oed_injection_presente" id="inj_pres_${idx}" ${q.oed_injection_presente ? 'checked' : ''}>
|
|
<label class="form-check-label small fw-semibold text-info" for="inj_pres_${idx}">
|
|
<i class="bi bi-funnel me-1"></i>{% translate "Une bouche d'injection est-elle présente ?" %}
|
|
<span class="extra-small text-muted d-block font-italic">{% translate "Activer pour inspecter les conduits d'injection d'eau et de drainage" %}</span>
|
|
</label>
|
|
</div>
|
|
|
|
<div class="ps-3 border-start border-2 border-info-subtle mt-3 ${q.oed_injection_presente ? '' : 'd-none'}">
|
|
${renderSegGroup(idx, 'oed_bi_niveaux_ok', '{% filter escapejs %}{% translate "Les niveaux du revêtement conduisent bien l'eau vers la bouche ?" %}{% endfilter %}', q.oed_bi_niveaux_ok)}
|
|
${renderSegGroup(idx, 'oed_bi_grille_propre', '{% filter escapejs %}{% translate "La grille est propre et dégagée ?" %}{% endfilter %}', q.oed_bi_grille_propre)}
|
|
${renderSegGroup(idx, 'oed_bi_decantation_vide', '{% filter escapejs %}{% translate "La décantation est-elle vide ou presque ?" %}{% endfilter %}', q.oed_bi_decantation_vide)}
|
|
${renderSegGroup(idx, 'oed_bi_filtre_present', '{% filter escapejs %}{% translate "La bouche d'injection dispose d'un filtre ?" %}{% endfilter %}', q.oed_bi_filtre_present)}
|
|
|
|
<div class="ps-3 border-start border-2 border-info-subtle mb-2 ${q.oed_bi_filtre_present === 'true' ? '' : 'd-none'}">
|
|
${renderSegGroup(idx, 'oed_bi_filtre_propre', '{% filter escapejs %}{% translate "Le filtre est propre ?" %}{% endfilter %}', q.oed_bi_filtre_propre)}
|
|
${renderSegGroup(idx, 'oed_bi_filtre_bon', '{% filter escapejs %}{% translate "Le filtre est en bon état ?" %}{% endfilter %}', q.oed_bi_filtre_bon)}
|
|
</div>
|
|
|
|
${renderSegGroup(idx, 'oed_bi_drain_colmate', '{% filter escapejs %}{% translate "Le drain semble colmaté ?" %}{% endfilter %}', q.oed_bi_drain_colmate)}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- OED: Switches de types de revêtements spécifiques -->
|
|
<div class="border rounded-3 p-3 mb-3 bg-white border-info-subtle shadow-sm">
|
|
<h6 class="fw-bold mb-3 small text-info text-uppercase border-bottom pb-1"><i class="bi bi-layers me-1"></i>{% translate "Type de structure & Revêtement OED" %}</h6>
|
|
|
|
<!-- 1. Structure enherbée ou remplissage minéral -->
|
|
<div class="form-check form-switch mb-2">
|
|
<input class="form-check-input q-check-dyn" type="checkbox" data-idx="${idx}" data-q="oed_rhm_presente" id="rhm_pres_${idx}" ${q.oed_rhm_presente ? 'checked' : ''}>
|
|
<label class="form-check-label small fw-semibold text-info" for="rhm_pres_${idx}">
|
|
{% translate "Structure enherbée ou remplissage minéral ?" %}
|
|
<span class="extra-small text-muted d-block font-italic">{% translate "Dalles gazon, pavés à joints larges, dalles alvéolaires végétalisées/gravier, etc." %}</span>
|
|
</label>
|
|
</div>
|
|
<div class="ps-3 border-start border-2 border-info-subtle mb-3 ${q.oed_rhm_presente ? '' : 'd-none'}">
|
|
${renderSegGroup(idx, 'oed_rhm_stagne', '{% filter escapejs %}{% translate "De l'eau stagne-t-elle en surface ?" %}{% endfilter %}', q.oed_rhm_stagne)}
|
|
|
|
<div class="ps-3 border-start border-2 border-danger-subtle mb-2 ${q.oed_rhm_stagne === 'true' ? '' : 'd-none'}">
|
|
${renderSegGroup(idx, 'oed_rhm_stagne_plus_2h', '{% filter escapejs %}{% translate "L'eau stagne plus de 2 heures ?" %}{% endfilter %}', q.oed_rhm_stagne_plus_2h)}
|
|
</div>
|
|
|
|
${renderSegGroup(idx, 'oed_rhm_joints_ok', '{% filter escapejs %}{% translate "Les joints sont-ils en bon état ?" %}{% endfilter %}', q.oed_rhm_joints_ok)}
|
|
|
|
<div class="ps-3 border-start border-2 border-danger-subtle mb-2 ${q.oed_rhm_joints_ok === 'false' ? '' : 'd-none'}">
|
|
${renderSegGroup(idx, 'oed_rhm_joints_fines', '{% filter escapejs %}{% translate "Présence importante de fines dans les joints ?" %}{% endfilter %}', q.oed_rhm_joints_fines)}
|
|
${renderSegGroup(idx, 'oed_rhm_joints_remplissage', '{% filter escapejs %}{% translate "Niveau de remplissage plus haut que la structure ?" %}{% endfilter %}', q.oed_rhm_joints_remplissage)}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 2. Modulaire poreux ou continu poreux -->
|
|
<div class="form-check form-switch mb-2">
|
|
<input class="form-check-input q-check-dyn" type="checkbox" data-idx="${idx}" data-q="oed_rp_presente" id="rp_pres_${idx}" ${q.oed_rp_presente ? 'checked' : ''}>
|
|
<label class="form-check-label small fw-semibold text-info" for="rp_pres_${idx}">
|
|
{% translate "Modulaire poreux ou continu poreux ?" %}
|
|
<span class="extra-small text-muted d-block font-italic">{% translate "Béton poreux, enrobés bitumineux poreux, graviers liés à la résine, EPDM, etc." %}</span>
|
|
</label>
|
|
</div>
|
|
<div class="ps-3 border-start border-2 border-info-subtle mb-3 ${q.oed_rp_presente ? '' : 'd-none'}">
|
|
${renderSegGroup(idx, 'oed_rp_stagne', '{% filter escapejs %}{% translate "De l'eau stagne-t-elle en surface ?" %}{% endfilter %}', q.oed_rp_stagne)}
|
|
|
|
<div class="ps-3 border-start border-2 border-danger-subtle mb-2 ${q.oed_rp_stagne === 'true' ? '' : 'd-none'}">
|
|
${renderSegGroup(idx, 'oed_rp_stagne_plus_2h', '{% filter escapejs %}{% translate "L'eau stagne plus de 2 heures ?" %}{% endfilter %}', q.oed_rp_stagne_plus_2h)}
|
|
</div>
|
|
|
|
${renderSegGroup(idx, 'oed_rp_depots', '{% filter escapejs %}{% translate "Présence de dépôts visibles (poussières, mousses, etc.) ?" %}{% endfilter %}', q.oed_rp_depots)}
|
|
|
|
<div class="ps-3 border-start border-2 border-danger-subtle mb-2 ${q.oed_rp_depots === 'true' ? '' : 'd-none'}">
|
|
${renderSegGroup(idx, 'oed_rp_test_permeabilite', '{% filter escapejs %}{% translate "Test de perméabilité nécessaire ?" %}{% endfilter %}', q.oed_rp_test_permeabilite)}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 3. Matériaux non agrégés -->
|
|
<div class="form-check form-switch mb-0">
|
|
<input class="form-check-input q-check-dyn" type="checkbox" data-idx="${idx}" data-q="oed_rna_presente" id="rna_pres_${idx}" ${q.oed_rna_presente ? 'checked' : ''}>
|
|
<label class="form-check-label small fw-semibold text-info" for="rna_pres_${idx}">
|
|
{% translate "Matériaux non agrégés (graviers/mulch) ?" %}
|
|
<span class="extra-small text-muted d-block font-italic">{% translate "Mulch végétal, graviers calcaires/non calcaires, terre battue, etc." %}</span>
|
|
</label>
|
|
</div>
|
|
<div class="ps-3 border-start border-2 border-info-subtle mt-2 ${q.oed_rna_presente ? '' : 'd-none'}">
|
|
${renderSegGroup(idx, 'oed_rna_stagne', '{% filter escapejs %}{% translate "De l'eau stagne-t-elle en surface ?" %}{% endfilter %}', q.oed_rna_stagne)}
|
|
|
|
<div class="ps-3 border-start border-2 border-danger-subtle mb-2 ${q.oed_rna_stagne === 'true' ? '' : 'd-none'}">
|
|
${renderSegGroup(idx, 'oed_rna_stagne_plus_2h', '{% filter escapejs %}{% translate "L'eau stagne plus de 2 heures ?" %}{% endfilter %}', q.oed_rna_stagne_plus_2h)}
|
|
</div>
|
|
|
|
${renderSegGroup(idx, 'oed_rna_matiere_ok', '{% filter escapejs %}{% translate "Le volume de matière est-il en suffisance ?" %}{% endfilter %}', q.oed_rna_matiere_ok)}
|
|
|
|
<div class="ps-3 border-start border-2 border-danger-subtle mb-2 ${q.oed_rna_matiere_ok === 'false' ? '' : 'd-none'}">
|
|
${renderSegGroup(idx, 'oed_rna_geotextile_visible', '{% filter escapejs %}{% translate "Le géotextile est-il visible ?" %}{% endfilter %}', q.oed_rna_geotextile_visible)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
// ── 3. TA (Technique Alternative / Bassin d'orage) ──
|
|
else if (ouv.device_type === 'ta') {
|
|
dynamicQuestionsHtml = `
|
|
<!-- TA: Points d'entrée -->
|
|
<div class="border rounded-3 p-3 mb-3 bg-white border-teal-subtle shadow-sm" style="border-color:#b2dfdb;">
|
|
<h6 class="fw-bold mb-3 small text-teal text-uppercase" style="color:#00796b;"><i class="bi bi-box-arrow-in-right me-1"></i>{% translate "Points d'entrée dans l'ouvrage" %}</h6>
|
|
${renderSegGroup(idx, 'ta_pe_ok', '{% filter escapejs %}{% translate "L'eau peut-elle facilement entrer dans l'ouvrage ?" %}{% endfilter %}', q.ta_pe_ok)}
|
|
${renderSegGroup(idx, 'ta_pe_conduits_ok', '{% filter escapejs %}{% translate "Les conduits et dispositifs amenant l'eau sont-ils fonctionnels ?" %}{% endfilter %}', q.ta_pe_conduits_ok)}
|
|
|
|
<div class="ps-3 border-start border-2 border-danger-subtle mb-2 ${q.ta_pe_conduits_ok === 'false' ? '' : 'd-none'}">
|
|
${renderSegGroup(idx, 'ta_pe_grilles', '{% filter escapejs %}{% translate "Les grilles sont-elles propres et dégagées ?" %}{% endfilter %}', q.ta_pe_grilles)}
|
|
${renderSegGroup(idx, 'ta_pe_feuilles', '{% filter escapejs %}{% translate "Des feuilles ou branches bloquent-elles l'eau ?" %}{% endfilter %}', q.ta_pe_feuilles)}
|
|
${renderSegGroup(idx, 'ta_pe_detritus', '{% filter escapejs %}{% translate "Un amas de détritus bloque-t-il l'eau ?" %}{% endfilter %}', q.ta_pe_detritus)}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- TA: Bassin d'orage -->
|
|
<div class="border rounded-3 p-3 mb-3 bg-white border-teal-subtle shadow-sm" style="border-color:#b2dfdb;">
|
|
<h6 class="fw-bold mb-3 small text-teal text-uppercase" style="color:#00796b;"><i class="bi bi-cloud-snow me-1"></i>{% translate "Bassin d'orage" %}</h6>
|
|
|
|
${renderSegGroup(idx, 'ta_bo_vegetation_etat', '{% filter escapejs %}{% translate "Quel est l'état de la végétation ?" %}{% endfilter %}', q.ta_bo_vegetation_etat, [
|
|
{val: 'bon', text: '{% filter escapejs %}{% translate "Bon" %}{% endfilter %}', activeClass: 'btn-success', inactiveClass: 'btn-outline-success'},
|
|
{val: 'mauvais', text: '{% filter escapejs %}{% translate "Mauvais" %}{% endfilter %}', activeClass: 'btn-danger', inactiveClass: 'btn-outline-danger'},
|
|
{val: 'null', text: '{% filter escapejs %}{% translate "Non vérifié" %}{% endfilter %}', activeClass: 'btn-secondary', inactiveClass: 'btn-outline-secondary'}
|
|
])}
|
|
|
|
<div class="ps-3 border-start border-2 border-danger-subtle mb-2 ${q.ta_bo_vegetation_etat === 'mauvais' ? '' : 'd-none'}">
|
|
${renderSegGroup(idx, 'ta_bo_plantes_mortes', '{% filter escapejs %}{% translate "Présence de plantes mortes ou absentes :" %}{% endfilter %}', q.ta_bo_plantes_mortes, [
|
|
{val: 'plus_10', text: '{% filter escapejs %}{% translate "+ de 10%" %}{% endfilter %}', activeClass: 'btn-danger', inactiveClass: 'btn-outline-danger'},
|
|
{val: 'moins_10', text: '{% filter escapejs %}{% translate "- de 10%" %}{% endfilter %}', activeClass: 'btn-success', inactiveClass: 'btn-outline-success'},
|
|
{val: 'null', text: '{% filter escapejs %}{% translate "Non vérifié" %}{% endfilter %}', activeClass: 'btn-secondary', inactiveClass: 'btn-outline-secondary'}
|
|
])}
|
|
</div>
|
|
|
|
${renderSegGroup(idx, 'ta_bo_chenaux', '{% filter escapejs %}{% translate "Présence de chenaux d'érosion ?" %}{% endfilter %}', q.ta_bo_chenaux)}
|
|
${renderSegGroup(idx, 'ta_bo_flaques', '{% filter escapejs %}{% translate "Présence de flaques d'eau persistantes ?" %}{% endfilter %}', q.ta_bo_flaques)}
|
|
${renderSegGroup(idx, 'ta_sediments', '{% filter escapejs %}{% translate "Présence de sédiments dans l'ouvrage ?" %}{% endfilter %}', q.ta_sediments)}
|
|
|
|
<div class="ps-3 border-start border-2 border-danger-subtle mb-2 ${q.ta_sediments === 'true' ? '' : 'd-none'}">
|
|
${renderSegGroup(idx, 'ta_sediments_rempli', '{% filter escapejs %}{% translate "L'ouvrage est-il rempli au 5e de sa capacité ?" %}{% endfilter %}', q.ta_sediments_rempli)}
|
|
</div>
|
|
|
|
${renderSegGroup(idx, 'ta_bo_detritus', '{% filter escapejs %}{% translate "Présence de détritus dans l'ouvrage ?" %}{% endfilter %}', q.ta_bo_detritus)}
|
|
${renderSegGroup(idx, 'ta_bo_envahissantes', '{% filter escapejs %}{% translate "Présence d'espèces exotiques envahissantes ?" %}{% endfilter %}', q.ta_bo_envahissantes)}
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
const titleHeader = ouv.asset_code ? `${ouv.asset_code} — ${ouv.asset_name || 'Ouvrage #' + (idx + 1)}` : `Ouvrage #${idx + 1}`;
|
|
|
|
card.innerHTML = `
|
|
<div class="d-flex align-items-center justify-content-between mb-3 border-bottom pb-2">
|
|
<span class="fw-bold text-dark"><i class="bi bi-gear-fill me-1.5 text-primary"></i>${titleHeader}</span>
|
|
<button type="button" class="btn btn-outline-danger btn-sm py-0.5 px-2.5 rounded-pill remove-ouv-btn" data-idx="${idx}">
|
|
<i class="bi bi-trash me-1"></i>{% translate "Supprimer" %}
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Liaison Équipement GIEP / Ouvrage -->
|
|
<div class="border rounded-3 p-3 mb-3 bg-white border-primary-subtle shadow-sm">
|
|
<div class="d-flex align-items-center justify-content-between mb-2">
|
|
<span class="extra-small fw-bold text-primary text-uppercase">
|
|
<i class="bi bi-link-45deg me-1"></i>{% translate "Équipement GIEP associé (Optionnel)" %}
|
|
</span>
|
|
${ouv.asset_id ? `<button type="button" class="btn btn-link text-danger p-0 extra-small text-decoration-none clear-asset-btn" data-idx="${idx}"><i class="bi bi-x-circle me-1"></i>{% translate "Délier" %}</button>` : ''}
|
|
</div>
|
|
|
|
${ouv.asset_id ? `
|
|
<div class="p-2.5 rounded-3 bg-primary-subtle bg-opacity-20 border border-primary-subtle d-flex align-items-center justify-content-between">
|
|
<div class="d-flex align-items-center gap-2">
|
|
<i class="bi bi-geo-alt-fill text-primary fs-5"></i>
|
|
<div>
|
|
<strong class="small text-primary d-block">${ouv.asset_code}</strong>
|
|
<span class="extra-small text-muted">${ouv.asset_name || ''}</span>
|
|
</div>
|
|
</div>
|
|
<span class="badge bg-primary text-white rounded-pill extra-small">{% translate "Lié" %}</span>
|
|
</div>
|
|
` : `
|
|
<div class="position-relative">
|
|
<div class="input-group input-group-sm">
|
|
<span class="input-group-text bg-white"><i class="bi bi-search text-muted"></i></span>
|
|
<input type="text" class="form-control asset-search-input" data-idx="${idx}" placeholder="{% filter escapejs %}{% translate "Rechercher par code (ex: BI-01...) ou par type..." %}{% endfilter %}" autocomplete="off">
|
|
<button type="button" class="btn btn-outline-primary open-map-modal-btn" data-idx="${idx}">
|
|
<i class="bi bi-geo-alt-fill me-1"></i>{% translate "Choisir sur la carte" %}
|
|
</button>
|
|
</div>
|
|
<div class="list-group position-absolute w-100 shadow-lg d-none asset-autocomplete-dropdown" data-idx="${idx}" style="z-index: 1050; max-height: 200px; overflow-y: auto; background: white;"></div>
|
|
</div>
|
|
`}
|
|
</div>
|
|
|
|
<!-- Device Selector Symbology -->
|
|
<div class="row g-2 mb-3">
|
|
<div class="col-4">
|
|
<div class="device-select-btn ${ouv.device_type === 'evc' ? 'active' : ''}" data-idx="${idx}" data-device="evc">
|
|
<i class="bi bi-flower1 text-success fs-5 d-block mb-1"></i>
|
|
<span class="extra-small fw-semibold">EVC</span>
|
|
</div>
|
|
</div>
|
|
<div class="col-4">
|
|
<div class="device-select-btn ${ouv.device_type === 'oed' ? 'active' : ''}" data-idx="${idx}" data-device="oed">
|
|
<i class="bi bi-grid-3x3-gap-fill text-info fs-5 d-block mb-1"></i>
|
|
<span class="extra-small fw-semibold">OED</span>
|
|
</div>
|
|
</div>
|
|
<div class="col-4">
|
|
<div class="device-select-btn ${ouv.device_type === 'ta' ? 'active' : ''}" data-idx="${idx}" data-device="ta">
|
|
<i class="bi bi-cloud-rain-fill text-teal fs-5 d-block mb-1"></i>
|
|
<span class="extra-small fw-semibold">TA</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Dynamic Questions Block -->
|
|
${dynamicQuestionsHtml}
|
|
|
|
<!-- Recommandations -->
|
|
<div class="border-top pt-2">
|
|
<label class="form-label extra-small text-muted fw-bold mb-2 d-block"><i class="bi bi-bookmark-star me-1"></i>{% translate "Recommandations" %}</label>
|
|
<div class="d-flex flex-column gap-1.5">
|
|
<div class="form-check">
|
|
<input class="form-check-input action-check" type="checkbox" data-idx="${idx}" data-act="aucune" id="act_auc_${idx}" ${act.aucune ? 'checked' : ''}>
|
|
<label class="form-check-label extra-small" for="act_auc_${idx}">{% translate "Aucune" %}</label>
|
|
</div>
|
|
<div class="form-check">
|
|
<input class="form-check-input action-check" type="checkbox" data-idx="${idx}" data-act="interventions_preventives" id="act_prev_${idx}" ${act.interventions_preventives ? 'checked' : ''}>
|
|
<label class="form-check-label extra-small" for="act_prev_${idx}">{% translate "Interventions préventives" %}</label>
|
|
</div>
|
|
<div class="form-check">
|
|
<input class="form-check-input action-check" type="checkbox" data-idx="${idx}" data-act="entretien_curatif" id="act_cur_${idx}" ${act.entretien_curatif ? 'checked' : ''}>
|
|
<label class="form-check-label extra-small" for="act_cur_${idx}">{% translate "Entretien curatif / Réparation / Adaptation nécessaire" %}</label>
|
|
</div>
|
|
<div class="form-check">
|
|
<input class="form-check-input action-check" type="checkbox" data-idx="${idx}" data-act="test_permeabilite" id="act_perm_${idx}" ${act.test_permeabilite ? 'checked' : ''}>
|
|
<label class="form-check-label extra-small" for="act_perm_${idx}">{% translate "Test de perméabilité" %}</label>
|
|
</div>
|
|
<div class="form-check">
|
|
<input class="form-check-input action-check" type="checkbox" data-idx="${idx}" data-act="inspection" id="act_insp_${idx}" ${act.inspection ? 'checked' : ''}>
|
|
<label class="form-check-label extra-small" for="act_insp_${idx}">{% translate "Inspection" %}</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
container.appendChild(card);
|
|
});
|
|
|
|
// Event listeners pour la carte et l'autocomplétion
|
|
container.querySelectorAll('.open-map-modal-btn').forEach(btn => {
|
|
btn.addEventListener('click', (e) => {
|
|
const idx = parseInt(e.currentTarget.getAttribute('data-idx'));
|
|
openMapModal(idx);
|
|
});
|
|
});
|
|
|
|
container.querySelectorAll('.clear-asset-btn').forEach(btn => {
|
|
btn.addEventListener('click', (e) => {
|
|
const idx = parseInt(e.currentTarget.getAttribute('data-idx'));
|
|
if (giepOuvrages[idx]) {
|
|
giepOuvrages[idx].asset_id = null;
|
|
giepOuvrages[idx].asset_code = null;
|
|
giepOuvrages[idx].asset_name = null;
|
|
renderOuvrages();
|
|
}
|
|
});
|
|
});
|
|
|
|
container.querySelectorAll('.asset-search-input').forEach(input => {
|
|
input.addEventListener('input', (e) => {
|
|
const idx = parseInt(e.target.getAttribute('data-idx'));
|
|
const val = e.target.value.trim().toLowerCase();
|
|
const dropdown = container.querySelector(`.asset-autocomplete-dropdown[data-idx="${idx}"]`);
|
|
if (!dropdown) return;
|
|
|
|
if (!val) {
|
|
dropdown.classList.add('d-none');
|
|
dropdown.innerHTML = '';
|
|
return;
|
|
}
|
|
|
|
fetchLocationAssets().then(assets => {
|
|
const matches = assets.filter(a => a.code.toLowerCase().includes(val) || (a.structure_type && a.structure_type.toLowerCase().includes(val)) || (a.name && a.name.toLowerCase().includes(val))).slice(0, 8);
|
|
if (matches.length === 0) {
|
|
dropdown.classList.add('d-none');
|
|
dropdown.innerHTML = '';
|
|
return;
|
|
}
|
|
dropdown.innerHTML = matches.map(a => `
|
|
<button type="button" class="list-group-item list-group-item-action py-2 px-3 text-start autocomplete-item" data-id="${a.id}">
|
|
<div class="fw-bold small text-primary">${a.code}</div>
|
|
<div class="extra-small text-muted">${a.structure_type || a.name || ''}</div>
|
|
</button>
|
|
`).join('');
|
|
dropdown.classList.remove('d-none');
|
|
|
|
dropdown.querySelectorAll('.autocomplete-item').forEach(itemBtn => {
|
|
itemBtn.addEventListener('click', () => {
|
|
const assetId = itemBtn.getAttribute('data-id');
|
|
const targetAsset = assets.find(a => String(a.id) === String(assetId));
|
|
if (targetAsset) selectAssetForOuvrage(idx, targetAsset);
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
// Event listeners pour le sélecteur de dispositif
|
|
container.querySelectorAll('.device-select-btn').forEach(btn => {
|
|
btn.addEventListener('click', (e) => {
|
|
const target = e.currentTarget;
|
|
const idx = parseInt(target.getAttribute('data-idx'));
|
|
const dev = target.getAttribute('data-device');
|
|
giepOuvrages[idx].device_type = dev;
|
|
renderOuvrages();
|
|
});
|
|
});
|
|
|
|
// Event listeners pour les boutons segmentés (Tactiles Oui/Non)
|
|
container.querySelectorAll('.btn-seg').forEach(btn => {
|
|
btn.addEventListener('click', (e) => {
|
|
const target = e.currentTarget;
|
|
const idx = parseInt(target.getAttribute('data-idx'));
|
|
const qKey = target.getAttribute('data-q');
|
|
const val = target.getAttribute('data-val');
|
|
giepOuvrages[idx].questions[qKey] = val;
|
|
renderOuvrages();
|
|
});
|
|
});
|
|
|
|
// Event listeners pour les checkboxes
|
|
container.querySelectorAll('.q-check-dyn').forEach(chk => {
|
|
chk.addEventListener('change', (e) => {
|
|
const idx = parseInt(e.target.getAttribute('data-idx'));
|
|
const qKey = e.target.getAttribute('data-q');
|
|
giepOuvrages[idx].questions[qKey] = e.target.checked;
|
|
renderOuvrages();
|
|
});
|
|
});
|
|
|
|
container.querySelectorAll('.action-check').forEach(chk => {
|
|
chk.addEventListener('change', (e) => {
|
|
const idx = parseInt(e.target.getAttribute('data-idx'));
|
|
const act = e.target.getAttribute('data-act');
|
|
if (!giepOuvrages[idx].actions) giepOuvrages[idx].actions = {};
|
|
giepOuvrages[idx].actions[act] = e.target.checked;
|
|
updateSerializedGiepData();
|
|
});
|
|
});
|
|
|
|
container.querySelectorAll('.remove-ouv-btn').forEach(btn => {
|
|
btn.addEventListener('click', (e) => {
|
|
const idx = parseInt(e.currentTarget.getAttribute('data-idx'));
|
|
giepOuvrages.splice(idx, 1);
|
|
renderOuvrages();
|
|
});
|
|
});
|
|
|
|
updateSerializedGiepData();
|
|
}
|
|
|
|
if (addBtn) {
|
|
addBtn.addEventListener('click', () => {
|
|
giepOuvrages.push(createEmptyOuvrage(giepOuvrages.length, "evc"));
|
|
renderOuvrages();
|
|
});
|
|
}
|
|
|
|
// Modal filter & shown listeners
|
|
const modalEl = document.getElementById('giepAssetMapModal');
|
|
if (modalEl) {
|
|
modalEl.addEventListener('shown.bs.modal', () => {
|
|
initOrUpdateModalMap();
|
|
});
|
|
}
|
|
|
|
document.getElementById('giep_modal_search_input')?.addEventListener('input', (e) => {
|
|
const text = e.target.value;
|
|
const type = document.getElementById('giep_modal_type_filter')?.value || '';
|
|
populateModalAssetsList(text, type);
|
|
renderModalMapFeatures(false);
|
|
});
|
|
|
|
document.getElementById('giep_modal_type_filter')?.addEventListener('change', (e) => {
|
|
const type = e.target.value;
|
|
const text = document.getElementById('giep_modal_search_input')?.value || '';
|
|
populateModalAssetsList(text, type);
|
|
renderModalMapFeatures(false);
|
|
});
|
|
|
|
document.querySelectorAll('.giep-input').forEach(el => {
|
|
el.addEventListener('change', updateSerializedGiepData);
|
|
});
|
|
|
|
window.setGiepFormData = function(data) {
|
|
if (!data) return;
|
|
const dateRain = document.getElementById('giep_date_derniere_pluie');
|
|
if (dateRain) {
|
|
dateRain.value = (data.date_derniere_pluie !== undefined && data.date_derniere_pluie !== null) ? String(data.date_derniere_pluie) : 'null';
|
|
}
|
|
const storm = document.getElementById('giep_orage_moins_une_heure');
|
|
if (storm) {
|
|
storm.value = (data.orage_moins_une_heure !== undefined && data.orage_moins_une_heure !== null) ? String(data.orage_moins_une_heure) : 'null';
|
|
}
|
|
if (data.giep_data && Array.isArray(data.giep_data.ouvrages)) {
|
|
giepOuvrages = JSON.parse(JSON.stringify(data.giep_data.ouvrages));
|
|
} else {
|
|
giepOuvrages = [];
|
|
}
|
|
renderOuvrages();
|
|
updateSerializedGiepData();
|
|
};
|
|
|
|
renderOuvrages();
|
|
})();
|
|
</script>
|
|
|