import ExcelJS from 'exceljs'; import type { DashboardReportPayload } from '../types/dashboardReport.ts'; const na = (value: number | null | undefined): number | string => value == null || !Number.isFinite(value) ? 'N/A' : value; export async function downloadReportExcel(payload: DashboardReportPayload): Promise { const workbook = new ExcelJS.Workbook(); workbook.creator = 'Dashboard CPSP'; const counting = workbook.addWorksheet('Chicken Counting'); counting.addRow([ 'Tanggal', 'Hari', 'Stok awal', 'Mortalitas', 'Panen', 'Stok akhir', 'IoT', 'Akurasi %', ]); for (const row of payload.counting) { counting.addRow([ row.date, row.day, na(row.countBefore), na(row.mortality), na(row.harvest), na(row.countAfter), na(row.iotCount), na(row.accuracy), ]); } const weight = workbook.addWorksheet('Weight'); weight.addRow([ 'Tanggal', 'Hari', 'AVG manual', 'AVG IoT', 'Keseragaman', 'Selisih', 'Akurasi %', ]); for (const row of payload.weight) { weight.addRow([ row.date, row.day, na(row.avgManual), na(row.avgIot), na(row.uniformity), na(row.difference), na(row.accuracy), ]); } const feedInSheet = workbook.addWorksheet('Feed In'); feedInSheet.addRow(['Tanggal', 'Manual in', 'IoT in', 'Akurasi in %']); for (const row of payload.feedIn) { feedInSheet.addRow([row.date, na(row.manualIn), na(row.iotIn), na(row.accuracy)]); } const feedUseSheet = workbook.addWorksheet('Feed Use'); feedUseSheet.addRow(['Tanggal', 'Hari', 'Manual use', 'IoT use', 'Akurasi use %']); for (const row of payload.feedUse) { feedUseSheet.addRow([row.date, row.day, na(row.manualUse), na(row.iotUse), na(row.accuracy)]); } const feedOutSheet = workbook.addWorksheet('Feed Out'); feedOutSheet.addRow(['Tanggal', 'Manual out', 'IoT out', 'Akurasi out %']); for (const row of payload.feedOut) { feedOutSheet.addRow([row.date, na(row.manualOut), na(row.iotOut), na(row.accuracy)]); } const fcrSheet = workbook.addWorksheet('FCR'); fcrSheet.addRow(['Hari', 'FCR', 'Total Pakan', 'Bobot IoT', 'Ayam Hidup', 'Total Bobot Panen']); for (const row of payload.fcr) { fcrSheet.addRow([ row.day, na(row.iotFcr), na(row.feedTotal), na(row.iotWeight), na(row.chickenLife), na(row.harvestWeightTotal), ]); } const eefSheet = workbook.addWorksheet('EEF'); eefSheet.addRow([ 'Hari', 'EEF', 'Persentase Ayam Hidup', 'BW Rata-rata Panen', 'Umur Rata-rata Panen', 'FCR', ]); for (const row of payload.eef) { eefSheet.addRow([ row.day, na(row.iotEef), na(row.chickenLifePercentage), na(row.iotAverageHarvestBw), na(row.iotAverageDayWeight), na(row.iotFcr), ]); } const buffer = await workbook.xlsx.writeBuffer(); const blob = new Blob([buffer], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', }); const period = payload.reportType === 'end_cycle' ? 'Akhir-Siklus' : `Harian-Hari-${payload.upToDay}`; const url = URL.createObjectURL(blob); const anchor = document.createElement('a'); anchor.href = url; anchor.download = `Laporan-${period}-${payload.area}-${payload.kandangName}-${payload.cycleStart}_sd_${payload.cycleEnd}.xlsx`; anchor.click(); URL.revokeObjectURL(url); }