update menu report
This commit is contained in:
@@ -16,9 +16,10 @@ const ListReport = memo(function ListReport(props) {
|
||||
const dateNow = dayjs();
|
||||
const dateNowFormated = dateNow.format('YYYY-MM-DD');
|
||||
|
||||
const [isLoadingModal, setIsLoadingModal] = useState(false); // Modal loading
|
||||
const [isLoadingTable, setIsLoadingTable] = useState(false); // Table loading
|
||||
const [isLoadingModal, setIsLoadingModal] = useState(false);
|
||||
const [isLoadingTable, setIsLoadingTable] = useState(false);
|
||||
const [tableData, setTableData] = useState([]);
|
||||
const [columns, setColumns] = useState([]);
|
||||
const [pivotData, setPivotData] = useState([]);
|
||||
const [valueReportData, setValueReportData] = useState([]);
|
||||
const [pagination, setPagination] = useState({
|
||||
@@ -33,46 +34,6 @@ const ListReport = memo(function ListReport(props) {
|
||||
const [endDate, setEndDate] = useState(dateNow);
|
||||
const [periode, setPeriode] = useState(30);
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: 'No',
|
||||
key: 'no',
|
||||
width: 60,
|
||||
align: 'center',
|
||||
fixed: 'left',
|
||||
render: (_, __, index) => {
|
||||
return (pagination.current - 1) * pagination.pageSize + index + 1;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'Datetime',
|
||||
dataIndex: 'datetime',
|
||||
key: 'datetime',
|
||||
width: 180,
|
||||
sorter: (a, b) => new Date(a.datetime) - new Date(b.datetime),
|
||||
},
|
||||
{
|
||||
title: 'Tag Name',
|
||||
dataIndex: 'tagName',
|
||||
key: 'tagName',
|
||||
width: 200,
|
||||
},
|
||||
{
|
||||
title: 'Value',
|
||||
dataIndex: 'value',
|
||||
key: 'value',
|
||||
width: 120,
|
||||
align: 'left', // Aligned kanan (seperti angka pada umumnya)
|
||||
render: (value) => {
|
||||
if (value === null || value === undefined) {
|
||||
return '-';
|
||||
}
|
||||
return Number(value).toFixed(2); // Format 2 desimal
|
||||
},
|
||||
}
|
||||
];
|
||||
|
||||
// Fungsi helper untuk generate semua waktu dalam sehari berdasarkan periode
|
||||
const generateFullDayTimes = (dateString, intervalMinutes) => {
|
||||
const times = [];
|
||||
const startOfDay = dayjs(dateString).startOf('day');
|
||||
@@ -84,7 +45,6 @@ const ListReport = memo(function ListReport(props) {
|
||||
times.push(currentTime.format('YYYY-MM-DD HH:mm:ss'));
|
||||
currentTime = currentTime.add(intervalMinutes, 'minute');
|
||||
|
||||
// Jika waktu berikutnya melebihi akhir hari, break
|
||||
if (currentTime.isAfter(endOfDay)) {
|
||||
break;
|
||||
}
|
||||
@@ -99,9 +59,9 @@ const ListReport = memo(function ListReport(props) {
|
||||
}
|
||||
|
||||
if (showModal) {
|
||||
setIsLoadingModal(true); // Modal untuk fetch pertama
|
||||
setIsLoadingModal(true);
|
||||
} else {
|
||||
setIsLoadingTable(true); // Spin untuk pagination
|
||||
setIsLoadingTable(true);
|
||||
}
|
||||
try {
|
||||
const formattedDateStart = startDate.format('YYYY-MM-DD');
|
||||
@@ -121,8 +81,6 @@ const ListReport = memo(function ListReport(props) {
|
||||
|
||||
if (pivotResponse && pivotResponse.data) {
|
||||
console.log('API Pivot Response:', pivotResponse);
|
||||
console.log('First row pivot data:', pivotResponse.data[0]);
|
||||
|
||||
setPivotData(pivotResponse.data);
|
||||
|
||||
if (valueReportResponse && valueReportResponse.data) {
|
||||
@@ -130,42 +88,90 @@ const ListReport = memo(function ListReport(props) {
|
||||
setValueReportData(valueReportResponse.data);
|
||||
}
|
||||
|
||||
const unpivotedData = [];
|
||||
// Buat struktur pivot: waktu sebagai baris, tag sebagai kolom
|
||||
const timeMap = new Map();
|
||||
const tagSet = new Set();
|
||||
|
||||
// Kumpulkan semua waktu unik dan tag unik
|
||||
pivotResponse.data.forEach((row) => {
|
||||
const tagName = row.id;
|
||||
const dataPoints = row.data || [];
|
||||
tagSet.add(tagName);
|
||||
|
||||
const dataPoints = row.data || [];
|
||||
dataPoints.forEach((item) => {
|
||||
if (item && typeof item === 'object' && 'x' in item && 'y' in item) {
|
||||
unpivotedData.push({
|
||||
datetime: item.x,
|
||||
tagName: tagName,
|
||||
value: item.y,
|
||||
});
|
||||
const datetime = item.x;
|
||||
if (!timeMap.has(datetime)) {
|
||||
timeMap.set(datetime, {});
|
||||
}
|
||||
timeMap.get(datetime)[tagName] = item.y;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
console.log('Unpivoted data sample:', unpivotedData.slice(0, 10));
|
||||
console.log('Total unpivoted rows:', unpivotedData.length);
|
||||
// Konversi ke array dan sort berdasarkan waktu
|
||||
const sortedTimes = Array.from(timeMap.keys()).sort();
|
||||
const sortedTags = Array.from(tagSet).sort();
|
||||
|
||||
unpivotedData.sort((a, b) => {
|
||||
if (a.tagName !== b.tagName) {
|
||||
return a.tagName.localeCompare(b.tagName);
|
||||
}
|
||||
return new Date(a.datetime) - new Date(b.datetime);
|
||||
// Buat data untuk table
|
||||
const pivotTableData = sortedTimes.map((datetime, index) => {
|
||||
const rowData = {
|
||||
key: index,
|
||||
datetime: datetime,
|
||||
};
|
||||
|
||||
sortedTags.forEach((tagName) => {
|
||||
rowData[tagName] = timeMap.get(datetime)[tagName];
|
||||
});
|
||||
|
||||
return rowData;
|
||||
});
|
||||
|
||||
const transformedData = unpivotedData.map((item, index) => ({
|
||||
key: index,
|
||||
...item,
|
||||
}));
|
||||
console.log('Pivot table data sample:', pivotTableData.slice(0, 5));
|
||||
console.log('Total pivot rows:', pivotTableData.length);
|
||||
|
||||
const total = transformedData.length;
|
||||
// Buat kolom dinamis
|
||||
const dynamicColumns = [
|
||||
{
|
||||
title: 'No',
|
||||
key: 'no',
|
||||
width: 60,
|
||||
align: 'center',
|
||||
fixed: 'left',
|
||||
render: (_, __, index) => {
|
||||
return (page - 1) * pageSize + index + 1;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'Datetime',
|
||||
dataIndex: 'datetime',
|
||||
key: 'datetime',
|
||||
width: 180,
|
||||
fixed: 'left',
|
||||
sorter: (a, b) => new Date(a.datetime) - new Date(b.datetime),
|
||||
},
|
||||
...sortedTags.map((tagName) => ({
|
||||
title: tagName,
|
||||
dataIndex: tagName,
|
||||
key: tagName,
|
||||
width: 120,
|
||||
align: 'center',
|
||||
render: (value) => {
|
||||
if (value === null || value === undefined) {
|
||||
return '-';
|
||||
}
|
||||
return Number(value).toFixed(2);
|
||||
},
|
||||
})),
|
||||
];
|
||||
|
||||
setColumns(dynamicColumns);
|
||||
|
||||
// Pagination
|
||||
const total = pivotTableData.length;
|
||||
const startIndex = (page - 1) * pageSize;
|
||||
const endIndex = startIndex + pageSize;
|
||||
const paginatedData = transformedData.slice(startIndex, endIndex);
|
||||
const paginatedData = pivotTableData.slice(startIndex, endIndex);
|
||||
|
||||
setTableData(paginatedData);
|
||||
setPagination({
|
||||
@@ -199,6 +205,7 @@ const ListReport = memo(function ListReport(props) {
|
||||
setEndDate(dateNow);
|
||||
setPeriode(30);
|
||||
setTableData([]);
|
||||
setColumns([]);
|
||||
setPivotData([]);
|
||||
setValueReportData([]);
|
||||
setPagination({
|
||||
@@ -256,47 +263,43 @@ const ListReport = memo(function ListReport(props) {
|
||||
const selectedSection = plantSubSectionList.find(item => item.plant_sub_section_id === plantSubSection);
|
||||
const sectionName = selectedSection ? selectedSection.plant_sub_section_name : 'Unknown';
|
||||
|
||||
// Generate data lengkap untuk setiap tanggal dengan semua interval waktu
|
||||
const dataByDate = {};
|
||||
// Buat struktur pivot yang sama seperti di tabel
|
||||
const timeMap = new Map();
|
||||
const tagSet = new Set();
|
||||
|
||||
// Pertama, kumpulkan semua tanggal yang ada
|
||||
const allDates = new Set();
|
||||
pivotData.forEach(series => {
|
||||
series.data.forEach(item => {
|
||||
const date = dayjs(item.x).format('YYYY-MM-DD');
|
||||
allDates.add(date);
|
||||
});
|
||||
});
|
||||
pivotData.forEach((row) => {
|
||||
const tagName = row.id;
|
||||
tagSet.add(tagName);
|
||||
|
||||
// Untuk setiap tanggal, generate semua waktu dan isi dengan data yang ada
|
||||
Array.from(allDates).forEach(date => {
|
||||
const fullDayTimes = generateFullDayTimes(date, periode);
|
||||
dataByDate[date] = {};
|
||||
|
||||
// Initialize dengan semua waktu
|
||||
pivotData.forEach(series => {
|
||||
dataByDate[date][series.id] = fullDayTimes.map(time => ({
|
||||
x: time,
|
||||
y: null // Default null, akan diisi jika ada data
|
||||
}));
|
||||
});
|
||||
|
||||
// Isi dengan data aktual yang ada
|
||||
pivotData.forEach(series => {
|
||||
series.data.forEach(item => {
|
||||
const itemDate = dayjs(item.x).format('YYYY-MM-DD');
|
||||
if (itemDate === date) {
|
||||
const itemTime = dayjs(item.x).format('YYYY-MM-DD HH:mm:ss');
|
||||
const timeIndex = fullDayTimes.indexOf(itemTime);
|
||||
if (timeIndex !== -1 && dataByDate[date][series.id][timeIndex]) {
|
||||
dataByDate[date][series.id][timeIndex].y = item.y;
|
||||
}
|
||||
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 sortedDates = Object.keys(dataByDate).sort();
|
||||
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('PDF Pivot data:', pivotTableData.slice(0, 5));
|
||||
console.log('Total rows for PDF:', pivotTableData.length);
|
||||
|
||||
const loadImage = (src) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
@@ -322,21 +325,17 @@ const ListReport = memo(function ListReport(props) {
|
||||
const marginRight = 10;
|
||||
const tableWidth = pageWidth - marginLeft - marginRight;
|
||||
|
||||
// Konstanta untuk mengatur lebar kolom
|
||||
const IO_TAG_COLUMN_WIDTH = 17; // Lebar kolom IO Soft Tag di TABEL (mm)
|
||||
const HEADER_LEFT_COLUMN_WIDTH = 40; // Lebar kolom KIRI di HEADER (untuk logo1) (mm)
|
||||
const MAX_TIME_COLUMNS_PER_PAGE = 24;
|
||||
const DATETIME_COLUMN_WIDTH = 25;
|
||||
const HEADER_LEFT_COLUMN_WIDTH = 40;
|
||||
const MAX_TAG_COLUMNS_PER_PAGE = 15;
|
||||
|
||||
let globalPageNumber = 1;
|
||||
|
||||
// FUNGSI HEADER LENGKAP - Untuk Halaman Pertama
|
||||
const drawFullHeader = (doc, date) => {
|
||||
const drawFullHeader = (doc) => {
|
||||
doc.setLineWidth(0.5);
|
||||
doc.line(marginLeft, 10, marginLeft + tableWidth, 10);
|
||||
doc.line(marginLeft, 10, marginLeft, 50);
|
||||
doc.line(marginLeft + tableWidth, 10, marginLeft + tableWidth, 50);
|
||||
|
||||
const col1Width = HEADER_LEFT_COLUMN_WIDTH; // Gunakan konstanta HEADER
|
||||
const col1Width = HEADER_LEFT_COLUMN_WIDTH;
|
||||
const col3Width = tableWidth * 0.20;
|
||||
const col2Width = tableWidth - col1Width - col3Width;
|
||||
|
||||
@@ -391,194 +390,199 @@ const ListReport = memo(function ListReport(props) {
|
||||
doc.addImage(logo2, 'PNG', logoX, logoY, logoWidth, logoHeight);
|
||||
}
|
||||
|
||||
doc.line(marginLeft + tableWidth - col3Width, 30, marginLeft + tableWidth - col3Width, 50);
|
||||
|
||||
const formattedDate = dayjs(date).format('DD-MM-YYYY');
|
||||
|
||||
doc.setFontSize(9);
|
||||
doc.setFont('helvetica', 'bold');
|
||||
doc.text('Laporan Periode :', marginLeft + tableWidth - col3Width / 2, 35, { align: 'center' });
|
||||
doc.setFont('helvetica', 'normal');
|
||||
doc.text(formattedDate, marginLeft + tableWidth - col3Width / 2, 40, { align: 'center' });
|
||||
|
||||
// Hitung waktu akhir berdasarkan periode
|
||||
const minutesInDay = 24 * 60;
|
||||
const lastTimeMinutes = Math.floor((minutesInDay - periode) / periode) * periode;
|
||||
const lastHour = Math.floor(lastTimeMinutes / 60);
|
||||
const lastMinute = lastTimeMinutes % 60;
|
||||
const endTime = `${String(lastHour).padStart(2, '0')}:${String(lastMinute).padStart(2, '0')}`;
|
||||
|
||||
doc.setFontSize(9);
|
||||
doc.text(`00:00 - ${endTime}`, marginLeft + tableWidth - col3Width / 2, 45, { align: 'center' });
|
||||
|
||||
doc.setFont('helvetica', 'bold');
|
||||
doc.setFontSize(10);
|
||||
doc.text(`Plant Section : ${sectionName}`, marginLeft + col1Width + col2Width / 2, 41, { align: 'center' });
|
||||
};
|
||||
|
||||
// FUNGSI HEADER SEDERHANA - Untuk Halaman Selanjutnya
|
||||
const drawSimpleHeader = (doc, date) => {
|
||||
const formattedDate = dayjs(date).format('DD-MM-YYYY');
|
||||
// Hitung total kolom tag chunks
|
||||
const totalTagColumns = sortedTags.length;
|
||||
const totalTagChunks = Math.ceil(totalTagColumns / MAX_TAG_COLUMNS_PER_PAGE);
|
||||
|
||||
// Gunakan struktur kolom yang SAMA seperti header lengkap
|
||||
const col1Width = HEADER_LEFT_COLUMN_WIDTH; // Gunakan konstanta HEADER
|
||||
const col3Width = tableWidth * 0.20;
|
||||
const col2Width = tableWidth - col1Width - col3Width;
|
||||
// PERBAIKAN: Variabel untuk tracking total halaman yang sebenarnya
|
||||
let actualTotalPages = 0;
|
||||
const pageInfoArray = []; // Array untuk menyimpan info setiap page
|
||||
|
||||
// Border luar
|
||||
doc.setLineWidth(0.5);
|
||||
doc.line(marginLeft, 10, marginLeft + tableWidth, 10);
|
||||
doc.line(marginLeft, 10, marginLeft, 30);
|
||||
doc.line(marginLeft + tableWidth, 10, marginLeft + tableWidth, 30);
|
||||
doc.line(marginLeft, 30, marginLeft + tableWidth, 30);
|
||||
// Loop pertama: hitung dulu total halaman yang akan dibuat
|
||||
for (let pageChunk = 0; pageChunk < totalTagChunks; pageChunk++) {
|
||||
const startTagIndex = pageChunk * MAX_TAG_COLUMNS_PER_PAGE;
|
||||
const endTagIndex = Math.min(startTagIndex + MAX_TAG_COLUMNS_PER_PAGE, totalTagColumns);
|
||||
const pageTagColumns = sortedTags.slice(startTagIndex, endTagIndex);
|
||||
const isFirstPage = (pageChunk === 0);
|
||||
|
||||
// Garis vertikal pemisah kolom
|
||||
doc.line(marginLeft + tableWidth - col3Width, 10, marginLeft + tableWidth - col3Width, 30);
|
||||
// Simulasi autoTable untuk menghitung jumlah halaman
|
||||
const tempDoc = new jsPDF({ orientation: 'landscape' });
|
||||
const headerRow = ['Datetime', ...pageTagColumns.map(tag => tagMapping[tag] || tag)];
|
||||
|
||||
// Kolom Kiri (KOSONG - tidak ada isi)
|
||||
|
||||
// Kolom Tengah - Plant Section
|
||||
doc.setFontSize(10);
|
||||
doc.setFont('helvetica', 'bold');
|
||||
doc.text(`Plant Section : ${sectionName}`, marginLeft + col1Width + col2Width / 2, 20, { align: 'center' });
|
||||
|
||||
// Kolom Kanan - Laporan Periode + Time Range
|
||||
doc.setFontSize(9);
|
||||
doc.setFont('helvetica', 'bold');
|
||||
doc.text('Laporan Periode :', marginLeft + tableWidth - col3Width / 2, 14, { align: 'center' });
|
||||
doc.setFont('helvetica', 'normal');
|
||||
doc.text(formattedDate, marginLeft + tableWidth - col3Width / 2, 19, { align: 'center' });
|
||||
|
||||
// Hitung waktu akhir berdasarkan periode
|
||||
const minutesInDay = 24 * 60;
|
||||
const lastTimeMinutes = Math.floor((minutesInDay - periode) / periode) * periode;
|
||||
const lastHour = Math.floor(lastTimeMinutes / 60);
|
||||
const lastMinute = lastTimeMinutes % 60;
|
||||
const endTime = `${String(lastHour).padStart(2, '0')}:${String(lastMinute).padStart(2, '0')}`;
|
||||
|
||||
doc.text(`00:00 - ${endTime}`, marginLeft + tableWidth - col3Width / 2, 24, { align: 'center' });
|
||||
};
|
||||
|
||||
sortedDates.forEach((date, dateIndex) => {
|
||||
const dateData = dataByDate[date];
|
||||
|
||||
// Ambil semua waktu yang sudah di-generate lengkap
|
||||
const allTimes = dateData[Object.keys(dateData)[0]].map(item => item.x);
|
||||
const formattedTimes = allTimes.map(time => dayjs(time).format('HH:mm'));
|
||||
|
||||
const sortedTags = Object.keys(dateData).sort();
|
||||
|
||||
const totalTimeColumns = formattedTimes.length;
|
||||
const totalPages = Math.ceil(totalTimeColumns / MAX_TIME_COLUMNS_PER_PAGE);
|
||||
|
||||
let totalPagesCount = 0;
|
||||
sortedDates.forEach((date) => {
|
||||
const dateData = dataByDate[date];
|
||||
const totalTimeColumns = dateData[Object.keys(dateData)[0]].length;
|
||||
const pagesForThisDate = Math.ceil(totalTimeColumns / MAX_TIME_COLUMNS_PER_PAGE);
|
||||
totalPagesCount += pagesForThisDate;
|
||||
const pdfRows = pivotTableData.map((rowData) => {
|
||||
const row = [dayjs(rowData.datetime).format('DD-MM-YYYY HH:mm')];
|
||||
pageTagColumns.forEach((tagName) => {
|
||||
const value = rowData[tagName];
|
||||
row.push(value !== undefined && value !== null ? Number(value).toFixed(2) : '-');
|
||||
});
|
||||
return row;
|
||||
});
|
||||
|
||||
for (let pageChunk = 0; pageChunk < totalPages; pageChunk++) {
|
||||
if (dateIndex > 0 || pageChunk > 0) {
|
||||
doc.addPage();
|
||||
}
|
||||
const availableWidthForTags = tableWidth - DATETIME_COLUMN_WIDTH;
|
||||
const TAG_COLUMN_WIDTH = availableWidthForTags / pageTagColumns.length;
|
||||
|
||||
const startColIndex = pageChunk * MAX_TIME_COLUMNS_PER_PAGE;
|
||||
const endColIndex = Math.min(startColIndex + MAX_TIME_COLUMNS_PER_PAGE, totalTimeColumns);
|
||||
const pageTimeColumns = formattedTimes.slice(startColIndex, endColIndex);
|
||||
const pageRawTimes = allTimes.slice(startColIndex, endColIndex);
|
||||
const tagColumnStyles = {};
|
||||
for (let i = 0; i < pageTagColumns.length; i++) {
|
||||
tagColumnStyles[i + 1] = {
|
||||
cellWidth: TAG_COLUMN_WIDTH,
|
||||
halign: 'center'
|
||||
};
|
||||
}
|
||||
|
||||
const isFirstPage = (dateIndex === 0 && pageChunk === 0);
|
||||
let pagesForThisChunk = 0;
|
||||
|
||||
// Gunakan header yang sesuai
|
||||
if (isFirstPage) {
|
||||
drawFullHeader(doc, date);
|
||||
} else {
|
||||
drawSimpleHeader(doc, date);
|
||||
}
|
||||
|
||||
const availableWidthForTime = tableWidth - IO_TAG_COLUMN_WIDTH;
|
||||
const TIME_COLUMN_WIDTH = availableWidthForTime / pageTimeColumns.length;
|
||||
|
||||
const headerRow = ['IO Soft Tag', ...pageTimeColumns];
|
||||
|
||||
const pdfRows = sortedTags.map(tagName => {
|
||||
const tagIdentifier = tagMapping[tagName] || tagName;
|
||||
const row = [tagIdentifier];
|
||||
|
||||
const tagData = dateData[tagName];
|
||||
|
||||
for (let i = startColIndex; i < endColIndex; i++) {
|
||||
const dataPoint = tagData[i];
|
||||
const val = dataPoint && dataPoint.y;
|
||||
row.push(val !== undefined && val !== null ? Number(val).toFixed(2) : '-');
|
||||
}
|
||||
|
||||
return row;
|
||||
});
|
||||
|
||||
const timeColumnStyles = {};
|
||||
for (let i = 0; i < pageTimeColumns.length; i++) {
|
||||
timeColumnStyles[i + 1] = {
|
||||
cellWidth: TIME_COLUMN_WIDTH,
|
||||
minCellWidht: 10,
|
||||
halign: 'center'
|
||||
};
|
||||
}
|
||||
|
||||
autoTable(doc, {
|
||||
head: [headerRow],
|
||||
body: pdfRows,
|
||||
startY: isFirstPage ? 50 : 30, // Sesuaikan startY untuk header sederhana (sama tinggi dengan header lengkap)
|
||||
theme: 'grid',
|
||||
styles: {
|
||||
fontSize: 5,
|
||||
cellPadding: 1,
|
||||
minCellHeight: 10,
|
||||
lineColor: [0, 0, 0],
|
||||
lineWidth: 0.1,
|
||||
halign: 'center',
|
||||
valign: 'middle',
|
||||
overflow: 'linebreak',
|
||||
},
|
||||
headStyles: {
|
||||
fillColor: [255, 255, 255],
|
||||
textColor: [0, 0, 0],
|
||||
autoTable(tempDoc, {
|
||||
head: [headerRow],
|
||||
body: pdfRows,
|
||||
startY: isFirstPage ? 50 : 15,
|
||||
theme: 'grid',
|
||||
rowPageBreak: 'avoid',
|
||||
styles: {
|
||||
fontSize: 7,
|
||||
cellPadding: 1.5,
|
||||
minCellHeight: 8,
|
||||
lineColor: [0, 0, 0],
|
||||
lineWidth: 0.1,
|
||||
halign: 'center',
|
||||
valign: 'middle',
|
||||
overflow: 'linebreak',
|
||||
},
|
||||
headStyles: {
|
||||
fillColor: [220, 220, 220],
|
||||
textColor: [0, 0, 0],
|
||||
fontStyle: 'bold',
|
||||
halign: 'center',
|
||||
valign: 'middle',
|
||||
lineColor: [0, 0, 0],
|
||||
lineWidth: 0.3,
|
||||
},
|
||||
columnStyles: {
|
||||
0: {
|
||||
cellWidth: DATETIME_COLUMN_WIDTH,
|
||||
fontStyle: 'bold',
|
||||
halign: 'center',
|
||||
valign: 'middle',
|
||||
lineColor: [0, 0, 0],
|
||||
lineWidth: 0.3,
|
||||
valign: 'middle'
|
||||
},
|
||||
columnStyles: {
|
||||
0: {
|
||||
cellWidth: IO_TAG_COLUMN_WIDTH,
|
||||
fontStyle: 'bold',
|
||||
halign: 'center',
|
||||
valign: 'middle'
|
||||
},
|
||||
...timeColumnStyles
|
||||
},
|
||||
margin: { left: marginLeft, right: marginRight },
|
||||
tableWidth: tableWidth,
|
||||
pageBreak: 'auto',
|
||||
didDrawPage: (data) => {
|
||||
doc.setFontSize(8);
|
||||
doc.setFont('helvetica', 'normal');
|
||||
doc.text(
|
||||
`Page ${globalPageNumber} of ${totalPagesCount}`,
|
||||
doc.internal.pageSize.width / 2,
|
||||
doc.internal.pageSize.height - 10,
|
||||
{ align: 'center' }
|
||||
);
|
||||
globalPageNumber++;
|
||||
},
|
||||
});
|
||||
}
|
||||
});
|
||||
...tagColumnStyles
|
||||
},
|
||||
margin: { left: marginLeft, right: marginRight, top: 15 },
|
||||
tableWidth: tableWidth,
|
||||
pageBreak: 'auto',
|
||||
didDrawPage: () => {
|
||||
pagesForThisChunk++;
|
||||
}
|
||||
});
|
||||
|
||||
doc.save(`Report_${startDate.format('DD-MM-YYYY')}_to_${endDate.format('DD-MM-YYYY')}_ByDate.pdf`);
|
||||
pageInfoArray.push({
|
||||
chunkIndex: pageChunk,
|
||||
pagesCount: pagesForThisChunk,
|
||||
startPage: actualTotalPages + 1
|
||||
});
|
||||
|
||||
actualTotalPages += pagesForThisChunk;
|
||||
}
|
||||
|
||||
console.log('Total pages akan dibuat:', actualTotalPages);
|
||||
|
||||
// Loop kedua: buat PDF yang sebenarnya dengan nomor halaman yang benar
|
||||
let globalPageNumber = 1;
|
||||
|
||||
for (let pageChunk = 0; pageChunk < totalTagChunks; pageChunk++) {
|
||||
if (pageChunk > 0) {
|
||||
doc.addPage();
|
||||
}
|
||||
|
||||
const startTagIndex = pageChunk * MAX_TAG_COLUMNS_PER_PAGE;
|
||||
const endTagIndex = Math.min(startTagIndex + MAX_TAG_COLUMNS_PER_PAGE, totalTagColumns);
|
||||
const pageTagColumns = sortedTags.slice(startTagIndex, endTagIndex);
|
||||
const isFirstPage = (pageChunk === 0);
|
||||
|
||||
if (isFirstPage) {
|
||||
drawFullHeader(doc);
|
||||
}
|
||||
|
||||
const headerRow = ['Datetime', ...pageTagColumns.map(tag => tagMapping[tag] || tag)];
|
||||
|
||||
const pdfRows = pivotTableData.map((rowData) => {
|
||||
const row = [dayjs(rowData.datetime).format('DD-MM-YYYY HH:mm')];
|
||||
|
||||
pageTagColumns.forEach((tagName) => {
|
||||
const value = rowData[tagName];
|
||||
row.push(value !== undefined && value !== null ? Number(value).toFixed(2) : '-');
|
||||
});
|
||||
|
||||
return row;
|
||||
});
|
||||
|
||||
const availableWidthForTags = tableWidth - DATETIME_COLUMN_WIDTH;
|
||||
const TAG_COLUMN_WIDTH = availableWidthForTags / pageTagColumns.length;
|
||||
|
||||
const tagColumnStyles = {};
|
||||
for (let i = 0; i < pageTagColumns.length; i++) {
|
||||
tagColumnStyles[i + 1] = {
|
||||
cellWidth: TAG_COLUMN_WIDTH,
|
||||
halign: 'center'
|
||||
};
|
||||
}
|
||||
|
||||
autoTable(doc, {
|
||||
head: [headerRow],
|
||||
body: pdfRows,
|
||||
startY: isFirstPage ? 50 : 15,
|
||||
theme: 'grid',
|
||||
rowPageBreak: 'avoid',
|
||||
styles: {
|
||||
fontSize: 7,
|
||||
cellPadding: 1.5,
|
||||
minCellHeight: 8,
|
||||
lineColor: [0, 0, 0],
|
||||
lineWidth: 0.1,
|
||||
halign: 'center',
|
||||
valign: 'middle',
|
||||
overflow: 'linebreak',
|
||||
},
|
||||
headStyles: {
|
||||
fillColor: [220, 220, 220],
|
||||
textColor: [0, 0, 0],
|
||||
fontStyle: 'bold',
|
||||
halign: 'center',
|
||||
valign: 'middle',
|
||||
lineColor: [0, 0, 0],
|
||||
lineWidth: 0.3,
|
||||
},
|
||||
columnStyles: {
|
||||
0: {
|
||||
cellWidth: DATETIME_COLUMN_WIDTH,
|
||||
fontStyle: 'bold',
|
||||
halign: 'center',
|
||||
valign: 'middle'
|
||||
},
|
||||
...tagColumnStyles
|
||||
},
|
||||
margin: { left: marginLeft, right: marginRight, top: 15 },
|
||||
tableWidth: tableWidth,
|
||||
pageBreak: 'auto',
|
||||
didDrawPage: (data) => {
|
||||
doc.setFontSize(8);
|
||||
doc.setFont('helvetica', 'normal');
|
||||
doc.text(
|
||||
`Page ${globalPageNumber} of ${actualTotalPages}`,
|
||||
doc.internal.pageSize.width / 2,
|
||||
doc.internal.pageSize.height - 10,
|
||||
{ align: 'center' }
|
||||
);
|
||||
globalPageNumber++;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
doc.save(`Report_Pivot_${startDate.format('DD-MM-YYYY')}_to_${endDate.format('DD-MM-YYYY')}.pdf`);
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -707,20 +711,23 @@ const ListReport = memo(function ListReport(props) {
|
||||
</Col>
|
||||
<Col xs={24} style={{ marginTop: '16px' }}>
|
||||
<Spin spinning={isLoadingTable}>
|
||||
<Table
|
||||
columns={columns}
|
||||
dataSource={tableData}
|
||||
pagination={{
|
||||
...pagination,
|
||||
showSizeChanger: true,
|
||||
showTotal: (total) => `Total ${total} data`,
|
||||
pageSizeOptions: ['10', '20', '50', '100'],
|
||||
}}
|
||||
onChange={handleTableChange}
|
||||
scroll={{ x: 'max-content', y: 500 }}
|
||||
bordered
|
||||
size="small"
|
||||
/>
|
||||
<div style={{ overflowX: 'auto', width: '100%' }}>
|
||||
<Table
|
||||
columns={columns}
|
||||
dataSource={tableData}
|
||||
pagination={{
|
||||
...pagination,
|
||||
showSizeChanger: true,
|
||||
showTotal: (total) => `Total ${total} data`,
|
||||
pageSizeOptions: ['10', '20', '50', '100'],
|
||||
}}
|
||||
onChange={handleTableChange}
|
||||
scroll={{ x: 'max-content', y: 500 }}
|
||||
bordered
|
||||
size="small"
|
||||
sticky
|
||||
/>
|
||||
</div>
|
||||
</Spin>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
Reference in New Issue
Block a user