Files
dashboard-cpsp/utils/reportExcel.ts
T
2026-08-26 13:46:05 +07:00

121 lines
3.4 KiB
TypeScript

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<void> {
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);
}