TG-121 : add administration space

This commit is contained in:
mpenchenat 2017-03-29 11:16:41 +02:00
parent fb75b05d1b
commit c7a574c97f
10 changed files with 470 additions and 3 deletions

View File

@ -46,6 +46,8 @@
<script src="bower_components/angular-material/angular-material.js"></script>
<script src="bower_components/angular-ui-router/release/angular-ui-router.js"></script>
<script src="bower_components/angular-material-icons/angular-material-icons.min.js"></script>
<script src="bower_components/underscore/underscore.js"></script>
<script src="bower_components/angular-file-upload/dist/angular-file-upload.min.js"></script>
<!-- endbower -->
<!-- endbuild -->
@ -53,6 +55,10 @@
<script src="scripts/app.js"></script>
<script src="scripts/controllers/login.js"></script>
<script src="scripts/controllers/studentSpace.js"></script>
<script src="scripts/controllers/administrationSpace.js"></script>
<script src="scripts/controllers/administrationDialog.js"></script>
<script src="scripts/services/Filters.js"></script>
<!-- endbuild -->
</body>
</html>

View File

@ -14,7 +14,8 @@ var app = angular.module('clientApp', [
'ngSanitize',
'ngMaterial',
'ui.router',
'ngMdIcons'
'ngMdIcons',
'angularFileUpload'
]);
app.config(function ($stateProvider, $urlRouterProvider) {
@ -36,5 +37,11 @@ app.config(function ($stateProvider, $urlRouterProvider) {
url: '/espace-etudiant',
templateUrl: 'views/studentSpace.html',
controller: 'StudentSpaceCtrl'
})
.state('administrationSpace', {
url: '/espace-secretariat',
templateUrl: 'views/administrationSpace.html',
controller: 'AdministrationSpaceCtrl'
});
});

View File

@ -0,0 +1,103 @@
(function () {
'use strict';
/**
* @ngdoc function
* @name frontendApp.controller:AdministrationDialogCtrl
* @description
* # AdministrationDialogCtrl
* Controller of the frontendApp
*/
angular.module('clientApp')
.controller('AdministrationDialogCtrl', function ($scope, $state, FileUploader, $mdDialog, fileNameFilter, illegalFileNamesFilter) {
// Public methods -------------------
$scope.hide = function () {
$mdDialog.hide();
};
$scope.cancel = function () {
$mdDialog.cancel();
};
$scope.answer = function (answer) {
$mdDialog.hide(answer);
};
$scope.allDocumentsAreIllegal = function() {
return (fileNameFilter(uploader.queue, 'absence').length === 0);
};
$scope.areThereIllegalFiles = function() {
return (illegalFileNamesFilter(uploader.queue, 'absence').length !== 0);
};
var uploader = $scope.uploader = new FileUploader({
url: 'upload.php'
});
// Private methods ------------------
// FILTERS
// a sync filter
uploader.filters.push({
name: 'syncFilter',
fn: function (item /*{File|FileLikeObject}*/, options) {
console.log('syncFilter');
return this.queue.length < 10;
}
});
// an async filter
uploader.filters.push({
name: 'asyncFilter',
fn: function (item /*{File|FileLikeObject}*/, options, deferred) {
console.log('asyncFilter');
setTimeout(deferred.resolve, 1e3);
}
});
// CALLBACKS
uploader.onWhenAddingFileFailed = function (item /*{File|FileLikeObject}*/, filter, options) {
console.info('onWhenAddingFileFailed', item, filter, options);
};
uploader.onAfterAddingFile = function (fileItem) {
console.info('onAfterAddingFile', fileItem);
};
uploader.onAfterAddingAll = function (addedFileItems) {
console.info('onAfterAddingAll', addedFileItems);
};
uploader.onBeforeUploadItem = function (item) {
console.info('onBeforeUploadItem', item);
};
uploader.onProgressItem = function (fileItem, progress) {
console.info('onProgressItem', fileItem, progress);
};
uploader.onProgressAll = function (progress) {
console.info('onProgressAll', progress);
};
uploader.onSuccessItem = function (fileItem, response, status, headers) {
console.info('onSuccessItem', fileItem, response, status, headers);
};
uploader.onErrorItem = function (fileItem, response, status, headers) {
console.info('onErrorItem', fileItem, response, status, headers);
};
uploader.onCancelItem = function (fileItem, response, status, headers) {
console.info('onCancelItem', fileItem, response, status, headers);
};
uploader.onCompleteItem = function (fileItem, response, status, headers) {
console.info('onCompleteItem', fileItem, response, status, headers);
};
uploader.onCompleteAll = function () {
console.info('onCompleteAll');
};
console.info('uploader', uploader);
});
})();

View File

@ -0,0 +1,106 @@
(function () {
'use strict';
/**
* @ngdoc function
* @name frontendApp.controller:AdministrationSpaceCtrl
* @description
* # AdministrationSpaceCtrl
* Controller of the frontendApp
*/
angular.module('clientApp')
.controller('AdministrationSpaceCtrl', function ($scope, $state, $mdDialog, FileUploader) {
angular.extend($scope, {
logout,
deleteAbsence,
deleteTrackingSheet,
importAbsences
})
init();
// Public methods -------------------
function logout() {
$state.go('login');
}
function deleteAbsence(groupIndex, periodIndex, absenceIndex) {
$scope.formationGroups[groupIndex].formattedAbsences[periodIndex].absences.splice(absenceIndex, 1);
}
function deleteTrackingSheet(groupIndex, trackingSheetIndex) {
$scope.formationGroups[groupIndex].trackingSheets.splice(trackingSheetIndex, 1);
}
function importAbsences(ev, type) {
$mdDialog.show({
controller: 'AdministrationDialogCtrl',
templateUrl: 'import-fiches-absences',
parent: angular.element(document.body),
targetEvent: ev,
clickOutsideToClose: true,
fullscreen: 'false'
})
.then(function (answer) {
$scope.status = 'You said the information was "' + answer + '".';
}, function () {
$scope.status = 'You cancelled the dialog.';
});
}
// Private methods ------------------
function init() {
var formationGroups = [{
label: "Master2 ICE",
absences: [
{ id: 1, title: "Absence_Matthieu_Penchenat_P1" },
{ id: 2, title: "Absence_Renan_Husson_P1" },
{ id: 3, title: "Absence_Renan_Husson_P2" },
{ id: 1, title: "Absence_Renan_Husson_P3" },
{ id: 2, title: "Absence_Matthieu_Penchenat_P2" },
{ id: 3, title: "Absence_Matthieu_Penchenat_P3" },
{ id: 1, title: "Absence_Quentin_Rouland_P1" },
{ id: 2, title: "Absence_Quentin_Rouland_P2" },
{ id: 3, title: "Absence_Quentin_Rouland_P3" },
{ id: 1, title: "Absence_Sitan_Coulibaly_P1" },
{ id: 2, title: "Absence_Sitan_Coulibaly_P2" },
{ id: 3, title: "Absence_Sitan_Coulibaly_P3" }
],
trackingSheets: [
{ id: 3, fileName: "FicheVisite_Sitan_Coulibaly_1" },
{ id: 2, fileName: "FicheVisite_Sitan_Coulibaly_2" },
{ id: 1, fileName: "FicheVisite_Sitan_Coulibaly_3" }
]
}, {
label: "Master1 ISMAG",
absences: [
{ id: 1, title: "Absence_Matthieu_Penchenat_P1" },
{ id: 2, title: "Absence_Matthieu_Penchenat_P2" },
{ id: 3, title: "Absence_Matthieu_Penchenat_P3" }
],
trackingSheets: [
{ id: 3, fileName: "FicheVisite_Renan_Husson_1" },
{ id: 2, fileName: "FicheVisite_Renan_Husson_2" },
{ id: 1, fileName: "FicheVisite_Renan_Husson_3" }
]
}];
$scope.formationGroups = formationGroups.map(function (formationGroup) {
formationGroup.formattedAbsences = reformatAbsences(formationGroup.absences);
return formationGroup;
});
}
function reformatAbsences(absences) {
var myObj = _.groupBy(absences, function (absence) { return absence.title.split('_').pop(); });
return _.map(myObj, function (value, index) {
return { period: index, absences: value };
});
}
});
})();

View File

@ -0,0 +1,28 @@
(function () {
'use strict';
angular.module('clientApp')
.filter('fileName', function () {
return function (queue, type) {
var reg = (type === 'absence') ?/^Absence_[A-Z][a-z]*_[A-Z][a-z]*_P\d*.pdf$/ : /^Visite_[A-Z][a-z]*_[A-Z][a-z]*_P\d*.pdf$/;
return queue.filter(function (item) {
return reg.test(item.file.name);
});
};
})
.filter('illegalFileNames', function () {
return function (queue, type) {
var reg = (type === 'absence') ?/^Absence_[A-Z][a-z]*_[A-Z][a-z]*_P\d*.pdf$/ : /^Visite_[A-Z][a-z]*_[A-Z][a-z]*_P\d*.pdf$/;
return queue.filter(function (item) {
return !reg.test(item.file.name);
}).map(function(item) {
return item.file.name;
});
};
});
})();

View File

@ -34,4 +34,26 @@ body > ui-view > div > div.bg-booklet.layout-align-center-center.layout-row.flex
.p-home {
font-size: 0.6em;
}
}
.well {
padding: 15px;
margin: 5px;
background-color: #e0e0e0;
border: dotted 3px lightgray;
}
.note {
padding: 15px;
margin: 5px;
background-color: #a5d6a7;
}
.error {
padding: 15px;
margin: 5px;
background-color: #ef9a9a;
}

View File

@ -0,0 +1,189 @@
<div layout="column">
<md-toolbar>
<div class="md-toolbar-tools">
<h2 md-truncate flex>Bienvenue Isabelle Michu</h2>
<md-button ng-click="logout()">
Se déconnecter
</md-button>
</div>
</md-toolbar>
</div>
<div layout="row" layout-margin>
<div ng-cloak flex="100">
<md-content>
<md-tabs md-dynamic-height md-border-bottom>
<md-tab ng-repeat="formationGroup in formationGroups" label="{{formationGroup.label}}">
<div layout="row" layout-margin>
<md-card flex="50">
<md-card-title>
<md-card-title-text>
<span class="md-headline">Fiches d'absence</span>
</md-card-title-text>
</md-card-title>
<md-card-content>
<md-content flex layout-padding>
<div style="height: 350px; overflow: auto">
<div ng-repeat="formattedAbsence in formationGroup.formattedAbsences">
<md-subheader class="md-no-sticky">Période {{formattedAbsence.period}}</md-subheader>
<md-list-item ng-repeat="absence in formattedAbsence.absences">
<p>{{absence.title}}</p>
<ng-md-icon icon="delete" style="fill: grey" size="24" ng-click="deleteAbsence($parent.$parent.$index, $parent.$index, $index)"></ng-md-icon>
</md-list-item>
</div>
</div>
<br />
<center>
<md-button class="md-raised md-primary" ng-click="importAbsences($event)">Importer des fiches d'absences</md-button>
</center>
</md-content>
</md-card-content>
</md-card>
<md-card flex="50">
<md-card-title>
<md-card-title-text>
<span class="md-headline">Fiches de visite</span>
</md-card-title-text>
</md-card-title>
<md-card-content>
<md-content flex layout-padding>
<div style="height: 350px; overflow: auto">
<md-list-item ng-repeat="sheet in formationGroup.trackingSheets">
<p>{{sheet.fileName}}</p>
<ng-md-icon icon="delete" style="fill: grey" size="24" ng-click="deleteTrackingSheet($parent.$index, $index)"></ng-md-icon>
</md-list-item>
</div>
<br />
<center>
<md-button class="md-raised md-primary">Importer des fiches de visite</md-button>
</center>
</md-content>
</md-card-content>
</md-card>
</div>
</md-tab>
</md-tabs>
</md-content>
</div>
</div>
<script type="text/ng-template" id="import-fiches-absences">
<md-dialog aria-label="Importer des fiches d'absences">
<form ng-cloak>
<md-toolbar>
<div class="md-toolbar-tools">
<h2>Importer des fiches d'absences</h2>
</div>
</md-toolbar>
<md-dialog-content>
<div class="md-dialog-content">
<div layout="row">
<div flex>
<h3>Importer des fiches d'absences</h3>
<input type="file" nv-file-select="" accept=".pdf" uploader="uploader" multiple /><br/><br/>
<p class="note">
<ng-md-icon icon="warning" size="20"></ng-md-icon>
Note d'utilisation : chaque fiche d'absence doit respecter une règle de nommage.<br/> Nom
de fichier : Absence_Prenom_Nom_PN.pdf<br/>
<i>Le N de PN étant un numéro - exemple : (P1, P2, P3, etc.)</i>
</p>
<div ng-if="uploader.queue.length !== 0">
<h3>Liste des documents : </h3>
<p>Nombre de documents : {{ uploader.queue.length }}</p>
<div ng-if="areThereIllegalFiles()" style="background-color: #ef9a9a; padding: 2px 10px 2px 10px;margin: 10px 0 10px 0">
<p>
Les documents suivants ne respecte pas la règle de nommage :
</p>
<ul>
<li ng-repeat="fileName in uploader.queue | illegalFileNames:'absence'">{{fileName}}</li>
</ul>
</div>
<div ng-if="!allDocumentsAreIllegal()">
<table class="bordered">
<thead>
<tr>
<th width="50%">Nom</th>
<th ng-show="uploader.isHTML5">Taille</th>
<th>Status</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="item in uploader.queue | fileName:'absence'">
<td><strong>{{ item.file.name }}</strong></td>
<td ng-show="uploader.isHTML5" nowrap>{{ item.file.size/1024/1024|number:2 }} MB</td>
<td class="text-center">
<span ng-show="item.isSuccess">
<ng-md-icon icon="done" size="24"></ng-md-icon>
</span>
<span ng-show="item.isCancel">
<ng-md-icon icon="cancel" size="24"></ng-md-icon>
</span>
<span ng-show="item.isError">
<ng-md-icon icon="remove_circle_outline" size="24"></ng-md-icon>
</span>
</td>
<td nowrap>
<md-button type="button" class="md-raised md-primary" ng-click="item.upload()" ng-disabled="item.isReady || item.isUploading || item.isSuccess">
<ng-md-icon icon="file_upload" size="24"></ng-md-icon> Charger
</md-button>
<md-button type="button" class="md-raised" ng-click="item.cancel()" ng-disabled="!item.isUploading">
<ng-md-icon icon="cancel" size="24"></ng-md-icon> Annuler
</md-button>
<md-button type="button" class="md-raised md-warn" ng-click="item.remove()">
<ng-md-icon icon="remove_circle_outline" size="24"></ng-md-icon> Supprimer
</md-button>
</td>
</tr>
</tbody>
</table>
<div style='margin-top : 40px'>
<div>
Niveau de progression :
<md-progress-linear md-mode="determinate" value="{{uploader.progress}}"></md-progress-linear>
</div>
<md-button type="button" class="md-raised md-primary" ng-click="uploader.uploadAll()" ng-disabled="!uploader.getNotUploadedItems().length">
<ng-md-icon icon="file_upload" size="24"></ng-md-icon> Tout charger
</md-button>
<md-button type="button" class="md-raised" ng-click="uploader.cancelAll()" ng-disabled="!uploader.isUploading">
<ng-md-icon icon="cancel" size="24"></ng-md-icon> Tout annuler
</md-button>
<md-button type="button" class="md-raised md-warn" ng-click="uploader.clearQueue()" ng-disabled="!uploader.queue.length">
<ng-md-icon icon="remove_circle_outline" size="24"></ng-md-icon> Tout supprimer
</md-button>
</div>
</div>
</div>
</div>
</div>
</div>
</md-dialog-content>
<md-dialog-actions layout="row">
<span flex></span>
<md-button ng-click="answer('useful')">
Fermer
</md-button>
</md-dialog-actions>
</form>
</md-dialog>
</script>

View File

@ -8,6 +8,8 @@
</md-card-title-text>
</md-card-title>
<md-card-content>
<md-button ui-sref="administrationSpace">Log to administration</md-button>
<p class="p-home">
The titles of Washed Out's breakthrough song and the first single from Paracosm share the two most important words in Ernest
Greene's musical language: feel it. It's a simple request, as well...

View File

@ -8,7 +8,9 @@
"angular-sanitize": "^1.4.0",
"angular-material": "^1.1.3",
"angular-ui-router": "^0.4.2",
"angular-material-icons": "^0.7.1"
"angular-material-icons": "^0.7.1",
"underscore": "^1.8.3",
"angular-file-upload": "^2.5.0"
},
"devDependencies": {
"angular-mocks": "^1.4.0"

View File

@ -29,6 +29,8 @@ module.exports = function(config) {
'bower_components/angular-material/angular-material.js',
'bower_components/angular-ui-router/release/angular-ui-router.js',
'bower_components/angular-material-icons/angular-material-icons.min.js',
'bower_components/underscore/underscore.js',
'bower_components/angular-file-upload/dist/angular-file-upload.min.js',
'bower_components/angular-mocks/angular-mocks.js',
// endbower
'app/scripts/**/*.js',