feat(5.12): modal editare + cont obligatoriu la import; design.md + PRD 5.13 revizuit (/autoplan)
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>
This commit is contained in:
@@ -54,7 +54,8 @@
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<!-- Panou inline: operatii fara cod RAR, mapabile in flux (fara re-upload) -->
|
||||
<!-- Panou inline: operatii fara cod RAR, mapabile in flux (fara re-upload).
|
||||
US-004: un singur <form> cu un select per operatie + un singur buton Salveaza. -->
|
||||
{% if unmapped_ops %}
|
||||
<div class="card" style="border-color:var(--err); background:color-mix(in srgb, var(--err) 12%, var(--card)); margin-bottom:14px;">
|
||||
<h3 style="font-size:14px; margin:0 0 6px;">Operatii de mapat la cod RAR</h3>
|
||||
@@ -63,51 +64,68 @@
|
||||
preselectata) si salveaza — randurile blocate trec automat in
|
||||
<span class="s-ok">ok</span> si maparea se retine pentru fisierele viitoare.
|
||||
</p>
|
||||
{% for e in unmapped_ops %}
|
||||
{%- set top = e.suggestions[0] if e.suggestions else None -%}
|
||||
{%- set preselect = top.cod_prestatie if (top and top.score >= 60) else '' -%}
|
||||
<form class="maprow" hx-post="/_import/{{ import_id }}/mapare-operatie"
|
||||
hx-target="#import-section" hx-swap="outerHTML"
|
||||
style="align-items:flex-end;">
|
||||
<form hx-post="/_import/{{ import_id }}/mapare-operatii"
|
||||
hx-target="#import-section" hx-swap="outerHTML">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token or '' }}">
|
||||
<input type="hidden" name="cod_op_service" value="{{ e.cod_op_service }}">
|
||||
<div class="mapcol grow">
|
||||
<div><strong>{{ e.cod_op_service }}</strong>
|
||||
<span class="pill" title="randuri blocate">{{ e.blocked }} randuri</span></div>
|
||||
{% if e.denumire and e.denumire != e.cod_op_service %}
|
||||
<div class="muted">{{ e.denumire }}</div>
|
||||
{% endif %}
|
||||
{% if e.suggestions %}
|
||||
<div class="muted" style="font-size:12px; margin-top:4px;">
|
||||
sugestii:
|
||||
{% for s in e.suggestions[:3] %}
|
||||
<span class="sugg">{{ s.cod_prestatie }} ({{ s.score|round|int }}%)</span>{% if not loop.last %}, {% endif %}
|
||||
{% endfor %}
|
||||
{% for e in unmapped_ops %}
|
||||
{%- set top = e.suggestions[0] if e.suggestions else None -%}
|
||||
{%- set preselect = top.cod_prestatie if (top and top.score >= 60) else '' -%}
|
||||
<div class="maprow" style="align-items:flex-end; margin-bottom:10px;">
|
||||
<input type="hidden" name="cod_op_service" value="{{ e.cod_op_service }}">
|
||||
<div class="mapcol grow">
|
||||
<div><strong>{{ e.cod_op_service }}</strong>
|
||||
<span class="pill" title="randuri blocate">{{ e.blocked }} randuri</span></div>
|
||||
{% if e.denumire and e.denumire != e.cod_op_service %}
|
||||
<div class="muted">{{ e.denumire }}</div>
|
||||
{% endif %}
|
||||
{% if e.suggestions %}
|
||||
<div class="muted" style="font-size:12px; margin-top:4px;">
|
||||
sugestii:
|
||||
{% for s in e.suggestions[:3] %}
|
||||
<span class="sugg">{{ s.cod_prestatie }} ({{ s.score|round|int }}%)</span>{% if not loop.last %}, {% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="mapcol">
|
||||
<select name="cod_prestatie" aria-label="Cod RAR pentru {{ e.cod_op_service }}">
|
||||
<option value="">— alege cod RAR —</option>
|
||||
{% for n in nomenclator %}
|
||||
<option value="{{ n.cod_prestatie }}" {% if n.cod_prestatie == preselect %}selected{% endif %}>
|
||||
{{ n.cod_prestatie }} — {{ n.nume_prestatie }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="mapcol">
|
||||
<select name="cod_prestatie" required aria-label="Cod RAR pentru {{ e.cod_op_service }}">
|
||||
<option value="">— alege cod RAR —</option>
|
||||
{% for n in nomenclator %}
|
||||
<option value="{{ n.cod_prestatie }}" {% if n.cod_prestatie == preselect %}selected{% endif %}>
|
||||
{{ n.cod_prestatie }} — {{ n.nume_prestatie }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="mapcol">
|
||||
<button type="submit" style="min-height:44px;">Salveaza</button>
|
||||
{% endfor %}
|
||||
<div style="margin-top:12px;">
|
||||
<button type="submit" style="min-height:44px;">Salveaza maparile</button>
|
||||
</div>
|
||||
</form>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Banner discoverability (T1, US-007): vizibil cand exista randuri needs_review.
|
||||
Explica operatorului ca randurile cu 'Verifica valori' nu pleaca la RAR
|
||||
pana le deschide in modal si apasa 'Confirma valorile'. Dispare via OOB
|
||||
cand summary.needs_review == 0. -->
|
||||
<div id="preview-needs-review-banner">
|
||||
{% 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>
|
||||
|
||||
<!-- Tabel preview in format identic cu tabelul Trimiteri (.tabel-trimiteri).
|
||||
Randurile au FORM PROPRIU pentru editare (NU sunt in #confirm-form,
|
||||
altfel Enter intr-un camp ar declansa trimiterea ireversibila). Bifele
|
||||
needs_review se asociaza la #confirm-form prin atributul form=. -->
|
||||
US-007: 8 coloane (coloana de verificare eliminata).
|
||||
Randurile au FORM PROPRIU pentru editare (NU sunt in #confirm-form). -->
|
||||
<div class="tablewrap tabel-trimiteri">
|
||||
<table>
|
||||
<thead>
|
||||
@@ -119,7 +137,6 @@
|
||||
<th class="col-data">Data</th>
|
||||
<th class="col-km">KM final</th>
|
||||
<th class="col-note">Note</th>
|
||||
<th class="col-verificat">Verificat?</th>
|
||||
<th class="col-actiuni">Actiuni</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -164,10 +181,7 @@
|
||||
style="max-width:80px;"
|
||||
aria-describedby="n-hint">
|
||||
<span id="n-hint" class="muted" style="font-size:12px; margin-left:6px;">
|
||||
(<span id="n-hint-ok">{{ summary.get('ok', 0) }}</span> ok
|
||||
{% if summary.get('needs_review', 0) %}
|
||||
+ pana la {{ summary.get('needs_review', 0) }} verificate manual
|
||||
{% endif %})
|
||||
(<span id="n-hint-ok">{{ summary.get('ok', 0) }}</span> ok)
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -226,20 +240,19 @@
|
||||
return el ? parseInt(el.dataset.ok || '0', 10) : 0;
|
||||
}
|
||||
|
||||
/* Actualizeaza N si bannerul cand se bifeaza needs_review SAU cand se editeaza un rand. */
|
||||
/* Actualizeaza N dupa editare/confirmare rand (OOB).
|
||||
US-007: reviewed_rows (checkboxe) eliminate; N = randurile ok din DB,
|
||||
actualizate via OOB (#preview-ok-count[data-ok]) dupa /confirma-review sau /editeaza. */
|
||||
function updateN() {
|
||||
var checked = document.querySelectorAll('input[name="reviewed_rows"]:checked').length;
|
||||
var total = getOk() + checked;
|
||||
var total = getOk();
|
||||
var inp = document.getElementById('n-confirmat');
|
||||
var disp = document.getElementById('n-display');
|
||||
var btn = document.getElementById('confirm-btn');
|
||||
/* Nu re-activa confirm cat un rand e in editare (mutual-exclusion). */
|
||||
var editing = document.querySelector('tr[data-editing="1"]') !== null;
|
||||
if (inp) inp.value = total;
|
||||
if (disp) disp.textContent = total;
|
||||
var hintOk = document.getElementById('n-hint-ok');
|
||||
if (hintOk) hintOk.textContent = getOk();
|
||||
if (btn) btn.disabled = (total === 0) || editing;
|
||||
if (hintOk) hintOk.textContent = total;
|
||||
if (btn) btn.disabled = (total === 0);
|
||||
}
|
||||
|
||||
/* Filtrare randuri dupa stare.
|
||||
|
||||
Reference in New Issue
Block a user