feat: measurement workflow improvements and recipe update-in-place
- Auto-advance to next task after completing all subtask measurements - 1s pause between measurements to show pass/fail/warning result - Colored marker strip (green/red/amber) based on measurement status - Replace duplicate measurements instead of appending (fixes progress bar) - Add Task column and Date/Time column to measurement summary table - Enrich summary with task_info for each measurement - Update-in-place for recipe versions without measurements (no copy-on-write) - Dark theme improvements and navbar cleanup - Server config: ignore extra env vars Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -121,11 +121,21 @@ def task_execute(task_id: int):
|
||||
lot_number = session.get("lot_number", "")
|
||||
serial_number = session.get("serial_number", "")
|
||||
|
||||
# Load all task IDs for this recipe (ordered) for auto-advance
|
||||
recipe_id = task_resp.get("recipe_id")
|
||||
all_task_ids = []
|
||||
if recipe_id:
|
||||
tasks_resp = api_client.get(f"/api/recipes/{recipe_id}/tasks")
|
||||
if isinstance(tasks_resp, list):
|
||||
sorted_tasks = sorted(tasks_resp, key=lambda t: t.get("order_index", 0))
|
||||
all_task_ids = [t["id"] for t in sorted_tasks]
|
||||
|
||||
return render_template(
|
||||
"measure/task_execute.html",
|
||||
task=task_resp,
|
||||
lot_number=lot_number,
|
||||
serial_number=serial_number,
|
||||
all_task_ids=all_task_ids,
|
||||
)
|
||||
|
||||
|
||||
@@ -150,18 +160,44 @@ def task_complete(recipe_id: int):
|
||||
)
|
||||
return redirect(url_for("measure.select_recipe"))
|
||||
|
||||
# Load tasks+subtasks for this recipe to build subtask and task lookup
|
||||
tasks_resp = api_client.get(f"/api/recipes/{recipe_id}/tasks")
|
||||
subtask_map = {}
|
||||
subtask_task_map = {} # subtask_id → task info
|
||||
if isinstance(tasks_resp, list):
|
||||
for task in tasks_resp:
|
||||
for st in task.get("subtasks", []):
|
||||
subtask_map[st["id"]] = st
|
||||
subtask_task_map[st["id"]] = {
|
||||
"id": task["id"],
|
||||
"title": task.get("title", ""),
|
||||
"order_index": task.get("order_index", 0),
|
||||
}
|
||||
|
||||
# Load measurements if version_id provided
|
||||
measurements = []
|
||||
if version_id:
|
||||
meas_resp = api_client.get(
|
||||
"/api/measurements",
|
||||
params={"version_id": version_id},
|
||||
params={"version_id": version_id, "per_page": 500},
|
||||
)
|
||||
if not (isinstance(meas_resp, dict) and meas_resp.get("error")):
|
||||
measurements = (
|
||||
raw = (
|
||||
meas_resp if isinstance(meas_resp, list)
|
||||
else meas_resp.get("items", [])
|
||||
)
|
||||
# Enrich each measurement with nested subtask data
|
||||
for m in raw:
|
||||
st = subtask_map.get(m.get("subtask_id"), {})
|
||||
m["subtask"] = st
|
||||
m["task_info"] = subtask_task_map.get(m.get("subtask_id"), {})
|
||||
# Compute deviation if not present
|
||||
if m.get("deviation") is None and st.get("nominal") is not None:
|
||||
try:
|
||||
m["deviation"] = m["value"] - st["nominal"]
|
||||
except (TypeError, KeyError):
|
||||
m["deviation"] = 0.0
|
||||
measurements = raw
|
||||
|
||||
lot_number = session.get("lot_number", "")
|
||||
serial_number = session.get("serial_number", "")
|
||||
@@ -243,25 +279,22 @@ def save_measurement():
|
||||
|
||||
# Validate required fields
|
||||
subtask_id = data.get("subtask_id")
|
||||
task_id = data.get("task_id")
|
||||
version_id = data.get("version_id")
|
||||
value = data.get("value")
|
||||
|
||||
if subtask_id is None or task_id is None or value is None:
|
||||
if subtask_id is None or version_id is None or value is None:
|
||||
return jsonify({
|
||||
"error": True,
|
||||
"detail": _("Dati mancanti: subtask_id, task_id e value sono obbligatori"),
|
||||
"detail": _("Dati mancanti: subtask_id, version_id e value sono obbligatori"),
|
||||
}), 400
|
||||
|
||||
# Build payload for the FastAPI backend
|
||||
payload = {
|
||||
"subtask_id": subtask_id,
|
||||
"task_id": task_id,
|
||||
"version_id": version_id,
|
||||
"value": value,
|
||||
"pass_fail": data.get("pass_fail", ""),
|
||||
"deviation": data.get("deviation"),
|
||||
"lot_number": data.get("lot_number", session.get("lot_number", "")),
|
||||
"serial_number": data.get("serial_number", session.get("serial_number", "")),
|
||||
"measured_by": session.get("user_id"),
|
||||
"input_method": data.get("input_method", "manual"),
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user