Merge branch 'main' of https://git.ebene.ovh/ebene/prestation
This commit is contained in:
commit
fb2bedd0e7
15
.gitignore
vendored
15
.gitignore
vendored
|
|
@ -1,5 +1,10 @@
|
|||
Config/
|
||||
Config
|
||||
Config/dev.ini
|
||||
vendor/
|
||||
vendor
|
||||
Config/
|
||||
Config
|
||||
Config/dev.ini
|
||||
vendor/
|
||||
vendor
|
||||
logs/
|
||||
logs
|
||||
Cron/prod.ini
|
||||
Temp/
|
||||
Temp
|
||||
24
Controleur/ControleurAjaxdemandereconnaissancefaciale.php
Executable file
24
Controleur/ControleurAjaxdemandereconnaissancefaciale.php
Executable file
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
require_once 'Framework/Controleur.php';
|
||||
require_once 'Modele/Beneficiaire.php';
|
||||
|
||||
class ControleurAjaxdemandereconnaissancefaciale extends Controleur {
|
||||
|
||||
private $beneficiaire;
|
||||
|
||||
public function __construct() {
|
||||
$this->beneficiaire = new Beneficiaire();
|
||||
}
|
||||
|
||||
public function index() {
|
||||
$this->beneficiaire->demandereconnaissancefaciale();
|
||||
$this->genererVueAjax();
|
||||
}
|
||||
|
||||
public function checkdemandereconnaissancefaciale()
|
||||
{
|
||||
$demandereconnaissancefaciale = $this->beneficiaire->checkdemandereconnaissancefaciale();
|
||||
$codeEtat = $demandereconnaissancefaciale["codeEtat"];
|
||||
$this->genererVueAjax(array('demandereconnaissancefaciale' => $demandereconnaissancefaciale, 'codeEtat' => $codeEtat));
|
||||
}
|
||||
}
|
||||
|
|
@ -17,7 +17,7 @@ class ControleurConnexion extends Controleur
|
|||
private $garantie;
|
||||
private $societeusercentral;
|
||||
|
||||
private $menuvue;
|
||||
private $menuvue;
|
||||
public function __construct()
|
||||
{
|
||||
$this->utilisateur = new Utilisateur();
|
||||
|
|
@ -770,7 +770,15 @@ class ControleurConnexion extends Controleur
|
|||
$this->rediriger("Kine");
|
||||
break;
|
||||
default:
|
||||
$this->rediriger("Recherche");
|
||||
$carteAvecDonnees = $utilisateur['carteAvecDonnees'];
|
||||
if($carteAvecDonnees=="1")
|
||||
{
|
||||
$this->rediriger("Rechercheparcarte");
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->rediriger("Recherche");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ require_once 'Modele/Bonpec.php';
|
|||
require_once 'Modele/Medecin.php';
|
||||
require_once 'Modele/Garantiesbaremepriseencharge.php';
|
||||
|
||||
class ControleurFichebeneficiaire extends Controleur {
|
||||
class ControleurFichebeneficiaire extends Controleur {
|
||||
private $menuvue;
|
||||
|
||||
private $beneficiaire;
|
||||
|
|
@ -209,6 +209,13 @@ class ControleurFichebeneficiaire extends Controleur {
|
|||
|
||||
$sexe = $beneficiaire['sexe'];
|
||||
$raison = $this->raison->getraisonconsultation($sexe);
|
||||
|
||||
// KANE => 24/02/205 => réponse demande reconnaissance faciale
|
||||
$etatDemanderecFac = $this->beneficiaire->fn_etat_demandereconnaissancefaciale();
|
||||
$libelleEtatDemanderecFac = $this->beneficiaire->fn_libelle_etat_demandereconnaissancefaciale();
|
||||
$messagePrestataireRecFac = $this->beneficiaire->fn_message_demandereconnaissancefaciale();
|
||||
|
||||
// if (in_array($etatDemanderecFac, ["-1", "3", "4", "5"] , true)){}
|
||||
|
||||
$this->genererVue(array(
|
||||
'beneficiaire' => $beneficiaire,
|
||||
|
|
@ -235,7 +242,10 @@ class ControleurFichebeneficiaire extends Controleur {
|
|||
'bonNonLivrePha' => $bonNonLivrePha,
|
||||
'nuit' => $nuit,
|
||||
'acte' => $acte,
|
||||
'specialite' => $specialite
|
||||
'specialite' => $specialite,
|
||||
'etatDemanderecFac' => $etatDemanderecFac,
|
||||
'libelleEtatDemanderecFac' => $libelleEtatDemanderecFac,
|
||||
'messagePrestataireRecFac' => $messagePrestataireRecFac
|
||||
));
|
||||
}
|
||||
|
||||
|
|
@ -439,4 +449,11 @@ class ControleurFichebeneficiaire extends Controleur {
|
|||
$this->beneficiaire->envoyer_otp($otpValue);
|
||||
$this->rediriger("Fichebeneficiaire");
|
||||
}
|
||||
|
||||
public function demandereconnaissancefaciale() {
|
||||
$telephoneAutre = $this->requete->getParametreFormulaire("telephoneAutre");
|
||||
$this->beneficiaire->demandereconnaissancefaciale($telephoneAutre);
|
||||
$this->rediriger("Fichebeneficiaire");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -35,15 +35,6 @@ class ControleurRechercheparcarte extends Controleur {
|
|||
$msgErreur="";
|
||||
}
|
||||
|
||||
/*
|
||||
var_dump(
|
||||
array(
|
||||
"msgErreur" => $msgErreur,
|
||||
)
|
||||
);
|
||||
exit();
|
||||
*/
|
||||
|
||||
$this->beneficiaire->getModeBiometrie();
|
||||
|
||||
$_SESSION['p_okId'] = "-1";
|
||||
|
|
@ -62,43 +53,29 @@ class ControleurRechercheparcarte extends Controleur {
|
|||
|
||||
if(isset($_POST['donneesCarte']))
|
||||
{
|
||||
// IS1 => Inter-Sante V1
|
||||
$donneesCarte = $_POST['donneesCarte']; // ex: "IS1|ebene|ESI6936000602"
|
||||
$versionTagCarteEncours = $this->beneficiaire->getVersionTagCarteEncours();
|
||||
$donneesCarte = $_POST['donneesCarte'];
|
||||
$parts = explode('|', $donneesCarte);
|
||||
|
||||
// var_dump($parts);
|
||||
// exit();
|
||||
$versionTagCarte = base64_decode($parts[0]);
|
||||
$codeEntite = base64_decode($parts[1]);
|
||||
|
||||
if (count($parts) !== 3 || $parts[0] !== 'IS1') {
|
||||
if (count($parts) !== 5 || $versionTagCarte !== $versionTagCarteEncours || $codeEntite != $_SESSION['p_codeSociete']) {
|
||||
$msgErreur = 'Carte invalide / Invalid card';
|
||||
}
|
||||
else{
|
||||
$codeEntite = $parts[1];
|
||||
$numeroBeneficiaireCarte = $parts[2];
|
||||
$numeroBeneficiaireCarte = base64_decode($parts[2]);
|
||||
$tagUuid = $parts[3];
|
||||
|
||||
$donneesCarte=trim($_POST['donneesCarte']);
|
||||
|
||||
/*
|
||||
var_dump(
|
||||
array(
|
||||
"codeEntite" => $codeEntite,
|
||||
"numeroBeneficiaireCarte" => $numeroBeneficiaireCarte,
|
||||
)
|
||||
);
|
||||
exit();
|
||||
*/
|
||||
|
||||
if($codeEntite<=" " || $numeroBeneficiaireCarte<=" ")
|
||||
if($codeEntite<=" " || $numeroBeneficiaireCarte<=" " || $tagUuid<=" ")
|
||||
{
|
||||
$msgErreur = 'Carte invalide / Invalid card';
|
||||
}
|
||||
else
|
||||
{
|
||||
// faire le traitement de la carte ici
|
||||
|
||||
$derniernumerobeneficiaires = $this->beneficiaire->getnumerobeneficiairesperdu($numeroBeneficiaireCarte);
|
||||
|
||||
$beneficiaires = $this->beneficiaire->getBeneficiaire($numeroBeneficiaireCarte);
|
||||
$beneficiaires = $this->beneficiaire->getBeneficiaireTag($versionTagCarte, $codeEntite, $numeroBeneficiaireCarte, $tagUuid);
|
||||
|
||||
$nbLignes = $beneficiaires->rowCount();
|
||||
|
||||
|
|
@ -106,30 +83,12 @@ class ControleurRechercheparcarte extends Controleur {
|
|||
{
|
||||
$beneficiaires->closeCursor(); // Fermer le curseur
|
||||
$msgErreur = "$numeroBeneficiaireCarte : Carte introuvable / Card not found";
|
||||
|
||||
/*
|
||||
var_dump(
|
||||
array(
|
||||
"nbLignes" => $nbLignes,
|
||||
"msgErreur" => $msgErreur,
|
||||
)
|
||||
);
|
||||
exit();
|
||||
*/
|
||||
}
|
||||
else
|
||||
{
|
||||
$beneficiaire = $beneficiaires->fetch();
|
||||
$beneficiaire = $beneficiaires->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
$beneficiaires->closeCursor(); // Fermer le curseur
|
||||
/*
|
||||
var_dump(
|
||||
array(
|
||||
"beneficiaire" => $beneficiaire,
|
||||
"nbLignes" => $nbLignes,
|
||||
)
|
||||
);
|
||||
exit();
|
||||
*/
|
||||
|
||||
$_SESSION['p_idBeneficiaire_C'] = $beneficiaire['idBeneficiaire'];
|
||||
$_SESSION['p_idBeneficiaire_sav'] = $_SESSION['p_idBeneficiaire_C'];
|
||||
|
|
@ -140,9 +99,6 @@ class ControleurRechercheparcarte extends Controleur {
|
|||
}
|
||||
}
|
||||
|
||||
// var_dump($msgErreur);
|
||||
// exit();
|
||||
|
||||
$this->genererVue(array('msgErreur' => $msgErreur));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,14 +1,16 @@
|
|||
<?php
|
||||
require_once 'Functions.php';
|
||||
require_once 'Societeusercentral.php';
|
||||
|
||||
class Cronnettoyerfihierstemp
|
||||
{
|
||||
private $societeusercentral;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
// $this->societeusercentral = new Societeusercentral();
|
||||
}
|
||||
|
||||
// function suppression($dossier_traite , $extension_choisie, $age_requis)
|
||||
function suppression($dossier_traite , $age_requis)
|
||||
{
|
||||
$repertoire = opendir($dossier_traite);
|
||||
|
|
@ -19,20 +21,10 @@ class Cronnettoyerfihierstemp
|
|||
|
||||
|
||||
$infos = pathinfo($chemin);
|
||||
// $extension = $infos['extension'];
|
||||
|
||||
$age_fichier = time() - filemtime($chemin);
|
||||
|
||||
// if($fichier!="." AND $fichier!=".." AND !is_dir($fichier)
|
||||
// $extension == $extension_choisie AND $age_fichier > $age_requis)
|
||||
|
||||
/*
|
||||
echo "Chemai, : ".$chemin." Age : ".$age_fichier;
|
||||
|
||||
echo "<br>";
|
||||
*/
|
||||
|
||||
if($fichier!="." AND $fichier!=".." AND !is_dir($fichier) AND $age_fichier > $age_requis)
|
||||
if($fichier!="." AND $fichier!=".." AND !is_dir($chemin) AND $age_fichier > $age_requis)
|
||||
{
|
||||
unlink($chemin);
|
||||
}
|
||||
|
|
@ -66,11 +58,51 @@ class Cronnettoyerfihierstemp
|
|||
|
||||
}
|
||||
|
||||
$nettoyerfihierstemp = new Cronnettoyerfihierstemp();
|
||||
$nettoyerfihierstemp = new Cronnettoyerfihierstemp();
|
||||
$societeusercentral = (new Societeusercentral())->getSocieteuserSaas();
|
||||
|
||||
/* KANE => maj 14/02/2026
|
||||
$nettoyerfihierstemp->suppression( "../Temp" , "3600" );
|
||||
|
||||
$nettoyerfihierstemp->suppression( "../Temp/import" , "432000" );
|
||||
*/
|
||||
|
||||
$tempProduction = $societeusercentral['tempProduction'];
|
||||
$tempPrestation = $societeusercentral['tempPrestation'];
|
||||
$tempGarant = $societeusercentral['tempGarant'];
|
||||
$tempAssure = $societeusercentral['tempAssure'];
|
||||
$tempRh = $societeusercentral['tempRh'];
|
||||
|
||||
/*
|
||||
var_dump(
|
||||
array(
|
||||
"tempProduction" => $tempProduction,
|
||||
"tempPrestation" =>$tempPrestation,
|
||||
"tempGarant" => $tempGarant,
|
||||
"tempAssure" => $tempAssure,
|
||||
"tempRh" => $tempRh
|
||||
)
|
||||
);
|
||||
exit();
|
||||
*/
|
||||
|
||||
// Production
|
||||
$nettoyerfihierstemp->suppression($tempProduction."/Temp" , "3600" );
|
||||
$nettoyerfihierstemp->suppression($tempProduction."/Temp/import" , "432000" );
|
||||
|
||||
// Prestation
|
||||
$nettoyerfihierstemp->suppression($tempPrestation."/Temp" , "3600" );
|
||||
$nettoyerfihierstemp->suppression($tempPrestation."/Temp/import" , "432000" );
|
||||
|
||||
// Garant
|
||||
$nettoyerfihierstemp->suppression($tempGarant."/Temp" , "3600" );
|
||||
$nettoyerfihierstemp->suppression($tempGarant."/Temp/import" , "432000" );
|
||||
|
||||
// Assure
|
||||
$nettoyerfihierstemp->suppression($tempAssure."/Temp" , "3600" );
|
||||
$nettoyerfihierstemp->suppression($tempAssure."/Temp/import" , "432000" );
|
||||
|
||||
// RH
|
||||
$nettoyerfihierstemp->suppression($tempRh."/Temp" , "3600" );
|
||||
$nettoyerfihierstemp->suppression($tempRh."/Temp/import" , "432000" );
|
||||
|
||||
?>
|
||||
|
|
|
|||
|
|
@ -1,95 +1,95 @@
|
|||
<?php //ICB0 71:0 81:c46 82:1515 ?><?php //002cd
|
||||
<?php //ICB0 71:0 81:c6e 82:1551 ?><?php //002cd
|
||||
if(extension_loaded('ionCube Loader')){die('The file '.__FILE__." is corrupted.\n");}echo("\nScript error: the ".(($cli=(php_sapi_name()=='cli')) ?'ionCube':'<a href="https://www.ioncube.com">ionCube</a>')." Loader for PHP needs to be installed.\n\nThe ionCube Loader is the industry standard PHP extension for running protected PHP code,\nand can usually be added easily to a PHP installation.\n\nFor Loaders please visit".($cli?":\n\nhttps://get-loader.ioncube.com\n\nFor":' <a href="https://get-loader.ioncube.com">get-loader.ioncube.com</a> and for')." an instructional video please see".($cli?":\n\nhttp://ioncu.be/LV\n\n":' <a href="http://ioncu.be/LV">http://ioncu.be/LV</a> ')."\n\n");exit(199);
|
||||
?>
|
||||
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
|
||||
jZHhVVVjDt8U6wVbImDDSy2Wsnnpsm===
|
||||
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
|
||||
ikCmGDPZ2oiThgQ1pPfA=
|
||||
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
|
||||
tzPK2sTgEiWU7VwUrPD7V7j87jqRUCGNislDCle==
|
||||
HR+cPxJofe0rMXktm4WpewZm7UUp1x6XUtXtOzsTyIDEi25Nmk7IKvVoQtzhzhynNSTGYGgh6fjF
|
||||
4oH4UV8tu8tUy1NhkXtkbEYP5SjT45ZuMhTbwn7+EzUKOH6wmBfRt+Q1bacsFsAyNQLSZyCu6IAZ
|
||||
QcoieXTE5fWdShtEslO6MGOxO9lYoL4KvN2FPinm46+455xuANRVSagSRBE0DLrn4qgazaQcvIWg
|
||||
KC/UZMGMqGYaiWuhrkr8+BeQ0YHxgJlXqFlLZFndn7nAgn5eMh3RBJDvDy6oQepsJ/idV39FsH0C
|
||||
NyRB8nLCauvu1hflQsmDL9N21R7P2HDA5T63Gp77n1iY4kfBYr1cMzV+dbK87dCU0q/ucqHd1CG3
|
||||
4ZcuJAJFjot1YllrPhfo7sExahvJ5k/tHN6meuR0CpEMOJHdEXANs7BVsuplrgD+yEu9UO7U4fFy
|
||||
3Eo7EzJUjMw1tanok/9Y8tpXlFlrdIqVjG6FHf1lkZGtYXzc1+nFASiEil0NoXm7XM+VDydtyabI
|
||||
fnEeg4FvNRwCTt4FCI9ez1y1T9kioMlv56wpY4bPRTrWqzbZuzMcoXe0rGHPFVAYB3S7cwvHOO3v
|
||||
Ov7hP24hFpxFCgCI1UARk3bJDM7Id9dX/D7EuUQXsNBF5Y3qrrDtSk8Wmn/2GJC+mVaEsxHUHz6t
|
||||
LCHaOnmqfxkWPa92+4Hi1YBNYayw7kjG25Kk50/v4isOs7S2MDWH2/XInqgr4n+xl8zi274uVi0f
|
||||
cYpJA8E8cYpMLKxHyfbYl9/hmLkgwXhz8pDOG7Q4I8HTET8Z4HjvWfVjP8nzDGzVsVjxHtIL7km0
|
||||
4Zcc5/MzbDZJcQVfgkjrdRtnAdc6IQaaXHkniY/9A+3rgkd2LoCJTvn3qQz9iHTdok/igIEhsJQa
|
||||
0eWUrVOFzrtaPMU1WFIpwDHcXAGpxTN6anI/BXrspPG3tD2F1fsrJMoDJFR+uXwobKaWOtCdeGGt
|
||||
4pt82qB2iS4KeEnZ6rR/ocrrTYFaYBfk7lKX39o9wno9koeOHGDhnMDxbsMk7mAe5qprrbGHQWPc
|
||||
sQXIE5k/tks1lnhvGe7vwd/06knSIH9gh44o5+l+8GO2mbt8S31J0cC8LE62EBAgQIjazEYCmFrU
|
||||
Zx7PL9Tes59N9HHwKnExvHhlR65gHQX25SHCm1VLNMyH1oLv7Y0PjZ/eaQhazJZiNarmURnyzepe
|
||||
PDbLZEZIbQywLCHCrdQN38XGctwDVgVAzyup7dZpaCteSsFor7JxWs/knajvOCsthhS0xk/RNg7Y
|
||||
PQbmxxBzjg+oHjHbUi7lvslgfEv7yBR+YGr2IJPJHGXA75YWR/JksvRKJdvf0XZ5w7SPOwfsH9Tw
|
||||
eEz2YFEYm/CvC0QHzQtvi4aCn1J+9DMsaZPFw3CB91vbI7aJwPIDp5G7N7OTw4R2cvkKdkaO77tY
|
||||
XZq3axkIhW9kvGP5K17qrYEx9z7RJjmdNBUS3erobM3TppJmSlcw+5+fAd6Rd4BRDffLCbQwOnsE
|
||||
T0c0bPwZcQPSr5bIT2lDa2yu4X5usQn/xj327rgW1cGbYQTtAxP0NqHzfPNf45Eu6o1eEeelZKDF
|
||||
l5xHv7+f/WhLihuBYGPxQxegfj0CkPL/SEEVNWAE1bXnqBipbPr/Xm03yLl+/c3I1Rv92fBKLiha
|
||||
qvrMw0UQnIuldM5wv/biNbyq4PIjxhakQQD6t9+BT7aVUrRQbEnHERG8ppARrreINzGsP9E1UC8z
|
||||
lICtVixPMj/uT0XkyotAmb4X4gHYQpAb8xTjZScfunFE4vaDK7BSiv773RCUH/9MvWokaf/3335y
|
||||
TixriqdbEehgP2yNSGGuT7kTDSNMhe6GypPG0NODlJzNjz4Qy/xOAX6lKrV6sjcpfVwhj6/fP6n0
|
||||
fpdKv/5O1tZkrmKDvbnnATP0Yvzl7Qn1FwFZ5F7RODzdu8IjhRQAzmaRZE+n50HsZNgOpVbTCl0f
|
||||
IK8TpTqHCviOK36zdWcvewP4DzYliFpiQRE4ituCcEKO1ZEdfiX7qCeEXR5uIYWs2DGRbd49hlQI
|
||||
2B7dlW7aaGDPNHxM8MIweC/tSCBbOMgeirfrk0VGzlkHkEfzVZINQNfEM6sGwfZ6iOTPx6HN+prC
|
||||
IKXAc0HokMgGDdOL8S/yqXIKAs+6R63OXQy2wWrH9kU3mR2oIQLXSh0TxovLcvaTBnPregXfKju4
|
||||
h6T2h1NpQMwMztYhVGtjiD3Cwf4=
|
||||
|
|
@ -28712,3 +28712,46 @@ function enregistrerconsultationassureur()
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function envoyer_demande_reconnaissance_faciale() {
|
||||
// alert("envoyer_demande_reconnaissance_faciale");
|
||||
// return;
|
||||
|
||||
// Demande de confirmation multilingue
|
||||
const isConfirm = await confirm_ebene_sweet(
|
||||
"Confirmez-vous la validation?",
|
||||
"Do you confirm validation?"
|
||||
);
|
||||
|
||||
if (!isConfirm) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
await $.ajax({
|
||||
url: $("#racineWeb").val() + "Ajaxdetaildentisterie/valider/",
|
||||
type: 'POST',
|
||||
data: ''
|
||||
});
|
||||
|
||||
alert_ebene(
|
||||
"Demande envoyée!",
|
||||
"Request sent!"
|
||||
);
|
||||
|
||||
fiche_beneficiaire();
|
||||
|
||||
} catch (error) {
|
||||
console.error("Erreur :", error);
|
||||
}
|
||||
}
|
||||
|
||||
function init_demande_reconnaissance_faciale() {
|
||||
// alert("init_demande_reconnaissance_faciale");
|
||||
// return;
|
||||
|
||||
// $("#idHtagcarte").val(idHtagcarte);
|
||||
$("#telephoneAutre").focus();
|
||||
$("#div_demande_reconnaissance_faciale").modal({backdrop: 'static', keyboard: false, show: true });
|
||||
$("#div_demande_reconnaissance_faciale").modal("show");
|
||||
}
|
||||
|
|
@ -1301,5 +1301,90 @@ public function getTarifActeAdherent($idAdherent)
|
|||
|
||||
$this->executerRequete($sql, array($idOtpprestation, $otpStatus, $user));
|
||||
}
|
||||
|
||||
public function getVersionTagCarteEncours() {
|
||||
$sql = 'SELECT versionTagCarte FROM societeuser LIMIT 1;';
|
||||
$resultat = $this->executerRequete($sql);
|
||||
$ligne = $resultat->fetch(PDO::FETCH_ASSOC);
|
||||
return $ligne['versionTagCarte'];
|
||||
}
|
||||
|
||||
public function getBeneficiaireTag($versionTagCarte, $codeEntite, $numeroBeneficiaireCarte, $tagUuid)
|
||||
{
|
||||
$sql = 'call sp_p_get_beneficiaire_tag(?, ?, ?, ?);';
|
||||
$beneficiaire = $this->executerRequete($sql, array($versionTagCarte, $codeEntite, $numeroBeneficiaireCarte, $tagUuid));
|
||||
return $beneficiaire;
|
||||
}
|
||||
|
||||
public function demandereconnaissancefaciale($telephoneAutre)
|
||||
{
|
||||
$codeSociete = $_SESSION['p_codeSociete'];
|
||||
$codePrestataire = $_SESSION['p_codePrestataire_C'];
|
||||
$idBeneficiaire = $_SESSION['p_idBeneficiaire_C'];
|
||||
$user = $_SESSION['p_login'];
|
||||
|
||||
$sql = 'call sp_p_demandereconnaissancefaciale(?, ?, ?, ?, ?);';
|
||||
$this->executerRequete($sql, array($codeSociete, $codePrestataire, $idBeneficiaire, $telephoneAutre, $user));
|
||||
}
|
||||
|
||||
public function checkdemandereconnaissancefaciale()
|
||||
{
|
||||
$codeSociete = $_SESSION['p_codeSociete'];
|
||||
$codePrestataire = $_SESSION['p_codePrestataire_C'];
|
||||
$idBeneficiaire = $_SESSION['p_idBeneficiaire_C'];
|
||||
|
||||
$sql = 'call sp_p_checkdemandereconnaissancefaciale(?, ?, ?);';
|
||||
$resultat = $this->executerRequete($sql, array($codeSociete, $codePrestataire, $idBeneficiaire));
|
||||
$ligne = $resultat->fetch(PDO::FETCH_ASSOC);
|
||||
return $ligne;
|
||||
}
|
||||
|
||||
public function fn_etat_demandereconnaissancefaciale()
|
||||
{
|
||||
$codeSociete = $_SESSION['p_codeSociete'];
|
||||
$codePrestataire = $_SESSION['p_codePrestataire_C'];
|
||||
$idBeneficiaire = $_SESSION['p_idBeneficiaire_C'];
|
||||
|
||||
$sql = 'select fn_etat_demandereconnaissancefaciale(?, ?, ?) as etatDemanderecFac';
|
||||
|
||||
$resultat = $this->executerRequete($sql, array($codeSociete, $codePrestataire, $idBeneficiaire));
|
||||
|
||||
$ligne = $resultat->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
|
||||
return $ligne['etatDemanderecFac'];
|
||||
}
|
||||
|
||||
public function fn_libelle_etat_demandereconnaissancefaciale()
|
||||
{
|
||||
$codeSociete = $_SESSION['p_codeSociete'];
|
||||
$codePrestataire = $_SESSION['p_codePrestataire_C'];
|
||||
$idBeneficiaire = $_SESSION['p_idBeneficiaire_C'];
|
||||
|
||||
$sql = 'select fn_libelle_etat_demandereconnaissancefaciale(?, ?, ?, ?) as libelleEtatDemanderecFac';
|
||||
|
||||
$resultat = $this->executerRequete($sql, array($codeSociete, $codePrestataire, $idBeneficiaire, $_SESSION['p_lang']));
|
||||
|
||||
$ligne = $resultat->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
|
||||
return $ligne['libelleEtatDemanderecFac'];
|
||||
}
|
||||
|
||||
public function fn_message_demandereconnaissancefaciale()
|
||||
{
|
||||
$codeSociete = $_SESSION['p_codeSociete'];
|
||||
$codePrestataire = $_SESSION['p_codePrestataire_C'];
|
||||
$idBeneficiaire = $_SESSION['p_idBeneficiaire_C'];
|
||||
|
||||
$sql = 'select fn_message_demandereconnaissancefaciale(?, ?, ?, ?) as messagePrestataireRecFac';
|
||||
|
||||
$resultat = $this->executerRequete($sql, array($codeSociete, $codePrestataire, $idBeneficiaire, $_SESSION['p_lang']));
|
||||
|
||||
$ligne = $resultat->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
|
||||
return $ligne['messagePrestataireRecFac'];
|
||||
}
|
||||
|
||||
}
|
||||
1
Societes/envoyx/Ged/test
Normal file
1
Societes/envoyx/Ged/test
Normal file
|
|
@ -0,0 +1 @@
|
|||
test
|
||||
1
Societes/fideliasn/Ged/test
Normal file
1
Societes/fideliasn/Ged/test
Normal file
|
|
@ -0,0 +1 @@
|
|||
test
|
||||
1
Societes/generaliacm/Ged/test
Normal file
1
Societes/generaliacm/Ged/test
Normal file
|
|
@ -0,0 +1 @@
|
|||
test
|
||||
|
|
@ -12,7 +12,7 @@
|
|||
</style>
|
||||
|
||||
<span class="login100-form-title" style="font-family: Play-Bold; color:#e5e5e5; margin-top: 12px; margin-bottom:10px;">
|
||||
Portail Prestataire centralisé dev01
|
||||
Portail Prestataire
|
||||
</span>
|
||||
|
||||
<?php if (isset($msgErreur) and $msgErreur>" "): ?>
|
||||
|
|
|
|||
|
|
@ -113,7 +113,6 @@
|
|||
$handle = null;
|
||||
if($_SESSION['p_lienPhoto_C']>" " && $faceRegistered=="1")
|
||||
{
|
||||
// $lienPhoto = $_SESSION['p_dossierPhoto_C'].$_SESSION['p_dossierSociete'].'/Photos/'.$_SESSION['p_lienPhoto_C'];
|
||||
$lienPhoto = $_SESSION['p_lienPhotoFace'].$_SESSION['p_lienPhoto_C'];
|
||||
// Vérifie si le fichier existe en essayant de l'ouvrir
|
||||
$handle = @fopen($lienPhoto, "r");
|
||||
|
|
@ -138,6 +137,9 @@
|
|||
"p_dossierPhoto_C" => $_SESSION['p_dossierPhoto_C'],
|
||||
"p_dossierSociete" => $_SESSION['p_dossierSociete'],
|
||||
"handle" => $handle,
|
||||
"etatDemanderecFac" => $etatDemanderecFac,
|
||||
"libelleEtatDemanderecFac" => $libelleEtatDemanderecFac,
|
||||
"messagePrestataireRecFac" => $messagePrestataireRecFac,
|
||||
)
|
||||
);
|
||||
*/
|
||||
|
|
@ -154,6 +156,32 @@
|
|||
|
||||
$imgData = $_SESSION['p_photoAssureCrypte'];
|
||||
?>
|
||||
|
||||
<!-- Recharger la page si photo vérifiée pour activer le bouton enregistrer -->
|
||||
<?php if ($faceRegistered=="1" && in_array($etatDemanderecFac, ["1", "6"] , true)) :
|
||||
$_SESSION['p_okId_face'] = "1";
|
||||
?>
|
||||
<script type="text/javascript">
|
||||
face_confirmee = <?= $face_confirmee ?>;
|
||||
if(face_confirmee!='1'){
|
||||
// alert("On va activer le bouton enregistrer");
|
||||
location.reload();
|
||||
}
|
||||
</script>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- Si une demande est détectée -->
|
||||
<?php if ($faceRegistered=="1" && in_array($etatDemanderecFac, ["0", "2", "4"] , true)) :
|
||||
// echo "<br> demande est détectée";
|
||||
?>
|
||||
<script type="text/javascript">
|
||||
// alert("On va recharger la page pour checker à nouveau");
|
||||
setTimeout(function() {
|
||||
location.reload();
|
||||
}, 10000);
|
||||
</script>
|
||||
<?php endif; ?>
|
||||
|
||||
<INPUT class="sr-only datepicker" TYPE="text" id="debutMoisDecompte" NAME="debutMoisDecompte" value="<?= dateLang($_SESSION['p_debutMoisDecompte']) ?>" readonly>
|
||||
<INPUT class="sr-only datepicker" TYPE="text" id="finMoisDecompte" name="finMoisDecompte">
|
||||
|
||||
|
|
@ -208,14 +236,45 @@
|
|||
<?php if ($faceRegistered=="1") : ?>
|
||||
<tr>
|
||||
<td>
|
||||
<button style='font-size:15pt; width:100%; font-weight:bold;' type="button" class="btn btn-primary" onClick="javascript:ebene_init_confirm_photo_face();">
|
||||
<i class="fa fa-camera" aria-hidden="true"></i> <?= _("AUTHENTIFIER LA PHOTO DU PATIENT") ?>
|
||||
</button>
|
||||
<?php if ($face_confirmee!="1") : ?>
|
||||
<button style='font-size:15pt; width:100%; font-weight:bold;' type="button" class="btn btn-primary" onClick="javascript:ebene_init_confirm_photo_face();">
|
||||
<i class="fa fa-camera" aria-hidden="true"></i> <?= _("AUTHENTIFIER LA PHOTO DU PATIENT") ?>
|
||||
</button>
|
||||
<?php else: ?>
|
||||
<button style='font-size:15pt; width:100%; font-weight:bold;' type="button" class="btn btn-primary" disabled >
|
||||
<i class="fa fa-camera" aria-hidden="true"></i> <?= _("AUTHENTIFIER LA PHOTO DU PATIENT") ?>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<?php if ($face_confirmee!="1" && in_array($etatDemanderecFac, ["-1", "3", "4", "5"] , true)) : ?>
|
||||
<button style='font-size:15pt; width:100%; font-weight:bold;' type="button" class="btn btn-info" onClick="javascript:init_demande_reconnaissance_faciale();">
|
||||
<i class="fa fa-mobile" aria-hidden="true"></i> <?= _("ENVOYER UNE DEMANDE POUR AUTHENTIFICATION") ?>
|
||||
</button>
|
||||
<?php else: ?>
|
||||
<button style='font-size:15pt; width:100%; font-weight:bold;' type="button" class="btn btn-info" disabled >
|
||||
<i class="fa fa-mobile" aria-hidden="true"></i> <?= _("ENVOYER UNE DEMANDE POUR AUTHENTIFICATION") ?>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
|
||||
<?php if($etatDemanderecFac>="0") : ?>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<marquee behavior="scroll" direction="left" scrollamount="15" style="background-color:red;color:white; font-weight:bold; font-size:14pt">
|
||||
<?= $messagePrestataireRecFac; ?>
|
||||
</marquee>
|
||||
|
||||
<td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php else: ?>
|
||||
<tr>
|
||||
<td>
|
||||
<td colspan='2'>
|
||||
<button style='font-size:15pt; width:100%; font-weight:bold;' type="button" class="btn btn-primary" onClick="javascript:ebene_init_photo_face();">
|
||||
<i class="fa fa-floppy-disk" aria-hidden="true"></i> <?= _("ENREGISTRER LA PHOTO DU PATIENT") ?>
|
||||
</button>
|
||||
|
|
@ -790,6 +849,49 @@
|
|||
</form>
|
||||
<?php endif; ?>
|
||||
|
||||
<div id="div_demande_reconnaissance_faciale" class="modal fade" role="dialog">
|
||||
<div class="modal-dialog" style="max-width: 50%;" role="document" data-bs-backdrop="static" data-bs-keyboard="false">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-bs-dismiss="modal">×</button>
|
||||
<legend class="modal-title text-center"><?= _("Destinanaire de la demande de reconnaissance faciale");?></legend>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
<form class="form-horizontal" action="Fichebeneficiaire/demandereconnaissancefaciale" method="post" style='font-size:10pt;'>
|
||||
<table class="table table-responsive table-condensed" style='font-size:12pt;'>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td> <?= _("Destinanaire de la demande");?></td>
|
||||
<td >
|
||||
<INPUT class="form-control" name="telephoneDefaut" id="telephoneDefaut" value="<?= $_SESSION['p_telephonePortableAdherent_C'] ?>" readonly style='font-size:12pt;'>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td> <?= _("Autre Destinanaire");?></td>
|
||||
<td >
|
||||
<INPUT class="form-control" name="telephoneAutre" id="telephoneAutre" value="<?= $_SESSION['p_telephonePortableAdherent_C'] ?>" required AUTOCOMPLETE="OFF" autofocus style='font-size:12pt;'>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<input id="btn_enreg_dm" name="btn_enreg_dm" class = "form-control btn btn-primary" type="submit" value="<?= _("Envoyer la demande") ?>" style='font-size:12pt;'>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button type="button" id="btn-fermer-modal" class="btn btn-default" data-bs-dismiss="modal"><?= _("Fermer") ?></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if($faceActif=='1') : ?>
|
||||
<?php include 'faceebene/ebenetraitementimage.php'; ?>
|
||||
<?php endif; ?>
|
||||
|
|
|
|||
|
|
@ -2,27 +2,329 @@
|
|||
$this->titre = "INTER-SANTE - "._("Recherche du patient par carte") ;
|
||||
?>
|
||||
|
||||
<style>
|
||||
@import url('https://fonts.googleapis.com/css2?family=Rajdhani:wght@500;700&family=Exo+2:wght@400;600&display=swap');
|
||||
|
||||
/* ===== WRAPPER & BORDURE ANIMÉE ===== */
|
||||
.scan-wrapper {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
max-width: 720px;
|
||||
margin: 40px auto;
|
||||
}
|
||||
|
||||
.scan-wrapper::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: -3px;
|
||||
border-radius: 20px;
|
||||
background: linear-gradient(135deg, #00c9ff, #0055a5, #00e5ff, #0055a5, #00c9ff);
|
||||
background-size: 300% 300%;
|
||||
animation: borderGlow 3s linear infinite;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.scan-wrapper.has-value::before {
|
||||
background: linear-gradient(135deg, #00c853, #1b5e20, #69f0ae, #1b5e20, #00c853);
|
||||
background-size: 300% 300%;
|
||||
}
|
||||
|
||||
.scan-wrapper.has-error::before {
|
||||
background: linear-gradient(135deg, #ff1744, #b71c1c, #ff6e6e, #b71c1c, #ff1744);
|
||||
background-size: 300% 300%;
|
||||
}
|
||||
|
||||
@keyframes borderGlow {
|
||||
0% { background-position: 0% 50%; }
|
||||
50% { background-position: 100% 50%; }
|
||||
100% { background-position: 0% 50%; }
|
||||
}
|
||||
|
||||
/* ===== INNER CONTAINER ===== */
|
||||
.scan-inner {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
background: #050f20;
|
||||
border-radius: 18px;
|
||||
padding: 16px 20px 20px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Ligne de scan animée */
|
||||
.scan-inner::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0; right: 0;
|
||||
height: 2px;
|
||||
background: linear-gradient(90deg, transparent 0%, #00e5ff 30%, #ffffff 50%, #00e5ff 70%, transparent 100%);
|
||||
animation: scanLine 2.5s ease-in-out infinite;
|
||||
pointer-events: none;
|
||||
z-index: 2;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
@keyframes scanLine {
|
||||
0% { top: 0%; opacity: 0; }
|
||||
5% { opacity: 0.8; }
|
||||
95% { opacity: 0.8; }
|
||||
100% { top: 100%; opacity: 0; }
|
||||
}
|
||||
|
||||
/* ===== COINS DÉCORATIFS ===== */
|
||||
.scan-corner {
|
||||
position: absolute;
|
||||
width: 20px; height: 20px;
|
||||
border-color: #00c9ff;
|
||||
border-style: solid;
|
||||
z-index: 4;
|
||||
transition: border-color 0.3s;
|
||||
}
|
||||
.scan-corner.tl { top: 10px; left: 10px; border-width: 2px 0 0 2px; border-radius: 4px 0 0 0; }
|
||||
.scan-corner.tr { top: 10px; right: 10px; border-width: 2px 2px 0 0; border-radius: 0 4px 0 0; }
|
||||
.scan-corner.bl { bottom: 10px; left: 10px; border-width: 0 0 2px 2px; border-radius: 0 0 0 4px; }
|
||||
.scan-corner.br { bottom: 10px; right: 10px; border-width: 0 2px 2px 0; border-radius: 0 0 4px 0; }
|
||||
|
||||
.scan-wrapper.has-value .scan-corner { border-color: #00c853; }
|
||||
.scan-wrapper.has-error .scan-corner { border-color: #ff1744; }
|
||||
|
||||
/* ===== LABEL EN-TÊTE ===== */
|
||||
.scan-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 10px;
|
||||
font-family: 'Exo 2', sans-serif;
|
||||
font-size: 9.5pt;
|
||||
font-weight: 600;
|
||||
letter-spacing: 3px;
|
||||
text-transform: uppercase;
|
||||
color: rgba(0, 180, 230, 0.6);
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.nfc-icon-pulse {
|
||||
animation: pulse 2.2s ease-in-out infinite;
|
||||
}
|
||||
@keyframes pulse {
|
||||
0%, 100% { opacity: 0.35; transform: scale(1); }
|
||||
50% { opacity: 1; transform: scale(1.2); }
|
||||
}
|
||||
|
||||
/* ===== CHAMP INPUT ===== */
|
||||
#donneesCarte {
|
||||
font-family: 'Rajdhani', monospace !important;
|
||||
font-size: 24pt !important;
|
||||
font-weight: 700;
|
||||
height: 130px !important;
|
||||
width: 100% !important;
|
||||
text-align: center;
|
||||
/* Données masquées (sécurité) */
|
||||
color: transparent !important;
|
||||
text-shadow: 0 0 10px rgba(0, 229, 255, 0.8) !important;
|
||||
caret-color: #00e5ff;
|
||||
/* Fond & bordure */
|
||||
background: transparent !important;
|
||||
border: none !important;
|
||||
outline: none !important;
|
||||
box-shadow: none !important;
|
||||
letter-spacing: 4px;
|
||||
position: relative;
|
||||
z-index: 3;
|
||||
transition: text-shadow 0.3s;
|
||||
}
|
||||
|
||||
#donneesCarte::placeholder {
|
||||
font-family: 'Exo 2', sans-serif !important;
|
||||
font-size: 20pt !important;
|
||||
font-weight: 600;
|
||||
color: rgba(0, 210, 255, 0.85) !important;
|
||||
text-shadow: 0 0 12px rgba(0, 210, 255, 0.5) !important;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
|
||||
#donneesCarte:focus::placeholder {
|
||||
color: rgba(0, 210, 255, 0.55) !important;
|
||||
text-shadow: 0 0 8px rgba(0, 210, 255, 0.3) !important;
|
||||
}
|
||||
|
||||
/* État : données détectées */
|
||||
#donneesCarte.reading {
|
||||
text-shadow: 0 0 14px rgba(0, 200, 83, 0.9) !important;
|
||||
animation: none !important;
|
||||
}
|
||||
|
||||
/* ===== INDICATEUR DE LECTURE ===== */
|
||||
.reading-indicator {
|
||||
display: none;
|
||||
text-align: center;
|
||||
margin-top: 6px;
|
||||
font-family: 'Exo 2', sans-serif;
|
||||
font-size: 11pt;
|
||||
font-weight: 600;
|
||||
letter-spacing: 2px;
|
||||
color: #00c853;
|
||||
text-transform: uppercase;
|
||||
animation: fadeInUp 0.3s ease;
|
||||
}
|
||||
|
||||
.reading-indicator.active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
@keyframes fadeInUp {
|
||||
from { opacity: 0; transform: translateY(6px); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
|
||||
/* ===== SPINNER WAIT ===== */
|
||||
#div_wait_nfc {
|
||||
min-height: 0;
|
||||
transition: min-height 0.3s;
|
||||
}
|
||||
|
||||
/* ===== MESSAGE ERREUR ===== */
|
||||
.alert-danger {
|
||||
max-width: 720px;
|
||||
margin: 16px auto 0;
|
||||
border-radius: 10px;
|
||||
border: 1px solid #ff1744;
|
||||
background: rgba(183, 28, 28, 0.15);
|
||||
color: #ff6e6e;
|
||||
text-align: center;
|
||||
padding: 10px 16px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<form id="frmrechercheparcarte" name="frmrechercheparcarte" method="post" action="Rechercheparcarte/index/">
|
||||
<INPUT style='font-size:40pt; height: 50px; text-align: center;' class="form-control" TYPE="text" id="donneesCarte" name="donneesCarte" autofocus AUTOCOMPLETE="OFF" placeholder="<?= _("Veuillez scanner la carte NFC!")?>">
|
||||
<input id="lancerrechercheparcarte" name="lancerrechercheparcarte" class="sr-only" type="submit" value="<?= _("Rechercher") ?>" >
|
||||
|
||||
<div class="scan-wrapper" id="scan-wrapper">
|
||||
<div class="scan-inner">
|
||||
<!-- Coins décoratifs -->
|
||||
<div class="scan-corner tl"></div>
|
||||
<div class="scan-corner tr"></div>
|
||||
<div class="scan-corner bl"></div>
|
||||
<div class="scan-corner br"></div>
|
||||
|
||||
<!-- Label -->
|
||||
<div class="scan-label">
|
||||
<svg class="nfc-icon-pulse" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#00c9ff" stroke-width="2" stroke-linecap="round">
|
||||
<path d="M20 6a10 10 0 0 1 0 12"/>
|
||||
<path d="M17 9a6 6 0 0 1 0 6"/>
|
||||
<path d="M14 11.5a2 2 0 0 1 0 1"/>
|
||||
<line x1="4" y1="12" x2="4.01" y2="12"/>
|
||||
</svg>
|
||||
INTER-SANTÉ · NFC / QR Code
|
||||
</div>
|
||||
|
||||
<!-- Champ principal -->
|
||||
<INPUT
|
||||
class="form-control"
|
||||
TYPE="text"
|
||||
id="donneesCarte"
|
||||
name="donneesCarte"
|
||||
autofocus
|
||||
AUTOCOMPLETE="OFF"
|
||||
placeholder="<?= _("Veuillez scanner la carte NFC ou le QR code!")?>">
|
||||
|
||||
<!-- Indicateur -->
|
||||
<div class="reading-indicator" id="reading-indicator">
|
||||
<i class="fa fa-check-circle"></i>
|
||||
<span id="indicator-text"><?= _("Carte détectée") ?></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<input id="lancerrechercheparcarte" name="lancerrechercheparcarte" class="sr-only" type="submit" value="<?= _("Rechercher") ?>">
|
||||
</form>
|
||||
|
||||
<div id ="div_wait_nfc"> </div>
|
||||
|
||||
<?php if (isset($msgErreur) && $msgErreur>" "): ?>
|
||||
<div class="alert alert-danger" style="height:38px; padding:5px; text-align: center;">
|
||||
<H4><?= $msgErreur ?></H4>
|
||||
</div>
|
||||
<div id="div_wait_nfc"></div>
|
||||
|
||||
<?php if (isset($msgErreur) && $msgErreur > " "): ?>
|
||||
<div class="alert alert-danger">
|
||||
<H4><?= $msgErreur ?></H4>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<script>
|
||||
document.getElementById('donneesCarte').addEventListener('change', function () {
|
||||
if (this.value.length > 3) {
|
||||
var div_wait_nfc = $('#div_wait_nfc');
|
||||
div_wait_nfc.html('<div style="padding-top:80px; text-align:center; font-size:14px; color: #4caf50;"><span><i class="fa fa-spinner fa-spin fa-5x" >' + '</span></div>');
|
||||
// alert("submit");
|
||||
this.form.submit();
|
||||
}
|
||||
const inputField = document.getElementById('donneesCarte');
|
||||
const indicator = document.getElementById('reading-indicator');
|
||||
const indicatorText = document.getElementById('indicator-text');
|
||||
const scanWrapper = document.getElementById('scan-wrapper');
|
||||
|
||||
// ===== SÉCURITÉ : empêcher copie/coller =====
|
||||
inputField.addEventListener('contextmenu', e => e.preventDefault());
|
||||
inputField.addEventListener('copy', e => e.preventDefault());
|
||||
inputField.addEventListener('cut', e => e.preventDefault());
|
||||
|
||||
// ===== MAINTIEN DU FOCUS =====
|
||||
inputField.addEventListener('blur', function() {
|
||||
setTimeout(() => this.focus(), 10);
|
||||
});
|
||||
|
||||
const focusInterval = setInterval(function() {
|
||||
if (document.activeElement !== inputField && !document.hidden) {
|
||||
inputField.focus();
|
||||
}
|
||||
}, 200);
|
||||
|
||||
document.addEventListener('keydown', function(e) {
|
||||
if (!e.ctrlKey && !e.altKey && !e.metaKey && document.activeElement !== inputField) {
|
||||
inputField.focus();
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById('frmrechercheparcarte').addEventListener('submit', function() {
|
||||
clearInterval(focusInterval);
|
||||
});
|
||||
|
||||
// ===== DÉTECTION DU TYPE =====
|
||||
function detectScanType(value) {
|
||||
return value.endsWith('qr') ? 'qr' : 'nfc';
|
||||
}
|
||||
|
||||
// ===== FEEDBACK VISUEL À LA SAISIE =====
|
||||
inputField.addEventListener('input', function() {
|
||||
if (this.value.length > 0) {
|
||||
this.classList.add('reading');
|
||||
indicator.classList.add('active');
|
||||
scanWrapper.classList.add('has-value');
|
||||
scanWrapper.classList.remove('has-error');
|
||||
|
||||
const type = detectScanType(this.value);
|
||||
indicatorText.textContent = type === 'qr'
|
||||
? '<?= _("QR code détecté") ?>'
|
||||
: '<?= _("Carte détectée") ?>';
|
||||
} else {
|
||||
this.classList.remove('reading');
|
||||
indicator.classList.remove('active');
|
||||
scanWrapper.classList.remove('has-value', 'has-error');
|
||||
}
|
||||
});
|
||||
|
||||
// ===== SOUMISSION AUTO =====
|
||||
inputField.addEventListener('change', function() {
|
||||
if (this.value.length > 3) {
|
||||
const type = detectScanType(this.value);
|
||||
const message = type === 'qr'
|
||||
? '<?= _("Traitement du QR code...") ?>'
|
||||
: '<?= _("Lecture de la carte...") ?>';
|
||||
|
||||
$('#div_wait_nfc').html(
|
||||
'<div style="padding-top:60px; text-align:center; font-family:\'Exo 2\',sans-serif; color:#00c9ff;">'
|
||||
+ '<i class="fa fa-spinner fa-spin fa-4x"></i>'
|
||||
+ '<p style="margin-top:20px; font-size:13pt; letter-spacing:2px; text-transform:uppercase;">' + message + '</p>'
|
||||
+ '</div>'
|
||||
);
|
||||
this.form.submit();
|
||||
}
|
||||
});
|
||||
|
||||
// ===== FOCUS INITIAL =====
|
||||
window.addEventListener('load', () => inputField.focus());
|
||||
document.addEventListener('DOMContentLoaded', () => inputField.focus());
|
||||
|
||||
// ===== Afficher erreur en rouge si présente =====
|
||||
<?php if (isset($msgErreur) && $msgErreur > " "): ?>
|
||||
scanWrapper.classList.add('has-error');
|
||||
<?php endif; ?>
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -432,8 +432,18 @@
|
|||
// $style = "background-color: #F5DF4D;";
|
||||
$style = "background-color: $colorTests;";
|
||||
$test = "MODE TEST";
|
||||
|
||||
error_reporting(E_ALL);
|
||||
ini_set('display_errors', 1);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
error_reporting(E_ALL & ~E_DEPRECATED & ~E_STRICT);
|
||||
ini_set('display_errors', 0);
|
||||
}
|
||||
ini_set('log_errors', 1);
|
||||
ini_set('error_log', __DIR__ . '/logs/error.log');
|
||||
|
||||
//var_dump($style);
|
||||
?>
|
||||
|
||||
|
|
@ -474,8 +484,6 @@
|
|||
<img src="<?= $_SESSION['p_lienLogo'] ?>"
|
||||
alt="Profile"
|
||||
style="max-height:40px;"
|
||||
class="rounded-circle">
|
||||
|
||||
<span class="text-truncate d-inline-block" style="max-width:300px;">
|
||||
<?=$companyDisplayName?>
|
||||
</span>
|
||||
|
|
@ -635,9 +643,29 @@
|
|||
<input class="sr-only" type="text" id="nomSociete" name="nomSociete" value="<?= $_SESSION['p_nomSociete'] ?>">
|
||||
<section class="section main-dashboard">
|
||||
<div id="contenu">
|
||||
<div id="div_test_gabarit">
|
||||
</div>
|
||||
|
||||
<div id="div_test_gabarit">
|
||||
|
||||
<?php
|
||||
/*
|
||||
$err_report = ini_get('error_reporting');
|
||||
$disp_err = ini_get('display_errors');
|
||||
|
||||
var_dump(
|
||||
array(
|
||||
// "codeGcAssureurDefaut" => $_SESSION['codeGcAssureurDefaut'],
|
||||
// "codeGcAssureur_C" => $_SESSION['codeGcAssureur_C'],
|
||||
// "dossierSociete" => $_SESSION['dossierSociete'],
|
||||
// "bdTests" => $_SESSION['p_bdTests_C'],
|
||||
// "err_report" => $err_report,
|
||||
// "disp_err" => $disp_err,
|
||||
)
|
||||
);
|
||||
*/
|
||||
?>
|
||||
|
||||
<?= $contenu ?>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
|
@ -889,7 +917,7 @@
|
|||
<!--<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.css" integrity="sha512-3pIirOrwegjM6erE5gPSwkUzO+3cTjpnV9lexlNZqvupR64iZBnOOTiiLPb9M36zpMScbmUNIcHUqKD47M719g==" crossorigin="anonymous" referrerpolicy="no-referrer" />-->
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.min.js" integrity="sha512-VEd+nq25CkR676O+pLBnDW09R7VQX9Mdiij052gVCp5yVH3jGtH70Ho/UUv4mJDsEdTvqRCFZg0NKGiojGnUCw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||
|
||||
<script src="Js/fonctions.js?ver=2026.02.11.00"></script>
|
||||
<script src="Js/fonctions.js?ver=2026.02.22.04"></script>
|
||||
<script src="Bootstrap/js/bootstrap.min.js"></script>
|
||||
|
||||
<script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>
|
||||
|
|
|
|||
|
|
@ -1,151 +0,0 @@
|
|||
<?php
|
||||
$_SESSION['p_messageFace'] = "";
|
||||
?>
|
||||
|
||||
<div class="modal fade" id="pop_rec_faciale" role="dialog" data-backdrop="static" data-keyboard="false" >
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
|
||||
<div class="modal-header">
|
||||
<button id="btn_close_pop_rec_faciale" name="btn_close_pop_rec_faciale" type="button" class="close" data-bs-dismiss="modal" onclick="javascript:fiche_beneficiaire();"> <?= _("Fermer") ?> </button>
|
||||
<h4 class="modal-title"> <?= _("RECONNAISSANCE FACIALE") ?> </h4>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
|
||||
<!-- Début ajout 25/09/20225 -->
|
||||
<div class="row">
|
||||
<?php include 'liveness.php'; ?>
|
||||
</div>
|
||||
|
||||
<!-- <div id="div_ebene" hidden> -->
|
||||
<div id="div_ebene">
|
||||
<!-- Fin ajout 25/09/20225 -->
|
||||
|
||||
<table class="table table-responsive table-condensed">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td width="48%">
|
||||
<button id="ebene_take_photo_face" name="ebene_take_photo_face" style='font-size:15pt;' type="button" class="form-control btn btn-primary" onclick="javascript:takephoto();"> <?= _("PRENDRE UNE PHOTO") ?> </button>
|
||||
</td>
|
||||
|
||||
<td > </td>
|
||||
<?php if ($faceRegistered=="1") : ?>
|
||||
<td width="48%">
|
||||
<button disabled id="ebene_confirmer_photo_face" name="ebene_confirmer_photo_face" style='font-size:15pt;' type="button" class="form-control btn btn-primary" onclick="javascript:ebene_confirmer_photo_face();"> <?= _("CONFIRMER LA PHOTO") ?> </button>
|
||||
</td>
|
||||
<?php endif; ?>
|
||||
|
||||
|
||||
<?php if ($faceRegistered!="1") : ?>
|
||||
<td width="48%">
|
||||
<button disabled id="ebene_enregistrer_photo_face" name="ebene_enregistrer_photo_face" style='font-size:15pt;' type="button" class="form-control btn btn-primary" onclick="javascript:ebene_enregistrer_photo_face();"> <?= _("ENREGISTRER LA PHOTO") ?> </button>
|
||||
</td>
|
||||
<?php endif; ?>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
<div class="row">
|
||||
<div class="col-6" >
|
||||
<legend style="text-align:center" >Webcam</legend>
|
||||
<video id="video_face" name="video_face" autoplay height="250" align="center"></video><br />
|
||||
</div>
|
||||
|
||||
<div class="col-6" >
|
||||
|
||||
<legend style="text-align:center" >Photo</legend>
|
||||
<img id="photo_face" name="photo_face" src="" />
|
||||
<form id="form_face" name="form_face" enctype="multipart/form-data" method="post" action="Fichebeneficiaire/ebeneenregistrerface">
|
||||
<INPUT class="sr-only" TYPE="text" id="compare_face" name="compare_face" value="<?= $faceRegistered ?>">
|
||||
<INPUT class="sr-only" TYPE="text" id="del_face" name="del_face" value="0">
|
||||
<INPUT class="image-tag" TYPE="hidden" id="image_face" name="image_face" >
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<canvas id="canvas" name="canvas" style="display: none;" width="350" height="260"></canvas>
|
||||
|
||||
<?php if ($faceRegistered=="1") : ?>
|
||||
<!--
|
||||
<button disabled id="ebene_supprimer_photo_face" name="ebene_supprimer_photo_face" style='font-size:15pt;' type="button" class="form-control btn btn-danger" onclick="javascript:ebene_supprimer_photo_face();"> <?= _("SUPPRIMER LA PHOTO") ?> </button>
|
||||
|
||||
<span style='font-size:12pt;font-weight: bold;' ><?= _("Motif Suppression") ?> :</span> <INPUT disabled class="form-control" TYPE="text" id="motif" NAME="motif" style='font-size:12pt;font-weight: bold;' >
|
||||
-->
|
||||
<?php endif; ?>
|
||||
|
||||
<div id="message_face" name="message_face" >
|
||||
<H2 style="background-color:yellow;">
|
||||
<marquee behavior="scroll" direction="left" scrollamount="10"> </marquee>
|
||||
</H2>
|
||||
<INPUT class="sr-only" TYPE="text" id="photo_succes" name="photo_succes" value="0">
|
||||
</div>
|
||||
|
||||
<div id="div_wait_face_ebene">
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
var video = document.getElementById('video_face');
|
||||
var canvas = document.getElementById('canvas');
|
||||
var photo = document.getElementById('photo_face');
|
||||
var image_face = document.getElementById('image_face');
|
||||
|
||||
|
||||
|
||||
navigator.getMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia || navigator.mediaDevices.getUserMedia || navigator.moxGetUserMedia;
|
||||
|
||||
if (navigator.mediaDevices.getUserMedia)
|
||||
{
|
||||
navigator.mediaDevices.getUserMedia({video: true })
|
||||
.then(function (stream) {
|
||||
video.srcObject = stream;
|
||||
})
|
||||
.catch(function (e) { alert(e.name + ": " + e.message); });
|
||||
}
|
||||
else
|
||||
{
|
||||
navigator.getMedia({ video: { mandatory: { maxWidth: 350, maxHeight: 260 } } }, function(stream) {
|
||||
video.src = stream;
|
||||
}, function(e) {
|
||||
alert(e);
|
||||
console.log("Failed!", e);
|
||||
});
|
||||
}
|
||||
|
||||
function takephoto() {
|
||||
|
||||
$('#message_face').html("");
|
||||
$("#div_wait_face_ebene").html('');
|
||||
|
||||
// var ctx = canvas.getContext("2d").drawImage(video, 0, 0, 350, 260, 0, 0, 350, 260);
|
||||
var ctx = canvas.getContext("2d").drawImage(video, 0, 0, 350, 260);
|
||||
var data = canvas.toDataURL('image/jpeg');
|
||||
// var data = canvas.toDataURL('image/jpeg', 0.7);
|
||||
photo.setAttribute('src', data);
|
||||
$("#image_face").val(data);
|
||||
var faceRegistered = $("#faceRegistered").val();
|
||||
$("#ebene_enregistrer_photo_face").enable();
|
||||
if(faceRegistered=="1")
|
||||
{
|
||||
$("#ebene_confirmer_photo_face").enable();
|
||||
$("#ebene_supprimer_photo_face").enable();
|
||||
$("#motif").enable();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button id="close_poprec_faciane" name="close_poprec_faciane" type="button" class="btn btn-default" data-bs-dismiss="modal" onclick="javascript:fiche_beneficiaire();" > <?= _("Fermer") ?> </button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -1,139 +0,0 @@
|
|||
<?php
|
||||
$_SESSION['p_messageFace'] = "";
|
||||
?>
|
||||
|
||||
<div class="modal fade" id="pop_rec_faciale" role="dialog" data-backdrop="static" data-keyboard="false" >
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
|
||||
<div class="modal-header">
|
||||
<button id="btn_close_pop_rec_faciale" name="btn_close_pop_rec_faciale" type="button" class="close" data-bs-dismiss="modal" onclick="javascript:fiche_beneficiaire();"> <?= _("Fermer") ?> </button>
|
||||
<h4 class="modal-title"> <?= _("RECONNAISSANCE FACIALE") ?> </h4>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
<table class="table table-responsive table-condensed">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td width="48%">
|
||||
<button id="ebene_take_photo_face" name="ebene_take_photo_face" style='font-size:15pt;' type="button" class="form-control btn btn-primary" onclick="javascript:takephoto();"> <?= _("PRENDRE UNE PHOTO") ?> </button>
|
||||
</td>
|
||||
|
||||
<td > </td>
|
||||
<?php if ($faceRegistered=="1") : ?>
|
||||
<td width="48%">
|
||||
<button disabled id="ebene_confirmer_photo_face" name="ebene_confirmer_photo_face" style='font-size:15pt;' type="button" class="form-control btn btn-primary" onclick="javascript:ebene_confirmer_photo_face();"> <?= _("CONFIRMER LA PHOTO") ?> </button>
|
||||
</td>
|
||||
<?php endif; ?>
|
||||
|
||||
|
||||
<?php if ($faceRegistered!="1") : ?>
|
||||
<td width="48%">
|
||||
<button disabled id="ebene_enregistrer_photo_face" name="ebene_enregistrer_photo_face" style='font-size:15pt;' type="button" class="form-control btn btn-primary" onclick="javascript:ebene_enregistrer_photo_face();"> <?= _("ENREGISTRER LA PHOTO") ?> </button>
|
||||
</td>
|
||||
<?php endif; ?>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
<div class="row">
|
||||
<div class="col-6" >
|
||||
<legend style="text-align:center" >Webcam</legend>
|
||||
<video id="video_face" name="video_face" autoplay 350="450" height="250" align="center"></video><br />
|
||||
</div>
|
||||
|
||||
<div class="col-6" >
|
||||
|
||||
<legend style="text-align:center" >Photo</legend>
|
||||
<img id="photo_face" name="photo_face" src="" />
|
||||
<form id="form_face" name="form_face" enctype="multipart/form-data" method="post" action="Fichebeneficiaire/ebeneenregistrerface">
|
||||
<INPUT class="sr-only" TYPE="text" id="compare_face" name="compare_face" value="<?= $faceRegistered ?>">
|
||||
<INPUT class="sr-only" TYPE="text" id="del_face" name="del_face" value="0">
|
||||
<INPUT class="image-tag" TYPE="hidden" id="image_face" name="image_face" >
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<canvas id="canvas" name="canvas" style="display: none;" width="350" height="260"></canvas>
|
||||
|
||||
<?php if ($faceRegistered=="1") : ?>
|
||||
<!--
|
||||
<button disabled id="ebene_supprimer_photo_face" name="ebene_supprimer_photo_face" style='font-size:15pt;' type="button" class="form-control btn btn-danger" onclick="javascript:ebene_supprimer_photo_face();"> <?= _("SUPPRIMER LA PHOTO") ?> </button>
|
||||
|
||||
<span style='font-size:12pt;font-weight: bold;' ><?= _("Motif Suppression") ?> :</span> <INPUT disabled class="form-control" TYPE="text" id="motif" NAME="motif" style='font-size:12pt;font-weight: bold;' >
|
||||
-->
|
||||
<?php endif; ?>
|
||||
|
||||
<div id="message_face" name="message_face" >
|
||||
<H2 style="background-color:yellow;">
|
||||
<marquee behavior="scroll" direction="left" scrollamount="10"> </marquee>
|
||||
</H2>
|
||||
<INPUT class="sr-only" TYPE="text" id="photo_succes" name="photo_succes" value="0">
|
||||
</div>
|
||||
|
||||
<div id="div_wait_face_ebene">
|
||||
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
var video = document.getElementById('video_face');
|
||||
var canvas = document.getElementById('canvas');
|
||||
var photo = document.getElementById('photo_face');
|
||||
var image_face = document.getElementById('image_face');
|
||||
|
||||
|
||||
|
||||
navigator.getMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia || navigator.mediaDevices.getUserMedia || navigator.moxGetUserMedia;
|
||||
|
||||
if (navigator.mediaDevices.getUserMedia)
|
||||
{
|
||||
navigator.mediaDevices.getUserMedia({video: true })
|
||||
.then(function (stream) {
|
||||
video.srcObject = stream;
|
||||
})
|
||||
.catch(function (e) { alert(e.name + ": " + e.message); });
|
||||
}
|
||||
else
|
||||
{
|
||||
navigator.getMedia({ video: { mandatory: { maxWidth: 350, maxHeight: 260 } } }, function(stream) {
|
||||
video.src = stream;
|
||||
}, function(e) {
|
||||
alert(e);
|
||||
console.log("Failed!", e);
|
||||
});
|
||||
}
|
||||
|
||||
function takephoto() {
|
||||
|
||||
$('#message_face').html("");
|
||||
$("#div_wait_face_ebene").html('');
|
||||
|
||||
// var ctx = canvas.getContext("2d").drawImage(video, 0, 0, 350, 260, 0, 0, 350, 260);
|
||||
var ctx = canvas.getContext("2d").drawImage(video, 0, 0, 350, 260);
|
||||
var data = canvas.toDataURL('image/jpeg');
|
||||
// var data = canvas.toDataURL('image/jpeg', 0.7);
|
||||
photo.setAttribute('src', data);
|
||||
$("#image_face").val(data);
|
||||
var faceRegistered = $("#faceRegistered").val();
|
||||
$("#ebene_enregistrer_photo_face").enable();
|
||||
if(faceRegistered=="1")
|
||||
{
|
||||
$("#ebene_confirmer_photo_face").enable();
|
||||
$("#ebene_supprimer_photo_face").enable();
|
||||
$("#motif").enable();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button id="close_poprec_faciane" name="close_poprec_faciane" type="button" class="btn btn-default" data-bs-dismiss="modal" onclick="javascript:fiche_beneficiaire();" > <?= _("Fermer") ?> </button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -1,337 +0,0 @@
|
|||
<style>
|
||||
:root { font-family: system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif; }
|
||||
/*body { margin: 0; background: #0f172a; color: #e2e8f0; }*/
|
||||
header { padding: 16px 24px; background: #111827; display:flex; align-items:center; gap:12px; }
|
||||
h1 { font-size: 18px; margin: 0; }
|
||||
/*main { display:grid; grid-template-columns: 1fr 360px; gap: 16px; padding: 16px; }*/
|
||||
.stage { position: relative; aspect-ratio: 16/9; background: #111827; border: 1px solid #1f2937; border-radius: 12px; overflow: hidden; }
|
||||
/* video, canvas { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; } */
|
||||
.panel { background: #111827; border: 1px solid #1f2937; border-radius: 12px; padding: 16px; }
|
||||
.row { display:flex; justify-content: space-between; align-items:center; margin: 8px 0; }
|
||||
.pill { display:inline-flex; align-items:center; gap:8px; padding:6px 10px; border-radius:999px; border:1px solid #1f2937; font-size:12px; }
|
||||
.ok { color:#10b981; }
|
||||
.warn { color:#f59e0b; }
|
||||
.bad { color:#ef4444; }
|
||||
button { background:#1f2937; color:#e5e7eb; border:1px solid #374151; border-radius:10px; padding:10px 12px; cursor:pointer; }
|
||||
button:disabled { opacity:.5; cursor:not-allowed; }
|
||||
small { color:#94a3b8; }
|
||||
.meter { height: 8px; border-radius: 999px; background:#0b1220; border:1px solid #1f2937; overflow:hidden; }
|
||||
.meter > div { height: 100%; background: linear-gradient(90deg,#22c55e,#16a34a); width:0%; }
|
||||
.grid { display:grid; grid-template-columns: 1fr 1fr; gap:8px; }
|
||||
.kpi { background:#0b1220; border:1px solid #1f2937; border-radius:10px; padding:10px; }
|
||||
code { background:#0b1220; padding:2px 6px; border-radius:6px; }
|
||||
</style>
|
||||
|
||||
<header>
|
||||
<h1>Détection de vivacité (Liveness)</h1>
|
||||
<div class="pill"><span>🎥</span><span id="camStatus">Caméra : inactif</span></div>
|
||||
<div class="pill"><span>🧠</span><span id="mpStatus">Modèle : non chargé</span></div>
|
||||
</header>
|
||||
|
||||
<div class="col-6" >
|
||||
<section class="stage">
|
||||
<video id="video" playsinline muted height="250"></video>
|
||||
<canvas id="overlay"></canvas>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div class="col-6" >
|
||||
<div class="row" style="margin-bottom:8px">
|
||||
<button id="btnStart">Démarrer</button>
|
||||
<button class="sr-only" id="btnStop" disabled>Arrêter</button>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<strong>Statut vivacité</strong>
|
||||
<span id="liveBadge" class="pill bad">Non vérifié</span>
|
||||
</div>
|
||||
<div class="meter" style="margin:8px 0 16px">
|
||||
<div id="liveMeter"></div>
|
||||
</div>
|
||||
|
||||
<div class="grid">
|
||||
<div class="kpi"><div>Clignements</div><div id="blinkCount" style="font-size:22px">0</div><small>EAR<seuil</small></div>
|
||||
<div class="kpi"><div>Mouvements tête</div><div id="headMoves" style="font-size:22px">0</div><small>yaw/roll Δ</small></div>
|
||||
<div class="kpi"><div>Confiance visage</div><div id="faceScore" style="font-size:22px">0.00</div><small>presence score</small></div>
|
||||
<div class="kpi"><div>FPS</div><div id="fps" style="font-size:22px">0</div><small>approx</small></div>
|
||||
</div>
|
||||
<!--
|
||||
<div id="blinkCount" style="font-size:22px">0</div>
|
||||
<div id="headMoves" style="font-size:22px">0</div>
|
||||
<div id="faceScore" style="font-size:22px">0.00</div>
|
||||
<div id="fps" style="font-size:22px">0</div>
|
||||
-->
|
||||
|
||||
<div class="sr-only">
|
||||
<input id="earThresh" type="number" min="0" max="1" step="0.01" value="0.21">
|
||||
<input id="closedFrames" type="number" min="1" max="15" step="1" value="3">
|
||||
<input id="moveThresh" type="number" min="0" max="30" step="0.5" value="6">
|
||||
<!-- <input id="proofNeeded" type="number" min="1" max="10" step="1" value="3"> -->
|
||||
<input id="proofNeeded" type="number" min="1" max="10" step="1" value="2">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- </main> -->
|
||||
|
||||
<!-- MediaPipe Tasks Vision (web) -->
|
||||
<script type="module">
|
||||
// -- Dépendances MediaPipe Tasks Vision
|
||||
import {
|
||||
FilesetResolver,
|
||||
FaceLandmarker,
|
||||
DrawingUtils
|
||||
} from "https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision/vision_bundle.js";
|
||||
|
||||
// URLs modèles (hébergés par Google)
|
||||
const MP_FACE_TASK = "https://storage.googleapis.com/mediapipe-models/face_landmarker/face_landmarker/float16/1/face_landmarker.task";
|
||||
|
||||
// Références DOM
|
||||
const video = document.getElementById('video');
|
||||
const canvas = document.getElementById('overlay');
|
||||
const ctx = canvas.getContext('2d');
|
||||
|
||||
const btnStart = document.getElementById('btnStart');
|
||||
const btnStop = document.getElementById('btnStop');
|
||||
|
||||
const camStatus = document.getElementById('camStatus');
|
||||
const mpStatus = document.getElementById('mpStatus');
|
||||
|
||||
const blinkCountEl = document.getElementById('blinkCount');
|
||||
const headMovesEl = document.getElementById('headMoves');
|
||||
const faceScoreEl = document.getElementById('faceScore');
|
||||
const fpsEl = document.getElementById('fps');
|
||||
const liveBadge = document.getElementById('liveBadge');
|
||||
const liveMeter = document.getElementById('liveMeter');
|
||||
|
||||
const earThreshEl = document.getElementById('earThresh');
|
||||
const closedFramesEl= document.getElementById('closedFrames');
|
||||
const moveThreshEl = document.getElementById('moveThresh');
|
||||
const proofNeededEl = document.getElementById('proofNeeded');
|
||||
|
||||
// État
|
||||
let running = false;
|
||||
let faceLandmarker; // modèle
|
||||
let lastVideoTime = -1;
|
||||
let rafId = null;
|
||||
|
||||
// Métriques liveness
|
||||
let blinkCount = 0;
|
||||
let closedConsec = 0;
|
||||
let lastEAR = 1;
|
||||
|
||||
let headMoves = 0;
|
||||
let lastYaw = null, lastRoll = null;
|
||||
|
||||
let facePresenceScore = 0;
|
||||
let livenessScore = 0; // somme pondérée des preuves
|
||||
|
||||
let lastFpsT = performance.now();
|
||||
let frames = 0;
|
||||
|
||||
// Indices MediaPipe FaceMesh pour calcul EAR (6 points par œil)
|
||||
// Schéma: EAR = (||p2-p6|| + ||p3-p5||) / (2*||p1-p4||)
|
||||
const LEFT_EYE = [33,160,158,133,153,144];
|
||||
const RIGHT_EYE = [263,387,385,362,380,373];
|
||||
|
||||
const distance = (a,b)=> Math.hypot(a.x-b.x, a.y-b.y);
|
||||
|
||||
function eyeEAR(landmarks, idxs){
|
||||
const [p1,p2,p3,p4,p5,p6] = idxs.map(i=>landmarks[i]);
|
||||
const vert = distance(p2,p6) + distance(p3,p5);
|
||||
const horiz= distance(p1,p4)*2;
|
||||
return horiz>0 ? (vert/horiz) : 0;
|
||||
}
|
||||
|
||||
function estimateYawRoll(landmarks){
|
||||
// yaw ~ orientation horizontale via ligne yeux, roll ~ inclinaison de la tête
|
||||
const left = avgPoint([33,133].map(i=>landmarks[i]));
|
||||
const right= avgPoint([263,362].map(i=>landmarks[i]));
|
||||
const dx = right.x - left.x;
|
||||
const dy = right.y - left.y;
|
||||
const roll = -rad2deg(Math.atan2(dy, dx));
|
||||
// yaw approximé par asymétrie distance nez-centres yeux
|
||||
const nose = landmarks[1] || landmarks[4];
|
||||
const midEye = {x:(left.x+right.x)/2, y:(left.y+right.y)/2};
|
||||
const yaw = rad2deg(Math.atan2(nose.x - midEye.x, 0.5)); // pseudo-yaw basé sur décalage nez
|
||||
return {yaw, roll};
|
||||
}
|
||||
const rad2deg = r=> r*180/Math.PI;
|
||||
const avgPoint = (pts)=>({x: pts.reduce((s,p)=>s+p.x,0)/pts.length, y: pts.reduce((s,p)=>s+p.y,0)/pts.length});
|
||||
|
||||
function updateLiveUI(){
|
||||
blinkCountEl.textContent = String(blinkCount);
|
||||
headMovesEl.textContent = String(headMoves);
|
||||
faceScoreEl.textContent = facePresenceScore.toFixed(2);
|
||||
|
||||
// Score simple: 1 point par clignement (max 2), 1 point par move tête (max 2), +1 si présence stable (>0.5)
|
||||
const maxBlinkPoints = Math.min(blinkCount, 2);
|
||||
const maxMovePoints = Math.min(headMoves, 2);
|
||||
const presencePoint = facePresenceScore > 0.5 ? 1 : 0;
|
||||
livenessScore = maxBlinkPoints + maxMovePoints + presencePoint;
|
||||
|
||||
const proofNeeded = Number(proofNeededEl.value);
|
||||
const pct = Math.min(100, Math.round(100*livenessScore/Math.max(1,proofNeeded)));
|
||||
liveMeter.style.width = pct + '%';
|
||||
|
||||
const div_ebene = document.getElementById("div_ebene");
|
||||
|
||||
if(livenessScore >= proofNeeded){
|
||||
liveBadge.className = 'pill ok';
|
||||
liveBadge.textContent = 'Vivant confirmé';
|
||||
|
||||
// alert('Vivant confirmé');
|
||||
stop();
|
||||
// $("#div_ebene").fadeIn();
|
||||
// $("#div_ebene").show();
|
||||
|
||||
// div_ebene.style.display = "block";
|
||||
// div_ebene.classList.remove("hidden");
|
||||
|
||||
} else if (livenessScore>0){
|
||||
liveBadge.className = 'pill warn';
|
||||
liveBadge.textContent = 'Indices de vivacité';
|
||||
} else {
|
||||
liveBadge.className = 'pill bad';
|
||||
liveBadge.textContent = 'Non vérifié';
|
||||
}
|
||||
}
|
||||
|
||||
async function loadModel(){
|
||||
mpStatus.textContent = 'Modèle : chargement…';
|
||||
const filesetResolver = await FilesetResolver.forVisionTasks(
|
||||
// wasm path (CDN jsDelivr) — laisse MediaPipe gérer les dépendances
|
||||
'https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@0.10.11/wasm'
|
||||
);
|
||||
faceLandmarker = await FaceLandmarker.createFromOptions(filesetResolver,{
|
||||
baseOptions: { modelAssetPath: MP_FACE_TASK },
|
||||
runningMode: 'VIDEO',
|
||||
numFaces: 1,
|
||||
outputFaceBlendshapes: false,
|
||||
outputFacialTransformationMatrixes: true
|
||||
});
|
||||
mpStatus.textContent = 'Modèle : prêt';
|
||||
}
|
||||
|
||||
async function start(){
|
||||
try{
|
||||
btnStart.disabled = true;
|
||||
await loadModel();
|
||||
|
||||
const stream = await navigator.mediaDevices.getUserMedia({
|
||||
video: { facingMode: 'user', width: {ideal: 1280}, height:{ideal:720} },
|
||||
audio: false
|
||||
});
|
||||
video.srcObject = stream;
|
||||
await video.play();
|
||||
|
||||
camStatus.textContent = 'Caméra : OK';
|
||||
running = true;
|
||||
canvas.width = video.videoWidth || 1280;
|
||||
canvas.height= video.videoHeight|| 720;
|
||||
btnStop.disabled = false;
|
||||
lastVideoTime = -1;
|
||||
loop();
|
||||
}catch(err){
|
||||
console.error(err);
|
||||
camStatus.textContent = 'Caméra : échec ('+ (err?.name||'Erreur') +')';
|
||||
btnStart.disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
function stop(){
|
||||
running = false;
|
||||
if(rafId) cancelAnimationFrame(rafId);
|
||||
const stream = video.srcObject;
|
||||
if(stream){
|
||||
stream.getTracks().forEach(t=>t.stop());
|
||||
}
|
||||
video.srcObject = null;
|
||||
btnStart.disabled = false;
|
||||
btnStop.disabled = true;
|
||||
camStatus.textContent = 'Caméra : inactif';
|
||||
mpStatus.textContent = faceLandmarker ? 'Modèle : prêt' : 'Modèle : non chargé';
|
||||
}
|
||||
|
||||
function drawLandmarks(landmarks){
|
||||
ctx.clearRect(0,0,canvas.width, canvas.height);
|
||||
const drawUtils = new DrawingUtils(ctx);
|
||||
// Points clés yeux + traits simples
|
||||
const eyePts = [...LEFT_EYE, ...RIGHT_EYE];
|
||||
drawUtils.drawLandmarks(landmarks.filter((_,i)=> eyePts.includes(i)), {lineWidth: 2, color: '#22c55e', radius: 2});
|
||||
}
|
||||
|
||||
function loop(){
|
||||
if(!running) return;
|
||||
const startT = performance.now();
|
||||
|
||||
const nowVideoTime = video.currentTime;
|
||||
if(nowVideoTime !== lastVideoTime){
|
||||
lastVideoTime = nowVideoTime;
|
||||
const res = faceLandmarker.detectForVideo(video, performance.now());
|
||||
const faces = res.faceLandmarks || [];
|
||||
|
||||
if(faces.length){
|
||||
const lm = faces[0];
|
||||
drawLandmarks(lm);
|
||||
|
||||
// EAR pour chaque œil
|
||||
const earL = eyeEAR(lm, LEFT_EYE);
|
||||
const earR = eyeEAR(lm, RIGHT_EYE);
|
||||
const ear = (earL + earR)/2;
|
||||
|
||||
const earThresh = Number(earThreshEl.value);
|
||||
const closedNeeded = Number(closedFramesEl.value);
|
||||
|
||||
if(ear < earThresh){
|
||||
closedConsec++;
|
||||
} else {
|
||||
if(closedConsec >= closedNeeded){
|
||||
blinkCount++;
|
||||
}
|
||||
closedConsec = 0;
|
||||
}
|
||||
|
||||
// Head movement (yaw/roll change)
|
||||
const {yaw, roll} = estimateYawRoll(lm);
|
||||
const moveThresh = Number(moveThreshEl.value);
|
||||
if(lastYaw!==null && lastRoll!==null){
|
||||
const dYaw = Math.abs(yaw - lastYaw);
|
||||
const dRoll= Math.abs(roll - lastRoll);
|
||||
if(dYaw > moveThresh || dRoll > moveThresh){
|
||||
headMoves++;
|
||||
}
|
||||
}
|
||||
lastYaw = yaw; lastRoll = roll;
|
||||
|
||||
// Présence visage (proxy via nb de points vs bruit)
|
||||
facePresenceScore = 0.7; // simplifié: présent
|
||||
|
||||
} else {
|
||||
ctx.clearRect(0,0,canvas.width, canvas.height);
|
||||
facePresenceScore = 0.0;
|
||||
}
|
||||
|
||||
// MAJ UI
|
||||
updateLiveUI();
|
||||
}
|
||||
|
||||
// FPS approx
|
||||
frames++;
|
||||
const t = performance.now();
|
||||
if(t - lastFpsT > 1000){
|
||||
fpsEl.textContent = String(frames);
|
||||
frames = 0; lastFpsT = t;
|
||||
}
|
||||
|
||||
rafId = requestAnimationFrame(loop);
|
||||
const endT = performance.now();
|
||||
// Option: utiliser endT-startT si besoin de profiler
|
||||
}
|
||||
|
||||
btnStart.addEventListener('click', start);
|
||||
btnStop.addEventListener('click', stop);
|
||||
|
||||
|
||||
// Conseil : demander permission caméra immédiatement (optionnel)
|
||||
// navigator.mediaDevices.getUserMedia({video:true}).then(s=>s.getTracks().forEach(t=>t.stop()));
|
||||
</script>
|
||||
|
|
@ -1,321 +0,0 @@
|
|||
<style>
|
||||
:root { font-family: system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif; }
|
||||
body { margin: 0; background: #0f172a; color: #e2e8f0; }
|
||||
header { padding: 16px 24px; background: #111827; display:flex; align-items:center; gap:12px; }
|
||||
h1 { font-size: 18px; margin: 0; }
|
||||
main { display:grid; grid-template-columns: 1fr 360px; gap: 16px; padding: 16px; }
|
||||
.stage { position: relative; aspect-ratio: 16/9; background: #111827; border: 1px solid #1f2937; border-radius: 12px; overflow: hidden; }
|
||||
video, canvas { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
|
||||
.panel { background: #111827; border: 1px solid #1f2937; border-radius: 12px; padding: 16px; }
|
||||
.row { display:flex; justify-content: space-between; align-items:center; margin: 8px 0; }
|
||||
.pill { display:inline-flex; align-items:center; gap:8px; padding:6px 10px; border-radius:999px; border:1px solid #1f2937; font-size:12px; }
|
||||
.ok { color:#10b981; }
|
||||
.warn { color:#f59e0b; }
|
||||
.bad { color:#ef4444; }
|
||||
button { background:#1f2937; color:#e5e7eb; border:1px solid #374151; border-radius:10px; padding:10px 12px; cursor:pointer; }
|
||||
button:disabled { opacity:.5; cursor:not-allowed; }
|
||||
small { color:#94a3b8; }
|
||||
.meter { height: 8px; border-radius: 999px; background:#0b1220; border:1px solid #1f2937; overflow:hidden; }
|
||||
.meter > div { height: 100%; background: linear-gradient(90deg,#22c55e,#16a34a); width:0%; }
|
||||
.grid { display:grid; grid-template-columns: 1fr 1fr; gap:8px; }
|
||||
.kpi { background:#0b1220; border:1px solid #1f2937; border-radius:10px; padding:10px; }
|
||||
code { background:#0b1220; padding:2px 6px; border-radius:6px; }
|
||||
</style>
|
||||
|
||||
<header>
|
||||
<h1>Détection de vivacité (Liveness)</h1>
|
||||
<div class="pill"><span>🎥</span><span id="camStatus">Caméra : inactif</span></div>
|
||||
<div class="pill"><span>🧠</span><span id="mpStatus">Modèle : non chargé</span></div>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<section class="stage">
|
||||
<video id="video" playsinline muted></video>
|
||||
<canvas id="overlay"></canvas>
|
||||
</section>
|
||||
|
||||
<aside class="panel">
|
||||
<div class="row" style="margin-bottom:8px">
|
||||
<button id="btnStart">Démarrer</button>
|
||||
<button id="btnStop" disabled>Arrêter</button>
|
||||
</div>
|
||||
<div class="row">
|
||||
<strong>Statut vivacité</strong>
|
||||
<span id="liveBadge" class="pill bad">Non vérifié</span>
|
||||
</div>
|
||||
<div class="meter" style="margin:8px 0 16px">
|
||||
<div id="liveMeter"></div>
|
||||
</div>
|
||||
|
||||
<div class="grid">
|
||||
<div class="kpi"><div>Clignements</div><div id="blinkCount" style="font-size:22px">0</div><small>EAR<seuil</small></div>
|
||||
<div class="kpi"><div>Mouvements tête</div><div id="headMoves" style="font-size:22px">0</div><small>yaw/roll Δ</small></div>
|
||||
<div class="kpi"><div>Confiance visage</div><div id="faceScore" style="font-size:22px">0.00</div><small>presence score</small></div>
|
||||
<div class="kpi"><div>FPS</div><div id="fps" style="font-size:22px">0</div><small>approx</small></div>
|
||||
</div>
|
||||
|
||||
<hr style="border-color:#1f2937; margin:16px 0" />
|
||||
|
||||
<input class="sr-only" id="earThresh" type="number" min="0" max="1" step="0.01" value="0.21">
|
||||
<input class="sr-only" id="closedFrames" type="number" min="1" max="15" step="1" value="3">
|
||||
<input class="sr-only" id="moveThresh" type="number" min="0" max="30" step="0.5" value="6">
|
||||
<input class="sr-only" id="proofNeeded" type="number" min="1" max="10" step="1" value="3">
|
||||
|
||||
<hr style="border-color:#1f2937; margin:16px 0" />
|
||||
|
||||
<p><strong>Conseils :</strong> placez-vous face caméra, éclairez le visage, clignez des yeux et tournez légèrement la tête.</p>
|
||||
</aside>
|
||||
</main>
|
||||
|
||||
<!-- MediaPipe Tasks Vision (web) -->
|
||||
<script type="module">
|
||||
// -- Dépendances MediaPipe Tasks Vision
|
||||
import {
|
||||
FilesetResolver,
|
||||
FaceLandmarker,
|
||||
DrawingUtils
|
||||
} from "https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision/vision_bundle.js";
|
||||
|
||||
// URLs modèles (hébergés par Google)
|
||||
const MP_FACE_TASK = "https://storage.googleapis.com/mediapipe-models/face_landmarker/face_landmarker/float16/1/face_landmarker.task";
|
||||
|
||||
// Références DOM
|
||||
const video = document.getElementById('video');
|
||||
const canvas = document.getElementById('overlay');
|
||||
const ctx = canvas.getContext('2d');
|
||||
|
||||
const btnStart = document.getElementById('btnStart');
|
||||
const btnStop = document.getElementById('btnStop');
|
||||
|
||||
const camStatus = document.getElementById('camStatus');
|
||||
const mpStatus = document.getElementById('mpStatus');
|
||||
|
||||
const blinkCountEl = document.getElementById('blinkCount');
|
||||
const headMovesEl = document.getElementById('headMoves');
|
||||
const faceScoreEl = document.getElementById('faceScore');
|
||||
const fpsEl = document.getElementById('fps');
|
||||
const liveBadge = document.getElementById('liveBadge');
|
||||
const liveMeter = document.getElementById('liveMeter');
|
||||
|
||||
const earThreshEl = document.getElementById('earThresh');
|
||||
const closedFramesEl= document.getElementById('closedFrames');
|
||||
const moveThreshEl = document.getElementById('moveThresh');
|
||||
const proofNeededEl = document.getElementById('proofNeeded');
|
||||
|
||||
// État
|
||||
let running = false;
|
||||
let faceLandmarker; // modèle
|
||||
let lastVideoTime = -1;
|
||||
let rafId = null;
|
||||
|
||||
// Métriques liveness
|
||||
let blinkCount = 0;
|
||||
let closedConsec = 0;
|
||||
let lastEAR = 1;
|
||||
|
||||
let headMoves = 0;
|
||||
let lastYaw = null, lastRoll = null;
|
||||
|
||||
let facePresenceScore = 0;
|
||||
let livenessScore = 0; // somme pondérée des preuves
|
||||
|
||||
let lastFpsT = performance.now();
|
||||
let frames = 0;
|
||||
|
||||
// Indices MediaPipe FaceMesh pour calcul EAR (6 points par œil)
|
||||
// Schéma: EAR = (||p2-p6|| + ||p3-p5||) / (2*||p1-p4||)
|
||||
const LEFT_EYE = [33,160,158,133,153,144];
|
||||
const RIGHT_EYE = [263,387,385,362,380,373];
|
||||
|
||||
const distance = (a,b)=> Math.hypot(a.x-b.x, a.y-b.y);
|
||||
|
||||
function eyeEAR(landmarks, idxs){
|
||||
const [p1,p2,p3,p4,p5,p6] = idxs.map(i=>landmarks[i]);
|
||||
const vert = distance(p2,p6) + distance(p3,p5);
|
||||
const horiz= distance(p1,p4)*2;
|
||||
return horiz>0 ? (vert/horiz) : 0;
|
||||
}
|
||||
|
||||
function estimateYawRoll(landmarks){
|
||||
// yaw ~ orientation horizontale via ligne yeux, roll ~ inclinaison de la tête
|
||||
const left = avgPoint([33,133].map(i=>landmarks[i]));
|
||||
const right= avgPoint([263,362].map(i=>landmarks[i]));
|
||||
const dx = right.x - left.x;
|
||||
const dy = right.y - left.y;
|
||||
const roll = -rad2deg(Math.atan2(dy, dx));
|
||||
// yaw approximé par asymétrie distance nez-centres yeux
|
||||
const nose = landmarks[1] || landmarks[4];
|
||||
const midEye = {x:(left.x+right.x)/2, y:(left.y+right.y)/2};
|
||||
const yaw = rad2deg(Math.atan2(nose.x - midEye.x, 0.5)); // pseudo-yaw basé sur décalage nez
|
||||
return {yaw, roll};
|
||||
}
|
||||
const rad2deg = r=> r*180/Math.PI;
|
||||
const avgPoint = (pts)=>({x: pts.reduce((s,p)=>s+p.x,0)/pts.length, y: pts.reduce((s,p)=>s+p.y,0)/pts.length});
|
||||
|
||||
function updateLiveUI(){
|
||||
blinkCountEl.textContent = String(blinkCount);
|
||||
headMovesEl.textContent = String(headMoves);
|
||||
faceScoreEl.textContent = facePresenceScore.toFixed(2);
|
||||
|
||||
// Score simple: 1 point par clignement (max 2), 1 point par move tête (max 2), +1 si présence stable (>0.5)
|
||||
const maxBlinkPoints = Math.min(blinkCount, 2);
|
||||
const maxMovePoints = Math.min(headMoves, 2);
|
||||
const presencePoint = facePresenceScore > 0.5 ? 1 : 0;
|
||||
livenessScore = maxBlinkPoints + maxMovePoints + presencePoint;
|
||||
|
||||
const proofNeeded = Number(proofNeededEl.value);
|
||||
const pct = Math.min(100, Math.round(100*livenessScore/Math.max(1,proofNeeded)));
|
||||
liveMeter.style.width = pct + '%';
|
||||
|
||||
if(livenessScore >= proofNeeded){
|
||||
liveBadge.className = 'pill ok';
|
||||
liveBadge.textContent = 'Vivant confirmé';
|
||||
} else if (livenessScore>0){
|
||||
liveBadge.className = 'pill warn';
|
||||
liveBadge.textContent = 'Indices de vivacité';
|
||||
} else {
|
||||
liveBadge.className = 'pill bad';
|
||||
liveBadge.textContent = 'Non vérifié';
|
||||
}
|
||||
}
|
||||
|
||||
async function loadModel(){
|
||||
mpStatus.textContent = 'Modèle : chargement…';
|
||||
const filesetResolver = await FilesetResolver.forVisionTasks(
|
||||
// wasm path (CDN jsDelivr) — laisse MediaPipe gérer les dépendances
|
||||
'https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@0.10.11/wasm'
|
||||
);
|
||||
faceLandmarker = await FaceLandmarker.createFromOptions(filesetResolver,{
|
||||
baseOptions: { modelAssetPath: MP_FACE_TASK },
|
||||
runningMode: 'VIDEO',
|
||||
numFaces: 1,
|
||||
outputFaceBlendshapes: false,
|
||||
outputFacialTransformationMatrixes: true
|
||||
});
|
||||
mpStatus.textContent = 'Modèle : prêt';
|
||||
}
|
||||
|
||||
async function start(){
|
||||
try{
|
||||
btnStart.disabled = true;
|
||||
await loadModel();
|
||||
|
||||
const stream = await navigator.mediaDevices.getUserMedia({
|
||||
video: { facingMode: 'user', width: {ideal: 1280}, height:{ideal:720} },
|
||||
audio: false
|
||||
});
|
||||
video.srcObject = stream;
|
||||
await video.play();
|
||||
|
||||
camStatus.textContent = 'Caméra : OK';
|
||||
running = true;
|
||||
canvas.width = video.videoWidth || 1280;
|
||||
canvas.height= video.videoHeight|| 720;
|
||||
btnStop.disabled = false;
|
||||
lastVideoTime = -1;
|
||||
loop();
|
||||
}catch(err){
|
||||
console.error(err);
|
||||
camStatus.textContent = 'Caméra : échec ('+ (err?.name||'Erreur') +')';
|
||||
btnStart.disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
function stop(){
|
||||
running = false;
|
||||
if(rafId) cancelAnimationFrame(rafId);
|
||||
const stream = video.srcObject;
|
||||
if(stream){
|
||||
stream.getTracks().forEach(t=>t.stop());
|
||||
}
|
||||
video.srcObject = null;
|
||||
btnStart.disabled = false;
|
||||
btnStop.disabled = true;
|
||||
camStatus.textContent = 'Caméra : inactif';
|
||||
mpStatus.textContent = faceLandmarker ? 'Modèle : prêt' : 'Modèle : non chargé';
|
||||
}
|
||||
|
||||
function drawLandmarks(landmarks){
|
||||
ctx.clearRect(0,0,canvas.width, canvas.height);
|
||||
const drawUtils = new DrawingUtils(ctx);
|
||||
// Points clés yeux + traits simples
|
||||
const eyePts = [...LEFT_EYE, ...RIGHT_EYE];
|
||||
drawUtils.drawLandmarks(landmarks.filter((_,i)=> eyePts.includes(i)), {lineWidth: 2, color: '#22c55e', radius: 2});
|
||||
}
|
||||
|
||||
function loop(){
|
||||
if(!running) return;
|
||||
const startT = performance.now();
|
||||
|
||||
const nowVideoTime = video.currentTime;
|
||||
if(nowVideoTime !== lastVideoTime){
|
||||
lastVideoTime = nowVideoTime;
|
||||
const res = faceLandmarker.detectForVideo(video, performance.now());
|
||||
const faces = res.faceLandmarks || [];
|
||||
|
||||
if(faces.length){
|
||||
const lm = faces[0];
|
||||
drawLandmarks(lm);
|
||||
|
||||
// EAR pour chaque œil
|
||||
const earL = eyeEAR(lm, LEFT_EYE);
|
||||
const earR = eyeEAR(lm, RIGHT_EYE);
|
||||
const ear = (earL + earR)/2;
|
||||
|
||||
const earThresh = Number(earThreshEl.value);
|
||||
const closedNeeded = Number(closedFramesEl.value);
|
||||
|
||||
if(ear < earThresh){
|
||||
closedConsec++;
|
||||
} else {
|
||||
if(closedConsec >= closedNeeded){
|
||||
blinkCount++;
|
||||
}
|
||||
closedConsec = 0;
|
||||
}
|
||||
|
||||
// Head movement (yaw/roll change)
|
||||
const {yaw, roll} = estimateYawRoll(lm);
|
||||
const moveThresh = Number(moveThreshEl.value);
|
||||
if(lastYaw!==null && lastRoll!==null){
|
||||
const dYaw = Math.abs(yaw - lastYaw);
|
||||
const dRoll= Math.abs(roll - lastRoll);
|
||||
if(dYaw > moveThresh || dRoll > moveThresh){
|
||||
headMoves++;
|
||||
}
|
||||
}
|
||||
lastYaw = yaw; lastRoll = roll;
|
||||
|
||||
// Présence visage (proxy via nb de points vs bruit)
|
||||
facePresenceScore = 0.7; // simplifié: présent
|
||||
|
||||
} else {
|
||||
ctx.clearRect(0,0,canvas.width, canvas.height);
|
||||
facePresenceScore = 0.0;
|
||||
}
|
||||
|
||||
// MAJ UI
|
||||
updateLiveUI();
|
||||
}
|
||||
|
||||
// FPS approx
|
||||
frames++;
|
||||
const t = performance.now();
|
||||
if(t - lastFpsT > 1000){
|
||||
fpsEl.textContent = String(frames);
|
||||
frames = 0; lastFpsT = t;
|
||||
}
|
||||
|
||||
rafId = requestAnimationFrame(loop);
|
||||
const endT = performance.now();
|
||||
// Option: utiliser endT-startT si besoin de profiler
|
||||
}
|
||||
|
||||
btnStart.addEventListener('click', start);
|
||||
btnStop.addEventListener('click', stop);
|
||||
|
||||
// Conseil : demander permission caméra immédiatement (optionnel)
|
||||
// navigator.mediaDevices.getUserMedia({video:true}).then(s=>s.getTracks().forEach(t=>t.stop()));
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
2
faceebene/sav1/webcam.min.js
vendored
2
faceebene/sav1/webcam.min.js
vendored
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user