Interactive Vendor Performance Dashboard
Analyze and visualize key vendor metrics to drive strategic decisions.
Awaiting Data Configuration
Navigate to the configuration tab to input or edit vendor data for analysis.
Configure Vendor Data
Add, edit, or remove vendors below. The dashboard will update with this data.
| Vendor Name | On-Time Delivery (%) | Quality Score (/100) | Cost Variance (%) | Response Time (hrs) | Actions |
|---|
${sortedVendors[sortedVendors.length-1].name}
`; downloadSection.classList.remove('hidden'); showTab(1); }; generateBtn.addEventListener('click', generateDashboard); // --- PDF DOWNLOAD --- const downloadPDF = () => { if (!currentData || !performanceChart) return; const { jsPDF } = window.jspdf; const pdf = new jsPDF({ orientation: 'landscape', unit: 'pt', format: 'a4' }); const btnText = getElem('pdf-btn-text'); const btnSpinner = getElem('pdf-btn-spinner'); btnText.classList.add('hidden'); btnSpinner.classList.remove('hidden'); downloadPdfBtn.disabled = true; try { const pageWidth = pdf.internal.pageSize.getWidth(); const margin = 40; let y = margin; pdf.setFont('helvetica', 'bold'); pdf.setFontSize(22); pdf.text("Vendor Performance Review", pageWidth / 2, y, { align: 'center' }); y += 15; pdf.setFont('helvetica', 'normal'); pdf.setFontSize(10); pdf.text(`Report Date: ${today.toLocaleDateString('en-US')}`, pageWidth / 2, y, { align: 'center' }); y += 30; const chartImage = performanceChart.toBase64Image('image/png', 1.0); const chartStartY = y + 15; const chartHeight = 200; const chartEndY = chartStartY + chartHeight; // --- Left Column: Chart --- pdf.setFont('helvetica', 'bold'); pdf.setFontSize(14); pdf.text("Performance Chart", margin, y); pdf.addImage(chartImage, 'PNG', margin, chartStartY, (pageWidth/2) - margin*1.5, chartHeight); // --- Right Column: KPIs --- let kpiTableEndY = 0; // This will be set by the hook or fallback pdf.setFont('helvetica', 'bold'); pdf.text("Key Performance Indicators", (pageWidth/2), y); pdf.autoTable({ startY: chartStartY, startX: (pageWidth/2), theme: 'grid', head: [['Metric', 'Value']], body: [ ['Avg. On-Time Delivery', `${currentData.avgDelivery.toFixed(1)}%`], ['Avg. Quality Score', `${currentData.avgQuality.toFixed(1)}/100`], ['Overall Cost Variance', `${currentData.overallCostVar.toFixed(1)}%`], ], didDrawPage: function(data) { kpiTableEndY = data.cursor.y; } }); // If the hook didn't fire, use the finalY property as a fallback. if (kpiTableEndY === 0) { kpiTableEndY = pdf.autoTable.previous ? pdf.autoTable.previous.finalY : chartStartY; } // Determine the starting Y for the next element by finding which column was taller. y = Math.max(chartEndY, kpiTableEndY) + 30; const tableData = currentData.vendors.map(v => [v.name, `${v.onTimeDelivery.toFixed(1)}%`, `${v.qualityScore.toFixed(1)}/100`, `${v.costVariance.toFixed(1)}%`, `${v.avgResponseTime} hrs`]); pdf.autoTable({ startY: y, head: [['Vendor', 'On-Time Delivery', 'Quality Score', 'Cost Variance', 'Response Time']], body: tableData, theme: 'striped', headStyles: { fillColor: [29, 78, 216] }, }); pdf.save(`Vendor-Performance-Review.pdf`); } catch(e) { console.error("PDF Generation failed:", e); } finally { btnText.classList.remove('hidden'); btnSpinner.classList.remove('hidden'); downloadPdfBtn.disabled = false; } }; downloadPdfBtn.addEventListener('click', downloadPDF); initialize(); });