assure/Vue/Fichebeneficiaire/index.php
2025-12-05 09:34:39 +00:00

979 lines
34 KiB
PHP
Executable File

<?php
$datejour = $this->datejour;
$estcouvert = ($_SESSION['dateEcheancePolice_C']>=$datejour);
$sorti = $this->nettoyer($beneficiaire['sorti']);
$dateSortieBeneficiaire = $this->nettoyer($beneficiaire['dateSortieBeneficiaire']);
$estsorti = false;
if($sorti=="1")
{
$estsorti = ($dateSortieBeneficiaire<=$datejour);
$estcouvert = ($estcouvert && ($dateSortieBeneficiaire>$datejour));
}
$dateEffetCouvert = $_SESSION['dateEffetCouvert'];
if (est_anglophone())
{
$produit = $beneficiaire['produitEng'];
$naturepiece = $beneficiaire['naturepieceEng'];
$lienparente = $beneficiaire['lienparenteEng'];
$motifsortie = $beneficiaire['motifsortieEng'];
$etatbeneficiaire = $beneficiaire['etatbeneficiaireEng'];
if($beneficiaire['sexe']=="M"){
$sexe = "Male";
}else{
$sexe = "Female";
}
}
else
{
$produit = $beneficiaire['produit'];
$naturepiece = $beneficiaire['naturepiece'];
$lienparente = $beneficiaire['lienparente'];
$motifsortie = $beneficiaire['motifsortie'];
$etatbeneficiaire = $beneficiaire['etatbeneficiaire'];
if($beneficiaire['sexe']=="M"){
$sexe = "Masculin";
}else{
$sexe = "Féminin";
}
}
$codeEtatBeneficiaire = $beneficiaire['codeEtatBeneficiaire'];
$produit = $beneficiaire['produit'];
$bareme = $beneficiaire['bareme'];
$idBaremePriseEnCharge = $beneficiaire['idBaremePriseEnCharge'];
$vip = $beneficiaire['vip'];
$faceRegistered = $this->nettoyer($beneficiaire['faceRegistered']);
$fingerActif = '0';
$faceActif = '0';
$imgData = $_SESSION['photoAssureCrypte'];
?>
<style>
.form-check-card {
cursor: pointer;
transition: all 0.2s ease;
border: 2px solid #dee2e6 !important;
}
.form-check-card:hover {
border-color: #0d6efd !important;
background-color: #f8f9fa;
}
.form-check-input:checked + .form-check-label {
color: #0d6efd;
}
.form-check-input {
border-color: #0d6efd !important;
}
.form-check-card:has(.form-check-input:checked) {
border-color: #0d6efd !important;
background-color: #e7f1ff;
}
/* Amélioration tactile pour mobile */
@media (max-width: 768px) {
.mx-auto[style*="max-width: 400px"] {
max-width: 95% !important;
padding: 5px 10px;
}
.form-check-label, .form-check-label i {
font-size: 1.8rem !important;
}
.form-check-card {
padding: 1rem !important;
min-height: 54px;
}
.btn, .form-control-lg {
min-height: 54px;
font-size: 1.1rem;
}
.fs-5 {
font-size: 1.2rem !important;
}
}
/* Pour les très petits écrans */
@media (max-width: 480px) {
.form-check-card {
padding: 0.75rem !important;
min-height: 50px;
}
.btn, .form-control-lg {
min-height: 50px;
font-size: 1rem;
}
}
</style>
<div class="container-fluid mt-3">
<!-- Champs cachés -->
<input class="sr-only" type="text" id="nomForm" name="nomForm" value="ficheBeneficiaire">
<input class="sr-only" type="text" id="primeArchive" name="primeArchive" value="<?= $beneficiaire['primeArchive'] ?>">
<input class="sr-only" type="text" id="idPolice" name="idPolice" value="<?= $beneficiaire['idPolice'] ?>">
<input class="sr-only" type="text" id="idCollege" name="idCollege" value="<?= $beneficiaire['idCollege'] ?>">
<input class="sr-only" type="text" id="idAdherent" name="idAdherent" value="<?= $beneficiaire['idAdherent'] ?>">
<input class="sr-only" type="text" id="idBeneficiaire" name="idBeneficiaire" value="<?= $_SESSION['idBeneficiaire_C'] ?>">
<input class="sr-only" type="text" id="numeroAdherent" name="numeroAdherent" value="<?= $beneficiaire['numeroAdherent'] ?>">
<input class="sr-only" type="text" id="numeroBeneficiaire" name="numeroBeneficiaire" value="<?= $beneficiaire['numeroBeneficiaire'] ?>">
<INPUT class="sr-only" TYPE="text" id="faceRegistered" name="faceRegistered" value="<?= $faceRegistered ?>">
<div id="div_patienter"></div>
<!-- Carte principale style interface.jpg -->
<div class="card shadow-lg border-0 mb-4" style="border-radius: 15px;">
<div class="card-header bg-primary text-white py-3" style="border-radius: 15px 15px 0 0;">
<div class="row align-items-center">
<div class="col-8">
<h4 class="mb-0 text-center">
<i class="fas fa-id-card me-2"></i>
<?= ("Bénéficiaire")?>
</h4>
</div>
<div class="col-4 text-end">
<span class="badge bg-light text-dark fs-8">
<?= $beneficiaire['numeroBeneficiaire'] ?>
</span>
</div>
</div>
</div>
<div class="card-body">
<!-- Photo et informations principales -->
<div class="row">
<!-- Photo -->
<div class="col-12 col-md-3 text-center mb-4">
<?php if ($beneficiaire['faceRegistered']=="1"): ?>
<img src="data:image/jpg;base64,<?=$imgData?>"
class="img-fluid rounded-circle shadow"
style="width: 120px; height: 120px; object-fit: cover; cursor:pointer;"
data-bs-toggle="modal"
data-bs-target="#pop_photo"
alt="Photo du bénéficiaire">
<?php else: ?>
<div class="bg-light rounded-circle d-flex align-items-center justify-content-center mx-auto mb-2"
style="width: 120px; height: 120px; border:1px solid #000 !important;">
<i class="fas fa-user fa-3x text-secondary photo-vide"></i>
</div>
<?php if ($faceRegistered!="1" && $_SESSION['assureAjoutPhoto']=="1"):
?>
<!-- Boutons radios - Version mobile first avec largeur réduite -->
<div class="mb-3">
<div class="d-grid gap-2 mx-auto" style="max-width: 400px;">
<div class="form-check form-check-card py-2 px-3 rounded border">
<input class="form-check-input" type="radio" name="photo_choice" id="prendre_photo_radio" value="" checked>
<label class="form-check-label w-100 d-block fw-medium" for="prendre_photo_radio">
<i class="fas fa-camera me-2 text-primary"></i><?= _("Prendre une photo") ?>
</label>
</div>
<div class="form-check form-check-card py-2 px-3 rounded border">
<input class="form-check-input" type="radio" name="photo_choice" id="choisir_photo_radio" value="choisir">
<label class="form-check-label w-100 d-block fw-medium" for="choisir_photo_radio">
<i class="fas fa-folder-open me-2 text-primary"></i><?= _("Choisir une photo") ?>
</label>
</div>
</div>
</div>
<!-- Div pour "Prendre une photo" -->
<div id="div_prendre_photo" class="mt-2 mb-2">
<div class="mx-auto" style="max-width: 400px;">
<button class="sr-only" id="btn_pop_save_face" name="btn_pop_save_face" type="button" data-bs-toggle="modal" data-bs-target="#pop_rec_faciale"></button>
<button class="btn btn-primary w-100 py-3 fw-bold btn_autre" type="button" onClick="javascript:ebene_init_photo_face();">
<i class="fas fa-camera me-2 fs-5"></i><?= _("Lancer l'appareil photo") ?>
</button>
</div>
</div>
<!-- Div pour "Choisir une photo" -->
<div id="div_choisir_photo" class="d-none">
<div class="mx-auto" style="max-width: 400px;">
<div class="d-grid gap-2 mt-2 mb-2">
<form enctype="multipart/form-data" action="Fichebeneficiaire/<?= $_SESSION['idBeneficiaire_C'] ?>/" method="post">
<input class="form-control form-control-lg" name="fichier_upload" type="file" id="fichier_upload" accept="image/*" />
<button type="submit" name="submit" class="btn btn-success btn-lg w-100 py-3 btn_autre">
<i class="fas fa-upload me-2 fs-5"></i><?= _("Envoyer la photo") ?>
</button>
</form>
</div>
<h4 style="text-align: center">
<?php if ($message>" "): ?>
<div class="col-12 alert alert-danger">
<?= $message ?>
</div>
<?php endif; ?>
</h4>
</div>
</div>
<?php endif;?>
<?php endif; ?>
<?php if($vip=="1"): ?>
<div class="mt-2">
<span class="badge bg-warning text-dark">
<i class="fas fa-star me-1"></i>VIP
</span>
</div>
<?php endif; ?>
</div>
<!-- Informations personnelles -->
<div class="col-12 col-md-9">
<div class="row">
<div class="col-12 mb-2">
<h3 class="text-primary mb-1"><?= $beneficiaire['nomBeneficiaire'] . ' ' . $beneficiaire['prenomsBeneficiaire'] ?></h3>
<p class="text-muted mb-0"><?= _("Né(e) le").": ".dateLang($this->nettoyer($beneficiaire['dateNaissance']))." => ".$this->nettoyer($beneficiaire['age'])." "._("an(s)") ?></p>
</div>
<div class="col-12 col-md-6">
<div class="mb-2">
<small class="text-muted"><?= _("N° Adhérent") ?></small>
<p class="fw-bold mb-0"><?= $beneficiaire['numeroAdherent'] ?></p>
</div>
<div class="mb-2">
<small class="text-muted"><?= _("Lien Parenté") ?></small>
<p class="fw-bold mb-0"><?= $lienparente ?></p>
</div>
<div class="mb-2">
<small class="text-muted"><?= _("Genre") ?></small>
<p class="fw-bold mb-0"><?= $sexe ?></p>
</div>
</div>
<div class="col-12 col-md-6">
<div class="mb-2">
<small class="text-muted"><?= _("Téléphone") ?></small>
<p class="fw-bold mb-0"><?= $beneficiaire['telephonePortable'] ?></p>
</div>
<div class="mb-2">
<small class="text-muted"><?= _("État") ?></small>
<?php if ($estcouvert) : ?>
<span class="badge bg-success"><?= $etatbeneficiaire ?></span>
<?php else: ?>
<span class="badge bg-danger"><?= _("Non couvert") ?></span>
<?php endif; ?>
</div>
</div>
</div>
</div>
</div>
<hr>
<!-- Informations de police -->
<div class="row">
<div class="col-12 col-md-6">
<div class="mb-2">
<small class="text-muted"><?= _("Souscripteur") ?></small>
<p class="fw-bold mb-0"><?= $beneficiaire['nomClient'] ?></p>
</div>
</div>
<div class="col-12 col-md-6">
<div class="mb-2">
<small class="text-muted"><?= _("Collège / N° Police") ?></small>
<p class="fw-bold mb-0"><?= $beneficiaire['libelleCollege'] ?> / <?= $beneficiaire['numeroPolice'] ?></p>
</div>
</div>
</div>
</div>
</div>
<!-- Section des plafonds et consommations -->
<div class="row">
<!-- Plafond Famille -->
<div class="col-12 col-lg-6 mb-4">
<div class="card shadow-sm h-100">
<div class="d-none d-md-block">
<div class="card-header bg-secondary py-2">
<h6 class="mb-0 text-center text-light">
<i class="fa fa-file-invoice-dollar me-2"></i><i class="fas fa-users me-2"></i>
<?= _("Dépenses familiales")." ".$_SESSION['exercieReference_C'] ?>
</h6>
</div>
</div>
<!-- Affichage mobile (cartes) -->
<div class="d-md-none">
<div class="card-header bg-dark py-2">
<h6 class="mb-0 text-center text-light">
<i class="fa fa-file-invoice-dollar me-2"></i><i class="fas fa-users me-2"></i>
<?= _("Dépenses familiales")." ".$_SESSION['exercieReference_C'] ?>
</h6>
</div>
</div>
<div class="card-body text-center">
<?php
$plafondGlobalFamille = $this->nettoyer($police['plafond']);
$consommationGlobaleFamille = $this->nettoyer($police['consommation']);
$niveauGlobalConsoFamille = ($consommationGlobaleFamille/$plafondGlobalFamille)*100;
$soldeConsommation = $this->nettoyer($police['soldeConsommation']);
?>
<div class="row mb-2 mt-2">
<div class="col-4">
<div class="rounded p-2 border border-primary">
<small class="text-muted d-block"><?= _("Dépense") ?></small>
<h4 class="text-primary mb-0"><?= format_N($consommationGlobaleFamille) ?></h4>
</div>
</div>
<div class="col-4">
<div class="rounded p-2 border border-success">
<small class="text-muted d-block"><?= _("Plafond") ?></small>
<h4 class="text-success mb-0"><?= format_N($plafondGlobalFamille) ?></h4>
</div>
</div>
<div class="col-4">
<div class="rounded p-2 border border-danger">
<small class="text-muted d-block"><?= _("Solde") ?></small>
<h4 class="text-danger mb-0"><?= format_N($soldeConsommation) ?></h4>
</div>
</div>
</div>
<div class="progress mb-3" >
<div class="progress-bar <?= $niveauGlobalConsoFamille >= 80 ? 'bg-danger' : ($niveauGlobalConsoFamille >= 50 ? 'bg-warning' : 'bg-success') ?>"
style="width: <?= min($niveauGlobalConsoFamille, 100) ?>%">
<?= number_format($niveauGlobalConsoFamille, 1) ?>%
</div>
</div>
<?php if($police['soldeConsommation']<="0") :?>
<div class="alert alert-danger py-1 mb-0">
<i class="fas fa-exclamation-triangle me-1"></i>
<?= _("Plafond familial atteint!") ?>
</div>
<?php endif; ?>
</div>
</div>
</div>
<!-- Plafond Bénéficiaire -->
<div class="col-12 col-lg-6 mb-4">
<div class="card shadow-sm h-100">
<div class="d-none d-md-block">
<div class="card-header bg-secondary py-2">
<h6 class="mb-0 text-center text-light">
<i class="fa fa-file-invoice-dollar me-2"></i><i class="fas fa-user me-2"></i>
<?= _("Dépenses individuelles")." ".$_SESSION['exercieReference_C'] ?>
</h6>
</div>
</div>
<!-- Affichage mobile (cartes) -->
<div class="d-md-none">
<div class="card-header bg-dark py-2">
<h6 class="mb-0 text-center text-light">
<i class="fa fa-file-invoice-dollar me-2"></i><i class="fas fa-user me-2"></i>
<?= _("Dépenses individuelles")." ".$_SESSION['exercieReference_C'] ?>
</h6>
</div>
</div>
<div class="card-body text-center">
<?php
$plafondGlobalBeneficiaire = $this->nettoyer($college['plafond']);
$consommationGlobaleBenef = $this->nettoyer($college['consommation']);
$niveauGlobalConsoBenef = ($consommationGlobaleBenef/$plafondGlobalBeneficiaire)*100;
$soldeConsommation = $this->nettoyer($college['soldeConsommation']);
?>
<div class="row mb-2 mt-2">
<div class="col-4">
<div class="border rounded p-2 border-primary">
<small class="text-muted d-block"><?= _("Dépense") ?></small>
<h4 class="text-primary mb-0"><?= format_N($consommationGlobaleBenef) ?></h4>
</div>
</div>
<div class="col-4">
<div class="border rounded p-2 border-success">
<small class="text-muted d-block"><?= _("Plafond") ?></small>
<h4 class="text-success mb-0"><?= format_N($plafondGlobalBeneficiaire) ?></h4>
</div>
</div>
<div class="col-4">
<div class="rounded p-2 border border-danger">
<small class="text-muted d-block"><?= _("Solde") ?></small>
<h4 class="text-danger mb-0"><?= format_N($soldeConsommation) ?></h4>
</div>
</div>
</div>
<div class="progress mb-3">
<div class="progress-bar <?= $niveauGlobalConsoBenef >= 80 ? 'bg-danger' : ($niveauGlobalConsoBenef >= 50 ? 'bg-warning' : 'bg-success') ?>"
style="width: <?= min($niveauGlobalConsoBenef, 100) ?>%">
<?= number_format($niveauGlobalConsoBenef, 1) ?>%
</div>
</div>
<?php if($college['soldeConsommation']<="0") :?>
<div class="alert alert-danger py-1 mb-0">
<i class="fas fa-exclamation-triangle me-1"></i>
<?= _("Plafond personnel atteint!") ?>
</div>
<?php endif; ?>
</div>
</div>
</div>
</div>
<!-- Message si aucune donnée -->
<div class="card shadow-sm mb-4">
<div class="d-none d-md-block">
<div class="card-header bg-secondary py-2">
<h6 class="mb-0 text-center text-light">
<i class="fa fa-file-invoice-dollar me-2"></i><i class="fa fa-calendar-alt me-2"></i>
<?= _("Dépenses individuelles par mois") ?>
</h6>
</div>
</div>
<!-- Affichage mobile (cartes) -->
<div class="d-md-none">
<div class="card-header bg-dark py-2">
<h6 class="mb-0 text-center text-light">
<i class="fa fa-file-invoice-dollar me-2"></i><i class="fa fa-calendar-alt me-2"></i>
<?= _("Dépenses individuelles par mois") ?>
</h6>
</div>
</div>
<!-- Responsive Area Chart -->
<div class="row mt-4">
<div class="col-12 mb-4">
<div class="card shadow h-100">
<div class="card-header py-3 d-flex flex-column flex-md-row justify-content-between align-items-center">
<div class="mt-2 mt-md-0">
<button id="exportTrendBtn" class="btn btn-sm btn-danger mr-2">
<i class="fas fa-download"></i> PDF
</button>
<small class="text-muted"><?= _("Évolution sur 12 mois") ?></small>
</div>
</div>
<div class="card-body">
<div class="chart-container" style="position: relative; height:300px; width:100%">
<canvas id="expenseTrendChart"></canvas>
</div>
</div>
</div>
</div>
</div>
<!-- Bar Chart Section -->
<div class="row mt-4">
<div class="col-12 mb-4">
<div class="card shadow h-100">
<div class="d-none d-md-block">
<div class="card-header bg-secondary py-2">
<h6 class="mb-0 text-center text-light">
<i class="fa fa-file-invoice-dollar me-2"></i><i class="fa fa-chart-bar me-2"></i>
<?= _("Dépenses individuelles par garantie") ?>
</h6>
</div>
</div>
<!-- Affichage mobile (cartes) -->
<div class="d-md-none">
<div class="card-header bg-dark py-2">
<h6 class="mb-0 text-center text-light">
<i class="fa fa-file-invoice-dollar me-2"></i><i class="fa fa-chart-bar me-2"></i>
<?= _("Dépenses individuelles par garantie") ?>
</h6>
</div>
</div>
<div class="card-header py-3 d-flex justify-content-between align-items-center">
<button id="exportBarBtn" class="btn btn-sm btn-danger">
<i class="fas fa-download"></i> PDF
</button>
</div>
<div class="card-body">
<div class="chart-container" style="position: relative; height:400px; width:100%">
<canvas id="depensesChart"></canvas>
</div>
</div>
</div>
</div>
</div>
<script>
// Configuration commune
(function() {
// Récupération de la devise depuis PHP
const userCurrency = '<?= isset($_SESSION['devise_C']) ? substr($_SESSION['devise_C'],0,1) : 'F CFA' ?>';
// Configuration des devises
const currencyFormats = {
'F CFA': {
symbol: 'F CFA',
format: (value) => new Intl.NumberFormat('fr-FR').format(value) + ' F'
},
'€': {
symbol: '€',
format: (value) => new Intl.NumberFormat('fr-FR', {style: 'currency', currency: 'EUR'}).format(value)
},
'$': {
symbol: '$',
format: (value) => new Intl.NumberFormat('fr-FR', {style: 'currency', currency: 'USD'}).format(value)
},
'XOF': {
symbol: 'F CFA',
format: (value) => new Intl.NumberFormat('fr-FR').format(value) + ' F'
}
};
// Format monétaire dynamique
const formatMoney = (value) => {
const currencyConfig = currencyFormats[userCurrency] || currencyFormats['F CFA'];
return currencyConfig.format(value);
};
// Format pourcentage
const formatPercentage = (value, total) => {
const percentage = (value * 100 / total).toFixed(1);
return percentage + '%';
};
// Détection mobile
const isMobile = window.matchMedia("(max-width: 768px)").matches;
// Génération des couleurs
const generateColors = (count) => {
const palette = [
'#4e73df', '#1cc88a', '#36b9cc', '#f6c23e',
'#e74a3b', '#858796', '#5a5c69', '#3a3b45',
'#2e59a9', '#17a673', '#2c9faf', '#dda20a'
];
return palette.slice(0, count).concat(
Array.from({length: Math.max(0, count - palette.length)}, (_, i) => {
const hue = Math.floor(360 * (i / Math.max(1, count - palette.length)));
return `hsl(${hue}, 70%, 60%)`;
})
);
};
// Fonction pour générer une légende personnalisée
function generateCustomLegend(chart, containerId) {
const legendContainer = document.getElementById(containerId);
legendContainer.innerHTML = '';
const items = chart.data.datasets[0].data.map((value, i) => {
const total = chart.data.datasets[0].data.reduce((a, b) => a + b, 0);
const percentage = formatPercentage(value, total);
return `
<div class="d-inline-block mx-2 my-1">
<span class="legend-color" style="
display: inline-block;
width: 12px;
height: 12px;
background-color: ${chart.data.datasets[0].backgroundColor[i]};
border: 1px solid #fff;
vertical-align: middle;
"></span>
<span class="legend-text small ml-1">
${chart.data.labels[i]}: ${formatMoney(value)} (${percentage})
</span>
</div>
`;
});
legendContainer.innerHTML = items.join('');
}
// Fonction pour exporter un graphique en PDF
function exportChartToPDF(chartId, fileName) {
const { jsPDF } = window.jspdf;
const canvas = document.getElementById(chartId);
html2canvas(canvas).then(canvasImage => {
const imgData = canvasImage.toDataURL('image/png');
const pdf = new jsPDF({
orientation: canvasImage.width > canvasImage.height ? 'landscape' : 'portrait'
});
const pageWidth = pdf.internal.pageSize.getWidth();
const pageHeight = pdf.internal.pageSize.getHeight();
const ratio = canvasImage.height / canvasImage.width;
let imgWidth = pageWidth - 20;
let imgHeight = imgWidth * ratio;
if (imgHeight > pageHeight - 20) {
imgHeight = pageHeight - 20;
imgWidth = imgHeight / ratio;
}
pdf.addImage(imgData, 'PNG',
(pageWidth - imgWidth) / 2,
(pageHeight - imgHeight) / 2,
imgWidth,
imgHeight
);
pdf.save(fileName + '.pdf');
});
}
// Graphique d'évolution des dépenses
const dataMois = <?= $dataConsoParMois ?>;
const trendCtx = document.getElementById('expenseTrendChart').getContext('2d');
const trendChart = new Chart(trendCtx, {
type: 'line',
data: {
labels: dataMois.mois,
datasets: [{
label: '<?= _("Montant dépensé") ?>',
data: dataMois.consos,
backgroundColor: 'rgba(78, 115, 223, 0.05)',
borderColor: 'rgba(78, 115, 223, 1)',
borderWidth: 2,
pointBackgroundColor: 'rgba(78, 115, 223, 1)',
pointRadius: isMobile ? 3 : 4,
pointHoverRadius: 6,
fill: true,
tension: 0.3
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
display: false
},
tooltip: {
mode: 'index',
intersect: false,
callbacks: {
label: function(context) {
return context.dataset.label + ': ' + formatMoney(context.parsed.y);
}
}
}
},
scales: {
x: {
grid: {
display: false
},
ticks: {
maxRotation: isMobile ? 45 : 0,
autoSkip: true,
maxTicksLimit: isMobile ? 6 : 12
}
},
y: {
beginAtZero: false,
ticks: {
callback: function(value) {
return formatMoney(value);
}
},
grid: {
color: 'rgba(0, 0, 0, 0.05)'
}
}
},
interaction: {
mode: 'nearest',
axis: 'x',
intersect: false
}
}
});
// Graphique des dépenses par garantie
const dataConso = <?= $dataConsoParGaranties ?>;
const barCtx = document.getElementById('depensesChart').getContext('2d');
const barChart = new Chart(barCtx, {
type: 'bar',
data: {
labels: dataConso.garanties,
datasets: [{
label: 'Dépenses',
data: dataConso.depenses,
backgroundColor: 'rgba(54, 162, 235, 0.7)',
borderColor: 'rgba(54, 162, 235, 1)',
borderWidth: 1
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
annotation: {
annotations: dataConso.plafonds.map((plafond, index) => {
if (plafond === null) return null;
return {
type: 'line',
yMin: plafond,
yMax: plafond,
borderColor: 'rgba(255, 99, 132, 0.7)',
borderWidth: 2,
borderDash: [6, 6],
label: {
content: `Plafond: ${formatMoney(plafond)}`,
enabled: true,
position: 'right'
}
};
}).filter(annotation => annotation !== null)
},
legend: {
display: false
},
tooltip: {
callbacks: {
label: function(context) {
const plafond = dataConso.plafonds[context.dataIndex];
let tooltip = `Dépenses: ${formatMoney(context.parsed.y)}`;
if (plafond !== null) {
const pourcentage = Math.min(100, Math.round((context.parsed.y / plafond) * 100));
tooltip += ` (${pourcentage}% du plafond)`;
} else {
tooltip += ' (plafond illimité)';
}
return tooltip;
}
}
}
},
scales: {
y: {
beginAtZero: true,
title: {
display: true,
text: `Montant des dépenses`,
font: {
weight: 'bold'
}
},
ticks: {
callback: function(value) {
return formatMoney(value);
}
},
suggestedMax: Math.max(...dataConso.depenses) * 1.5
},
x: {
title: {
display: true,
text: 'Garanties',
font: {
weight: 'bold'
}
},
grid: {
display: false
}
}
}
}
});
// Boutons d'export PDF
document.getElementById('exportTrendBtn').addEventListener('click', () => {
exportChartToPDF('expenseTrendChart', 'evolution_depenses_mensuelles');
});
document.getElementById('exportBarBtn').addEventListener('click', () => {
exportChartToPDF('depensesChart', 'depenses_par_garantie');
});
})();
</script>
<style>
/* Styles communs pour tous les graphiques */
.chart-container {
position: relative;
width: 100%;
min-height: 300px;
}
#pieChartLegend {
font-size: 0.8rem;
line-height: 1.4;
}
.legend-text {
vertical-align: middle;
}
.btn-export {
padding: 0.25rem 0.5rem;
font-size: 0.75rem;
}
@media (max-width: 768px) {
#pieChartLegend {
font-size: 0.7rem;
}
.chart-container {
height: 60vh;
}
.card-header {
flex-direction: column;
align-items: flex-start !important;
}
.btn-export {
margin-top: 0.5rem;
align-self: flex-end;
}
}
</style>
</div>
</div>
</div>
<?php
if($faceRegistered!="1" && $_SESSION['assureAjoutPhoto']=="1")
{
include 'faceebene/ebenetraitementimage.php';
}
?>
<style>
/* Styles modernes inspirés de l'interface.jpg */
.card {
border: none;
border-radius: 12px;
}
.badge {
font-weight: 500;
}
/* Styles pour mobile */
@media (max-width: 768px) {
.card-body {
padding: 1rem;
}
.btn {
padding: 0.3rem 0.6rem;
font-size: 0.8rem;
}
}
/* Version ultra-mobile */
@media (max-width: 576px) {
.card-body {
padding: 0.75rem;
}
.btn-sm {
font-size: 0.7rem;
padding: 0.2rem 0.4rem;
}
.row.text-center .col {
margin-bottom: 0.5rem;
}
}
/* Style pour les badges VIP */
.bg-warning {
background: linear-gradient(45deg, #ffc107, #ff9800) !important;
}
/* Ombres portées */
.shadow-lg {
box-shadow: 0 4px 20px rgba(0,0,0,0.1) !important;
}
/* Bordures arrondies */
.rounded-circle {
border: 3px solid #e3f2fd;
}
</style>
<script>
// Initialisation des tooltips Bootstrap
document.addEventListener('DOMContentLoaded', function() {
// Tooltips
var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
return new bootstrap.Tooltip(tooltipTriggerEl);
});
// Animation des progress bars
setTimeout(function() {
document.querySelectorAll('.progress-bar').forEach(function(bar) {
const width = bar.style.width;
bar.style.width = '0';
setTimeout(function() {
bar.style.width = width;
}, 100);
});
}, 500);
});
</script>
<script>
document.addEventListener('DOMContentLoaded', function() {
const prendreRadio = document.getElementById('prendre_photo_radio');
const choisirRadio = document.getElementById('choisir_photo_radio');
const divPrendre = document.getElementById('div_prendre_photo');
const divChoisir = document.getElementById('div_choisir_photo');
// Fonction pour gérer l'affichage
function togglePhotoDivs() {
if (prendreRadio.checked) {
divPrendre.classList.remove('d-none');
divChoisir.classList.add('d-none');
} else {
divPrendre.classList.add('d-none');
divChoisir.classList.remove('d-none');
}
}
if(prendreRadio){
// Événements sur les boutons radios
prendreRadio.addEventListener('change', togglePhotoDivs);
choisirRadio.addEventListener('change', togglePhotoDivs);
// Initialisation
togglePhotoDivs();
}
});
</script>