diff --git a/src/pages/report/report/component/ListReport.jsx b/src/pages/report/report/component/ListReport.jsx
index 693a18e..f48f51e 100644
--- a/src/pages/report/report/component/ListReport.jsx
+++ b/src/pages/report/report/component/ListReport.jsx
@@ -9,6 +9,8 @@ import {
import { getAllPlantSection } from '../../../../api/master-plant-section';
import jsPDF from 'jspdf';
import autoTable from 'jspdf-autotable';
+import ExcelJS from 'exceljs';
+import { saveAs } from 'file-saver';
const { Text } = Typography;
@@ -54,9 +56,9 @@ const ListReport = memo(function ListReport(props) {
};
const fetchData = async (page = 1, pageSize = 10, showModal = false) => {
- if (!plantSubSection) {
- return;
- }
+ // if (!plantSubSection) {
+ // return;
+ // }
if (showModal) {
setIsLoadingModal(true);
@@ -195,8 +197,34 @@ const ListReport = memo(function ListReport(props) {
fetchData(pagination.current, pagination.pageSize, false);
};
- const handleSearch = () => {
- fetchData(1, pagination.pageSize, true);
+ const handleSearch = async () => {
+ setIsLoadingModal(true);
+
+ try {
+ const formattedDateStart = startDate.format('YYYY-MM-DD');
+ const formattedDateEnd = endDate.format('YYYY-MM-DD');
+
+ const params = new URLSearchParams({
+ plant_sub_section_id: plantSubSection,
+ from: formattedDateStart,
+ to: formattedDateEnd,
+ interval: periode,
+ page: 1,
+ limit: 1000,
+ });
+
+ const pivotResponse = await getAllHistoryValueReportPivot(params);
+
+ // Jika response sukses, proses data
+ if (pivotResponse && pivotResponse.data) {
+ await fetchData(1, pagination.pageSize, false);
+ }
+ } catch (error) {
+ console.error('Error fetching data:', error);
+ // Error akan ditangkap oleh api-request.js dan muncul Swal otomatis
+ } finally {
+ setIsLoadingModal(false);
+ }
};
const handleReset = () => {
@@ -247,6 +275,168 @@ const ListReport = memo(function ListReport(props) {
{ value: 120, label: '2 Hour', disabled: false },
];
+ const exportToExcel = async () => {
+ if (pivotData.length === 0) {
+ alert('No data to export');
+ return;
+ }
+
+ const tagMapping = {};
+ valueReportData.forEach(item => {
+ if (item.tag_name && item.tag_number) {
+ tagMapping[item.tag_name] = item.tag_number;
+ }
+ });
+
+ const selectedSection = plantSubSectionList.find(
+ item => item.plant_sub_section_id === plantSubSection
+ );
+ const sectionName = selectedSection ? selectedSection.plant_sub_section_name : 'Unknown';
+
+ // Buat struktur pivot yang sama seperti di tabel
+ const timeMap = new Map();
+ const tagSet = new Set();
+
+ pivotData.forEach((row) => {
+ const tagName = row.id;
+ tagSet.add(tagName);
+
+ const dataPoints = row.data || [];
+ dataPoints.forEach((item) => {
+ if (item && typeof item === 'object' && 'x' in item && 'y' in item) {
+ const datetime = item.x;
+ if (!timeMap.has(datetime)) {
+ timeMap.set(datetime, {});
+ }
+ timeMap.get(datetime)[tagName] = item.y;
+ }
+ });
+ });
+
+ const sortedTimes = Array.from(timeMap.keys()).sort();
+ const sortedTags = Array.from(tagSet).sort();
+
+ const pivotTableData = sortedTimes.map((datetime) => {
+ const rowData = {
+ datetime: datetime,
+ };
+
+ sortedTags.forEach((tagName) => {
+ rowData[tagName] = timeMap.get(datetime)[tagName];
+ });
+
+ return rowData;
+ });
+
+ console.log('Excel Pivot data:', pivotTableData.slice(0, 5));
+ console.log('Total rows for Excel:', pivotTableData.length);
+
+ const workbook = new ExcelJS.Workbook();
+ const ws = workbook.addWorksheet('Pivot Report');
+
+ // Buat header info (3 baris pertama)
+ ws.addRow(['PT. PUPUK INDONESIA UTILITAS']);
+ ws.addRow(['GRESIK GAS COGENERATION PLANT']);
+ ws.addRow([`${sectionName}`]);
+ ws.addRow([]); // Baris kosong sebagai pemisah
+
+ // Buat header kolom dengan tag number
+ const headerRow = [
+ 'Datetime',
+ ...sortedTags.map(tag => tagMapping[tag] || tag)
+ ];
+ ws.addRow(headerRow);
+
+ // Buat data rows - PERBAIKAN: Simpan sebagai number murni
+ pivotTableData.forEach((rowData) => {
+ const row = [dayjs(rowData.datetime).format('DD-MM-YYYY HH:mm')];
+ sortedTags.forEach((tagName) => {
+ const value = rowData[tagName];
+ // Simpan sebagai number, bukan string
+ if (value !== undefined && value !== null) {
+ row.push(Number(value));
+ } else {
+ row.push('-');
+ }
+ });
+ ws.addRow(row);
+ });
+
+ // Set column widths
+ ws.getColumn(1).width = 18; // Datetime column
+ for (let i = 2; i <= sortedTags.length + 1; i++) {
+ ws.getColumn(i).width = 12; // Tag columns
+ }
+
+ // Merge cells untuk header info
+ const totalCols = sortedTags.length + 1;
+ ws.mergeCells(1, 1, 1, totalCols); // Baris 1
+ ws.mergeCells(2, 1, 2, totalCols); // Baris 2
+ ws.mergeCells(3, 1, 3, totalCols); // Baris 3
+
+ // Style untuk header info (3 baris pertama - bold dan center)
+ for (let i = 1; i <= 3; i++) {
+ const cell = ws.getCell(i, 1);
+ cell.font = { bold: true, size: 12 };
+ cell.alignment = { horizontal: 'center', vertical: 'middle', wrapText: true };
+ }
+
+ // Style untuk header kolom (bold, background color, center, border)
+ const headerRowIndex = 5; // Baris header
+ for (let col = 1; col <= totalCols; col++) {
+ const cell = ws.getCell(headerRowIndex, col);
+ cell.font = { bold: true, size: 11 };
+ cell.fill = {
+ type: 'pattern',
+ pattern: 'solid',
+ fgColor: { argb: 'FFDCDCDC' }
+ };
+ cell.alignment = { horizontal: 'center', vertical: 'middle', wrapText: true };
+ cell.border = {
+ top: { style: 'thin', color: { argb: 'FF000000' } },
+ bottom: { style: 'thin', color: { argb: 'FF000000' } },
+ left: { style: 'thin', color: { argb: 'FF000000' } },
+ right: { style: 'thin', color: { argb: 'FF000000' } }
+ };
+ }
+
+ // Style untuk data cells (border dan alignment) - PERBAIKAN: Format number dengan 2 desimal
+ for (let row = headerRowIndex + 1; row <= ws.rowCount; row++) {
+ for (let col = 1; col <= totalCols; col++) {
+ const cell = ws.getCell(row, col);
+
+ cell.alignment = {
+ horizontal: 'center',
+ vertical: 'middle',
+ wrapText: true
+ };
+ cell.border = {
+ top: { style: 'thin', color: { argb: 'FF000000' } },
+ bottom: { style: 'thin', color: { argb: 'FF000000' } },
+ left: { style: 'thin', color: { argb: 'FF000000' } },
+ right: { style: 'thin', color: { argb: 'FF000000' } }
+ };
+
+ // Format number dengan 2 desimal untuk kolom value (kolom 2 dst)
+ if (col > 1) {
+ const cellValue = cell.value;
+ // Hanya set format number jika cell berisi angka
+ if (typeof cellValue === 'number') {
+ cell.numFmt = '0.00';
+ }
+ }
+ }
+ }
+
+ // Generate file name
+ const fileName = `Report_Pivot_${startDate.format('DD-MM-YYYY')}_to_${endDate.format('DD-MM-YYYY')}.xlsx`;
+
+ // Save file
+ const buffer = await workbook.xlsx.writeBuffer();
+ const blob = new Blob([buffer], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
+ saveAs(blob, fileName);
+ };
+
const exportToPDF = async () => {
if (pivotData.length === 0) {
alert('No data to export');
@@ -393,7 +583,7 @@ const ListReport = memo(function ListReport(props) {
doc.setFontSize(9);
doc.setFont('helvetica', 'bold');
doc.setFontSize(10);
- doc.text(`Plant Section : ${sectionName}`, marginLeft + col1Width + col2Width / 2, 41, { align: 'center' });
+ doc.text(`${sectionName}`, marginLeft + col1Width + col2Width / 2, 38, { align: 'center' });
};
// Hitung total kolom tag chunks
@@ -534,7 +724,7 @@ const ListReport = memo(function ListReport(props) {
autoTable(doc, {
head: [headerRow],
body: pdfRows,
- startY: isFirstPage ? 50 : 15,
+ startY: isFirstPage ? 43 : 15,
theme: 'grid',
rowPageBreak: 'avoid',
styles: {
@@ -542,7 +732,7 @@ const ListReport = memo(function ListReport(props) {
cellPadding: 1.5,
minCellHeight: 8,
lineColor: [0, 0, 0],
- lineWidth: 0.1,
+ lineWidth: 0.5,
halign: 'center',
valign: 'middle',
overflow: 'linebreak',
@@ -554,7 +744,7 @@ const ListReport = memo(function ListReport(props) {
halign: 'center',
valign: 'middle',
lineColor: [0, 0, 0],
- lineWidth: 0.3,
+ lineWidth: 0.5,
},
columnStyles: {
0: {
@@ -694,11 +884,23 @@ const ListReport = memo(function ListReport(props) {
type="primary"
icon={