- Renommage questionnaire.nom → questionnaire.titre dans QuestionnaireReponse.tsx, AdminQuestionnaireEdit.tsx, questionnaireScheduler.ts, questionnaireExport.ts - Correction des requêtes SQL dans questionnaireDb.ts (suppression de la condition complete inexistante) - Ajout des colonnes valeurMin et valeurMax dans la table questions - Renommage de la colonne nom en titre dans la table questionnaires
146 lines
6.0 KiB
TypeScript
146 lines
6.0 KiB
TypeScript
/**
|
|
* Service d'export des rapports analytiques en PDF et Excel
|
|
*/
|
|
|
|
import ExcelJS from 'exceljs';
|
|
import { getGlobalStats, getInscriptionsByMonth, getTauxRemplissageByMonth, getParticipationByEtablissement, getParticipationByFonction } from './analyticsDb';
|
|
|
|
/**
|
|
* Génère un rapport Excel des statistiques analytiques
|
|
*/
|
|
export async function generateAnalyticsExcel(startDate?: Date, endDate?: Date): Promise<Buffer> {
|
|
const workbook = new ExcelJS.Workbook();
|
|
|
|
// Récupérer toutes les données
|
|
const globalStats = await getGlobalStats();
|
|
const inscriptionsByMonth = await getInscriptionsByMonth(startDate, endDate);
|
|
const tauxRemplissage = await getTauxRemplissageByMonth();
|
|
const participationEtablissement = await getParticipationByEtablissement();
|
|
const participationFonction = await getParticipationByFonction();
|
|
|
|
// Feuille 1: Statistiques globales
|
|
const statsSheet = workbook.addWorksheet('Statistiques globales');
|
|
statsSheet.columns = [
|
|
{ header: 'Indicateur', key: 'indicateur', width: 30 },
|
|
{ header: 'Valeur', key: 'valeur', width: 15 },
|
|
];
|
|
|
|
if (globalStats) {
|
|
statsSheet.addRows([
|
|
{ indicateur: 'Total Formations actives', valeur: globalStats.totalFormations },
|
|
{ indicateur: 'Total Séquences', valeur: globalStats.totalSequences },
|
|
{ indicateur: 'Séquences ouvertes', valeur: globalStats.sequencesOuvertes },
|
|
{ indicateur: 'Total Apprenants', valeur: globalStats.totalApprenants },
|
|
{ indicateur: 'Total Inscriptions', valeur: globalStats.totalInscriptions },
|
|
{ indicateur: 'Inscriptions confirmées', valeur: globalStats.inscriptionsConfirmees },
|
|
{ indicateur: 'Inscriptions en liste d\'attente', valeur: globalStats.inscriptionsListeAttente },
|
|
{ indicateur: 'Taux de remplissage moyen (%)', valeur: globalStats.tauxRemplissageMoyen },
|
|
]);
|
|
}
|
|
|
|
// Feuille 2: Inscriptions par mois
|
|
const inscriptionsSheet = workbook.addWorksheet('Inscriptions par mois');
|
|
inscriptionsSheet.columns = [
|
|
{ header: 'Mois', key: 'mois', width: 15 },
|
|
{ header: 'Total', key: 'total', width: 12 },
|
|
{ header: 'Confirmées', key: 'confirmees', width: 12 },
|
|
{ header: 'Liste d\'attente', key: 'listeAttente', width: 15 },
|
|
{ header: 'Annulées', key: 'annulees', width: 12 },
|
|
];
|
|
|
|
inscriptionsByMonth.forEach(item => {
|
|
inscriptionsSheet.addRow({
|
|
mois: item.mois,
|
|
total: Number(item.total),
|
|
confirmees: Number(item.confirmees),
|
|
listeAttente: Number(item.listeAttente),
|
|
annulees: Number(item.annulees),
|
|
});
|
|
});
|
|
|
|
// Feuille 3: Taux de remplissage
|
|
const tauxSheet = workbook.addWorksheet('Taux de remplissage');
|
|
tauxSheet.columns = [
|
|
{ header: 'Mois', key: 'mois', width: 15 },
|
|
{ header: 'Capacité totale', key: 'capaciteTotale', width: 15 },
|
|
{ header: 'Inscrits confirmés', key: 'inscritsConfirmes', width: 18 },
|
|
{ header: 'Taux de remplissage (%)', key: 'tauxRemplissage', width: 20 },
|
|
];
|
|
|
|
tauxRemplissage.forEach(item => {
|
|
tauxSheet.addRow({
|
|
mois: item.mois,
|
|
capaciteTotale: Number(item.capaciteTotale),
|
|
inscritsConfirmes: Number(item.inscritsConfirmes),
|
|
tauxRemplissage: Number(item.tauxRemplissage),
|
|
});
|
|
});
|
|
|
|
// Feuille 4: Participation par établissement
|
|
const etablissementSheet = workbook.addWorksheet('Participation par établissement');
|
|
etablissementSheet.columns = [
|
|
{ header: 'Code établissement', key: 'codeEtablissement', width: 20 },
|
|
{ header: 'Total apprenants', key: 'totalApprenants', width: 15 },
|
|
{ header: 'Total inscriptions', key: 'totalInscriptions', width: 18 },
|
|
{ header: 'Confirmées', key: 'confirmees', width: 12 },
|
|
{ header: 'Liste d\'attente', key: 'listeAttente', width: 15 },
|
|
{ header: 'Annulées', key: 'annulees', width: 12 },
|
|
];
|
|
|
|
participationEtablissement.forEach(item => {
|
|
etablissementSheet.addRow({
|
|
codeEtablissement: item.codeEtablissement,
|
|
totalApprenants: Number(item.totalApprenants),
|
|
totalInscriptions: Number(item.totalInscriptions),
|
|
confirmees: Number(item.inscriptionsConfirmees),
|
|
listeAttente: Number(item.inscriptionsListeAttente),
|
|
annulees: Number(item.inscriptionsAnnulees),
|
|
});
|
|
});
|
|
|
|
// Feuille 5: Participation par fonction
|
|
const fonctionSheet = workbook.addWorksheet('Participation par fonction');
|
|
fonctionSheet.columns = [
|
|
{ header: 'Fonction', key: 'fonction', width: 20 },
|
|
{ header: 'Total apprenants', key: 'totalApprenants', width: 15 },
|
|
{ header: 'Total inscriptions', key: 'totalInscriptions', width: 18 },
|
|
{ header: 'Confirmées', key: 'confirmees', width: 12 },
|
|
];
|
|
|
|
participationFonction.forEach(item => {
|
|
fonctionSheet.addRow({
|
|
fonction: item.fonction === 'directeur' ? 'Directeurs' :
|
|
item.fonction === 'chef_service' ? 'Chefs de service' : 'Autres',
|
|
totalApprenants: Number(item.totalApprenants),
|
|
totalInscriptions: Number(item.totalInscriptions),
|
|
confirmees: Number(item.inscriptionsConfirmees),
|
|
});
|
|
});
|
|
|
|
// Styliser les en-têtes
|
|
[statsSheet, inscriptionsSheet, tauxSheet, etablissementSheet, fonctionSheet].forEach(sheet => {
|
|
sheet.getRow(1).font = { bold: true };
|
|
sheet.getRow(1).fill = {
|
|
type: 'pattern',
|
|
pattern: 'solid',
|
|
fgColor: { argb: 'FF3B82F6' },
|
|
};
|
|
sheet.getRow(1).font = { bold: true, color: { argb: 'FFFFFFFF' } };
|
|
});
|
|
|
|
// Générer le buffer
|
|
const buffer = await workbook.xlsx.writeBuffer();
|
|
return Buffer.from(buffer);
|
|
}
|
|
|
|
/**
|
|
* Génère un rapport PDF des statistiques analytiques
|
|
* Note: Cette fonction retourne actuellement un placeholder
|
|
* Une implémentation complète nécessiterait une bibliothèque comme puppeteer ou pdfkit
|
|
*/
|
|
export async function generateAnalyticsPDF(startDate?: Date, endDate?: Date): Promise<Buffer> {
|
|
// Pour l'instant, retourner un message indiquant que la fonctionnalité est en développement
|
|
// Une implémentation complète nécessiterait de générer un HTML et de le convertir en PDF
|
|
throw new Error("L'export PDF sera implémenté dans une prochaine version");
|
|
}
|