5.12 (livrat): editare in modal a randurilor de preview, cont obligatoriu inainte de import, formular editare extras (_form_editare, _editare_preview_modal), plus suita de teste aferenta (preview edit/compact, mapare op, form editare, signup, admin panel). Design + planificare: - docs/design.md: sistem de design (tokeni, breakpoints, scara control, componente, a11y). - docs/prd/prd-5.12-* si prd-5.13-* (5.13 cu raport /autoplan: CEO+Design+Eng, audit trail). Curatare: sterse PNG-urile de test/mockup temporare din radacina. Nota: implementarea CSS 5.13 (responsive compact + sistem butoane) NU e inca facuta — planul revizuit cere refactorul testelor fragile din test_web_responsive.py INAINTE de CSS. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
122 lines
6.4 KiB
HTML
122 lines
6.4 KiB
HTML
{#
|
|
_preview_rand.html — un singur rand de preview import.
|
|
US-006 (PRD 5.12): editarea inline (tr.preview-edit + mutual-exclusion script)
|
|
a fost eliminata. Butonul Editeaza deschide MODALUL global (#detaliu-modal-body).
|
|
|
|
Parametri:
|
|
editing — ELIMINAT (ignorat, pastrat pentru compatibilitate apeluri vechi)
|
|
include_oob — True: randeaza OOB rezumat + contor + script recalc (swap dupa save)
|
|
oob_tr — True: adauga hx-swap-oob pe <tr> insusi (pentru raspunsul POST succes)
|
|
summary — dict cu contoarele per status
|
|
|
|
Campuri pre-computate de _web_compute_preview (NOT din template raw):
|
|
row.prez — prezentare_din_payload(resolved): vehicul_nr, vin_scurt,
|
|
operatie, cod_rar, data_prestatie, odometru
|
|
row.stare_eticheta — text uman (ex. "Gata de trimis"), din STARI_PREVIEW
|
|
row.stare_css — clasa CSS (ex. "s-ok"), din STARI_PREVIEW
|
|
row.nota_umana — mesaj uman formatat pentru coloana Note (fara repr Python)
|
|
#}
|
|
{%- set res = row.resolved -%}
|
|
{%- set status = row.resolved_status -%}
|
|
{%- set disp_fix_map = {} -%}
|
|
{%- for e in row.errors -%}{%- if e is mapping and e.get('field') and e.get('fix') -%}{%- set _ = disp_fix_map.update({e.field: e.get('fix')}) -%}{%- endif -%}{%- endfor -%}
|
|
<tr id="preview-row-{{ row.row_index }}" data-status="{{ status }}"
|
|
{% if oob_tr %}hx-swap-oob="outerHTML:#preview-row-{{ row.row_index }}"{% endif %}
|
|
style="{% if status == 'needs_review' %}background:rgba(230,179,74,.04);{% elif status in ('already_sent', 'duplicate_in_file') %}opacity:.65;{% endif %}">
|
|
<td class="col-id muted" data-eticheta="#">{{ row.row_index + 1 }}</td>
|
|
<td class="col-stare" data-eticheta="Stare">
|
|
<span class="pill {{ row.stare_css }}">{{ row.stare_eticheta }}</span>
|
|
</td>
|
|
<td class="col-vehicul" data-eticheta="Vehicul">
|
|
{{ row.prez.vehicul_nr }}
|
|
{% if row.prez.vin_scurt and row.prez.vin_scurt != '—' %}
|
|
<div class="muted" style="font-size:12px; white-space:nowrap;">{{ row.prez.vin_scurt }}</div>
|
|
{% endif %}
|
|
{# Fix-uri de validare pe vehicul #}
|
|
{% if disp_fix_map.get('vin') %}<span class="camp-fix">{{ disp_fix_map.get('vin') }}</span>{% endif %}
|
|
{% if disp_fix_map.get('nr_inmatriculare') %}<span class="camp-fix">{{ disp_fix_map.get('nr_inmatriculare') }}</span>{% endif %}
|
|
</td>
|
|
<td class="col-operatie" data-eticheta="Operatie">
|
|
<div>{{ row.prez.operatie }}</div>
|
|
{% if row.prez.cod_rar and row.prez.cod_rar != '—' %}
|
|
<div class="cod-rar-sub"><span class="cod-rar-cod">{{ row.prez.cod_rar }}</span></div>
|
|
{% else %}
|
|
<div class="muted cod-rar-sub">nemapat</div>
|
|
{% endif %}
|
|
</td>
|
|
<td class="col-data" data-eticheta="Data prestatie">
|
|
{{ row.prez.data_prestatie }}
|
|
{% if disp_fix_map.get('data_prestatie') %}<span class="camp-fix">{{ disp_fix_map.get('data_prestatie') }}</span>{% endif %}
|
|
</td>
|
|
<td class="col-km" data-eticheta="KM final">
|
|
{{ row.prez.odometru }}
|
|
{% if disp_fix_map.get('odometru_final') %}<span class="camp-fix">{{ disp_fix_map.get('odometru_final') }}</span>{% endif %}
|
|
</td>
|
|
<td class="col-note" data-eticheta="Note"
|
|
style="font-size:12px; white-space:normal;">
|
|
{% if status == 'already_sent' and row.get('already_sent_info') %}
|
|
{% set ai = row.already_sent_info %}
|
|
deja trimis {{ (ai.get('created_at') or '')[:10] }}
|
|
{% if ai.get('id_prezentare') %}(#{{ ai.id_prezentare }}){% endif %}
|
|
{% elif status == 'duplicate_in_file' and row.get('duplicate_with') %}
|
|
dubla cu randul
|
|
{% for idx in row.duplicate_with %}{{ idx + 1 }}{% if not loop.last %}, {% endif %}{% endfor %}
|
|
{% else %}
|
|
{{ row.nota_umana or '' }}
|
|
{% endif %}
|
|
</td>
|
|
<td class="col-actiuni" data-eticheta="Actiuni" style="text-align:center;">
|
|
{% if status not in ('already_sent', 'duplicate_in_file') %}
|
|
<button type="button" class="btn-editeaza"
|
|
style="min-height:44px; padding:6px 14px; font-size:13px;
|
|
background:transparent; border-color:var(--line); color:var(--ink);"
|
|
hx-get="/_import/{{ import_id }}/rand/{{ row.row_index }}/editare-modal"
|
|
hx-target="#detaliu-modal-body" hx-swap="innerHTML"
|
|
aria-label="Editeaza randul {{ row.row_index + 1 }} (VIN: {{ res.get('vin', '') }})">
|
|
Editeaza
|
|
</button>
|
|
{% endif %}
|
|
</td>
|
|
</tr>
|
|
{% if include_oob %}
|
|
{# OOB: actualizeaza rezumatul, contorul, bannerul needs_review dupa save/confirma-review. #}
|
|
{% set status_labels = [
|
|
('ok','Gata de trimis'), ('needs_review','Verifica valori'), ('needs_mapping','Cod RAR lipsa'),
|
|
('needs_data','Date incomplete'), ('already_sent','Deja trimis'), ('duplicate_in_file','Duplicat in fisier')] %}
|
|
<div id="preview-rezumat" hx-swap-oob="true"
|
|
style="display:flex; gap:8px; flex-wrap:wrap; margin-bottom:12px;">
|
|
{% for status_key, label in status_labels %}
|
|
{%- set cnt = summary.get(status_key, 0) -%}
|
|
{% if cnt > 0 %}<span class="pill s-{{ status_key }}">{{ cnt }} {{ label | lower }}</span>{% endif %}
|
|
{% endfor %}
|
|
</div>
|
|
<span id="preview-ok-count" hx-swap-oob="true" data-ok="{{ summary.get('ok', 0) }}" hidden></span>
|
|
{# Banner discoverability: OOB swap dupa confirmare/editare → dispare cand needs_review==0. #}
|
|
<div id="preview-needs-review-banner" hx-swap-oob="true">
|
|
{% if summary.get('needs_review', 0) %}
|
|
<div class="banner warn" role="note" aria-live="polite"
|
|
style="margin-bottom:12px; padding:8px 14px; border-radius:6px;
|
|
background:color-mix(in srgb, var(--warn, #e6b34a) 12%, var(--card));
|
|
border:1px solid var(--warn, #e6b34a); font-size:13px;">
|
|
Randurile cu <span class="pill s-needs_review" style="font-size:11px;">Verifica valori</span>
|
|
nu pleaca la RAR pana le deschizi in modal si confirmi in modal
|
|
cu butonul <strong>Confirma valorile</strong>.
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
<script>
|
|
(function() {
|
|
/* Editare incheiata: re-activeaza confirm + butoanele Editeaza, recalculeaza N.
|
|
Defer pe tick-ul urmator: la momentul rularii scriptului, swap-ul randului poate
|
|
sa nu se fi asezat inca, deci tr[data-editing] ar fi inca prezent si updateN ar
|
|
lasa confirm dezactivat (editing=true). Dupa setTimeout(0) randul e in mod display. */
|
|
setTimeout(function() {
|
|
document.querySelectorAll('.btn-editeaza').forEach(function(b) { b.disabled = false; });
|
|
var btn = document.getElementById('confirm-btn');
|
|
if (btn) btn.title = '';
|
|
if (window.updateN) window.updateN();
|
|
}, 0);
|
|
})();
|
|
</script>
|
|
{% endif %}
|