[FEAT] Visura auto-fill, adesione volontaria, modulo NCR/CAPA
1. Fix auto-fill visura: mapping corretto suggested_sector e employees_range, indicatori visivi verdi sui campi auto-compilati, fatturato sempre manuale 2. Adesione volontaria: colonna voluntary_compliance, checkbox in onboarding step 5 quando not_applicable, toggle in settings, reset su ri-classificazione 3. Modulo NCR/CAPA: NonConformityController con 10 endpoint API, tabelle non_conformities + capa_actions, generazione NCR dai gap assessment, predisposizione integrazione SistemiG.agile (webhook + sync) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -99,6 +99,25 @@
|
||||
</div>
|
||||
<div class="card-body" id="ai-analysis-content"></div>
|
||||
</div>
|
||||
|
||||
<!-- Generate NCR from gaps -->
|
||||
<div class="card mb-24" id="ncr-generation-card">
|
||||
<div class="card-header">
|
||||
<h3>Non Conformita'</h3>
|
||||
</div>
|
||||
<div class="card-body" style="text-align:center; padding:32px;">
|
||||
<p style="color:var(--gray-600); margin-bottom:16px; font-size:0.875rem;">
|
||||
Genera automaticamente le non conformita' (NCR) dai gap identificati nell'assessment.
|
||||
I controlli con stato "Non Implementato" saranno classificati come <strong>major</strong>,
|
||||
quelli "Parzialmente Implementato" come <strong>minor</strong>.
|
||||
</p>
|
||||
<button class="btn btn-primary" id="btn-generate-ncr" onclick="generateNCRs()">
|
||||
<svg viewBox="0 0 20 20" fill="currentColor" width="16" height="16"><path fill-rule="evenodd" d="M6 2a2 2 0 00-2 2v12a2 2 0 002 2h8a2 2 0 002-2V7.414A2 2 0 0015.414 6L12 2.586A2 2 0 0010.586 2H6zm5 6a1 1 0 10-2 0v2H7a1 1 0 100 2h2v2a1 1 0 102 0v-2h2a1 1 0 100-2h-2V8z" clip-rule="evenodd"/></svg>
|
||||
Genera Non Conformita' dai Gap
|
||||
</button>
|
||||
<div id="ncr-generation-result" style="display:none; margin-top:16px;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
@@ -590,6 +609,54 @@
|
||||
showNotification('Errore di connessione.', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// ── Generate NCRs from Assessment Gaps ─────────────────────
|
||||
async function generateNCRs() {
|
||||
if (!currentAssessmentId) {
|
||||
showNotification('Nessun assessment selezionato.', 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
const btn = document.getElementById('btn-generate-ncr');
|
||||
btn.disabled = true;
|
||||
btn.innerHTML = '<div class="spinner" style="width:16px;height:16px;border-width:2px;margin:0;"></div> Generazione in corso...';
|
||||
|
||||
try {
|
||||
const result = await api.createNCRsFromAssessment(currentAssessmentId);
|
||||
const resultDiv = document.getElementById('ncr-generation-result');
|
||||
resultDiv.style.display = 'block';
|
||||
|
||||
if (result.success && result.data) {
|
||||
const total = result.data.total || 0;
|
||||
if (total > 0) {
|
||||
const majorCount = (result.data.created || []).filter(n => n.severity === 'major').length;
|
||||
const minorCount = total - majorCount;
|
||||
resultDiv.innerHTML = `
|
||||
<div style="background:var(--secondary-bg); border:1px solid #bbf7d0; border-radius:var(--border-radius); padding:16px; text-align:left;">
|
||||
<strong style="color:#15803d;">${total} non conformita' generate con successo</strong>
|
||||
<div style="margin-top:8px; font-size:0.8125rem; color:var(--gray-600);">
|
||||
${majorCount > 0 ? `<span style="color:var(--danger); font-weight:600;">${majorCount} major</span> ` : ''}
|
||||
${minorCount > 0 ? `<span style="color:var(--warning); font-weight:600;">${minorCount} minor</span>` : ''}
|
||||
</div>
|
||||
</div>`;
|
||||
showNotification(`${total} non conformita' generate.`, 'success');
|
||||
} else {
|
||||
resultDiv.innerHTML = '<p style="color:var(--gray-500);">Nessun gap trovato — tutti i controlli sono implementati.</p>';
|
||||
showNotification('Nessun gap trovato.', 'info');
|
||||
}
|
||||
btn.style.display = 'none';
|
||||
} else {
|
||||
resultDiv.innerHTML = `<p style="color:var(--danger);">${escapeHtml(result.message || 'Errore nella generazione.')}</p>`;
|
||||
showNotification(result.message || 'Errore.', 'error');
|
||||
btn.disabled = false;
|
||||
btn.innerHTML = '<svg viewBox="0 0 20 20" fill="currentColor" width="16" height="16"><path fill-rule="evenodd" d="M6 2a2 2 0 00-2 2v12a2 2 0 002 2h8a2 2 0 002-2V7.414A2 2 0 0015.414 6L12 2.586A2 2 0 0010.586 2H6zm5 6a1 1 0 10-2 0v2H7a1 1 0 100 2h2v2a1 1 0 102 0v-2h2a1 1 0 100-2h-2V8z" clip-rule="evenodd"/></svg> Genera Non Conformita\' dai Gap';
|
||||
}
|
||||
} catch (e) {
|
||||
showNotification('Errore di connessione.', 'error');
|
||||
btn.disabled = false;
|
||||
btn.innerHTML = '<svg viewBox="0 0 20 20" fill="currentColor" width="16" height="16"><path fill-rule="evenodd" d="M6 2a2 2 0 00-2 2v12a2 2 0 002 2h8a2 2 0 002-2V7.414A2 2 0 0015.414 6L12 2.586A2 2 0 0010.586 2H6zm5 6a1 1 0 10-2 0v2H7a1 1 0 100 2h2v2a1 1 0 102 0v-2h2a1 1 0 100-2h-2V8z" clip-rule="evenodd"/></svg> Genera Non Conformita\' dai Gap';
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user