Project Status Report Template Generator

Project Status Report Generator

Project Status Report Generator

Basic Project Information

Progress and Milestones

Key Accomplishments (This Period)

Upcoming Milestones (Next Period)

Risks and Issues

Potential Risks

Current Issues / Blockers

Report Preview

Project Manager: ${reportData.projectManager || 'N/A'}

Report Date: ${reportData.reportDate || 'N/A'}

Overall Status: ${reportData.overallStatus}

Executive Summary

${reportData.summary || 'No summary provided.'}

`; if (reportData.accomplishments.length > 0) { previewHTML += `

Key Accomplishments

    `; reportData.accomplishments.forEach(item => previewHTML += `
  • ${item}
  • `); previewHTML += `
`; } if (reportData.milestones.length > 0) { previewHTML += `

Upcoming Milestones

    `; reportData.milestones.forEach(item => previewHTML += `
  • ${item}
  • `); previewHTML += `
`; } if (reportData.risks.length > 0) { previewHTML += `

Potential Risks

    `; reportData.risks.forEach(item => previewHTML += `
  • ${item}
  • `); previewHTML += `
`; } if (reportData.issues.length > 0) { previewHTML += `

Current Issues

    `; reportData.issues.forEach(item => previewHTML += `
  • ${item}
  • `); previewHTML += `
`; } previewContent.innerHTML = previewHTML; } // --- PDF Generation --- function downloadPDF() { if (typeof window.jspdf === 'undefined' || typeof window.jspdf.jsPDF === 'undefined') { alert('Error: jsPDF library not loaded.'); return; } if (typeof window.jspdf.jsPDF.autoTable === 'undefined') { alert('Error: jsPDF-AutoTable library not loaded.'); return; } updateReportData(); // Ensure latest data const { jsPDF } = window.jspdf; const doc = new jsPDF(); const margin = 40; const pageWidth = doc.internal.pageSize.getWidth(); let currentY = margin; // --- Header --- doc.setFontSize(18); doc.setFont('helvetica', 'bold'); doc.text("Project Status Report", pageWidth / 2, currentY, { align: 'center' }); currentY += 25; // --- Project Details Table --- doc.setFontSize(10); doc.setFont('helvetica', 'normal'); const projectDetailsData = [ ["Project Name:", reportData.projectName || 'N/A'], ["Project Manager:", reportData.projectManager || 'N/A'], ["Report Date:", reportData.reportDate || 'N/A'], ["Overall Status:", reportData.overallStatus], ]; doc.autoTable({ startY: currentY, body: projectDetailsData, theme: 'plain', styles: { cellPadding: 2, fontSize: 10 }, columnStyles: { 0: { fontStyle: 'bold' } } }); currentY = doc.autoTable.previous.finalY + 15; // --- Summary --- doc.setFontSize(12); doc.setFont('helvetica', 'bold'); doc.text("Executive Summary", margin, currentY); currentY += 15; doc.setFontSize(10); doc.setFont('helvetica', 'normal'); const summaryLines = doc.splitTextToSize(reportData.summary || 'N/A', pageWidth - margin * 2); doc.text(summaryLines, margin, currentY); currentY += summaryLines.length * 12 + 15; // Approx line height // --- Helper for List Sections --- function addListSection(title, list) { if (list.length > 0) { // Check for page break const estimatedHeight = 20 + list.length * 15; if (currentY + estimatedHeight > doc.internal.pageSize.getHeight() - margin) { doc.addPage(); currentY = margin; } doc.setFontSize(12); doc.setFont('helvetica', 'bold'); doc.text(title, margin, currentY); currentY += 15; doc.setFontSize(10); doc.setFont('helvetica', 'normal'); list.forEach(item => { doc.text(`• ${item}`, margin + 10, currentY, { maxWidth: pageWidth - margin * 2 - 10 }); currentY += 15; // Adjust spacing as needed }); currentY += 10; // Space after section } } // --- Sections --- addListSection("Key Accomplishments", reportData.accomplishments); addListSection("Upcoming Milestones", reportData.milestones); addListSection("Potential Risks", reportData.risks); addListSection("Current Issues", reportData.issues); doc.save(`${reportData.projectName || 'project'}-status-report.pdf`); } // --- Event Listeners --- addAccomplishmentBtn.addEventListener('click', () => addItem('accomplishments', accomplishmentInput, accomplishmentsList)); addMilestoneBtn.addEventListener('click', () => addItem('milestones', milestoneInput, milestonesList)); addRiskBtn.addEventListener('click', () => addItem('risks', riskInput, risksList)); addIssueBtn.addEventListener('click', () => addItem('issues', issueInput, issuesList)); // Add item on Enter press accomplishmentInput.addEventListener('keypress', (e) => { if (e.key === 'Enter') { e.preventDefault(); addItem('accomplishments', accomplishmentInput, accomplishmentsList); }}); milestoneInput.addEventListener('keypress', (e) => { if (e.key === 'Enter') { e.preventDefault(); addItem('milestones', milestoneInput, milestonesList); }}); riskInput.addEventListener('keypress', (e) => { if (e.key === 'Enter') { e.preventDefault(); addItem('risks', riskInput, risksList); }}); issueInput.addEventListener('keypress', (e) => { if (e.key === 'Enter') { e.preventDefault(); addItem('issues', issueInput, issuesList); }}); pdfBtn.addEventListener('click', downloadPDF); // --- Initial Load --- // Set default report date to today const today = new Date().toISOString().split('T')[0]; reportDateInput.value = today; // Initial render of empty lists renderList('accomplishments', accomplishmentsList); renderList('milestones', milestonesList); renderList('risks', risksList); renderList('issues', issuesList); psrgShowTab(0); // Show first tab initially });
Scroll to Top