up wiki compare
This commit is contained in:
parent
d2936d5730
commit
1535cf8ee3
8 changed files with 1036 additions and 79 deletions
|
@ -93,41 +93,169 @@
|
|||
<select name="theme" id="theme" class="form-select" onchange="this.form.submit()">
|
||||
<option value="all" {{ theme == 'all' ? 'selected' : '' }}>Tous les thèmes</option>
|
||||
{% for themeKey, themeLabel in themes %}
|
||||
<option value="{{ themeKey }}" {{ theme == themeKey ? 'selected' : '' }}>
|
||||
{{ themeLabel }}
|
||||
</option>
|
||||
{% if themeKey != 'other' or issuesByTheme['other'] > 0 %}
|
||||
<option value="{{ themeKey }}" {{ theme == themeKey ? 'selected' : '' }}>
|
||||
{{ themeLabel }}{% if issuesByTheme[themeKey] > 0 %} ({{ issuesByTheme[themeKey] }}){% endif %}
|
||||
</option>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-6 text-end">
|
||||
<a href="{{ osmoseApiUrl }}" target="_blank" class="btn btn-primary">
|
||||
<i class="fas fa-external-link-alt"></i> Voir sur Osmose
|
||||
</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div id="map"></div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h3>Liste des problèmes ({{ osmoseIssues|length }})</h3>
|
||||
|
||||
{% if osmoseIssues|length > 0 %}
|
||||
<div class="issue-list">
|
||||
{% for issue in osmoseIssues %}
|
||||
<div class="issue-item level-{{ issue.level }}" data-lat="{{ issue.lat }}" data-lon="{{ issue.lon }}">
|
||||
<h5>{{ issue.title }}</h5>
|
||||
{% if issue.subtitle %}
|
||||
<p>{{ issue.subtitle }}</p>
|
||||
{% endif %}
|
||||
<div class="d-flex justify-content-between">
|
||||
<span class="badge bg-secondary">Item: {{ issue.item }}</span>
|
||||
<a href="{{ issue.url }}" target="_blank" class="btn btn-sm btn-primary">Voir sur Osmose</a>
|
||||
<!-- Statistiques des alertes -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-header bg-primary text-white">
|
||||
<h5 class="card-title mb-0">Répartition par thème</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
{% if osmoseIssues|length > 0 %}
|
||||
<div class="row">
|
||||
{% for themeKey, count in issuesByTheme %}
|
||||
{% if count > 0 %}
|
||||
<div class="col-md-6 mb-2">
|
||||
<div class="d-flex justify-content-between">
|
||||
<span>{{ themes[themeKey] }}</span>
|
||||
<span class="badge bg-primary">{{ count }}</span>
|
||||
</div>
|
||||
<div class="progress">
|
||||
<div class="progress-bar" role="progressbar"
|
||||
style="width: {{ (count / osmoseIssues|length * 100)|round }}%;"
|
||||
aria-valuenow="{{ count }}"
|
||||
aria-valuemin="0"
|
||||
aria-valuemax="{{ osmoseIssues|length }}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<p class="text-center">Aucun problème trouvé</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-header bg-primary text-white">
|
||||
<h5 class="card-title mb-0">Répartition par niveau de sévérité</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
{% if osmoseIssues|length > 0 %}
|
||||
<div class="row">
|
||||
<div class="col-md-12 mb-2">
|
||||
<div class="d-flex justify-content-between">
|
||||
<span>Critique</span>
|
||||
<span class="badge bg-danger">{{ issuesByLevel[1] }}</span>
|
||||
</div>
|
||||
<div class="progress">
|
||||
<div class="progress-bar bg-danger" role="progressbar"
|
||||
style="width: {{ (issuesByLevel[1] / osmoseIssues|length * 100)|round }}%;"
|
||||
aria-valuenow="{{ issuesByLevel[1] }}"
|
||||
aria-valuemin="0"
|
||||
aria-valuemax="{{ osmoseIssues|length }}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-12 mb-2">
|
||||
<div class="d-flex justify-content-between">
|
||||
<span>Important</span>
|
||||
<span class="badge bg-warning text-dark">{{ issuesByLevel[2] }}</span>
|
||||
</div>
|
||||
<div class="progress">
|
||||
<div class="progress-bar bg-warning" role="progressbar"
|
||||
style="width: {{ (issuesByLevel[2] / osmoseIssues|length * 100)|round }}%;"
|
||||
aria-valuenow="{{ issuesByLevel[2] }}"
|
||||
aria-valuemin="0"
|
||||
aria-valuemax="{{ osmoseIssues|length }}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-12 mb-2">
|
||||
<div class="d-flex justify-content-between">
|
||||
<span>Avertissement</span>
|
||||
<span class="badge bg-info">{{ issuesByLevel[3] }}</span>
|
||||
</div>
|
||||
<div class="progress">
|
||||
<div class="progress-bar bg-info" role="progressbar"
|
||||
style="width: {{ (issuesByLevel[3] / osmoseIssues|length * 100)|round }}%;"
|
||||
aria-valuenow="{{ issuesByLevel[3] }}"
|
||||
aria-valuemin="0"
|
||||
aria-valuemax="{{ osmoseIssues|length }}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<p class="text-center">Aucun problème trouvé</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="no-issues">
|
||||
<p>Aucun problème Osmose trouvé pour cette ville avec le filtre actuel.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="map"></div>
|
||||
|
||||
<div class="row mt-4">
|
||||
<div class="col-md-12">
|
||||
<div class="card">
|
||||
<div class="card-header bg-primary text-white d-flex justify-content-between align-items-center">
|
||||
<h3 class="mb-0">Liste des problèmes ({{ osmoseIssues|length }})</h3>
|
||||
<div class="btn-group">
|
||||
<button class="btn btn-sm btn-light" id="sort-by-level">Trier par sévérité</button>
|
||||
<button class="btn btn-sm btn-light" id="sort-by-item">Trier par type</button>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="card-body">
|
||||
{% if osmoseIssues|length > 0 %}
|
||||
<div class="issue-list">
|
||||
{% for issue in osmoseIssues %}
|
||||
<div class="issue-item level-{{ issue.level }}" data-lat="{{ issue.lat }}" data-lon="{{ issue.lon }}" data-level="{{ issue.level }}" data-item="{{ issue.item }}">
|
||||
<div class="row">
|
||||
<div class="col-md-9">
|
||||
<h5>{{ issue.title }}</h5>
|
||||
{% if issue.subtitle %}
|
||||
<p class="text-muted">{{ issue.subtitle }}</p>
|
||||
{% endif %}
|
||||
<div class="d-flex gap-2 mt-2">
|
||||
<span class="badge bg-secondary">Item: {{ issue.item }}</span>
|
||||
{% if issue.level == 1 %}
|
||||
<span class="badge bg-danger">Critique</span>
|
||||
{% elseif issue.level == 2 %}
|
||||
<span class="badge bg-warning text-dark">Important</span>
|
||||
{% elseif issue.level == 3 %}
|
||||
<span class="badge bg-info">Avertissement</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3 text-end d-flex flex-column justify-content-between">
|
||||
<a href="{{ issue.url }}" target="_blank" class="btn btn-sm btn-primary mb-2">
|
||||
<i class="fas fa-external-link-alt"></i> Voir sur Osmose
|
||||
</a>
|
||||
<button class="btn btn-sm btn-outline-secondary locate-on-map">
|
||||
<i class="fas fa-map-marker-alt"></i> Localiser sur la carte
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="no-issues">
|
||||
<p class="text-center">Aucun problème Osmose trouvé pour cette ville avec le filtre actuel.</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -311,29 +439,47 @@
|
|||
map.getCanvas().style.cursor = '';
|
||||
});
|
||||
|
||||
// Ajouter un événement de clic sur les éléments de la liste
|
||||
{% for issue in osmoseIssues %}
|
||||
document.querySelector(`.issue-item[data-lat="{{ issue.lat }}"][data-lon="{{ issue.lon }}"]`)?.addEventListener('click', function() {
|
||||
map.flyTo({
|
||||
center: [{{ issue.lon }}, {{ issue.lat }}],
|
||||
zoom: 18
|
||||
});
|
||||
|
||||
// Simuler un clic sur le point pour ouvrir la popup
|
||||
const features = map.queryRenderedFeatures(
|
||||
map.project([{{ issue.lon }}, {{ issue.lat }}]),
|
||||
{ layers: ['unclustered-point'] }
|
||||
);
|
||||
|
||||
if (features.length > 0) {
|
||||
map.fire('click', {
|
||||
lngLat: { lng: {{ issue.lon }}, lat: {{ issue.lat }} },
|
||||
point: map.project([{{ issue.lon }}, {{ issue.lat }}]),
|
||||
features: [features[0]]
|
||||
});
|
||||
}
|
||||
// Fonction pour localiser un problème sur la carte
|
||||
function locateIssueOnMap(lat, lon) {
|
||||
map.flyTo({
|
||||
center: [lon, lat],
|
||||
zoom: 18
|
||||
});
|
||||
{% endfor %}
|
||||
|
||||
// Simuler un clic sur le point pour ouvrir la popup
|
||||
const features = map.queryRenderedFeatures(
|
||||
map.project([lon, lat]),
|
||||
{ layers: ['unclustered-point'] }
|
||||
);
|
||||
|
||||
if (features.length > 0) {
|
||||
map.fire('click', {
|
||||
lngLat: { lng: lon, lat: lat },
|
||||
point: map.project([lon, lat]),
|
||||
features: [features[0]]
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Ajouter un événement de clic sur les boutons "Localiser sur la carte"
|
||||
document.querySelectorAll('.locate-on-map').forEach(function(button) {
|
||||
button.addEventListener('click', function(e) {
|
||||
e.stopPropagation(); // Empêcher la propagation au parent
|
||||
const issueItem = this.closest('.issue-item');
|
||||
const lat = parseFloat(issueItem.dataset.lat);
|
||||
const lon = parseFloat(issueItem.dataset.lon);
|
||||
locateIssueOnMap(lat, lon);
|
||||
});
|
||||
});
|
||||
|
||||
// Ajouter un événement de clic sur les éléments de la liste
|
||||
document.querySelectorAll('.issue-item').forEach(function(item) {
|
||||
item.addEventListener('click', function() {
|
||||
const lat = parseFloat(this.dataset.lat);
|
||||
const lon = parseFloat(this.dataset.lon);
|
||||
locateIssueOnMap(lat, lon);
|
||||
});
|
||||
});
|
||||
|
||||
// Ajuster la vue pour montrer tous les marqueurs si nécessaire
|
||||
if (features.length > 0) {
|
||||
|
@ -347,6 +493,37 @@
|
|||
padding: 50
|
||||
});
|
||||
}
|
||||
|
||||
// Fonctions de tri pour les problèmes
|
||||
function sortIssuesByLevel() {
|
||||
const issueList = document.querySelector('.issue-list');
|
||||
const issues = Array.from(issueList.querySelectorAll('.issue-item'));
|
||||
|
||||
issues.sort(function(a, b) {
|
||||
return parseInt(a.dataset.level) - parseInt(b.dataset.level);
|
||||
});
|
||||
|
||||
issues.forEach(function(issue) {
|
||||
issueList.appendChild(issue);
|
||||
});
|
||||
}
|
||||
|
||||
function sortIssuesByItem() {
|
||||
const issueList = document.querySelector('.issue-list');
|
||||
const issues = Array.from(issueList.querySelectorAll('.issue-item'));
|
||||
|
||||
issues.sort(function(a, b) {
|
||||
return parseInt(a.dataset.item) - parseInt(b.dataset.item);
|
||||
});
|
||||
|
||||
issues.forEach(function(issue) {
|
||||
issueList.appendChild(issue);
|
||||
});
|
||||
}
|
||||
|
||||
// Ajouter des événements de clic sur les boutons de tri
|
||||
document.getElementById('sort-by-level').addEventListener('click', sortIssuesByLevel);
|
||||
document.getElementById('sort-by-item').addEventListener('click', sortIssuesByItem);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue