Loading front/src/ActivityTypeSelector.vue 0 → 100644 +169 −0 Original line number Diff line number Diff line <template> <div id="activitytype" class="type-tree-selector" @mouseleave="handlerHideSelector"> <div class="value-area" v-show="!showSelector" @click="handlerShowSelector()"> <span> <i class="icon" :class="{'icon-tag' : selectedItem.children.length == 0, 'icon-archive': selectedItem.children.length > 0}"></i> {{ selectedItem.label }} </span> <i class="icon-down-dir"></i> </div> <input type="hidden" :name="inputName" v-model="selectedItem.id" /> <div class="search-area" v-show="showSelector" > <div class="search"> <input type="search" ref="search" :placeholder="selectedItem.label" v-model="filter" class="input-search" /> </div> <div class="icon"> <i class="icon-trash" @click="selected = ''"></i> </div> </div> <div class="types-selector" v-show="showSelector"> <activity-type-item v-for="item in options" :infos="item" @select="handlerSelect" :selected="selected" :allow-node-selection="allowNodeSelection" :filter="filter" :key="item.id"></activity-type-item> </div> </div> </template> <script> /******************************************************************************************************************/ /* ! DEVELOPPEUR Depuis la racine OSCAR : cd front Pour compiler en temps réél : node node_modules/.bin/vue-cli-service build --name ActivityTypeSelector --dest ../public/js/oscar/dist --no-clean --formats umd,umd-min --target lib src/ActivityTypeSelector.vue Pour compiler : node node_modules/.bin/gulp contratTypePCRU */ export default { props: { // Données JSON pour les types d'activié typesAvailable: { required: true }, // ID du type sélectionné initialSelected: { default: "" }, // allowNodeSelection: { default: false }, inputName: { default: "" } }, data() { return { formData: null, configuration: null, types: [], filter: "", selected: null, showSelector: false } }, computed: { options(){ if( this.typesAvailable[0] ){ return this.typesAvailable[0].children } }, selectedItem(){ if( !this.selected ){ return { id: "", label: "", children: [] } } else { return this.getItem(this.typesAvailable[0]) } } }, methods: { handlerShowSelector(){ this.showSelector = true; this.focusSearchInput(); }, handlerHideSelector(){ this.filter = ""; this.showSelector = false; }, focusSearchInput(){ this.$nextTick(() => { this.$refs.search.focus(); }); }, getItem(itemRoot){ if( itemRoot.id == this.selected ){ return itemRoot; } for( let i=0; i<itemRoot.children.length; i++ ){ let item = itemRoot.children[i]; let find = this.getItem(item); if( find ){ return find; } } return null; }, /** * Quand l'utilisateur à selectionner un type d'activité Oscar depuis le liste proposée. * @param evt */ handlerSelect(evt) { this.selected = evt; this.handlerHideSelector(); this.$emit('select', this.selectedItem.id); }, handlerClose(){ }, handlerAssociateError(){ }, handlerAssociateSuccess(){ }, //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // TRAITEMENT des DONNEES /** * Chargement des données */ fetch() { }, /** * Fin du chargement des données * @param success */ handlerSuccess(success) { } }, mounted() { this.selected = this.initialSelected; } } </script> No newline at end of file front/src/components/ActivityTypeItem.vue 0 → 100644 +120 −0 Original line number Diff line number Diff line <template> <div class="item-tree item" v-show="show"> <div class="item-label" @click="handlerEmitSelect()" :style="{'pointer-events': selectable ? 'auto' : 'none', 'text-decoration': selectable ? 'underline' : 'none'}"> <i class="icon-archive" v-if="isDir"></i> <i class="icon-tag" v-else></i> <strong>{{ infos.label }}</strong> <small v-if="route"> ~ {{ route }}</small> </div> <div v-if="infos.children.length > 0" class="children"> <activity-type-item v-for="child in infos.children" @select="relayEmitSelect" :class="{'selected': selected == child.id}" :selected="selected" :infos="child" :key="infos.id" :filter="filter" :route="customRoute"></activity-type-item> </div> </div> </template> <script> /******************************************************************************************************************/ /* ! DEVELOPPEUR Depuis la racine OSCAR : cd front Pour compiler en temps réél : node node_modules/.bin/vue-cli-service build --name ActivityTypeItem --dest ../public/js/oscar/dist --no-clean --formats umd,umd-min --target lib src/components/ActivityTypeItem.vue Pour compiler : node node_modules/.bin/gulp contratTypePCRU */ export default { props: { // Données de l'option { id: INT, label: STRING, children: ARRAY } infos: { required: true }, // Chaîne de recherche filter: { default: "" }, // Chemin route: { default: "" }, // ID de l'item selectionné selected: { default: null }, // Authorise la selection d'item avec des enfants allowNodeSelection: { default: false } }, computed: { /** * @returns {boolean} */ selectable(){ if( this.allowNodeSelection == true ){ return true; } else { return this.infos.children.length == 0; } }, /** * Est un "dossier" (contient des enfants) * @returns {boolean} */ isDir(){ return this.infos.children.length > 0 }, /** * L'élément est visible ? * @returns {boolean} */ show(){ let displayed = this.filter == "" || this.searchableText.indexOf(this.filter.toLowerCase()) >= 0; if( displayed == false && this.infos.children.length > 0 ){ for( let i = 0; i<this.infos.children.length; i++ ){ let child = this.infos.children[i]; if( child.label.toLowerCase().indexOf(this.filter.toLowerCase()) >= 0 ){ return true; } } } return displayed; }, /** * Retourne le "chemin" * @returns {*} */ customRoute(){ let r = this.route.split(','); r.push(this.infos.label); return r.join(','); }, searchableText(){ return (this.infos.label +" "+ this.route).toLowerCase(); } }, methods: { handlerEmitSelect( id = null ){ console.log("SELECT !", this.selectable); if( this.selectable ){ this.relayEmitSelect(id); } }, relayEmitSelect( id = null ){ let send = id ? id : this.infos.id; this.$emit('select', send); } } } </script> No newline at end of file module/Oscar/src/Oscar/Controller/AdministrationController.php +9 −0 Original line number Diff line number Diff line Loading @@ -275,6 +275,11 @@ class AdministrationController extends AbstractOscarController implements UsePro if ($this->getHttpXMethod() == "POST") { $option = $this->params()->fromPost('parameter_name'); switch ($option) { case OscarConfigurationService::allow_node_selection: $value = $this->params()->fromPost('parameter_value') == "on"; $this->getOscarConfigurationService()->setAllowNodeSelection($value); return $this->redirect()->toRoute('administration/parameters'); case OscarConfigurationService::allow_numerotation_custom: $value = $this->params()->fromPost('parameter_value') == "on"; $this->getOscarConfigurationService()->setNumerotationEditable($value); Loading Loading @@ -368,6 +373,7 @@ class AdministrationController extends AbstractOscarController implements UsePro OscarConfigurationService::pfi_strict => $this->getOscarConfigurationService()->isPfiStrict(), OscarConfigurationService::pfi_strict_format => $pfiFixed, "pfi_default_format" => $this->getOscarConfigurationService()->getConfiguration('validation.pfi'), "allow_node_selection" => $this->getOscarConfigurationService()->isAllowNodeSelection(), ]; } Loading Loading @@ -1417,6 +1423,7 @@ class AdministrationController extends AbstractOscarController implements UsePro 'validatorsRelance2' => $this->getOscarConfigurationService()->getValidatorsRelance2(), 'validatorsRelanceJour2' => $this->getOscarConfigurationService()->getvalidatorsRelanceJour2(), 'highdelayRelance' => $this->getOscarConfigurationService()->getHighDelayRelance(), 'highdelayRelanceJour' => $this->getOscarConfigurationService()->getHighDelayRelanceJour(), ]; switch ($method) { Loading @@ -1435,6 +1442,7 @@ class AdministrationController extends AbstractOscarController implements UsePro $declarersRelanceConflitMessage = $this->params()->fromPost('declarersRelanceConflitMessage'); $declarersRelanceConflitJour = (int)$this->params()->fromPost('declarersRelanceConflitJour'); $highdelayRelance = $this->params()->fromPost('highdelayRelance'); $highdelayRelanceJour = intval($this->params()->fromPost('highdelayRelanceJour')); $this->getOscarConfigurationService()->setDeclarersRelance1($declarersRelance1); $this->getOscarConfigurationService()->setDeclarersRelanceJour1($declarersRelanceJour1); Loading @@ -1449,6 +1457,7 @@ class AdministrationController extends AbstractOscarController implements UsePro ); $this->getOscarConfigurationService()->setDeclarersRelanceConflitJour($declarersRelanceConflitJour); $this->getOscarConfigurationService()->setHighDelayRelance($highdelayRelance); $this->getOscarConfigurationService()->setHighDelayRelanceJour($highdelayRelanceJour); return $this->redirect()->toRoute('administration/messages'); } Loading module/Oscar/src/Oscar/Controller/ProjectGrantController.php +6 −2 Original line number Diff line number Diff line Loading @@ -800,7 +800,9 @@ class ProjectGrantController extends AbstractOscarController implements UseNotif 'hidden' => $hidden, 'form' => $form, 'activity' => $projectGrant, 'numbers_keys' => $numerotationKeys 'numbers_keys' => $numerotationKeys, 'allowNodeSelection' => $this->getOscarConfigurationService()->isAllowNodeSelection(), "tree" => $this->getPersonService()->getProjectGrantService()->getActivityTypesTree() ] ); $view->setTemplate('oscar/project-grant/form'); Loading Loading @@ -1372,7 +1374,9 @@ class ProjectGrantController extends AbstractOscarController implements UseNotif 'activity' => $projectGrant, 'project' => $project, 'numerotationKeys' => $numerotationKeys, 'numbers_keys' => $numerotationKeys 'numbers_keys' => $numerotationKeys, 'allowNodeSelection' => $this->getOscarConfigurationService()->isAllowNodeSelection(), "tree" => $this->getPersonService()->getProjectGrantService()->getActivityTypesTree() ] ); Loading module/Oscar/src/Oscar/Controller/PublicController.php +5 −1 Original line number Diff line number Diff line Loading @@ -170,7 +170,11 @@ class PublicController extends AbstractOscarController implements UseTimesheetSe public function testAction() { if( DEBUG_OSCAR ){ return []; $json = $this->getPersonService()->getProjectGrantService()->getActivityTypes(true); return [ "json" => $json, "tree" => $this->getPersonService()->getProjectGrantService()->getActivityTypesTree() ]; } die("to test"); } Loading Loading
front/src/ActivityTypeSelector.vue 0 → 100644 +169 −0 Original line number Diff line number Diff line <template> <div id="activitytype" class="type-tree-selector" @mouseleave="handlerHideSelector"> <div class="value-area" v-show="!showSelector" @click="handlerShowSelector()"> <span> <i class="icon" :class="{'icon-tag' : selectedItem.children.length == 0, 'icon-archive': selectedItem.children.length > 0}"></i> {{ selectedItem.label }} </span> <i class="icon-down-dir"></i> </div> <input type="hidden" :name="inputName" v-model="selectedItem.id" /> <div class="search-area" v-show="showSelector" > <div class="search"> <input type="search" ref="search" :placeholder="selectedItem.label" v-model="filter" class="input-search" /> </div> <div class="icon"> <i class="icon-trash" @click="selected = ''"></i> </div> </div> <div class="types-selector" v-show="showSelector"> <activity-type-item v-for="item in options" :infos="item" @select="handlerSelect" :selected="selected" :allow-node-selection="allowNodeSelection" :filter="filter" :key="item.id"></activity-type-item> </div> </div> </template> <script> /******************************************************************************************************************/ /* ! DEVELOPPEUR Depuis la racine OSCAR : cd front Pour compiler en temps réél : node node_modules/.bin/vue-cli-service build --name ActivityTypeSelector --dest ../public/js/oscar/dist --no-clean --formats umd,umd-min --target lib src/ActivityTypeSelector.vue Pour compiler : node node_modules/.bin/gulp contratTypePCRU */ export default { props: { // Données JSON pour les types d'activié typesAvailable: { required: true }, // ID du type sélectionné initialSelected: { default: "" }, // allowNodeSelection: { default: false }, inputName: { default: "" } }, data() { return { formData: null, configuration: null, types: [], filter: "", selected: null, showSelector: false } }, computed: { options(){ if( this.typesAvailable[0] ){ return this.typesAvailable[0].children } }, selectedItem(){ if( !this.selected ){ return { id: "", label: "", children: [] } } else { return this.getItem(this.typesAvailable[0]) } } }, methods: { handlerShowSelector(){ this.showSelector = true; this.focusSearchInput(); }, handlerHideSelector(){ this.filter = ""; this.showSelector = false; }, focusSearchInput(){ this.$nextTick(() => { this.$refs.search.focus(); }); }, getItem(itemRoot){ if( itemRoot.id == this.selected ){ return itemRoot; } for( let i=0; i<itemRoot.children.length; i++ ){ let item = itemRoot.children[i]; let find = this.getItem(item); if( find ){ return find; } } return null; }, /** * Quand l'utilisateur à selectionner un type d'activité Oscar depuis le liste proposée. * @param evt */ handlerSelect(evt) { this.selected = evt; this.handlerHideSelector(); this.$emit('select', this.selectedItem.id); }, handlerClose(){ }, handlerAssociateError(){ }, handlerAssociateSuccess(){ }, //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // TRAITEMENT des DONNEES /** * Chargement des données */ fetch() { }, /** * Fin du chargement des données * @param success */ handlerSuccess(success) { } }, mounted() { this.selected = this.initialSelected; } } </script> No newline at end of file
front/src/components/ActivityTypeItem.vue 0 → 100644 +120 −0 Original line number Diff line number Diff line <template> <div class="item-tree item" v-show="show"> <div class="item-label" @click="handlerEmitSelect()" :style="{'pointer-events': selectable ? 'auto' : 'none', 'text-decoration': selectable ? 'underline' : 'none'}"> <i class="icon-archive" v-if="isDir"></i> <i class="icon-tag" v-else></i> <strong>{{ infos.label }}</strong> <small v-if="route"> ~ {{ route }}</small> </div> <div v-if="infos.children.length > 0" class="children"> <activity-type-item v-for="child in infos.children" @select="relayEmitSelect" :class="{'selected': selected == child.id}" :selected="selected" :infos="child" :key="infos.id" :filter="filter" :route="customRoute"></activity-type-item> </div> </div> </template> <script> /******************************************************************************************************************/ /* ! DEVELOPPEUR Depuis la racine OSCAR : cd front Pour compiler en temps réél : node node_modules/.bin/vue-cli-service build --name ActivityTypeItem --dest ../public/js/oscar/dist --no-clean --formats umd,umd-min --target lib src/components/ActivityTypeItem.vue Pour compiler : node node_modules/.bin/gulp contratTypePCRU */ export default { props: { // Données de l'option { id: INT, label: STRING, children: ARRAY } infos: { required: true }, // Chaîne de recherche filter: { default: "" }, // Chemin route: { default: "" }, // ID de l'item selectionné selected: { default: null }, // Authorise la selection d'item avec des enfants allowNodeSelection: { default: false } }, computed: { /** * @returns {boolean} */ selectable(){ if( this.allowNodeSelection == true ){ return true; } else { return this.infos.children.length == 0; } }, /** * Est un "dossier" (contient des enfants) * @returns {boolean} */ isDir(){ return this.infos.children.length > 0 }, /** * L'élément est visible ? * @returns {boolean} */ show(){ let displayed = this.filter == "" || this.searchableText.indexOf(this.filter.toLowerCase()) >= 0; if( displayed == false && this.infos.children.length > 0 ){ for( let i = 0; i<this.infos.children.length; i++ ){ let child = this.infos.children[i]; if( child.label.toLowerCase().indexOf(this.filter.toLowerCase()) >= 0 ){ return true; } } } return displayed; }, /** * Retourne le "chemin" * @returns {*} */ customRoute(){ let r = this.route.split(','); r.push(this.infos.label); return r.join(','); }, searchableText(){ return (this.infos.label +" "+ this.route).toLowerCase(); } }, methods: { handlerEmitSelect( id = null ){ console.log("SELECT !", this.selectable); if( this.selectable ){ this.relayEmitSelect(id); } }, relayEmitSelect( id = null ){ let send = id ? id : this.infos.id; this.$emit('select', send); } } } </script> No newline at end of file
module/Oscar/src/Oscar/Controller/AdministrationController.php +9 −0 Original line number Diff line number Diff line Loading @@ -275,6 +275,11 @@ class AdministrationController extends AbstractOscarController implements UsePro if ($this->getHttpXMethod() == "POST") { $option = $this->params()->fromPost('parameter_name'); switch ($option) { case OscarConfigurationService::allow_node_selection: $value = $this->params()->fromPost('parameter_value') == "on"; $this->getOscarConfigurationService()->setAllowNodeSelection($value); return $this->redirect()->toRoute('administration/parameters'); case OscarConfigurationService::allow_numerotation_custom: $value = $this->params()->fromPost('parameter_value') == "on"; $this->getOscarConfigurationService()->setNumerotationEditable($value); Loading Loading @@ -368,6 +373,7 @@ class AdministrationController extends AbstractOscarController implements UsePro OscarConfigurationService::pfi_strict => $this->getOscarConfigurationService()->isPfiStrict(), OscarConfigurationService::pfi_strict_format => $pfiFixed, "pfi_default_format" => $this->getOscarConfigurationService()->getConfiguration('validation.pfi'), "allow_node_selection" => $this->getOscarConfigurationService()->isAllowNodeSelection(), ]; } Loading Loading @@ -1417,6 +1423,7 @@ class AdministrationController extends AbstractOscarController implements UsePro 'validatorsRelance2' => $this->getOscarConfigurationService()->getValidatorsRelance2(), 'validatorsRelanceJour2' => $this->getOscarConfigurationService()->getvalidatorsRelanceJour2(), 'highdelayRelance' => $this->getOscarConfigurationService()->getHighDelayRelance(), 'highdelayRelanceJour' => $this->getOscarConfigurationService()->getHighDelayRelanceJour(), ]; switch ($method) { Loading @@ -1435,6 +1442,7 @@ class AdministrationController extends AbstractOscarController implements UsePro $declarersRelanceConflitMessage = $this->params()->fromPost('declarersRelanceConflitMessage'); $declarersRelanceConflitJour = (int)$this->params()->fromPost('declarersRelanceConflitJour'); $highdelayRelance = $this->params()->fromPost('highdelayRelance'); $highdelayRelanceJour = intval($this->params()->fromPost('highdelayRelanceJour')); $this->getOscarConfigurationService()->setDeclarersRelance1($declarersRelance1); $this->getOscarConfigurationService()->setDeclarersRelanceJour1($declarersRelanceJour1); Loading @@ -1449,6 +1457,7 @@ class AdministrationController extends AbstractOscarController implements UsePro ); $this->getOscarConfigurationService()->setDeclarersRelanceConflitJour($declarersRelanceConflitJour); $this->getOscarConfigurationService()->setHighDelayRelance($highdelayRelance); $this->getOscarConfigurationService()->setHighDelayRelanceJour($highdelayRelanceJour); return $this->redirect()->toRoute('administration/messages'); } Loading
module/Oscar/src/Oscar/Controller/ProjectGrantController.php +6 −2 Original line number Diff line number Diff line Loading @@ -800,7 +800,9 @@ class ProjectGrantController extends AbstractOscarController implements UseNotif 'hidden' => $hidden, 'form' => $form, 'activity' => $projectGrant, 'numbers_keys' => $numerotationKeys 'numbers_keys' => $numerotationKeys, 'allowNodeSelection' => $this->getOscarConfigurationService()->isAllowNodeSelection(), "tree" => $this->getPersonService()->getProjectGrantService()->getActivityTypesTree() ] ); $view->setTemplate('oscar/project-grant/form'); Loading Loading @@ -1372,7 +1374,9 @@ class ProjectGrantController extends AbstractOscarController implements UseNotif 'activity' => $projectGrant, 'project' => $project, 'numerotationKeys' => $numerotationKeys, 'numbers_keys' => $numerotationKeys 'numbers_keys' => $numerotationKeys, 'allowNodeSelection' => $this->getOscarConfigurationService()->isAllowNodeSelection(), "tree" => $this->getPersonService()->getProjectGrantService()->getActivityTypesTree() ] ); Loading
module/Oscar/src/Oscar/Controller/PublicController.php +5 −1 Original line number Diff line number Diff line Loading @@ -170,7 +170,11 @@ class PublicController extends AbstractOscarController implements UseTimesheetSe public function testAction() { if( DEBUG_OSCAR ){ return []; $json = $this->getPersonService()->getProjectGrantService()->getActivityTypes(true); return [ "json" => $json, "tree" => $this->getPersonService()->getProjectGrantService()->getActivityTypesTree() ]; } die("to test"); } Loading