85 lines
2.4 KiB
JavaScript
85 lines
2.4 KiB
JavaScript
/**
|
|
* services/export-xlsx.js
|
|
* Génération XLSX avec ExcelJS (SuperAdmin uniquement)
|
|
*/
|
|
const ExcelJS = require('exceljs');
|
|
|
|
const HEADER_FILL = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF002D62' } };
|
|
const HEADER_FONT = { color: { argb: 'FFFFFFFF' }, bold: true, size: 10 };
|
|
const ALT_FILL = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFF1F5F9' } };
|
|
|
|
function styleHeader(row) {
|
|
row.eachCell(cell => {
|
|
cell.fill = HEADER_FILL;
|
|
cell.font = HEADER_FONT;
|
|
cell.alignment = { vertical: 'middle', horizontal: 'center' };
|
|
cell.border = { bottom: { style: 'thin', color: { argb: 'FFE2E8F0' } } };
|
|
});
|
|
row.height = 22;
|
|
}
|
|
|
|
function styleDataRow(row, alt) {
|
|
if (alt) {
|
|
row.eachCell(cell => { cell.fill = ALT_FILL; });
|
|
}
|
|
row.height = 16;
|
|
}
|
|
|
|
async function generateXlsx(view, data) {
|
|
const wb = new ExcelJS.Workbook();
|
|
wb.creator = 'RLA API';
|
|
wb.created = new Date();
|
|
|
|
const titles = {
|
|
synthese: 'Synthèse Globale',
|
|
alertes: 'Alertes Délais',
|
|
'en-service': 'Marchés en Service',
|
|
'en-cours': 'Marchés en Cours',
|
|
'par-region': 'Par Région',
|
|
clotures: 'Marchés Clôturés',
|
|
pilotage: 'Pilotage Proactif',
|
|
'matrice-risque': 'Matrice de Risque',
|
|
};
|
|
|
|
const title = titles[view] || view;
|
|
const ws = wb.addWorksheet(title.slice(0, 31));
|
|
|
|
const items = data.items || data.regions || [];
|
|
|
|
if (!items.length) {
|
|
ws.addRow(['Aucune donnée disponible.']);
|
|
return wb.xlsx.writeBuffer();
|
|
}
|
|
|
|
const sample = items[0];
|
|
const keys = Object.keys(sample).filter(k => !k.endsWith('_raw') && k !== 'id' && typeof sample[k] !== 'object');
|
|
|
|
// En-tête
|
|
ws.columns = keys.map(k => ({ header: k, key: k, width: 20 }));
|
|
styleHeader(ws.getRow(1));
|
|
|
|
// Données
|
|
items.forEach((item, i) => {
|
|
const row = ws.addRow(keys.map(k => item[k] ?? ''));
|
|
styleDataRow(row, i % 2 === 1);
|
|
});
|
|
|
|
// Freeze header
|
|
ws.views = [{ state: 'frozen', ySplit: 1 }];
|
|
|
|
// Onglet résumé si synthèse
|
|
if (view === 'synthese' && data.par_statut) {
|
|
const ws2 = wb.addWorksheet('Par Statut');
|
|
ws2.columns = [{ header: 'Statut', key: 'statut', width: 30 }, { header: 'Nombre', key: 'nb', width: 15 }];
|
|
styleHeader(ws2.getRow(1));
|
|
Object.entries(data.par_statut).forEach(([s, n], i) => {
|
|
const row = ws2.addRow({ statut: s, nb: n });
|
|
styleDataRow(row, i % 2 === 1);
|
|
});
|
|
}
|
|
|
|
return wb.xlsx.writeBuffer();
|
|
}
|
|
|
|
module.exports = { generateXlsx };
|