266 lines
11 KiB
HTML
266 lines
11 KiB
HTML
{% extends base_template|default:"base.html" %}
|
|
{% load i18n static %}
|
|
|
|
{% block title %}{% translate "Inspection Rapide Carte GPS" %}{% endblock %}
|
|
|
|
{% block extra_head %}
|
|
<link href="{% static 'common/maplibre-gl.css' %}" rel="stylesheet">
|
|
<style>
|
|
body {
|
|
padding-top: 54px !important;
|
|
padding-bottom: 0 !important;
|
|
}
|
|
main.container, main {
|
|
margin: 0 !important;
|
|
padding: 0 !important;
|
|
max-width: 100% !important;
|
|
width: 100% !important;
|
|
}
|
|
footer {
|
|
display: none !important;
|
|
}
|
|
#inspection-map-wrapper {
|
|
position: relative;
|
|
height: calc(100vh - 54px);
|
|
min-height: 500px;
|
|
width: 100%;
|
|
overflow: hidden;
|
|
}
|
|
#inspection-map {
|
|
min-height: 500px;
|
|
height: 100%;
|
|
width: 100%;
|
|
z-index: 1;
|
|
}
|
|
.map-controls-overlay {
|
|
position: absolute;
|
|
top: 6px;
|
|
left: 8px;
|
|
right: 8px;
|
|
z-index: 1000;
|
|
pointer-events: none;
|
|
}
|
|
.map-controls-overlay > * {
|
|
pointer-events: auto;
|
|
}
|
|
/* Transition fluide pour le repositionnement dynamique des contrôles MapLibre */
|
|
#inspection-map .maplibregl-ctrl-top-left,
|
|
#inspection-map .maplibregl-ctrl-top-right {
|
|
transition: margin-top 0.15s ease-out;
|
|
}
|
|
.map-floating-actions {
|
|
position: absolute;
|
|
bottom: 24px;
|
|
right: 16px;
|
|
z-index: 1000;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 8px;
|
|
}
|
|
.user-gps-dot {
|
|
width: 16px;
|
|
height: 16px;
|
|
background-color: #0d6efd;
|
|
border: 2px solid #ffffff;
|
|
border-radius: 50%;
|
|
box-shadow: 0 0 10px rgba(13, 110, 253, 0.8);
|
|
}
|
|
|
|
/* Bottom Sheet Modal Styling for Mobile */
|
|
.modal-bottom-sheet .modal-dialog {
|
|
margin: 0;
|
|
position: fixed;
|
|
bottom: 0;
|
|
left: 0;
|
|
right: 0;
|
|
max-width: 100%;
|
|
}
|
|
.modal-bottom-sheet .modal-content {
|
|
border-bottom-left-radius: 0;
|
|
border-bottom-right-radius: 0;
|
|
border-top-left-radius: 1.25rem;
|
|
border-top-right-radius: 1.25rem;
|
|
border: none;
|
|
max-height: 85vh;
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
.modal-bottom-sheet .modal-body {
|
|
max-height: 70vh;
|
|
overflow-y: auto;
|
|
overscroll-behavior: contain;
|
|
-webkit-overflow-scrolling: touch;
|
|
}
|
|
.thematic-tile {
|
|
border: 2px solid #e9ecef;
|
|
border-radius: 0.85rem;
|
|
padding: 0.75rem 1rem;
|
|
transition: all 0.2s ease;
|
|
cursor: pointer;
|
|
background: #ffffff;
|
|
}
|
|
.thematic-tile.active {
|
|
border-color: #0d6efd;
|
|
background-color: rgba(13, 110, 253, 0.06);
|
|
}
|
|
.thematic-tile-icon {
|
|
width: 40px;
|
|
height: 40px;
|
|
border-radius: 50%;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-size: 1.2rem;
|
|
flex-shrink: 0;
|
|
}
|
|
.filter-btn-pill {
|
|
background-color: #ffffff;
|
|
border: 1px solid #dee2e6;
|
|
box-shadow: 0 2px 6px rgba(0,0,0,0.08);
|
|
border-radius: 50rem;
|
|
padding: 0.4rem 0.85rem;
|
|
font-size: 0.85rem;
|
|
transition: all 0.15s ease;
|
|
}
|
|
.filter-btn-pill:active {
|
|
transform: scale(0.97);
|
|
}
|
|
</style>
|
|
{% endblock %}
|
|
|
|
{% block content %}
|
|
<div id="inspection-map-wrapper">
|
|
<!-- Overlay des filtres mémorisés (Boutons tactiles mobiles) -->
|
|
<div class="map-controls-overlay">
|
|
<div class="card shadow-sm border-0 bg-white opacity-95 rounded-4">
|
|
<div class="card-body p-2 d-flex align-items-center justify-content-between gap-2 flex-wrap">
|
|
<div class="d-flex align-items-center gap-1.5">
|
|
<i class="bi bi-geo-alt-fill text-primary fs-6"></i>
|
|
<span class="fw-bold small me-1">{% translate "Inspection Rapide" %}</span>
|
|
<span class="badge bg-light text-muted border small" id="gps-status-text">{% translate "GPS actif" %}</span>
|
|
</div>
|
|
|
|
<div class="d-flex align-items-center gap-2">
|
|
<!-- Bouton Déclencheur Thématique -->
|
|
<button id="btn-select-thematic" type="button" class="btn filter-btn-pill d-flex align-items-center gap-1.5" data-bs-toggle="modal" data-bs-target="#thematicChooserModal">
|
|
<i id="thematic-icon-display" class="bi bi-collection text-primary"></i>
|
|
<span id="thematic-name-display" class="fw-semibold">{% translate "Thématique" %}</span>
|
|
<i class="bi bi-chevron-down text-muted ms-1 small"></i>
|
|
</button>
|
|
|
|
<!-- Bouton Déclencheur Catégorie -->
|
|
<button id="btn-select-category" type="button" class="btn filter-btn-pill d-flex align-items-center gap-1.5" data-bs-toggle="modal" data-bs-target="#categoryChooserModal">
|
|
<i class="bi bi-tag-fill text-secondary"></i>
|
|
<span id="category-name-display" class="fw-semibold">{% translate "Catégorie" %}</span>
|
|
<i class="bi bi-chevron-down text-muted ms-1 small"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Sélecteurs cachés synchronisés avec le JS d'inspection -->
|
|
<select id="filter-thematic" class="d-none">
|
|
<option value="">{% translate "-- Thématique --" %}</option>
|
|
{% for t in thematics %}
|
|
<option value="{{ t.code }}" data-icon="{{ t.icon|default:'bi-folder2' }}" data-name="{{ t.name }}" {% if t.code == 'parking' %}selected{% endif %}>{{ t.name }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
|
|
<select id="filter-category" class="d-none">
|
|
<option value="">{% translate "-- Catégorie --" %}</option>
|
|
{% for c in categories %}
|
|
<option value="{{ c.id }}" data-thematic="{{ c.thematic.code }}" data-name="{{ c.get_name }}">{{ c.get_name }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
|
|
<div id="map-warning-alert" class="alert alert-warning alert-dismissible fade show d-none shadow-sm py-2 px-3 mt-2 mb-0 small" role="alert">
|
|
<i class="bi bi-exclamation-triangle-fill me-1 text-warning"></i>
|
|
<span id="map-warning-text">{% translate "Veuillez zoomer sur la carte (zoom 16+) pour afficher les équipements." %}</span>
|
|
<button type="button" class="btn-close py-2" data-bs-dismiss="alert" aria-label="Close"></button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Carte MapLibre -->
|
|
<div id="inspection-map"></div>
|
|
|
|
<!-- Actions Flottantes (Bouton GPS) -->
|
|
<div class="map-floating-actions">
|
|
<button id="btn-gps-locate" class="btn btn-white btn-lg shadow rounded-circle border" title="{% translate 'Ma position GPS' %}">
|
|
<i class="bi bi-crosshair text-primary fs-5"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Modal Choix de Thématique (Style Mobile Bottom Sheet) -->
|
|
<div class="modal fade modal-bottom-sheet" id="thematicChooserModal" tabindex="-1" aria-labelledby="thematicChooserModalLabel" aria-hidden="true">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content shadow-lg">
|
|
<div class="modal-header border-0 pb-1">
|
|
<h6 class="modal-title fw-bold" id="thematicChooserModalLabel">
|
|
<i class="bi bi-layers-fill text-primary me-1"></i>{% translate "Choisir une thématique" %}
|
|
</h6>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Fermer"></button>
|
|
</div>
|
|
<div class="modal-body p-3">
|
|
<div class="row g-2" id="thematic-tiles-container">
|
|
{% for t in thematics %}
|
|
<div class="col-12 col-sm-6">
|
|
<div class="thematic-tile d-flex align-items-center gap-3 {% if t.code == 'parking' %}active{% endif %}" data-code="{{ t.code }}" data-icon="{{ t.icon|default:'bi-folder2' }}" data-name="{{ t.name }}" data-bs-dismiss="modal">
|
|
<div class="thematic-tile-icon" style="background-color: {{ t.color|default:'#0d6efd' }}15; color: {{ t.color|default:'#0d6efd' }};">
|
|
<i class="bi {{ t.icon|default:'bi-folder2' }}"></i>
|
|
</div>
|
|
<div class="flex-grow-1">
|
|
<h6 class="mb-0 fw-bold small text-dark">{{ t.name }}</h6>
|
|
<small class="text-muted" style="font-size: 0.75rem;">{{ t.description|default:""|truncatechars:45 }}</small>
|
|
</div>
|
|
<i class="bi bi-check-circle-fill text-primary fs-5 thematic-check d-none"></i>
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Modal Choix de Catégorie (Style Mobile Bottom Sheet) -->
|
|
<div class="modal fade modal-bottom-sheet" id="categoryChooserModal" tabindex="-1" aria-labelledby="categoryChooserModalLabel" aria-hidden="true">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content shadow-lg">
|
|
<div class="modal-header border-0 pb-1">
|
|
<h6 class="modal-title fw-bold" id="categoryChooserModalLabel">
|
|
<i class="bi bi-tags-fill text-primary me-1"></i>{% translate "Filtrer par catégorie" %}
|
|
</h6>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Fermer"></button>
|
|
</div>
|
|
<div class="modal-body p-3">
|
|
<div class="list-group list-group-flush" id="category-list-container">
|
|
<button type="button" class="list-group-item list-group-item-action d-flex justify-content-between align-items-center py-2.5 px-3 rounded-3 mb-1 border-0 category-item active" data-id="" data-name="{% translate 'Toutes les catégories' %}" data-bs-dismiss="modal">
|
|
<span class="fw-semibold small">{% translate "Toutes les catégories" %}</span>
|
|
<i class="bi bi-check-lg text-primary category-check"></i>
|
|
</button>
|
|
{% for c in categories %}
|
|
<button type="button" class="list-group-item list-group-item-action d-flex justify-content-between align-items-center py-2.5 px-3 rounded-3 mb-1 border-0 category-item" data-id="{{ c.id }}" data-thematic="{{ c.thematic.code }}" data-name="{{ c.get_name }}" data-bs-dismiss="modal">
|
|
<span class="fw-semibold small text-dark">{{ c.get_name }}</span>
|
|
<i class="bi bi-check-lg text-primary category-check d-none"></i>
|
|
</button>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Inclure la Modale d'inspection -->
|
|
{% include "assets/components/inspection_form_modal.html" %}
|
|
|
|
{% endblock %}
|
|
|
|
{% block footer %}{% endblock %}
|
|
|
|
{% block extra_js %}
|
|
<script src="{% static 'common/layer-switcher-control.js' %}"></script>
|
|
<script src="{% static 'common/address_search_control.js' %}"></script>
|
|
<script>window.AUTOCOMPLETE_STREET_URL = "{% url 'common:autocomplete_street' %}";</script>
|
|
<script src="{% static 'assets/inspection_map.js' %}"></script>
|
|
{% endblock %}
|