const sqlite3 = require('sqlite3').verbose(); const ExcelJS = require('exceljs'); async function exportData() { const db = new sqlite3.Database('database.sqlite'); const workbook = new ExcelJS.Workbook(); const sheet = workbook.addWorksheet('Опрацювання територій'); // Обычная тонкая рамка function setThinBorder(cell) { cell.border = { top: { style: 'thin', color: { argb: 'FF000000' } }, left: { style: 'thin', color: { argb: 'FF000000' } }, bottom: { style: 'thin', color: { argb: 'FF000000' } }, right: { style: 'thin', color: { argb: 'FF000000' } }, }; } // Жирные рамки для Вісників function setTopCellBorder(cell) { cell.border = { top: { style: 'thick', color: { argb: 'FF000000' } }, left: { style: 'thick', color: { argb: 'FF000000' } }, right: { style: 'thick', color: { argb: 'FF000000' } }, bottom: { style: 'thin', color: { argb: 'FF000000' } }, }; } function setStartColBorder(cell) { cell.border = { top: { style: 'thin', color: { argb: 'FF000000' } }, left: { style: 'thick', color: { argb: 'FF000000' } }, bottom: { style: 'thick', color: { argb: 'FF000000' } }, right: { style: 'thin', color: { argb: 'FF000000' } }, }; } function setEndColBorder(cell) { cell.border = { top: { style: 'thin', color: { argb: 'FF000000' } }, left: { style: 'thin', color: { argb: 'FF000000' } }, bottom: { style: 'thick', color: { argb: 'FF000000' } }, right: { style: 'thick', color: { argb: 'FF000000' } }, }; } sheet.addRow([]); sheet.addRow([]); // № объекта sheet.getCell('A1').value = '№'; sheet.mergeCells('A1:A2'); sheet.getCell('A1').alignment = { vertical: 'middle', horizontal: 'center' }; sheet.getCell('A1').font = { bold: true }; setThinBorder(sheet.getCell('A1')); sheet.getColumn(1).width = 5; // "Об’єкт" sheet.getCell('B1').value = 'Територія'; sheet.mergeCells('B1:B2'); sheet.getCell('B1').alignment = { vertical: 'middle', horizontal: 'center' }; sheet.getCell('B1').font = { bold: true }; setThinBorder(sheet.getCell('B1')); sheet.getColumn(2).width = 40; // "Остання дата опрацювання" sheet.getCell('C1').value = 'Остання дата опрацювання'; sheet.mergeCells('C1:C2'); sheet.getCell('C1').alignment = { vertical: 'middle', horizontal: 'center', wrapText: true }; sheet.getCell('C1').font = { bold: true }; setThinBorder(sheet.getCell('C1')); sheet.getColumn(3).width = 20; // Вісники for (let i = 0; i < 10; i++) { const startCol = 4 + i * 2; const endCol = startCol + 1; sheet.mergeCells(1, startCol, 1, endCol); const topCell = sheet.getCell(1, startCol); topCell.value = `Вісник (група) ${i + 1}`; topCell.alignment = { horizontal: 'center', vertical: 'middle' }; topCell.font = { bold: true }; setThinBorder(topCell); const recvCell = sheet.getCell(2, startCol); recvCell.value = 'Дата отримання'; recvCell.alignment = { horizontal: 'center', vertical: 'middle', wrapText: true }; recvCell.font = { bold: true }; setThinBorder(recvCell); const procCell = sheet.getCell(2, endCol); procCell.value = 'Дата опрацювання'; procCell.alignment = { horizontal: 'center', vertical: 'middle', wrapText: true }; procCell.font = { bold: true }; setThinBorder(procCell); sheet.getColumn(startCol).width = 16; sheet.getColumn(endCol).width = 16; } const objects = await new Promise((resolve, reject) => { db.all(` SELECT e.id as object_id, e.entrance_number as number, h.number as house_number, h.title as house_title, NULL as settlement, 'entrance' as type FROM entrance e JOIN house h ON e.house_id = h.id UNION ALL SELECT hm.id as object_id, hm.number as number, NULL as house_number, hm.title as house_title, hm.settlement, 'homestead' as type FROM homestead hm `, (err, rows) => { if (err) return reject(err); resolve(rows); }); }); let currentRow = 3; let objIndex = 1; for (const obj of objects) { const table = obj.type === 'entrance' ? 'entrance_history' : 'homestead_history'; const idField = obj.type === 'entrance' ? 'entrance_id' : 'homestead_id'; const history = await new Promise((resolve, reject) => { db.all(` SELECT date_start, date_end, name, group_id FROM ${table} WHERE ${idField} = ? ORDER BY date_start DESC `, [obj.object_id], (err, rows) => { if (err) return reject(err); resolve(rows); }); }); // № объекта const numCell = sheet.getCell(currentRow, 1); numCell.value = objIndex; numCell.alignment = { vertical: 'middle', horizontal: 'center' }; setThinBorder(numCell); sheet.mergeCells(currentRow, 1, currentRow + 1, 1); // Название объекта let objectName; if (obj.type === 'homestead' && obj.settlement) { objectName = `(${obj.settlement}) ${obj.house_title} ${obj.number}`; } else if (obj.type === 'homestead') { objectName = `${obj.house_title} ${obj.number}`; } else { objectName = `${obj.house_title} ${obj.house_number} (П. ${obj.number + 1})`; } const objCell = sheet.getCell(currentRow, 2); objCell.value = objectName; sheet.mergeCells(currentRow, 2, currentRow + 1, 2); objCell.alignment = { vertical: 'middle', horizontal: 'left' }; setThinBorder(objCell); // Последняя дата обработки let lastDate = null; for (const h of history) { if (h.date_end && h.date_end !== 0) { lastDate = new Date(h.date_end); break; } } const lastDateCell = sheet.getCell(currentRow, 3); lastDateCell.value = lastDate; lastDateCell.numFmt = 'dd.mm.yyyy'; sheet.mergeCells(currentRow, 3, currentRow + 1, 3); lastDateCell.alignment = { vertical: 'middle', horizontal: 'center' }; setThinBorder(lastDateCell); // История Вісників history.forEach((h, idx) => { const startCol = 4 + idx * 2; const endCol = startCol + 1; let name = h.name; if (h.name === 'Групова') name = `${h.name} (${h.group_id})`; // Верхняя ячейка имени const nameCell = sheet.getCell(currentRow, startCol); sheet.mergeCells(currentRow, startCol, currentRow, endCol); nameCell.value = name; nameCell.alignment = { horizontal: 'center' }; setTopCellBorder(nameCell); // Дата получения const startDate = h.date_start ? new Date(h.date_start) : null; const recvCell = sheet.getCell(currentRow + 1, startCol); recvCell.value = startDate; recvCell.numFmt = 'dd.mm.yyyy'; recvCell.alignment = { horizontal: 'center' }; setStartColBorder(recvCell); // Дата опрацювання const endDate = h.date_end ? new Date(h.date_end) : null; const procCell = sheet.getCell(currentRow + 1, endCol); procCell.value = endDate; procCell.numFmt = 'dd.mm.yyyy'; procCell.alignment = { horizontal: 'center' }; setEndColBorder(procCell); }); // Чётное затемнение только для блока данных if (objIndex % 2 === 0) { for (let col = 1; col <= 11; col++) { sheet.getCell(currentRow, col).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFEFEFEF' }, }; sheet.getCell(currentRow + 1, col).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFEFEFEF' }, }; } } currentRow += 2; objIndex++; } await workbook.xlsx.writeFile('Опрацювання територій.xlsx'); console.log('Файл создан: Опрацювання територій.xlsx'); db.close(); } exportData();