feat: FASE 5b/6.1+6.2 - SPC Backend + Dashboard Metrologist (Plotly.js)
Aggiunge servizio SPC con calcoli Cp/Cpk/Pp/Ppk, carta di controllo (UCL/LCL), istogramma con curva normale. Router FastAPI con 5 endpoint statistics, blueprint Flask con proxy AJAX, dashboard interattiva Alpine.js + Plotly.js con filtri per ricetta/subtask/date, riepilogo pass/fail, gauge Cpk e i18n IT/EN completo. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,77 +1,63 @@
|
||||
<!--
|
||||
Caliper Status Indicator
|
||||
Compact component for navbar or header
|
||||
Shows connection status and last reading
|
||||
Caliper Status Indicator - Passive HID Monitor
|
||||
Shows USB caliper reading feedback without Web Serial.
|
||||
Flashes green when a caliper reading is detected via burst timing.
|
||||
-->
|
||||
<div x-data="caliperConnection()"
|
||||
x-init="$watch('connected', value => console.log('Caliper connected:', value))"
|
||||
<div x-data="caliperStatus()"
|
||||
class="inline-block">
|
||||
|
||||
<!-- Compact indicator button -->
|
||||
<button @click="connected ? disconnect() : connect()"
|
||||
:disabled="!isSupported"
|
||||
class="flex items-center gap-2 px-3 py-1.5 rounded-lg border transition-all duration-200 hover:shadow-md disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
:class="{
|
||||
'bg-white dark:bg-slate-800 border-slate-200 dark:border-slate-700': status === 'disconnected',
|
||||
'bg-green-50 dark:bg-green-900/20 border-green-200 dark:border-green-800': status === 'connected',
|
||||
'bg-amber-50 dark:bg-amber-900/20 border-amber-200 dark:border-amber-800': status === 'connecting',
|
||||
'bg-red-50 dark:bg-red-900/20 border-red-200 dark:border-red-800': status === 'error'
|
||||
}">
|
||||
<!-- Passive indicator (no connect/disconnect button needed) -->
|
||||
<div class="flex items-center gap-2 px-3 py-1.5 rounded-lg border transition-all duration-300"
|
||||
:class="active
|
||||
? 'bg-green-50 dark:bg-green-900/20 border-green-300 dark:border-green-700 shadow-md shadow-green-100 dark:shadow-green-900/30'
|
||||
: 'bg-[var(--bg-card)] border-[var(--border-color)]'"
|
||||
:title="readingCount > 0
|
||||
? '{{ _('Letture calibro') }}: ' + readingCount
|
||||
: '{{ _('Calibro USB') }}'">
|
||||
|
||||
<!-- Status dot with animation -->
|
||||
<!-- Status dot -->
|
||||
<span class="relative flex h-2.5 w-2.5">
|
||||
<!-- Ping animation for active states -->
|
||||
<span x-show="status === 'connected' || status === 'connecting'"
|
||||
class="absolute inline-flex h-full w-full rounded-full opacity-75 animate-ping"
|
||||
:class="{
|
||||
'bg-green-400': status === 'connected',
|
||||
'bg-amber-400': status === 'connecting'
|
||||
}"></span>
|
||||
<!-- Ping animation when active -->
|
||||
<span x-show="active"
|
||||
x-transition
|
||||
class="absolute inline-flex h-full w-full rounded-full bg-green-400 opacity-75 animate-ping"></span>
|
||||
|
||||
<!-- Static dot -->
|
||||
<span class="relative inline-flex rounded-full h-2.5 w-2.5"
|
||||
:class="{
|
||||
'bg-green-500': status === 'connected',
|
||||
'bg-slate-400': status === 'disconnected',
|
||||
'bg-amber-400': status === 'connecting',
|
||||
'bg-red-500': status === 'error'
|
||||
}"></span>
|
||||
<span class="relative inline-flex rounded-full h-2.5 w-2.5 transition-colors duration-300"
|
||||
:class="active
|
||||
? 'bg-green-500'
|
||||
: readingCount > 0
|
||||
? 'bg-green-400'
|
||||
: 'bg-slate-400 dark:bg-slate-500'
|
||||
"></span>
|
||||
</span>
|
||||
|
||||
<!-- Caliper icon -->
|
||||
<svg class="w-4 h-4 text-slate-600 dark:text-slate-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 7h6m0 10v-3m-3 3h.01M9 17h.01M9 14h.01M12 14h.01M15 11h.01M12 11h.01M9 11h.01M7 21h10a2 2 0 002-2V5a2 2 0 00-2-2H7a2 2 0 00-2 2v14a2 2 0 002 2z"/>
|
||||
<svg class="w-4 h-4 transition-colors duration-300"
|
||||
:class="active ? 'text-green-600 dark:text-green-400' : 'text-slate-500 dark:text-slate-400'"
|
||||
fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M9 7h6m0 10v-3m-3 3h.01M9 17h.01M9 14h.01M12 14h.01M15 11h.01M12 11h.01M9 11h.01M7 21h10a2 2 0 002-2V5a2 2 0 00-2-2H7a2 2 0 00-2 2v14a2 2 0 002 2z"/>
|
||||
</svg>
|
||||
|
||||
<!-- Status label -->
|
||||
<span class="text-xs font-medium text-slate-700 dark:text-slate-300"
|
||||
x-text="status === 'connected' ? '{{ _('Calibro') }}' :
|
||||
status === 'connecting' ? '{{ _('Connessione...') }}' :
|
||||
status === 'error' ? '{{ _('Errore calibro') }}' :
|
||||
'{{ _('Calibro') }}'"></span>
|
||||
<!-- Label -->
|
||||
<span class="text-xs font-medium transition-colors duration-300"
|
||||
:class="active ? 'text-green-700 dark:text-green-300' : 'text-slate-600 dark:text-slate-400'"
|
||||
x-text="active ? '{{ _('Lettura calibro') }}' : '{{ _('Calibro USB') }}'"></span>
|
||||
|
||||
<!-- Last reading (when connected) -->
|
||||
<span x-show="connected && lastReading !== null"
|
||||
<!-- Last reading value (shows when active or when there's a recent reading) -->
|
||||
<span x-show="lastReading !== null"
|
||||
x-transition
|
||||
class="font-mono text-xs font-semibold text-primary px-1.5 py-0.5 bg-blue-50 dark:bg-blue-900/30 rounded"
|
||||
class="font-mono text-xs font-semibold px-1.5 py-0.5 rounded transition-colors duration-300"
|
||||
:class="active
|
||||
? 'text-green-700 dark:text-green-200 bg-green-100 dark:bg-green-800/40'
|
||||
: 'text-primary bg-blue-50 dark:bg-blue-900/30'"
|
||||
x-text="lastReading?.toFixed(3) + ' mm'"></span>
|
||||
|
||||
<!-- Not supported warning icon -->
|
||||
<template x-if="!isSupported">
|
||||
<div class="flex items-center gap-1.5" x-data="{ showTooltip: false }">
|
||||
<svg @mouseenter="showTooltip = true"
|
||||
@mouseleave="showTooltip = false"
|
||||
class="w-4 h-4 text-amber-500" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fill-rule="evenodd" d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z" clip-rule="evenodd"/>
|
||||
</svg>
|
||||
|
||||
<!-- Tooltip -->
|
||||
<div x-show="showTooltip"
|
||||
x-transition
|
||||
class="absolute z-50 px-2 py-1 text-xs text-white bg-slate-900 rounded shadow-lg whitespace-nowrap -translate-y-8">
|
||||
{{ _('Browser non supporta Web Serial API') }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</button>
|
||||
<!-- Reading counter badge -->
|
||||
<span x-show="readingCount > 0 && !active"
|
||||
x-transition
|
||||
class="text-[10px] font-mono text-slate-400 dark:text-slate-500"
|
||||
x-text="'(' + readingCount + ')'"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user