Quality Control Plan Generator

Quality Control Plan Generator

Quality Control Plan Generator

This section presents the full Quality Control Plan, organized by project phase. Each section details the necessary checks, frequency, and responsible party to ensure quality assurance.

Project QC Plan:

No QC checks defined yet. Go to the 'Data Configuration' tab.

`; qc_planSummary.innerHTML = ''; return; } // 1. Group items by Phase (ensure standard order) const phasesInPlan = qc_getUnique(qc_data.items, 'phase'); const sortedPhases = PHASE_OPTIONS.filter(phase => phasesInPlan.includes(phase)); // 2. Render Summary qc_planSummary.innerHTML = `

Total Checks: ${qc_data.items.length}

Phases Covered: ${sortedPhases.join(', ')}

`; // 3. Render Schedule sortedPhases.forEach(phase => { const phaseItems = qc_data.items.filter(item => item.phase === phase); if (phaseItems.length === 0) return; const sectionDiv = document.createElement('div'); sectionDiv.className = 'qc-table-section pl-4 bg-white rounded-r-lg shadow-md'; const h3Class = "text-xl font-bold text-emerald-700 border-b border-gray-300 pb-2 mb-3"; const tableClass = "w-full text-left border-collapse"; const thClass = "p-3 bg-gray-100 text-sm font-semibold text-gray-600 border-b border-gray-300"; const tdClass = "p-3 border-b border-gray-200 text-sm"; let itemsHTML = phaseItems.map(item => ` ${qc_escapeHTML(item.check)} ${qc_escapeHTML(item.frequency)} ${qc_escapeHTML(item.standard)} ${qc_escapeHTML(item.owner)} `).join(''); sectionDiv.innerHTML = `

${phase} Checks

${itemsHTML}
QC Check / Task Frequency Standard Responsible Owner
`; targetDiv.appendChild(sectionDiv); }); } function qc_renderPdfClone() { // Clone the essential structure for PDF qc_pdfRenderClone.innerHTML = document.getElementById('qc-dashboard-output').outerHTML; // Remove the ID to avoid conflicts, add a distinct class for targeting const cloneOutput = qc_pdfRenderClone.querySelector('#qc-dashboard-output'); if(cloneOutput) { cloneOutput.removeAttribute('id'); cloneOutput.classList.add('pdf-clone-output'); } // Re-render the content inside the clone to ensure clean styles/no interaction listeners const cloneScheduleOutput = qc_pdfRenderClone.querySelector('#qc-schedule-output'); if(cloneScheduleOutput) qc_renderDashboard(cloneScheduleOutput, true); } /** * Generates and downloads a PDF of the schedule */ async function qc_downloadPDF() { if (qc_data.items.length === 0) { alert("Please add some QC checks before downloading."); return; } if (typeof jspdf === 'undefined' || typeof html2canvas === 'undefined') { alert("Error: PDF libraries failed to load."); return; } qc_renderPdfClone(); const { jsPDF } = window.jspdf; try { // Target the clone div const canvas = await html2canvas(qc_pdfRenderClone.querySelector('.pdf-clone-output'), { scale: 1.5, useCORS: true, windowWidth: qc_pdfRenderClone.scrollWidth, windowHeight: qc_pdfRenderClone.scrollHeight }); const imgData = canvas.toDataURL('image/png'); const imgProps = { width: canvas.width, height: canvas.height }; const pdf = new jsPDF({ orientation: 'l', unit: 'pt', format: 'a4' }); const pdfWidth = pdf.internal.pageSize.getWidth(); const pdfHeight = pdf.internal.pageSize.getHeight(); const margin = 40; const contentWidth = pdfWidth - (margin * 2); const contentHeight = (contentWidth * imgProps.height) / imgProps.width; let heightLeft = contentHeight; let position = 0; pdf.addImage(imgData, 'PNG', margin, position + margin, contentWidth, contentHeight); heightLeft -= (pdfHeight - margin * 2); while (heightLeft > 0) { position -= (pdfHeight - margin * 2); pdf.addPage(); pdf.addImage(imgData, 'PNG', margin, position + margin, contentWidth, contentHeight); heightLeft -= (pdfHeight - margin * 2); } const safeName = (qc_data.projectName || 'qc_plan').replace(/[^a-z0-9]/gi, '_').toLowerCase(); pdf.save(`${safeName}_QC_Plan.pdf`); } catch (error) { console.error("PDF generation failed:", error); alert("An error occurred while generating the PDF."); } } // --- EVENT LISTENERS --- // Tab link clicks qc_tabLinks.forEach((link, index) => { link.addEventListener('click', () => qc_switchTab(index)); }); // Next/Prev button clicks if (qc_prevButton) { qc_prevButton.addEventListener('click', () => { if (qc_currentTab > 0) qc_switchTab(qc_currentTab - 1); }); } if (qc_nextButton) { qc_nextButton.addEventListener('click', () => { if (qc_currentTab === qc_tabLinks.length - 1) { qc_updateDataFromConfig(); qc_switchTab(0); } else { if (qc_currentTab < qc_tabLinks.length - 1) qc_switchTab(qc_currentTab + 1); } }); } // PDF download if (qc_downloadPdfButton) { qc_downloadPdfButton.addEventListener('click', qc_downloadPDF); } // --- Config Tab Listeners --- if (qc_addCheckButton) { qc_addCheckButton.addEventListener('click', () => { qc_checksContainer.appendChild(qc_createCheckInput()); }); } if (qc_configTab) { // Handle remove qc_configTab.addEventListener('click', (e) => { const removeButton = e.target.closest('.qc-remove-item'); if (removeButton) { removeButton.closest('.border[data-id]').remove(); if(qc_checksContainer.children.length === 0){ qc_checksContainer.appendChild(qc_createCheckInput()); } } }); } // --- INITIALIZATION --- qc_renderConfig(); qc_renderDashboard(); // Set initial tab state qc_tabPanes.forEach((pane, index) => { pane.classList.toggle('hidden', index !== 0); pane.classList.toggle('qc-active', index === 0); }); qc_tabLinks.forEach((link, index) => { TAB_CLASSES.active.forEach(cls => link.classList.remove(cls)); TAB_CLASSES.inactive.forEach(cls => link.classList.remove(cls)); if (index === 0) { TAB_CLASSES.active.forEach(cls => link.classList.add(cls)); } else { TAB_CLASSES.inactive.forEach(cls => link.classList.add(cls)); } }); });
Scroll to Top