loko/streetup/controls/templates/controls/remark_form_content.html
2026-07-22 14:48:40 +02:00

257 lines
13 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{% load i18n tz controls_custom_filters short_name %}
<div class="container mt-4">
<!-- Carte MapLibre -->
<div id="layer-controls">
{% for plan in plans %}
<button class="btn btn-light" onclick="showPlan({{ plan.id }})">{{ plan.name }}</button>
{% endfor %}
{% if plans %}
<button class="btn btn-light" onclick="resetView()">{% translate "Carte" %}</button>
{% endif %}
</div>
<div id="map" class="border-bottom invisible"></div>
<!-- Formulaire d'ajout de remarque -->
<form id="remark-form" method="post" class="mt-3" enctype="multipart/form-data">
{% csrf_token %}
<!-- ✅ Management form du formset (obligatoire) -->
{{ qty_formset.management_form }}
<input type="hidden" name="v" value="{{ request.GET.v }}">
<input type="hidden" id="control_id" name="control" value="{{ remark.control.id }}">
{% if mode == "update" and remark.history.exists %}
<div class="mb-3">
<label class="form-label fw-bold">{% translate "Historique des suivis" %} :</label>
<div class="list-group border rounded p-2 bg-light mb-3" style="max-height: 200px; overflow-y: auto;">
{% for entry in remark.history.all %}
<div class="list-group-item bg-transparent border-0 border-bottom py-2 px-1">
<div class="d-flex align-items-center gap-2 flex-wrap mb-1">
<span class="small text-muted fw-semibold">📅 {{ entry.created_at|timezone:"Europe/Paris"|date:"d/m/Y H:i" }}</span>
<span class="badge {{ entry.status|status_badge }}">
<i class="bi {{ entry.status|status_icon }}"></i>
{{ entry.get_status_display }}
</span>
<span class="small text-muted">({% translate 'par' %} {{ entry.created_by|short_name|default:entry.created_by.username }})</span>
</div>
{% if entry.description %}
<div class="small text-dark" style="white-space: pre-wrap;">{{ entry.description }}</div>
{% endif %}
{% if entry.images.exists %}
<div class="d-flex flex-wrap gap-1 mt-1">
{% for img in entry.images.all %}
{% private_file_url img 'thumbnail' as thumbnail_url %}
<img src="{{ thumbnail_url }}" style="width: 40px; height: 40px; object-fit: cover; border-radius: 4px;">
{% endfor %}
</div>
{% endif %}
</div>
{% endfor %}
</div>
</div>
<hr>
{% endif %}
<div id="status-badges" class="d-flex justify-content-center gap-2">
<span class="badge {% if remark.status == 'information' %}bg-info{% else %}bg-secondary{%endif%} status-badge me-1" data-value="information">Info</span>
<span class="badge {% if remark.status == 'validated' %}bg-success{% else %}bg-secondary{%endif%} status-badge me-1" data-value="validated">OK</span>
<span class="badge {% if remark.status == 'to_be_processed' %}bg-danger{% else %}bg-secondary{%endif%} status-badge" data-value="to_be_processed">NOK</span>
<input type="hidden" name="status" id="selectedStatusInput" value="{{ remark.status }}">
</div>
<hr>
<div class="mb-3">
<label for="{{ remark_form.description.id_for_label }}" class="form-label">{% translate "Description / Commentaire de suivi" %}:</label>
{{ remark_form.description }}
</div>
<hr>
{% if mode == "update" %}
<div class="mb-3 form-check">
<input type="checkbox" class="form-check-input" id="id_new_history_entry" name="new_history_entry" checked>
<label class="form-check-label fw-semibold text-primary" for="id_new_history_entry">
{% translate "Enregistrer comme un nouveau suivi dans l'historique" %}
</label>
<div class="form-text small text-muted">
{% translate "Décochez uniquement si vous souhaitez corriger une faute ou modifier la saisie précédente sans ajouter de nouvelle étape à l'historique." %}
</div>
</div>
<hr>
{% endif %}
<div class="mb-3">
<label class="form-label">{% translate "Images" %}:</label>
<div class="d-grid gap-2">
<button type="button" id="open-camera-modal-btn" class="btn btn-outline-primary">
<i class="bi bi-camera-fill me-2"></i>{% translate "Prendre des photos (mode continu)" %}
</button>
<button type="button" id="select-files-btn" class="btn btn-outline-primary">
<i class="bi bi-folder2-open me-2"></i>{% translate "Photos, vidéos, fichiers" %}
</button>
</div>
<input type="file" id="id_images" name="images" multiple class="d-none">
<div id="photo-inputs" class="d-none"></div>
</div>
<div id="preview" class="d-flex flex-wrap gap-2"></div>
<hr>
<div class="mb-3">
<label class="form-label">Tags :</label>
<div id="category-badges" data-selected="{{ selected_category_ids|join:',' }}">
{% for category in categories %}
<span
class="badge category-badge me-1 {% if category.id in selected_category_ids %}bg-primary active{% else %}bg-secondary{% endif %}"
data-id="{{ category.id }}">
{{ category.get_name }}
</span>
{% endfor %}
</div>
<input type="hidden" name="categories" id="selectedCategoriesInput" value="{{ selected_category_ids|join:',' }}">
</div>
<hr>
<!-- ✅ Récapitulatif des quantités (lisible, pas des inputs) -->
<div class="mt-3">
<div class="d-flex justify-content-between align-items-center">
<h6 class="m-0">{% translate 'Quantités liées à la remarque' %}</h6>
<button type="button" class="btn btn-sm btn-outline-primary" id="open-qty-editor">
<i class="bi bi-plus-square"></i> {% translate 'Ajouter des quantités' %}
</button>
</div>
<div id="qty-summary" class="mt-2">
<!-- rempli par JS à partir des lignes du formset -->
<div class="text-muted small" id="qty-summary-empty">
{% translate "Aucune quantité pour l'instant." %}
</div>
<div class="list-group" id="qty-summary-list"></div>
</div>
</div>
<!-- ✅ Les formulaires réels du formset (inputs) sont *cachés* ici mais restent dans le <form> -->
<div id="qty-hidden-forms" class="d-none">
{% for form in qty_formset.forms %}
<div class="qty-form" data-form-index="{{ forloop.counter0 }}">
{{ form.as_p }}
</div>
{% endfor %}
<!-- gabarit pour création dynamique -->
<template id="qty-empty-form-template">
<div class="qty-form" data-form-index="__prefix__">
{{ qty_formset.empty_form.as_p }}
</div>
</template>
</div>
<!-- ✅ Champ caché pour stocker la localisation -->
<input type="hidden" id="longitude" name="lon">
<input type="hidden" id="latitude" name="lat">
<input type="hidden" id="coord_x" name="x">
<input type="hidden" id="coord_y" name="y">
<input type="hidden" name="reference_plan" id="reference_plan" value="map">
<button id="submit-remark-button" type="submit" name="submit_remark" class="btn btn-primary w-100 mt-3">
<span id="submit-remark-button-text">
{% if mode == "update" %} {% translate "Mettre à jour" %} {% else %} {% translate "Enregistrer" %} {% endif %}
</span>
<span id="spinner-remark" class="spinner-border spinner-border-sm d-none" role="status" aria-hidden="true"></span>
</button>
{{ remark_form.control.id }}
{% if '/mobile/' in request.path %}
<a href="{% url 'mobile:controls_detail' remark.control.id %}" class="btn btn-secondary mt-3">{% translate "Annuler" %}</a>
{% else %}
<a href="{% url 'controls:controls_detail' remark.control.id %}?v={{ request.GET.v }}" class="btn btn-secondary mt-3">{% translate "Annuler" %}</a>
{% endif %}
</form>
<!-- ✅ Bottom sheet plein écran: éditeur des quantités (formset UI) -->
<div id="qty-editor" class="position-fixed top-0 start-0 w-100 h-100 bg-body" style="z-index:1060; display:none;">
<div class="d-flex align-items-center justify-content-between p-3 border-bottom">
<h6 class="m-0">{% translate 'Quantités de la remarque' %}</h6>
<button type="button" class="btn btn-outline-secondary btn-sm" id="close-qty-editor">
<i class="bi bi-x-lg"></i>
</button>
</div>
<!-- ⚠️ Pas un formulaire séparé : ce sont des *clones visibles* des inputs déjà dans qty-hidden-forms -->
<div class="d-flex flex-column h-100">
<div class="flex-grow-1 overflow-auto p-3 content-scroll">
<div id="qty-editor-rows" class="vstack gap-3">
<!-- lignes injectées par JS en clonant les champs du formset -->
</div>
<template id="qty-editor-row-template">
<div class="card shadow-sm p-3" data-form-index="__idx__">
<div class="d-flex justify-content-between align-items-center mb-2">
<strong>{% translate 'Ligne' %} <span class="row-number">__num__</span></strong>
<button type="button" class="btn btn-outline-danger btn-sm editor-remove-row">
<i class="bi bi-trash"></i> {% translate 'Supprimer' %}
</button>
</div>
<!-- Marché -->
<div class="mb-2">
<label class="form-label">{% translate 'Marché (optionnel)' %}</label>
<div class="field-contract"></div>
</div>
<!-- Poste (compat. avec ton autocomplete : label visible + hidden id si tu les as dans le form) -->
<div class="mb-2">
<label class="form-label">{% translate 'Poste (autocomplete si un marché est choisi)' %}</label>
<div class="field-contract_post_label"></div>
<div class="field-contract_post_id"></div>
<div class="list-group mt-1 d-none position-relative" id="qty-post-suggestions-__idx__"></div>
</div>
<!-- Description -->
<div class="mb-2">
<label class="form-label">{% translate 'Description (si pas de marché/poste)' %}</label>
<div class="field-description"></div>
</div>
<!-- q1 q2 q3 -->
<div class="row g-2">
<div class="col-4">
<label class="form-label">{% translate 'Quantité (1)' %}</label>
<div class="field-q1"></div>
</div>
<div class="col-4">
<label class="form-label">{% translate 'Quantité (2)' %}</label>
<div class="field-q2"></div>
</div>
<div class="col-4">
<label class="form-label">{% translate 'Quantité (3)' %}</label>
<div class="field-q3"></div>
</div>
</div>
<div class="row g-2 mt-1">
<div class="col-6">
<label class="form-label">{% translate 'Résultat' %}</label>
<input class="form-control qty-preview" type="text" value="" readonly>
</div>
</div>
<!-- Champ DELETE (si présent dans formset) -->
<div class="field-DELETE d-none"></div>
</div>
</template>
</div>
<!-- Barre d’actions fixe -->
<div class="action-bar fixed-bottom border-top bg-body">
<div class="container-fluid p-3">
<div class="d-grid gap-2">
<button type="button" class="btn btn-outline-primary btn-lg" id="add-qty-row">
<i class="bi bi-plus-square"></i> {% translate 'Ajouter une ligne' %}
</button>
<button type="button" class="btn btn-primary btn-lg" id="apply-qty-and-close">
{% translate 'Terminer et revenir' %}
</button>
</div>
</div>
</div>
</div>
</div>
</div>