feat(tasks): il tipo di un task si dichiara, non si deduce
Punto 2 del documento modifiche del 28/07, prima richiesta di Menoncin. Il sistema distingueva un task di misura da uno documentale deducendolo: se aveva quote era una misura, altrimenti una nota. Conseguenza: un task di misura a cui le quote non erano ancora state inserite veniva trattato come nota, e il sistema si comportava in modo diverso a seconda di quanto fosse completa la ricetta. Nuovo campo task_type su recipe_tasks (migrazione 007) con nota, misura e disegno, piu' xf_compare e camera_measure gia' nell'enum: allargare un enum MySQL piu' avanti e' un ALTER su tabella viva, e non costa nulla prevederli adesso. Il backfill riproduce la classificazione che era a schermo, cosi' nessuna ricetta cambia comportamento all'aggiornamento: i task con quote diventano 'measure'; quelli senza quote ma con un disegno allegato diventano 'drawing' e non 'note', perche' e' gia' cio' che mostravano - chiamarli note sarebbe stato l'unico punto in cui questa migrazione cambiava le carte in tavola. Il tipo viene copiato esplicitamente nel copy-on-write del versioning: una nuova versione che lo perdesse riclassificherebbe in silenzio tutti i task alla prima modifica di una ricetta. Il task "Technical Drawing" creato d'ufficio quando si carica un disegno su una ricetta senza task nasce come 'drawing'. Lato operatore decide ora il tipo, non il conteggio delle quote: fermo linea, fine produzione, avvio produzione e la barra di produzione seguono il tipo. Dove servono davvero delle quote da mostrare - elenco marker, tastierino, fine ciclo misura - resta anche il controllo che ce ne sia almeno una, e un task di misura ancora privo di quote lo dichiara invece di somigliare a una nota. Nella lista task compare il tipo, cosi' si vede prima di aprire. La 007 e' stata eseguita su SQLite usa e getta con tre righe costruite apposta - una con quote, una col solo disegno, una nota secca - e il backfill le classifica come atteso. Il backfill girera' sui dati reali del cliente, provarlo a mano non bastava. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -114,7 +114,7 @@
|
||||
</div>
|
||||
|
||||
{# Fermo linea + Fine produzione (measurement tasks only) #}
|
||||
<template x-if="subtasks.length > 0">
|
||||
<template x-if="isMeasureTask">
|
||||
<div class="shrink-0 flex items-center gap-1.5">
|
||||
{# While the line is stopped this becomes the way to restart it, so the
|
||||
capoturno never has to hunt for a second control. #}
|
||||
@@ -182,7 +182,7 @@
|
||||
{# ──────────────────────────────────────────────
|
||||
LEFT SIDEBAR — Marker list (vertical, hidden when no subtasks)
|
||||
────────────────────────────────────────────── #}
|
||||
<div x-show="subtasks.length > 0"
|
||||
<div x-show="isMeasureTask && subtasks.length > 0"
|
||||
class="shrink-0 w-14 md:w-16 bg-[var(--bg-card)] border-r border-[var(--border-color)] flex flex-col sidebar-markers overflow-y-auto">
|
||||
<template x-for="(st, idx) in subtasks" :key="st.id">
|
||||
<button @click="goToSubtask(idx)"
|
||||
@@ -272,7 +272,7 @@
|
||||
{# ──────────────────────────────────────────────
|
||||
RIGHT PANEL — Info + tolerances + numpad (hidden when no subtasks)
|
||||
────────────────────────────────────────────── #}
|
||||
<div x-show="subtasks.length > 0"
|
||||
<div x-show="isMeasureTask && subtasks.length > 0"
|
||||
class="shrink-0 w-72 lg:w-80 bg-[var(--bg-card)] border-l border-[var(--border-color)] flex flex-col right-panel overflow-y-auto">
|
||||
|
||||
{# ---- Subtask header ---- #}
|
||||
@@ -439,6 +439,25 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# ================================================================
|
||||
MISURA SENZA QUOTE — declared a measurement task but none configured yet.
|
||||
Under the old rule this screen quietly looked like a note; now the task keeps
|
||||
its identity and says what is missing instead.
|
||||
================================================================ #}
|
||||
<div x-show="isMeasureTaskWithoutQuotes"
|
||||
x-transition
|
||||
x-cloak
|
||||
class="shrink-0 bg-amber-50 dark:bg-amber-900/20 border-t border-amber-300 dark:border-amber-700 px-4 py-2">
|
||||
<div class="flex items-center justify-center gap-2">
|
||||
<svg class="w-4 h-4 text-amber-600 shrink-0" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z"/>
|
||||
</svg>
|
||||
<span class="text-sm text-amber-800 dark:text-amber-200">
|
||||
{{ _('Task di misura senza quote configurate: la ricetta è incompleta') }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# ================================================================
|
||||
LINEA FERMA — the countdown is frozen, not merely hidden. Stated plainly
|
||||
because a stopped line that looks like a running one is how a measurement
|
||||
@@ -486,7 +505,7 @@
|
||||
{# ================================================================
|
||||
AVVIO PRODUZIONE — visible after first cycle, before production started
|
||||
================================================================ #}
|
||||
<div x-show="cycleConfirmed && cycleCount === 1 && !productionStarted && subtasks.length > 0"
|
||||
<div x-show="cycleConfirmed && cycleCount === 1 && !productionStarted && isMeasureTask"
|
||||
x-transition
|
||||
x-cloak
|
||||
class="shrink-0 border-t border-[var(--border-color)] bg-[var(--bg-card)] px-4 py-3">
|
||||
@@ -505,7 +524,7 @@
|
||||
{{ _('Invia segnale al gestionale per avviare il timer della linea') }}
|
||||
</p>
|
||||
</div>
|
||||
<div x-show="productionStarted && subtasks.length > 0"
|
||||
<div x-show="productionStarted && isMeasureTask"
|
||||
x-transition
|
||||
x-cloak
|
||||
class="shrink-0 border-t border-emerald-200 dark:border-emerald-800 bg-emerald-50 dark:bg-emerald-900/20 px-4 py-1.5">
|
||||
@@ -548,7 +567,7 @@
|
||||
</div>
|
||||
|
||||
{# Right: Fine ciclo misura (measurement tasks) / Completato (non-measurement or after cycle) #}
|
||||
<template x-if="subtasks.length > 0">
|
||||
<template x-if="isMeasureTask && subtasks.length > 0">
|
||||
<div class="flex items-center gap-1.5">
|
||||
<button x-show="isComplete && !cycleConfirmed"
|
||||
x-transition
|
||||
@@ -575,7 +594,7 @@
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
<template x-if="subtasks.length === 0">
|
||||
<template x-if="!isMeasureTask || subtasks.length === 0">
|
||||
<button @click="goToNextTask()"
|
||||
class="btn text-xs shrink-0 gap-1 py-1.5 px-3 shadow-md
|
||||
bg-measure-pass text-white hover:opacity-90">
|
||||
@@ -1238,6 +1257,23 @@ function taskExecute() {
|
||||
this.supervisorError = '';
|
||||
},
|
||||
|
||||
/* What kind of task this is, as declared in the recipe.
|
||||
Deducing it from the quotes meant a measurement task whose quotes had not
|
||||
been entered yet behaved as a note - the screen changed shape depending on
|
||||
how finished the recipe was. Falls back to the old rule for tasks saved
|
||||
before the type existed and not yet migrated. */
|
||||
get isMeasureTask() {
|
||||
const declared = this.task.task_type;
|
||||
if (!declared) return this.subtasks.length > 0;
|
||||
return declared === 'measure' || declared === 'camera_measure';
|
||||
},
|
||||
|
||||
/* A measurement task with no quotes yet: the recipe is unfinished. Said out
|
||||
loud rather than silently rendering an empty screen. */
|
||||
get isMeasureTaskWithoutQuotes() {
|
||||
return this.isMeasureTask && this.subtasks.length === 0;
|
||||
},
|
||||
|
||||
// ---- Is the production stopped? ----
|
||||
get isPaused() {
|
||||
return !!this.productionRun && this.productionRun.status === 'paused';
|
||||
|
||||
@@ -164,8 +164,26 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- Indicators (top-right): measurements + attachment -->
|
||||
<!-- Indicators (top-right): type + measurements + attachment -->
|
||||
<div class="shrink-0 self-start flex items-center gap-2.5">
|
||||
{# The declared type, so the operator sees what a task is before opening
|
||||
it - and a measurement task still reads as one before its quotes are in. #}
|
||||
{% set task_type_labels = {
|
||||
'measure': _('Misura'),
|
||||
'drawing': _('Disegno'),
|
||||
'note': _('Nota'),
|
||||
'xf_compare': _('Confronto profilo'),
|
||||
'camera_measure': _('Misura camera'),
|
||||
} %}
|
||||
{% set is_measure = task.task_type in ('measure', 'camera_measure') %}
|
||||
{% if task.task_type %}
|
||||
<span class="inline-flex items-center px-1.5 py-0.5 rounded text-[11px] font-medium
|
||||
{% if is_measure %}bg-primary-50 dark:bg-primary-900/20 text-primary
|
||||
{% else %}bg-steel-100 dark:bg-steel-800 text-steel-600 dark:text-steel-300{% endif %}">
|
||||
{{ task_type_labels.get(task.task_type, task.task_type) }}
|
||||
</span>
|
||||
{% endif %}
|
||||
|
||||
{% if task.subtask_count is defined or task.subtasks %}
|
||||
<span class="inline-flex items-center gap-1 text-xs text-[var(--text-secondary)]"
|
||||
title="{{ _('misurazioni') }}">
|
||||
|
||||
Reference in New Issue
Block a user