fix(thematics, home): mise à jour des thématiques (Sécurité, Stationnement, Propreté) et sécurisation du chargement de la carte sur l'accueil
This commit is contained in:
parent
bbaa092550
commit
aad07929b9
5 changed files with 620 additions and 610 deletions
|
|
@ -9,7 +9,7 @@ def create_parking_thematic(apps, schema_editor):
|
|||
thematic, _created = Thematic.objects.get_or_create(
|
||||
code='parking',
|
||||
defaults={
|
||||
'name_fr': 'Stationnement & Mobilité',
|
||||
'name_fr': 'Stationnement',
|
||||
'name_nl': 'Parkeren & Mobiliteit',
|
||||
'description': 'Thématique dédiée aux emplacements de stationnement et zones de mobilité (vélos, trottinettes, PMR, livraison)',
|
||||
'icon': 'bi-p-square',
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ def create_bike_parking_category(apps, schema_editor):
|
|||
thematic, _ = Thematic.objects.get_or_create(
|
||||
code='parking',
|
||||
defaults={
|
||||
'name_fr': 'Stationnement & Mobilité',
|
||||
'name_fr': 'Stationnement',
|
||||
'name_nl': 'Parkeren & Mobiliteit',
|
||||
'description': 'Thématique dédiée aux emplacements de stationnement et zones de mobilité (vélos, trottinettes, PMR, livraison)',
|
||||
'icon': 'bi-p-square',
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ MAX_ASSET_FEATURES = 5000
|
|||
|
||||
@login_required
|
||||
def parking_index(request):
|
||||
"""Page d'accueil de la thématique Stationnement & Mobilité."""
|
||||
"""Page d'accueil de la thématique Stationnement."""
|
||||
check_thematic_access(request.user, 'parking')
|
||||
|
||||
parking_thematic = Thematic.objects.filter(code='parking').first()
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -1,86 +1,3 @@
|
|||
|
||||
const map = new maplibregl.Map({
|
||||
container: "map",
|
||||
style: window.MAP_STYLE_LIGHT,
|
||||
//style: 'https://tiles.openfreemap.org/styles/positron',
|
||||
center: [4.3572, 50.8477],
|
||||
zoom: 11,
|
||||
minzoom: 0,
|
||||
maxzoom: 24
|
||||
});
|
||||
|
||||
async function fetchAndMergeGeoJSON(urls) {
|
||||
const allFeatures = [];
|
||||
|
||||
for (const url of urls) {
|
||||
const response = await fetch(url);
|
||||
const data = await response.json();
|
||||
if (data && data.features) {
|
||||
allFeatures.push(...data.features);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
type: 'FeatureCollection',
|
||||
features: allFeatures
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
map.on('load', async () => {
|
||||
const mergedGeoJSON = await fetchAndMergeGeoJSON(interventions_geojson_urls);
|
||||
|
||||
map.addSource('interventions', {
|
||||
'type': 'geojson',
|
||||
'data': mergedGeoJSON
|
||||
});
|
||||
|
||||
// map.addLayer({
|
||||
// id: 'heatmap',
|
||||
// type: 'heatmap',
|
||||
// source: 'interventions',
|
||||
// paint: {
|
||||
// 'heatmap-weight': ['get', 'density'],
|
||||
// 'heatmap-intensity': 1,
|
||||
// 'heatmap-color': [
|
||||
// 'interpolate',
|
||||
// ['linear'],
|
||||
// ['heatmap-density'],
|
||||
// 0, 'rgba(33,102,172,0)',
|
||||
// 0.2, 'rgb(103,169,207)',
|
||||
// 0.4, 'rgb(209,229,240)',
|
||||
// 0.6, 'rgb(253,219,199)',
|
||||
// 0.8, 'rgb(239,138,98)',
|
||||
// 1, 'rgb(178,24,43)'
|
||||
// ],
|
||||
// 'heatmap-radius': 15,
|
||||
// 'heatmap-opacity': 0.75
|
||||
// }
|
||||
// });
|
||||
|
||||
map.addLayer({
|
||||
'id': 'interventions',
|
||||
'type': 'circle',
|
||||
'source': 'interventions',
|
||||
//filter: ['has', 'point_count'],
|
||||
minzoom: 0,
|
||||
maxzoom: 24,
|
||||
'paint': {
|
||||
'circle-radius': [
|
||||
'interpolate',
|
||||
['linear'],
|
||||
['zoom'],
|
||||
10, 5,
|
||||
22, 15
|
||||
],
|
||||
//'circle-color': '#0094ff',
|
||||
'circle-color': INTERVENTION_STATUS_COLOR_EXPR,
|
||||
'circle-opacity': 0.7
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
function statusFormatter(value) {
|
||||
const icons = {
|
||||
'in_preparation': { label: gettext('En préparation'), icon: 'bi-pencil', color: 'secondary' },
|
||||
|
|
@ -97,7 +14,6 @@ function statusFormatter(value) {
|
|||
'validated': { label: gettext('Validé'), icon: 'bi-award', color: 'success' },
|
||||
'invoiced': { label: gettext('Comptabilisé'), icon: 'bi-receipt', color: 'dark' },
|
||||
'closed': { label: gettext('Finalisé'), icon: 'bi-archive', color: 'dark' },
|
||||
// 'archived': { label: gettext('Archivé'), icon: 'bi-box-seam', color: 'dark' },
|
||||
'canceled': { label: gettext('Annulé'), icon: 'bi-x-circle', color: 'secondary' },
|
||||
};
|
||||
|
||||
|
|
@ -107,8 +23,71 @@ function statusFormatter(value) {
|
|||
return `<span class="badge text-bg-${entry.color} status-${value}"><i class="bi ${entry.icon} me-2"></i>${entry.label}</span>`;
|
||||
}
|
||||
|
||||
map.on('click', function(e) {
|
||||
const radiusInPixels = 10; // Rayon autour du clic
|
||||
const mapContainer = document.getElementById("map");
|
||||
|
||||
if (mapContainer && typeof maplibregl !== 'undefined') {
|
||||
const map = new maplibregl.Map({
|
||||
container: mapContainer,
|
||||
style: window.MAP_STYLE_LIGHT,
|
||||
center: [4.3572, 50.8477],
|
||||
zoom: 11,
|
||||
minzoom: 0,
|
||||
maxzoom: 24
|
||||
});
|
||||
|
||||
async function fetchAndMergeGeoJSON(urls) {
|
||||
const allFeatures = [];
|
||||
|
||||
for (const url of urls) {
|
||||
try {
|
||||
const response = await fetch(url);
|
||||
const data = await response.json();
|
||||
if (data && data.features) {
|
||||
allFeatures.push(...data.features);
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn('Error fetching geojson:', url, err);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
type: 'FeatureCollection',
|
||||
features: allFeatures
|
||||
};
|
||||
}
|
||||
|
||||
map.on('load', async () => {
|
||||
if (typeof interventions_geojson_urls !== 'undefined' && interventions_geojson_urls.length > 0) {
|
||||
const mergedGeoJSON = await fetchAndMergeGeoJSON(interventions_geojson_urls);
|
||||
|
||||
map.addSource('interventions', {
|
||||
'type': 'geojson',
|
||||
'data': mergedGeoJSON
|
||||
});
|
||||
|
||||
map.addLayer({
|
||||
'id': 'interventions',
|
||||
'type': 'circle',
|
||||
'source': 'interventions',
|
||||
minzoom: 0,
|
||||
maxzoom: 24,
|
||||
'paint': {
|
||||
'circle-radius': [
|
||||
'interpolate',
|
||||
['linear'],
|
||||
['zoom'],
|
||||
10, 5,
|
||||
22, 15
|
||||
],
|
||||
'circle-color': typeof INTERVENTION_STATUS_COLOR_EXPR !== 'undefined' ? INTERVENTION_STATUS_COLOR_EXPR : '#0094ff',
|
||||
'circle-opacity': 0.7
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
map.on('click', function(e) {
|
||||
const radiusInPixels = 10;
|
||||
|
||||
const features = map.queryRenderedFeatures([
|
||||
[e.point.x - radiusInPixels, e.point.y - radiusInPixels],
|
||||
|
|
@ -121,12 +100,14 @@ map.on('click', function(e) {
|
|||
return;
|
||||
}
|
||||
|
||||
// Générer le contenu de la popup avec tous les points proches
|
||||
const popupContent = features.map((feature) => {
|
||||
const props = feature.properties;
|
||||
const detailUrl = (typeof interventionDetailUrlPattern !== 'undefined')
|
||||
? interventionDetailUrlPattern.replace('/0/', '/' + props.id + '/')
|
||||
: '#';
|
||||
return `
|
||||
<div>
|
||||
<strong><a href="${interventionDetailUrlPattern.replace('/0/', '/' + props.id + '/')}">${props.code || gettext('Intervention')}</a></strong><br/>
|
||||
<strong><a href="${detailUrl}">${props.code || gettext('Intervention')}</a></strong><br/>
|
||||
${gettext("Statut")}: ${statusFormatter(props.status)}<br/>
|
||||
${gettext("Titre")}: ${props.title || '-'}
|
||||
</div>
|
||||
|
|
@ -134,21 +115,20 @@ map.on('click', function(e) {
|
|||
`;
|
||||
}).join('');
|
||||
|
||||
// Afficher la popup à l’endroit du clic
|
||||
new maplibregl.Popup()
|
||||
.setLngLat(e.lngLat)
|
||||
.setHTML(popupContent)
|
||||
.addTo(map);
|
||||
});
|
||||
});
|
||||
|
||||
map.on('mouseenter', 'interventions', () => {
|
||||
map.on('mouseenter', 'interventions', () => {
|
||||
map.getCanvas().style.cursor = 'pointer';
|
||||
});
|
||||
map.on('mouseleave', 'interventions', () => {
|
||||
});
|
||||
map.on('mouseleave', 'interventions', () => {
|
||||
map.getCanvas().style.cursor = '';
|
||||
});
|
||||
});
|
||||
|
||||
function populateLegend() {
|
||||
function populateLegend() {
|
||||
const statuses = ['to_be_processed', 'assigned', 'in_progress', 'on_pause', 'finished'];
|
||||
const legendContainer = document.getElementById('map-legend');
|
||||
|
||||
|
|
@ -158,49 +138,53 @@ function populateLegend() {
|
|||
return `<div class="mb-1">${statusFormatter(status)}</div>`;
|
||||
});
|
||||
|
||||
legendContainer.innerHTML = `
|
||||
${legendItems.join('')}
|
||||
`;
|
||||
legendContainer.innerHTML = legendItems.join('');
|
||||
}
|
||||
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', populateLegend);
|
||||
} else {
|
||||
populateLegend();
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', populateLegend);
|
||||
|
||||
// ### chart ###
|
||||
|
||||
const series = [
|
||||
const chartDom = document.getElementById('chartNbrInterventions');
|
||||
if (chartDom && typeof echarts !== 'undefined' && typeof seriesData !== 'undefined') {
|
||||
const series = [
|
||||
{
|
||||
name: gettext('Correctif'),
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
data: seriesData['Correctif'],
|
||||
itemStyle: { color: '#dc3545' } // Bootstrap "danger"
|
||||
data: seriesData['Correctif'] || [],
|
||||
itemStyle: { color: '#dc3545' }
|
||||
},
|
||||
{
|
||||
name: gettext('Préventif'),
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
data: seriesData['Préventif'],
|
||||
itemStyle: { color: '#ffc107' } // Bootstrap "warning"
|
||||
data: seriesData['Préventif'] || [],
|
||||
itemStyle: { color: '#ffc107' }
|
||||
},
|
||||
{
|
||||
name: gettext('Amélioratif'),
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
data: seriesData['Amélioratif'],
|
||||
itemStyle: { color: '#28a745' } // Bootstrap "success"
|
||||
data: seriesData['Amélioratif'] || [],
|
||||
itemStyle: { color: '#28a745' }
|
||||
}
|
||||
];
|
||||
];
|
||||
|
||||
const option = {
|
||||
legend: { data: ['Correctif', 'Préventif', 'Amélioratif'] },
|
||||
const option = {
|
||||
legend: { data: [gettext('Correctif'), gettext('Préventif'), gettext('Amélioratif')] },
|
||||
tooltip: { trigger: 'axis' },
|
||||
xAxis: { type: 'category', data: seriesData.dates },
|
||||
xAxis: { type: 'category', data: seriesData.dates || [] },
|
||||
yAxis: { type: 'value' },
|
||||
series: series
|
||||
};
|
||||
};
|
||||
|
||||
const chartDom = document.getElementById('chartNbrInterventions');
|
||||
const myChart = echarts.init(chartDom);
|
||||
myChart.setOption(option);
|
||||
const myChart = echarts.init(chartDom);
|
||||
myChart.setOption(option);
|
||||
|
||||
window.addEventListener('resize', () => myChart.resize());
|
||||
window.addEventListener('resize', () => myChart.resize());
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue