From 786316864614a5b0e73a43ac4a0a7606b749c51d Mon Sep 17 00:00:00 2001 From: xdrm-brackets Date: Sat, 2 Jan 2016 18:43:33 +0100 Subject: [PATCH] =?UTF-8?q?[x]=20Export=20groupes=20=09+=20format=20=09+?= =?UTF-8?q?=20excelManager=20=09+=20g=C3=A9n=C3=A9ration=20=09+=20t=C3=A9l?= =?UTF-8?q?=C3=A9chargement?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.php | 1 - manager/database.php | 16 +-- manager/excel.php | 123 ++++++++----------- manager/groups.php | 2 +- manager/repo/group.php | 26 +++- page/_JS/career.js | 3 +- page/_JS/groups.js | 64 +++++++++- page/groups.php | 12 +- src/files/admin2_export_liste_etudiants.xlsx | Bin 0 -> 6522 bytes 9 files changed, 152 insertions(+), 95 deletions(-) create mode 100644 src/files/admin2_export_liste_etudiants.xlsx diff --git a/index.php b/index.php index 6b62931..7a6a1d9 100755 --- a/index.php +++ b/index.php @@ -3,7 +3,6 @@ require_once __ROOT__.'/manager/security.php'; /* VARIABLES DES NOTIFICATIONS */ $notifNotifNum = 5; - ?> diff --git a/manager/database.php b/manager/database.php index 436e753..4968a83 100755 --- a/manager/database.php +++ b/manager/database.php @@ -549,19 +549,7 @@ class DataBase{ if( !semestreRepo::exists($semestre) ) return 'unknown_semestre'; else $semestreUID = $semestre; - // on cherche tout les groupes du même semestre de la même année - $getGroupesUID = DataBase::getPDO()->prepare("SELECT DISTINCT g.id_groupe as id, g.nom, s.rang, s.nom as semestre - FROM groupe as g, semestre as s, appartenance as app - WHERE g.id_groupe = app.id_groupe - AND s.id_semestre = app.id_semestre - - AND s.id_semestre = :semestreUID - ORDER BY g.nom"); - $getGroupesUID->execute(array( - ':semestreUID' => $semestreUID - )); - - $grouplist = DataBase::delNumeric( $getGroupesUID->fetchAll() ); // contiendra tout les groupes + $grouplist = groupRepo::forSemestre($semestreUID); // contiendra tout les groupes // on parcourt tous les groupes foreach($grouplist as $iter=>$val) @@ -576,7 +564,7 @@ class DataBase{ /******************************************************************/ public function listeEtudiantsTousGroupesAnnee($annee, $semestre_pair){ // on récupère la liste des groupes - $grouplist = DataBase::delNumeric( groupRepo::forYear($semestre_pair, $annee) ); + $grouplist = groupRepo::forYear($semestre_pair, $annee); foreach($grouplist as $iter=>$val) // pour chaque groupe un récupère la liste des utilisateurs $grouplist[$iter]['userlist'] = groupRepo::membres($grouplist[$iter]['id'], $grouplist[$iter]['id_semestre']); diff --git a/manager/excel.php b/manager/excel.php index 55d830b..cddb33a 100755 --- a/manager/excel.php +++ b/manager/excel.php @@ -1,5 +1,6 @@ level_1){ - /***************************************************/ - /* Export la liste des étudiants d'un groupe donné */ - /***************************************************/ - case 'export_userlist_group': + /*****************************************************/ + /* Export la liste des étudiants d'un semestre donné */ + /*****************************************************/ + case 'export_grouplist': // Vérification de la présence des groupes - if( isset($request->grouplist) && $request->grouplist != null ){ - - //On crée une instance du fichier xls,activation de la feuille + if( isset($request->grouplist) ){ + // [1] On crée une instance du fichier xls, activation de la feuille $workbook = new PHPExcel(); $sheet = $workbook->getActiveSheet(); $writer = new PHPExcel_Writer_Excel2007($workbook); - // Définition des paramètres du document - + // [2] Définition des paramètres du document $workbook->getProperties()->setCreator($_SESSION['identifiant']); $workbook->getProperties()->setLastModifiedBy('ACGA'); $workbook->getProperties()->setTitle('Liste étudiants '.$_SESSION['annee']); - // Définition du format des cellules (document Excel) + // [3] Définition du format des cellules (document Excel) + $sheet->getColumnDimension('A')->setWidth(15); + $sheet->getColumnDimension('B')->setWidth(15); + $sheet->getColumnDimension('C')->setWidth(15); + $sheet->getColumnDimension('D')->setWidth(5); + $sheet->getColumnDimension('E')->setWidth(15); + $sheet->getColumnDimension('F')->setWidth(10); + $sheet->getColumnDimension('G')->setWidth(10); - $sheet->getColumnDimension('B')->setWidth(20); - $sheet->getColumnDimension('C')->setWidth(20); - $sheet->getColumnDimension('D')->setWidth(15); - $sheet->getColumnDimension('E')->setWidth(8); - $sheet->getColumnDimension('F')->setWidth(35); - $sheet->getColumnDimension('G')->setWidth(12); - $sheet->getColumnDimension('H')->setWidth(12); - - // Écriture des colonnes du tableau - - $sheet->setCellValue('B1', "GROUPE DES ETUDIANTS DE L'ANNEE ".$_SESSION['annee']); + // [4] Écriture des colonnes du tableau + $sheet->setCellValue('B1', ""); $sheet->setCellValue('A2', date("d/m/Y G:m")); - $sheet->setCellValue('A4', 'Numéro'); - $sheet->setCellValue('B4', 'Nom'); - $sheet->setCellValue('C4', 'Prénom'); - $sheet->setCellValue('D4', 'Identifiant'); - $sheet->setCellValue('E4', 'Sexe'); - $sheet->setCellValue('F4', 'Mail étudiant'); - $sheet->setCellValue('G4', 'Code IAE'); - $sheet->setCellValue('H4', 'IAE Etape'); - - // Écriture des valeurs dans le document Excel + $sheet->setCellValue('A4', 'Identifiant'); + $sheet->setCellValue('B4', 'Prénom'); + $sheet->setCellValue('C4', 'Nom'); + $sheet->setCellValue('D4', 'Sexe'); + $sheet->setCellValue('E4', 'Mail étudiant'); + $sheet->setCellValue('F4', 'Groupe'); + $sheet->setCellValue('G4', 'Formation'); + // [5] Écriture des valeurs dans le document Excel $index = 5; - foreach ( $request->grouplist as $group ) { + foreach($request->grouplist as $group){ + $index++; - $groupeName = $group['nom']; - $formation = $group['formation']; + foreach($group->userlist as $student){ - foreach ( $group['userlist'] as $student ) { - - $sheet->setCellValue('A'.$index, $index-4); - $sheet->setCellValue('B'.$index, $student['nom']); - $sheet->setCellValue('C'.$index, $student['prenom']); - $sheet->setCellValue('D'.$index, $student['identifiant']); - $sheet->setCellValue('E'.$index, $student['sexe']); - $sheet->setCellValue('F'.$index, $student['mail']); - $sheet->setCellValue('G'.$index, $formation); - $sheet->setCellValue('H'.$index, $groupeName); + $sheet->setCellValue('A'.$index, $student->identifiant); + $sheet->setCellValue('B'.$index, $student->prenom); + $sheet->setCellValue('C'.$index, $student->nom); + $sheet->setCellValue('D'.$index, ($student->sexe)?'M':'F'); + $sheet->setCellValue('E'.$index, $student->mail); + $sheet->setCellValue('F'.$index, $group->nom); + $sheet->setCellValue('G'.$index, $group->formation); $index++; } } - //On enregistre ce nouveau fichier, et on lance son téléchargement + // [6] On enregistre ce nouveau fichier, et on lance son téléchargement + $filePath = __EXCEL_PATH__.$_SESSION['identifiant'].'_export_liste_etudiants.xlsx'; + $writer->save( $filePath ); - $docPath = DIRECTORY_SEPARATOR.join(DIRECTORY_SEPARATOR, array("page", "excelTemplates", - "Liste Etudiant ".$_SESSION['annee'].".xlsx")); - if(file_exists (__ROOT__.$docPath)){ - $index = 1; - $titleLen = strlen($docPath) - 5; - while(file_exists (__ROOT__.$docPath)){ - $docPath = mb_strimwidth($docPath, 0, $titleLen, "")." (".$index.").xlsx"; - $index++; - } - } - $writer->save(__ROOT__.$docPath); - $answer->docPath = $docPath; + + // [7] On retourne l'état du traitement 'success' + $answer->request = 'success'; + + // [8] On retourne le chemin relatif du serveur + $answer->pathfile = '/src/files/'.$_SESSION['identifiant'].'_export_liste_etudiants.xlsx'; } - // Erreur de paramètre(s) - - else { - + // [7] On retourne l'état du traitement 'param_error' + else $answer->request = 'param_error'; - } break; @@ -118,7 +103,7 @@ class excelManager{ case 'import_inscrits': // Récupération du nom du fichier - $filePath = __ROOT__.'/src/files/'.$_SESSION['identifiant'].'_import_inscrits.xlsx'; + $filePath = __EXCEL_PATH__.$_SESSION['identifiant'].'_import_inscrits.xlsx'; // si on a pas le droit d'écriture, on quitte // if( !is_readable($filePath) ){ $answer->request = 'read_permission'; return; } @@ -236,7 +221,7 @@ class excelManager{ // // Écriture des valeurs dans le document Excel // $index = 5; - // foreach ( $request->resultat as $eleve ) { + // foreach( $request->resultat as $eleve ) { // $sheet->setCellValue('A'.$index,$eleve->nom); // $sheet->setCellValue('B'.$index,$eleve->prenom); @@ -320,17 +305,17 @@ class excelManager{ case 'import_mcc': - $filePath = __ROOT__.'/src/files/'.$_SESSION['identifiant'].'_import_mcc.xlsx'; + $filePath = __EXCEL_PATH__.$_SESSION['identifiant'].'_import_mcc.xlsx'; // si on a pas le droit d'écriture, on quitte // if( !is_readable($filePath) ){ $answer->request = 'read_permission'; return; } // Charger le fichier en tant que document Excel - $objPHPExcel = PHPExcel_IOFactory::load($filePath); + $objPHPExcel = PHPExcel_IOFactory::load($filePath); // Get sur la première case - $sheet = $objPHPExcel->getSheet(0); - $mccData = $sheet->rangeToArray('A2:'.$sheet->getHighestColumn().''.$sheet->getHighestRow()); + $sheet = $objPHPExcel->getSheet(0); + $mccData = $sheet->rangeToArray('A2:'.$sheet->getHighestColumn().''.$sheet->getHighestRow()); /* permet d'éviter les doublons */ diff --git a/manager/groups.php b/manager/groups.php index edff9e4..4e00ba2 100755 --- a/manager/groups.php +++ b/manager/groups.php @@ -126,7 +126,7 @@ class groupsManager{ /*******************************************************************/ /* retourne les utilisateurs de tous les groupes du semestre donné */ /*******************************************************************/ - case 'grouplist': if( permission('student') ){ + case 'grouplist': if( permission('student') || permission('master') || permission('admin') ){ $areSetParam = isset($request->semestre); // les arguments existent // $formationCheck = $areSetParam && checkParam($request->formation, 'auto_increment_id'); // formation (formation) bon format diff --git a/manager/repo/group.php b/manager/repo/group.php index 43c8c27..f4344fe 100755 --- a/manager/repo/group.php +++ b/manager/repo/group.php @@ -171,7 +171,7 @@ class groupRepo{ public static function membres($groupeUID, $semestreUID){ // si le groupe existe => on récupère ses utilisateurs // var_dump($groupeUID.' - '.$semestreUID); - $getMembres = DataBase::getPDO()->prepare("SELECT u.identifiant, u.prenom, u.nom, u.mail, u.droits, s.nom as semestre, g.id_groupe, g.nom as groupe + $getMembres = DataBase::getPDO()->prepare("SELECT u.identifiant, u.prenom, u.nom, u.sexe, u.mail, u.droits, s.nom as semestre, g.id_groupe, g.nom as groupe FROM utilisateur as u, groupe as g, semestre as s, appartenance as app, formation as f WHERE s.id_formation = f.id_formation AND u.identifiant = app.id_etudiant @@ -318,6 +318,30 @@ class groupRepo{ + /* RETOURNE TOUS LES GROUPES DU SEMESTRE SPÉCIFIÉ + * + * @semestreUID L'UID du semestre en question + * + * + * @return groupes retourne la liste des groupes correspondant aux critères + * + */ + public static function forSemestre($semestreUID){ + + $getGroupeList = DataBase::getPDO()->prepare("SELECT DISTINCT g.id_groupe as id, g.nom, s.rang, s.id_semestre, s.nom as semestre, f.id_formation, f.code as formation, f.nom as nom_formation + FROM groupe as g, semestre as s, appartenance as app, formation as f + WHERE s.id_formation = f.id_formation + AND g.id_groupe = app.id_groupe + AND s.id_semestre = app.id_semestre + + AND s.id_semestre = :semestreUID + ORDER BY g.nom"); + $getGroupeList->execute(array( ':semestreUID' => $semestreUID )); + + return DataBase::delNumeric( $getGroupeList->fetchAll() ); + } + + /* RETOURNE TOUS LES GROUPES DES SEMESTRES COURANT D'UNE ANNÉE * * @semestre_pair VRAI si le semestre courant est pair (***OPTIONNEL***) diff --git a/page/_JS/career.js b/page/_JS/career.js index 2903271..6aaf264 100755 --- a/page/_JS/career.js +++ b/page/_JS/career.js @@ -46,7 +46,8 @@ for( var i = 0 ; i < partList.length ; i++ ){ reload(); // import/export affinage par semestre - }else if( e.target.parentNode.getAttribute('name') == 'semestre' && e.target.dataset.hasOwnProperty('stre') ){ + }else if( e.target.parentNode.getAttribute('name') == 'semestre' && e.target.dataset.hasOwnProperty('stre') && e.target.dataset.hasOwnProperty('year') ){ + pageM.vars[1] = 'a:'+e.target.dataset.year; pageM.vars[2] = 's:'+e.target.dataset.stre; reload(); } diff --git a/page/_JS/groups.js b/page/_JS/groups.js index 0406b01..03c54e7 100755 --- a/page/_JS/groups.js +++ b/page/_JS/groups.js @@ -98,7 +98,7 @@ if( canMoveStudents ){ // si c'set l'admin var selectList = document.querySelectorAll("#CONTAINER > section[name] > select[name=groupe], #CONTAINER > section[name] > .p > select[name=annee]"); var partList = document.querySelectorAll("#CONTAINER > section[name] > table.partlist[name=semestre], "+ "#CONTAINER > section[name] > table.partlist[name=formation], "+ - "#CONTAINER > section[name] > .p > div.partlist[name=semestre] > span[data-stre]"); + "#CONTAINER > section[name] > .p > div.partlist[name=semestre] > span[data-stre][data-year]"); // GESTION DE L'AFFINAGE PAR FORMATION/SEMESTRE // for( var i = 0 ; i < partList.length ; i++ ){ @@ -121,7 +121,8 @@ for( var i = 0 ; i < partList.length ; i++ ){ pageM.vars[2] = 's:'+e.target.dataset.value; // affinage par semestre (exportation) - }else if( e.target.parentNode.getAttribute('name') == 'semestre' && e.target.dataset.hasOwnProperty('stre') ){ + }else if( e.target.parentNode.getAttribute('name') == 'semestre' && e.target.dataset.hasOwnProperty('stre') && e.target.dataset.hasOwnProperty('year') ){ + pageM.vars[1] = 'a:'+e.target.dataset.year; pageM.vars[2] = 's:'+e.target.dataset.stre; } @@ -179,8 +180,67 @@ for( var i = 0 ; i < selectList.length ; i++ ){ +/********************************/ +/* GESTION DE L'EXPORT DE LISTE */ +/********************************/ +var exportInscrits = document.getElementById('export_grouplist'); +if( exportInscrits != null ){ + exportInscrits.addEventListener('click', function(e){ + var selectedSemestre = document.querySelector("#CONTAINER > section[name] > .p > div.partlist[name] > span[data-stre][data-year].active"); + + // on récupère l'année et le semestre selectionnés + var fSemestre = (selectedSemestre!=null) ? selectedSemestre.dataset.stre : null; + var fAnnee = (selectedSemestre!=null) ? selectedSemestre.dataset.year : null; + console.log(fSemestre); + console.log(fAnnee); + + /* [1] On récupère la liste des groupes en question (groupManager) + ===================================================================*/ + /* (1) Tous les semestres */ + var request1; + if( fSemestre == '*' ){ + request1 = { + level_0: 'groups', + level_1: 'grouplistForYear', + annee: fAnnee, + }; + }else{ + request1 = { + level_0: 'groups', + level_1: 'grouplist', + semestre: fSemestre, + }; + } + + API.send(request1, function(answer1){ + // si on a bien récupéré les étudiants + if( answer1.request == 'success' ){ + console.log( answer1.grouplist ); + + /* [2] On génère le fichier associé (excelManager) + ===================================================================*/ + var request2 = { + level_0: 'excel', + level_1: 'export_grouplist', + grouplist: answer1.grouplist // on envoie la liste qu'on vient de récupérer + }; + + API.send(request2, function(answer2){ + if( answer2.request == 'success' ){ // le fichier a bien été généré, on lance le téléchargement + document.location = answer2.pathfile; + reload(); + } + }); + } + }); + + + + }, false); + +} diff --git a/page/groups.php b/page/groups.php index db005d3..c844084 100755 --- a/page/groups.php +++ b/page/groups.php @@ -605,17 +605,17 @@ if( permission('master') || permission('admin') ){ if( !in_array($semestreOpt, $semestresListe) ) $semestreOpt = null; echo "
"; - if( $semestreOpt == null ) echo "Tous"; - else echo "Tous"; + if( $semestreOpt == null ) echo "Tous"; + else echo "Tous"; /* On récupère la liste des SEMESTRES en accord avec l'ANNEE sélectionnée */ foreach($answer->yearList as $annee){ if( $anneeOpt == $annee['annee'] ){ foreach($annee['semestres'] as $semestre){ if( in_array($semestre['id'], $semestresListe) ){ if( $semestre['id'] == $semestreOpt ) // si c'est le semestre séléctionné - echo "".$semestre['formation']." - ".$semestre['nom'].''; + echo "".$semestre['formation']." - ".$semestre['nom'].''; else // sinon on affiche normalement - echo "".$semestre['formation']." - ".$semestre['nom'].''; + echo "".$semestre['formation']." - ".$semestre['nom'].''; }} }} echo "


"; @@ -635,8 +635,8 @@ if( permission('master') || permission('admin') ){ } - echo "
Générer le fichier
"; - echo "
Télécharger le fichier
"; + echo "
Générer le fichier
"; + echo "
Télécharger le fichier
"; echo ""; diff --git a/src/files/admin2_export_liste_etudiants.xlsx b/src/files/admin2_export_liste_etudiants.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..8c78c8cfc0851c1aef71bdf1b06fb423037e3bc5 GIT binary patch literal 6522 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 we7jZs2GbM%7yN%3*KL;Dsq>p