Total Units
${line.totalUnits.toLocaleString()}
Defective Units
${line.defects}
Reworked Units
${line.rework}
`;
container.innerHTML += card;
});
};
// --- CHARTING LOGIC ---
const createOrUpdateChart = (ctx, type, data, options) => {
if (!ctx) return;
const chartId = ctx.id;
if (chartInstances[chartId]) chartInstances[chartId].destroy();
chartInstances[chartId] = new Chart(ctx, { type, data, options });
};
const renderCharts = () => {
// Defect Rate by Line
createOrUpdateChart(document.getElementById('defectRateByLineChart'), 'bar', {
labels: productionLines.map(p => p.name),
datasets: [{
label: 'Defect Rate (%)',
data: productionLines.map(p => p.totalUnits > 0 ? (p.defects / p.totalUnits * 100) : 0),
backgroundColor: '#ef4444'
}]
}, { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: false } }, scales: {y: {ticks: {callback: (value) => value + '%'}} } });
// Defects by Type Chart
createOrUpdateChart(document.getElementById('defectsByTypeChart'), 'pie', {
labels: Object.keys(defectTypes),
datasets: [{ data: Object.values(defectTypes), backgroundColor: ['#3b82f6', '#ef4444', '#f59e0b', '#16a34a', '#6366f1'] }]
}, { responsive: true, maintainAspectRatio: false });
// FPY Trend Chart
const today = new Date();
const labels = Array.from({length: 7}, (_, i) => {
const d = new Date();
d.setDate(today.getDate() - (6 - i));
return d;
});
const avgFpyHistory = Array.from({length: 7}, (_, i) => {
let totalFpy = 0;
productionLines.forEach(line => { totalFpy += line.fpyHistory[i]; });
return totalFpy / productionLines.length;
});
createOrUpdateChart(document.getElementById('fpyTrendChart'), 'line', {
labels: labels,
datasets: [{
label: 'Average First Pass Yield',
data: avgFpyHistory,
borderColor: '#16a34a',
tension: 0.3,
fill: true,
backgroundColor: 'rgba(22, 163, 74, 0.1)'
}]
}, { responsive: true, maintainAspectRatio: false, scales: { x: { type: 'time', time: { unit: 'day' } }, y: { min: 80, max: 100, ticks: {callback: (value) => value + '%'}} } });
};
// --- FORM HANDLING ---
const populateLineSelect = () => {
if (!lineSelect) return;
lineSelect.innerHTML = productionLines.map(p => `
`).join('');
updateFormForSelectedLine();
};
const updateFormForSelectedLine = () => {
const selectedId = lineSelect.value;
const line = productionLines.find(p => p.id === selectedId);
if (line) {
document.getElementById('line-id-input').value = line.id;
document.getElementById('line-total-units').value = line.totalUnits;
document.getElementById('line-defects').value = line.defects;
document.getElementById('line-rework').value = line.rework;
}
};
lineSelect.addEventListener('change', updateFormForSelectedLine);
qualityForm.addEventListener('submit', (e) => {
e.preventDefault();
const id = document.getElementById('line-id-input').value;
const index = productionLines.findIndex(p => p.id === id);
if (index !== -1) {
const line = productionLines[index];
line.totalUnits = parseInt(document.getElementById('line-total-units').value);
line.defects = parseInt(document.getElementById('line-defects').value);
line.rework = parseInt(document.getElementById('line-rework').value);
// Update last point in history
const fpy = line.totalUnits > 0 ? (line.totalUnits - line.defects) / line.totalUnits * 100 : 0;
line.fpyHistory[line.fpyHistory.length - 1] = fpy;
}
renderAll();
alert('Quality data updated successfully.');
});
resetDataBtn.addEventListener('click', () => { if (confirm('Reset all data to sample data?')) init(); });
// --- PDF DOWNLOAD ---
downloadPdfBtn.addEventListener('click', () => {
const { jsPDF } = window.jspdf;
const content = document.getElementById('dashboard-content-to-print');
html2canvas(content, { scale: 2, useCORS: true, backgroundColor: '#ffffff' }).then(canvas => {
const imgData = canvas.toDataURL('image/png');
const pdf = new jsPDF({ orientation: 'p', unit: 'mm', format: 'a4' });
const imgProps = pdf.getImageProperties(imgData);
const pdfWidth = pdf.internal.pageSize.getWidth();
const pdfHeight = (imgProps.height * pdfWidth) / imgProps.width;
pdf.addImage(imgData, 'PNG', 0, 0, pdfWidth, pdfHeight);
pdf.save('Manufacturing_QC_Dashboard.pdf');
});
});
// --- INITIALIZATION ---
const init = () => {
generateSampleData();
renderAll();
updateNavButtons();
};
init();
});