This commit is contained in:
KONE SOREL 2025-12-31 10:58:28 +00:00
parent ea2242f79a
commit 503d141996
2 changed files with 270 additions and 158 deletions

View File

@ -61,8 +61,9 @@ $(function() {
// On ne lance le timer que si l'utilisateur est connecté (pas sur la vue Connexion)
if (vueActuelle !== "Connexion") {
setInterval(function() {
console.log("Actualisation gabarit");
raffraichier_gabarit();
/* On vérifie si l'onglet est actif pour éviter des requêtes inutiles
if (!document.hidden) {
@ -523,15 +524,8 @@ function afficher_quittances_police_periode() {
}
// 3. Préparation de l'interface (Loader)
$conteneur.html(`
<div class="text-center my-5 py-5">
<div class="spinner-border text-primary" role="status" style="width: 3rem; height: 3rem;">
<span class="visually-hidden">Chargement...</span>
</div>
<p class="mt-2 text-primary fw-bold">Chargement des quittances...</p>
</div>
`);
showLoader("#div_quittancepolice", { size: 3 });
// 4. Appel AJAX
$.ajax({
url: racine + "Ajaxfichepolice/",
@ -617,15 +611,9 @@ function imprimer_quittance_client(idQuittance) {
/* ===================================================
* 3. Préparation visuelle (Spinner)
* =================================================== */
divExport.innerHTML = `
<div class="text-center my-5 py-5">
<div class="spinner-border text-primary" role="status" style="width: 3rem; height: 3rem;">
<span class="visually-hidden">Chargement...</span>
</div>
<p class="mt-3 text-muted fw-bold">Génération du document client en cours...</p>
</div>
`;
showLoader("#div_export_quittance", { size: 3 });
/* ===================================================
* 4. Initialisation de l'instance Bootstrap
* =================================================== */
@ -794,8 +782,8 @@ function adherents_police()
function afficher_adherents_police()
{
$("#div_liste_adherent").html('<div style="padding-top:80px;"><img src="Bootstrap/images/loading.gif"/>&nbsp;&nbsp;<span style="font-size:15pt;">' + 'Veuillez patienter... / Please wait...' + '</span></div>');
showLoader("#div_liste_adherent", { size: 3 });
$.ajax({
url: $("#racineWeb").val()+"Ajaxlisteadherent/",
type : 'post',
@ -809,150 +797,274 @@ function afficher_adherents_police()
}
// --- I18n dictionary ---
const I18N = {
fr_FR: {
loading: "Affichage en cours...",
exportPdf: "Exporter les graphiques en PDF",
dashboardTitle: "Graphiques des sinistres",
charts: {
claimsTitle: "Répartition des sinistres",
claimsCount: "Nombre de sinistres",
monthlyTitle: "Évolution mensuelle",
monthlyCumulative: "Sinistres cumulés",
monthlySingle: "Sinistres uniques",
lossRatioTitle: "Ratio de sinistralité",
lossRatioLabel: "Ratio de sinistralité"
},
months: ["Jan", "Fév", "Mar", "Avr", "Mai", "Juin", "Juil", "Août", "Sep", "Oct", "Nov", "Déc"],
errors: {
ajax: "Impossible de charger les graphiques.",
pdfLib: "Erreur : jsPDF n'est pas chargé."
}
},
en_US: {
loading: "Loading in progress...",
exportPdf: "Export charts to PDF",
dashboardTitle: "Claims Charts",
charts: {
claimsTitle: "Claims distribution",
claimsCount: "Number of claims",
monthlyTitle: "Monthly trend",
monthlyCumulative: "Claims cumulative",
monthlySingle: "Claims single",
lossRatioTitle: "Loss ratio",
lossRatioLabel: "Loss ratio"
},
months: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
errors: {
ajax: "Unable to load charts.",
pdfLib: "Error: jsPDF is not loaded."
}
}
};
// --- Helpers ---
function getLang() {
const codeLangue = $("#codeLangue").val() || "fr_FR";
return I18N[codeLangue] ? codeLangue : "fr_FR";
}
function t(path) {
const lang = getLang();
return path.split(".").reduce((acc, key) => (acc && acc[key] != null ? acc[key] : null), I18N[lang]);
}
// Optional: normalize backend month keys to localized labels
function localizeMonths(months) {
const map = {
Jan: "Jan", Feb: "Feb", Mar: "Mar", Apr: "Apr", May: "May", Jun: "Jun",
Jul: "Jul", Aug: "Aug", Sep: "Sep", Oct: "Oct", Nov: "Nov", Dec: "Dec"
};
const langMonths = t("months");
// If backend already provides localized months, keep them; else map to language months by index
if (!Array.isArray(months) || months.length !== 12) return months;
const canonical = months.map(m => map[m] || m);
// Use the language month names but preserve array length and order
return langMonths && langMonths.length === 12 ? langMonths : canonical;
}
function showLoader(selector, options = {}) {
const { message = null, size = 3 } = options;
const text = message || t("loading");
const loaderHtml = `
<div class="text-center my-5 py-5 js-generic-loader">
<div class="spinner-border text-primary" role="status" style="width: ${size}rem; height: ${size}rem;">
<span class="visually-hidden">${text}</span>
</div>
<p class="mt-3 text-muted fw-bold">${text}</p>
</div>
`;
$(selector).html(loaderHtml);
}
function hideLoader(selector, contentHtml = "") {
$(selector).html(contentHtml);
}
function graphique_sinistre() {
// Spinner pendant le chargement
$("#div_graphique").html(`
<div class="text-center my-5 py-5">
<div class="spinner-border text-primary" role="status" style="width: 3rem; height: 3rem;">
<span class="visually-hidden">Chargement...</span>
</div>
<p class="mt-3 text-muted fw-bold">Affichage des graphiques en cours...</p>
showLoader("#div_graphique", { size: 3 });
$.ajax({
url: $("#racineWeb").val() + "Ajaxgraphiquesinistres/api/",
type: "get",
dataType: "json",
success: function (data) {
const exportLabel = t("exportPdf");
const html = `
<div class="text-end my-3">
<button id="exportPdfBtn" class="btn btn-danger">
<i class="fas fa-file-pdf"></i> ${exportLabel}
</button>
</div>
`);
<div class="row">
<div class="col-md-6 mb-4">
<div class="card shadow-sm">
<div class="card-body">
<h5 class="card-title text-primary">${t("charts.claimsTitle")}</h5>
<canvas id="claimsChart"></canvas>
</div>
</div>
</div>
<div class="col-md-6 mb-4">
<div class="card shadow-sm">
<div class="card-body">
<h5 class="card-title text-success">${t("charts.monthlyTitle")}</h5>
<canvas id="claimsMonthChart"></canvas>
</div>
</div>
</div>
<div class="col-md-12 mb-4">
<div class="card shadow-sm">
<div class="card-body">
<h5 class="card-title text-danger">${t("charts.lossRatioTitle")}</h5>
<canvas id="lossRatioChart"></canvas>
</div>
</div>
</div>
</div>
`;
hideLoader("#div_graphique", html);
$.ajax({
url: $("#racineWeb").val() + "Ajaxgraphiquesinistres/api/",
type: 'get',
dataType: 'json',
success: function(data) {
console.log("Réponse JSON reçue:", data);
// Render charts with localized labels
renderClaimsChart(data.claims);
renderClaimsMonthChart(data.claimsMonth);
renderLossRatioChart(data.lossRatio);
// Layout HTML
$("#div_graphique").html(`
<div class="text-end my-3">
<button id="exportPdfBtn" class="btn btn-danger">
<i class="fas fa-file-pdf"></i> Exporter le tableau de bord en PDF
</button>
</div>
<div class="row">
<div class="col-md-6 mb-4">
<div class="card shadow-sm">
<div class="card-body">
<h5 class="card-title text-primary">Répartition des sinistres</h5>
<canvas id="claimsChart"></canvas>
</div>
</div>
</div>
<div class="col-md-6 mb-4">
<div class="card shadow-sm">
<div class="card-body">
<h5 class="card-title text-success">Évolution mensuelle</h5>
<canvas id="claimsMonthChart"></canvas>
</div>
</div>
</div>
<div class="col-md-12 mb-4">
<div class="card shadow-sm">
<div class="card-body">
<h5 class="card-title text-danger">Ratio de sinistralité</h5>
<canvas id="lossRatioChart"></canvas>
</div>
</div>
</div>
</div>
`);
setupExportPdf();
},
error: function (err) {
console.error("Erreur AJAX:", err);
hideLoader("#div_graphique", `
<div class="alert alert-danger">${t("errors.ajax")}</div>
`);
}
});
}
// --- Graphiques Chart.js ---
// --- Charts ---
// 1. Répartition
new Chart(document.getElementById('claimsChart'), {
type: 'bar',
data: {
labels: data.claims.claimsLabels,
datasets: [{
label: 'Nombre de sinistres',
data: data.claims.claimsValues,
backgroundColor: 'rgba(54, 162, 235, 0.6)'
}]
}
});
function renderClaimsChart(claims) {
new Chart(document.getElementById("claimsChart"), {
type: "bar",
data: {
labels: claims.claimsLabels,
datasets: [{
label: t("charts.claimsCount"),
data: claims.claimsValues,
backgroundColor: "rgba(54, 162, 235, 0.6)"
}]
},
options: {
plugins: {
legend: { display: true }
},
scales: {
x: { title: { display: false } },
y: { title: { display: false }, beginAtZero: true }
}
}
});
}
// 2. Évolution mensuelle
new Chart(document.getElementById('claimsMonthChart'), {
type: 'line',
data: {
labels: data.claimsMonth.months,
datasets: [
{
label: 'Sinistres mensuels',
data: data.claimsMonth.monthlyClaims,
borderColor: 'rgba(255, 99, 132, 0.8)',
fill: false
},
{
label: 'Sinistres uniques',
data: data.claimsMonth.singleClaims,
borderColor: 'rgba(75, 192, 192, 0.8)',
fill: false
}
]
}
});
function renderClaimsMonthChart(claimsMonth) {
const labels = localizeMonths(claimsMonth.months);
// 3. Ratio de sinistralité
new Chart(document.getElementById('lossRatioChart'), {
type: 'line',
data: {
labels: data.lossRatio.lossRatioLabels,
datasets: [{
label: 'Ratio de sinistralité',
data: data.lossRatio.lossRatioValues,
borderColor: 'rgba(255, 206, 86, 0.8)',
fill: false
}]
}
});
// --- Export PDF ---
$("#exportPdfBtn").on("click", function() {
if (!window.jspdf) {
alert("Erreur : jsPDF n'est pas chargé.");
return;
}
const { jsPDF } = window.jspdf;
const pdf = new jsPDF('p', 'mm', 'a4');
pdf.setFontSize(18);
pdf.text("Tableau de bord - Synthèse", 10, 20);
// Ajout des graphiques
addChartToPdf(pdf, 'claimsChart', 'Répartition des sinistres', 40);
addChartToPdf(pdf, 'claimsMonthChart', 'Évolution mensuelle', 120);
pdf.addPage();
addChartToPdf(pdf, 'lossRatioChart', 'Ratio de sinistralité', 40);
pdf.save('Tableau_de_bord.pdf');
});
function addChartToPdf(pdf, canvasId, title, startY) {
const canvas = document.getElementById(canvasId);
if (canvas) {
const imgData = canvas.toDataURL('image/png', 1.0);
pdf.setFontSize(14);
pdf.text(title, 10, startY);
pdf.addImage(imgData, 'PNG', 10, startY + 5, 180, 60);
}
}
new Chart(document.getElementById("claimsMonthChart"), {
type: "line",
data: {
labels,
datasets: [
{
label: t("charts.monthlyCumulative"),
data: claimsMonth.monthlyClaims,
borderColor: "rgba(255, 99, 132, 0.8)",
backgroundColor: "rgba(255, 99, 132, 0.2)",
tension: 0.25,
fill: false
},
error: function(err) {
console.error("Erreur AJAX:", err);
$("#div_graphique").html(`
<div class="alert alert-danger">
Impossible de charger les graphiques.
</div>
`);
{
label: t("charts.monthlySingle"),
data: claimsMonth.singleClaims,
borderColor: "rgba(75, 192, 192, 0.8)",
backgroundColor: "rgba(75, 192, 192, 0.2)",
tension: 0.25,
fill: false
}
});
}
]
},
options: {
plugins: {
legend: { display: true }
},
scales: {
x: { title: { display: false } },
y: { title: { display: false }, beginAtZero: true }
}
}
});
}
function renderLossRatioChart(lossRatio) {
const labels = localizeMonths(lossRatio.lossRatioLabels);
new Chart(document.getElementById("lossRatioChart"), {
type: "line",
data: {
labels,
datasets: [{
label: t("charts.lossRatioLabel"),
data: lossRatio.lossRatioValues,
borderColor: "rgba(255, 206, 86, 0.8)",
backgroundColor: "rgba(255, 206, 86, 0.2)",
tension: 0.25,
fill: false
}]
},
options: {
plugins: {
legend: { display: true }
},
scales: {
x: { title: { display: false } },
y: { title: { display: false }, beginAtZero: true }
}
}
});
}
// --- Export PDF ---
function setupExportPdf() {
$("#exportPdfBtn").on("click", function () {
if (!window.jspdf) {
alert(t("errors.pdfLib"));
return;
}
const { jsPDF } = window.jspdf;
const pdf = new jsPDF("p", "mm", "a4");
pdf.setFontSize(18);
pdf.text(t("dashboardTitle"), 10, 20);
addChartToPdf(pdf, "claimsChart", t("charts.claimsTitle"), 40);
addChartToPdf(pdf, "claimsMonthChart", t("charts.monthlyTitle"), 120);
pdf.addPage();
addChartToPdf(pdf, "lossRatioChart", t("charts.lossRatioTitle"), 40);
pdf.save("Tableau_de_bord.pdf"); // you can also localize the filename if needed
});
}
function addChartToPdf(pdf, canvasId, title, startY) {
const canvas = document.getElementById(canvasId);
if (canvas) {
const imgData = canvas.toDataURL("image/png", 1.0);
pdf.setFontSize(14);
pdf.text(title, 10, startY);
pdf.addImage(imgData, "PNG", 10, startY + 5, 180, 60);
}
}

View File

@ -599,7 +599,7 @@ $activeChildId = $menuData['child'];
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<!-- Application Scripts -->
<script src="/Js/fonctions.js?ver=2025.12.31.03"></script>
<script src="/Js/fonctions.js?ver=2025.12.31.04"></script>
<?php if (est_anglophone()): ?>
<script src="/Js/datepicker-eng.js"></script>