979 lines
34 KiB
PHP
979 lines
34 KiB
PHP
<?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>
|