feat(recipes): la ricetta decide cosa pretendere e come si misura
Tre cose che prima non erano di nessuno diventano regole della ricetta, decise da chi la scrive e fatte valere dal server. Punto 8 — tracciabilita' obbligatoria. Lotto e seriale si dichiarano obbligatori sulla ricetta. L'operatore li inserisce alla selezione, dove il pulsante non si attiva finche' mancano, e la stessa regola vale sulla lista task, raggiungibile anche per link diretto, e sul barcode: uno sbarramento che dura solo finche' qualcuno prende in mano il lettore non e' uno sbarramento. La produzione non si apre e la misura non si salva senza cio' che la ricetta pretende, perche' un valore senza il suo lotto non e' riconducibile a niente, e accorgersene dopo significa accorgersene tardi. Punto 9 — inserimento manuale. Una ricetta puo' vietare i valori digitati, ed e' il valore predefinito: il calibro e' lo strumento, digitare e' cio' che va concesso. Dove e' vietato il tastierino non viene disegnato (non nascosto con i CSS: il markup nascosto e' markup che si puo' rimostrare) e restano correzione e conferma, perche' una lettura sbagliata va cancellata. Il controllo vero e' sul server: una regola che vive solo nel frontend e' un consiglio. Migliorato al passaggio il riconoscimento del calibro. Contava solo la raffica di cifre, cosi' una lettura corta come "9.5" — tre battute — finiva registrata come digitata a mano; ora conta anche l'Invio che il wedge manda dentro la stessa raffica. Senza questa correzione il divieto avrebbe respinto misure legittime. Punto 11 — formattazione delle descrizioni. A capo e grassetto sopravvivono: chi scrive le ricette incolla dal PDF della scheda tecnica e il testo arrivava appiattito, da risistemare a mano ogni volta. Nessun HTML viene accettato o salvato — il testo viene escapato e gli unici tag nel risultato sono quelli prodotti dal renderer. La sanificazione e' questa: non c'e' niente da sanificare perche' non si accetta niente. Le stesse due regole in Jinja e in JS, cosi' una descrizione si legge uguale ovunque. E la descrizione ora si vede anche in esecuzione: era scritta per l'operatore e la vedeva solo chi la scriveva. Migrazione 009: tre colonne sulla ricetta. Le due di tracciabilita' partono false, che e' il comportamento di oggi; l'inserimento manuale parte *vero* sulle ricette gia' esistenti — il default della colonna e' falso, quindi le ricette nuove sono solo-calibro, ma spegnerlo d'ufficio su quelle in uso fermerebbe una linea alla misura successiva. Chi possiede la ricetta lo decide dall'editor. Test: +26 (291). Coprono il rifiuto sul server per lotto, seriale e valore digitato, il calibro sempre ammesso, le regole che sopravvivono alla nuova versione, il tastierino assente in pagina, l'Avvia sbarrato, e il renderer delle descrizioni compreso il caso in cui si prova a farci passare un tag. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -67,6 +67,7 @@
|
||||
x-data="taskExecute()"
|
||||
x-init="init()"
|
||||
@numpad-confirm.window="handleMeasurement($event.detail.value, $event.detail.inputMethod)"
|
||||
@numpad-rejected.window="onNumpadRejected($event.detail)"
|
||||
@marker-click.window="goToSubtaskByMarker($event.detail.marker_number)">
|
||||
|
||||
{# ================================================================
|
||||
@@ -229,6 +230,26 @@
|
||||
────────────────────────────────────────────── #}
|
||||
<div class="flex-1 flex flex-col overflow-hidden bg-[var(--bg-secondary)]">
|
||||
|
||||
{# What the task says to do. It was written for the operator and until now
|
||||
only the maker ever saw it; the line breaks and the bold of the technical
|
||||
sheet survive here as they do in the editor. #}
|
||||
{% if task.directive or task.description %}
|
||||
<div class="shrink-0 max-h-36 overflow-y-auto px-4 py-2.5
|
||||
bg-[var(--bg-card)] border-b border-[var(--border-color)]">
|
||||
{% if task.directive %}
|
||||
<p class="text-sm font-semibold text-[var(--text-primary)] leading-snug">
|
||||
{{ task.directive|rich_text }}
|
||||
</p>
|
||||
{% endif %}
|
||||
{% if task.description %}
|
||||
<div class="text-sm text-[var(--text-secondary)] leading-relaxed
|
||||
{% if task.directive %}mt-1{% endif %}">
|
||||
{{ task.description|rich_text }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{# Main image area #}
|
||||
<div class="flex-1 overflow-hidden relative">
|
||||
|
||||
@@ -1034,6 +1055,15 @@ function taskExecute() {
|
||||
return m ? m.pass_fail : null;
|
||||
},
|
||||
|
||||
/* The keypad refused a value because this recipe wants the caliper. Said on
|
||||
the same line as any other measurement error, so there is one place to look
|
||||
when a value does not go in. */
|
||||
onNumpadRejected(detail) {
|
||||
if (detail && detail.reason === 'manual_not_allowed') {
|
||||
this.errorMessage = '{{ _("Questa ricetta non ammette valori digitati: usare il calibro") }}';
|
||||
}
|
||||
},
|
||||
|
||||
// ---- Handle numpad confirm ----
|
||||
async handleMeasurement(value, inputMethod) {
|
||||
if (!this.currentSubtask || this.saving) return;
|
||||
|
||||
Reference in New Issue
Block a user