Loading config/module.config.php +35 −2 Changes for config/module.config.php: 35 added lines, 2 removed lines. Original line number Diff line number Diff line Loading @@ -53,15 +53,48 @@ return [ 'unicaen-signature' => [ 'get_recipients_methods' => [ [ 'key' => 'persons_by_role', 'label' => 'Personnes par rôle', 'description' => 'Selectionne les personnes en fonction de leurs rôles', 'options' => [ [ 'key' => 'role_person_id', 'label' => "Rôle dans l'activité", 'type' => 'checkbox', 'values' => [ ['id' => 7, 'label' => 'Responsable scientifique'], ['id' => 9, 'label' => 'Chargé de projet'] ] ], [ 'key' => 'role_organisation_id', 'label' => "étendre aux structures", 'type' => 'checkbox', 'values' => [ ['id' => 3, 'label' => 'Laboratoire'], ['id' => 5, 'label' => 'Composante de gestion'] ] ] ], 'methods_on_create' => null ], [ 'key' => \UnicaenSignature\Utils\SignatureConstants::GET_RECIPIENTS_METHOD_FIXED, 'label' => 'Destinataires fixes', 'methods' => 'fixed' 'description' => 'Destinataires nommés explicitement', 'methods' => 'fixed', 'options' => [], 'methods_on_create' => null ], [ 'key' => \UnicaenSignature\Utils\SignatureConstants::GET_RECIPIENTS_METHOD_FREE, 'label' => 'Destinataires libres', 'methods' => 'free' 'description' => 'Destinataires nommés au déclenchement du processus', 'methods' => 'free', 'options' => [], 'methods_on_create' => null ] ], Loading public/src/views/SignatureFlows.vue +301 −40 Changes for public/src/views/SignatureFlows.vue: 301 added lines, 40 removed lines. Original line number Diff line number Diff line <template> <section class="signatureflows"> <div class="alert alert-danger" v-if="error"> <div class="overlay error" v-if="error"> <div class="overlay-content"> {{ error }} <hr> <a href="#" @click="error = ''">Fermer</a> <a href="#" class="btn btn-default" @click="error = ''">Fermer</a> </div> </div> <div class="overlay" v-if="loading"> <div class="overlay-content"> <i class="icon-spinner animate-spin"></i> {{ loading }} </div> </div> <section class="row"> <div class="col-md-6"> <div class="col-md-8"> <article v-if="editSignatureFlow" class="signatureflows-edit"> <h2>Edition de la procédure</h2> <div> <label for="label"> Intitulé </label> <input type="text" placeholder="Intitulé" name="label" id="label" class="form-control" /> <input type="text" v-model="editSignatureFlow.label" placeholder="Intitulé" name="label" id="label" class="form-control"/> </div> <div> <label for="description"> Description </label> <input type="text" placeholder="Intitulé" name="description" id="description" class="form-control" /> <input type="text" v-model="editSignatureFlow.description" placeholder="Une description" name="description" id="description" class="form-control"/> </div> <section class="steps"> <h3>étapes</h3> <article v-if="editStep" class="step-edit"> <h3> Modification de l'étape <strong>{{ editStep.label }}</strong> </h3> <input type="text" v-model="editStep.label" class="form-control"/> <div> ORDER : {{ editStep.order }} </div> <label for="letterfile">Parapheur</label> <select v-model="editStep.letterfile" id="letterfile" class="form-control"> <option v-for="l in letterfiles" :value="l.name">{{ l.label }}</option> Loading @@ -37,37 +50,87 @@ <label for="level">Type de validation</label> <select v-model="editStep.level" v-if="editStep.letterfile" id="level" class="form-control"> <option v-for="l in getLevel(editStep.letterfile)" :value="l.key">{{ l.label }}</option> <option v-for="l in getLevels(editStep.letterfile)" :value="l.key">{{ l.label }}</option> </select> <label for="method">Méthode d'obtention des destinataires</label> <select v-model="editStep.method" id="method" class="form-control"> <select v-model="editStep.method" id="method" class="form-control" @change="handlerChangeMethod"> <option v-for="l in get_recipients_methods" :value="l.key">{{ l.label }}</option> </select> <section class="options" v-if="stepHasOptions(editStep)"> <h3>Paramètres de récupération des destinataires</h3> <section v-for="o in getStepOptions(editStep)"> <h4>{{ o.label }}</h4> <p>{{ o.description }}</p> <section v-if="o.type == 'checkbox'"> <label :for="o.key +'_'+ id" v-for="v,id in o.values" class="form-control"> <input v-model="editStep.options[o.key]" type="checkbox" :value="v.id" :id="o.key +'_'+ id" /> {{ v.label }} </label> </section> </section> </section> <nav> <button @click="handlerEditStepSave" class="btn btn-success">Enregistré</button> <button @click="handlerEditStepCancel" class="btn btn-danger">Annulé</button> <button @click="handlerEditStepSave" class="btn btn-success">Terminer</button> <button @click="handlerEditStepCancel" class="btn btn-danger">Annuler</button> </nav> </article> <article v-for="s in editSignatureFlow.steps" class="step" v-else> {{ s }} - <button class="btn btn-success btn-xs" @click="handlerEditStep(s)">Modifier</button> <button class="btn btn-danger btn-xs" @click="handlerDeleteStep(s)">Supprimer</button> <section v-else> <h3>étapes</h3> <article v-for="s in editSignatureFlow.steps" class="step"> <h4> <i class="icon-location"></i> {{ s.label }}</h4> <div> Niveau de validation : <strong>{{ getLevelsLabel(s) }}</strong><br> Parapheur : <strong>{{ getLetterfileLabel(s.letterfile) }}</strong><br> Destinataires : <strong>{{ getMethodLabel(s.method) }}</strong> </div> <nav class="buttons-bar"> <button class="btn btn-default btn-xs" @click="handlerEditStep(s)">Modifier</button> <button class="btn btn-default btn-xs" @click="handlerDeleteStep(s)">Supprimer</button> </nav> </article> <button @click="handlerNewStep" class="btn btn-success btn-xs">Nouvelle étape</button> <nav class="buttons-bar"> <button @click="handlerNewStep" class="btn btn-default"> <i class="icon-location"></i> Nouvelle étape </button> </nav> <hr> <nav> <button @click="handlerEditSignatureFlowSave" class="btn btn-success">Enregistrer</button> <button @click="handlerEditSignatureFlowCancel" class="btn btn-success">Annuler</button> <button @click="handlerEditSignatureFlowSave" class="btn btn-large btn-success">Enregistrer la procédure</button> <button @click="handlerEditSignatureFlowCancel" class="btn btn-danger">Annuler les modifications</button> </nav> </section> </section> </article> <section v-else> <article v-for="sf in signatureflows" class="signatureflow"> {{ sf }} - <button class="btn btn-xs btn-success" @click="handlerEditSignatureFlow(sf)">Modifier</button> <button class="btn btn-xs btn-danger" @click="handlerDeleteSignatureFlow(sf)">Supprimer</button> <h3>Procédure : <strong>{{ sf.label }}</strong> <small> (ID: {{ sf.id }})</small></h3> <p><small>{{ sf.description }}</small></p> <section class="steps" v-if="sf.steps.length"> <article v-for="s in sf.steps" class="step"> <h4>{{ s.label }}</h4> <small> Parapheur : <strong>{{ getLetterfileLabel(s.letterfile) }}</strong> - Niveau de validation : <strong>{{ getLevelsLabel(s) }}</strong> - Destinataires : <strong>{{ getMethodLabel(s.method) }}</strong> </small> </article> </section> <section class="alert alert-info" v-else> Aucune étape configurée </section> <nav class="buttons-bar"> <button class="btn btn-xs" @click="handlerEditSignatureFlow(sf)">Modifier la procédure</button> <button class="btn btn-xs" @click="handlerDeleteSignatureFlow(sf)">Supprimer la procédure</button> </nav> </article> <nav> <button class="btn btn-success" @click="handlerNewSignatureFlow"> Loading @@ -77,8 +140,9 @@ </section> <hr> </div> <div class="col-md-6"> <pre style="font-size: 12px">{{ $data }}</pre> <div class="col-md-4"> <pre style="font-size: 12px">{{ letterfiles }}</pre> <pre style="font-size: 12px">{{ signatureflows }}</pre> </div> </section> Loading @@ -91,39 +155,53 @@ export default { props: { entrypoint: {required: true, type: String} }, data() { return { signatureflows: [], letterfiles: [], get_recipients_methods: null, editSignatureFlow: null, editStep: null, editedStep: null, editSignatureFlow: null, editedSignatureFlow: null, error: '' } }, methods: { //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // PROCESSUS handlerEditSignatureFlow(sf) { this.editedSignatureFlow = sf; this.editSignatureFlow = JSON.parse(JSON.stringify(sf)); }, handlerDeleteSignatureFlow(sf) { let i = this.signatureflows.indexOf(sf); this.signatureflows.splice(i, 1); this.remoteDelete(sf); // let i = this.signatureflows.indexOf(sf); // this.signatureflows.splice(i, 1); }, handlerEditSignatureFlowCancel() { this.editedStep = null; this.editStep = null; this.editSignatureFlow = null; this.editedSignatureFlow = null; }, handlerEditSignatureFlowSave() { if (this.editedSignatureFlow) { let i = this.signatureflows.indexOf(this.editSignatureFlow); this.signatureflows[i] = JSON.parse(JSON.stringify(this.editSignatureFlow)); this.editedSignatureFlow = null; } else { this.signatureflows.push(JSON.parse(JSON.stringify(this.editSignatureFlow))); this.editSignatureFlow = null; } this.remoteSave(this.editSignatureFlow); this.editSignatureFlow = null; }, handlerNewSignatureFlow() { this.editSignatureFlow = { id: null, Loading @@ -131,16 +209,19 @@ export default { description: "", letterfile: "", level: "", steps: [ ] steps: [], options: null } }, //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // ETAPES handlerNewStep() { let order = this.editSignatureFlow.steps.length; let autoOrder = this.editSignatureFlow.steps.length; this.editSignatureFlow.steps.push({ id: null, label: "Nouvelle étape", order : order, order: autoOrder, letterfile: null, level: null, allValid: false, Loading @@ -160,14 +241,19 @@ export default { handlerEditStep(step) { this.editStep = JSON.parse(JSON.stringify(step)); this.editedStep = step; let options = this.getStepOptions(step); console.log("options", options); }, handlerDeleteStep(step) { let i = this.editSignatureFlow.steps.indexOf(step); this.editSignatureFlow.steps.splice(i, 1); }, // getLevel(letterfileKey){ //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Accès aux données getLevels(letterfileKey) { for (let i = 0; i < this.letterfiles.length; i++) { if (this.letterfiles[i].name == letterfileKey) { return this.letterfiles[i].levels; Loading @@ -175,14 +261,137 @@ export default { } return []; }, getLevelsLabel(step) { let levelKey = step.level; if( !levelKey ) { return 'Non configuré'; } else { let letterfile = step.letterfile; if( !letterfile ){ return 'Pas de parapheur'; } else { let levels = this.getLevels(step.letterfile); for (let i = 0; i < levels.length; i++) { if (levels[i].key == step.level) { return levels[i].label; } } return 'inconnue'; } } }, handlerChangeMethod(evt){ console.log("Changement de méthode", this.editStep.method); let methodConfig = this.getMethodOption(this.editStep.method); if( !this.editStep.options || Array.isArray(this.editStep.options) ){ this.editStep.options = {}; } methodConfig.forEach(opt => { if(!this.editStep.options.hasOwnProperty(opt.key)){ this.editStep.options[opt.key] = []; } }); console.log(methodConfig); }, getMethod( methodKey ){ for ( let i=0; i<this.get_recipients_methods.length; i++) { if( this.get_recipients_methods[i].key == methodKey ){ return this.get_recipients_methods[i]; } } return null; }, getMethodLabel( methodKey ){ let method = this.getMethod(methodKey); if( method ){ return method.label; } else { return "N.D"; } }, getStepOptions(step) { let method = this.getMethod(step.method); if( method ){ return method.options; } else { return null; } }, stepHasOptions(step) { let options = this.getStepOptions(step); return options != null; }, getLetterfile( letterFileKey) { for ( let i=0; i<this.letterfiles.length; i++) { if( this.letterfiles[i].name == letterFileKey ){ return this.letterfiles[i]; } } return null; }, getLetterfileLabel( letterFileKey) { let letterfile = this.getLetterfile(letterFileKey); if( letterfile ){ return letterfile.label; } else { return "N.D"; } }, fetch() { console.log(this.entrypoint); this.loading = "Chargement des processus"; axios.get(this.entrypoint).then(ok => { this.signatureflows = ok.data.signatureflows this.letterfiles = ok.data.letterfiles this.get_recipients_methods = ok.data.get_recipients_methods this.loading = ""; }, ko => { this.error = ""; }) }, remoteDelete(signatureflow) { this.loading = "Suppression"; let datas = new FormData(); datas.append('action', 'delete'); datas.append('json', JSON.stringify(signatureflow)); axios.post(this.entrypoint, datas).then(ok => { this.loading = ""; this.fetch(); }, ko => { this.loading = ""; try { this.error = ko.response.data.error; } catch (err) { this.error = "Une erreur inconnue est survenue côté serveur"; } }) }, remoteSave(signatureflow) { this.loading = "Enregistement"; let datas = new FormData(); datas.append('action', 'save'); datas.append('json', JSON.stringify(signatureflow)); axios.post(this.entrypoint, datas).then(ok => { this.loading = ""; this.fetch(); }, ko => { this.loading = ""; try { this.error = ko.response.data.error; } catch (err) { this.error = "Une erreur inconnue est survenue côté serveur"; } }) } }, Loading @@ -192,15 +401,67 @@ export default { } </script> <style type="text/css"> <style lang="scss"> .signatureflow { border: solid #dde2e5 thin; padding: .5em 1em; margin: 1em 0; } .step { .buttons-bar { padding-top: .5em; border-top: solid #dde2e5 thin; } .steps { margin: 1em 0; padding: 1em; border: solid #dde2e5 thin; } .step { padding: .5em 1em; border: solid #dde2e5 thin; border-left: solid #dde2e5 4px; margin: 1em 0; } .buttons-right { text-align: right; } .overlay { display: flex; position: fixed; top: 0; left: 0; bottom: 0; right: 0; transition: all .3s; background: rgba(255, 255, 255, .9); .overlay-content { font-size: 1.2em; flex: 0 50%; padding: 1em 2em; border: solid 1px #dae1e5; background: #ffffff; box-shadow: 0 0 3em rgba(0, 0, 0, .25); } } .overlay.error { display: flex; position: fixed; top: 0; left: 0; bottom: 0; right: 0; background: rgba(0, 10, 0, .9); .overlay-content { color: white; background: rgba(150, 10, 0, 1); } } </style> No newline at end of file src/Controller/SignatureController.php +67 −6 Changes for src/Controller/SignatureController.php: 67 added lines, 6 removed lines. Original line number Diff line number Diff line Loading @@ -3,11 +3,14 @@ namespace UnicaenSignature\Controller; use Exception; use Laminas\Http\Request; use Laminas\Http\Response; use Laminas\Mvc\Controller\AbstractActionController; use Laminas\Mvc\Plugin\FlashMessenger\FlashMessenger; use Laminas\View\Model\JsonModel; use Laminas\View\Model\ViewModel; use UnicaenSignature\Entity\Db\Signature; use UnicaenSignature\Entity\Db\SignatureFlow; use UnicaenSignature\Form\SignatureForm; use UnicaenSignature\Service\SignatureServiceAwareTrait; use UnicaenSignature\Utils\SignatureConstants; Loading @@ -22,14 +25,72 @@ class SignatureController extends AbstractActionController return $this->getPluginManager()->get('flashmessenger'); } public function signatureflowsAction() :ViewModel { return new JsonModel([ public function signatureflowsAction(): ViewModel|\Laminas\Http\Response { if ($this->getRequest()->isPost()) { $this->getSignatureService()->getLoggerService()->debug("Traitement des données envoyées"); $posted = $this->getRequest()->getPost()->toArray(); $action = $posted['action']; switch ($action) { case 'save' : $datas = json_decode($posted['json'], true); try { $this->getSignatureService()->saveSignatureFlowFromJSON($datas); return new JsonModel(['message' => "ok"]); } catch (Exception $e) { $this->response->setCustomStatusCode(Response::STATUS_CODE_501); return new JsonModel(['error' => $e->getMessage()]); } break; case 'delete' : $datas = json_decode($posted['json'], true); try { $this->getSignatureService()->deleteSignatureFlowFromJSON($datas); return new JsonModel(['message' => "ok"]); } catch (Exception $e) { $this->response->setCustomStatusCode(Response::STATUS_CODE_501); return new JsonModel(['error' => $e->getMessage()]); } break; default: $this->response->setCustomStatusCode(Response::STATUS_CODE_400); return new JsonModel(['error' => "Mauvaise utilisation de l'API"]); } $this->getSignatureService()->getLoggerService()->debug(print_r($posted, true)); } // SignatureFlow normalize $signatureflows = $this->getSignatureService()->getSignatureFlows(SignatureConstants::FORMAT_ARRAY); foreach ($signatureflows as $i=>$sf) { foreach ($sf['steps'] as $j=>&$step) { $this->getSignatureService()->getLoggerService()->debug("ICI"); $options = $this->getSignatureService()->getSignatureConfigurationService()->getDefaultMethodOptionsByKey($step['method']); $this->getSignatureService()->getLoggerService()->debug(print_r($options,true)); foreach ($options as $key=>$value) { if( !array_key_exists($key,$step['options']) ){ $step['options'][$key] = $value; } } $signatureflows[$i]['steps'][$j]['options'] = $step['options']; } } return new JsonModel( [ 'version' => 1.0, 'signatureflows' => $this->getSignatureService()->getSignatureFlows(SignatureConstants::FORMAT_ARRAY), 'letterfiles' => $this->getSignatureService()->getLetterFiles(SignatureConstants::FORMAT_ARRAY), 'get_recipients_methods' => $this->getSignatureService()->getSignatureConfigurationService()->getRecipientsMethods(), 'signatureflows' => $signatureflows, 'letterfiles' => $this->getSignatureService()->getLetterFiles( SignatureConstants::FORMAT_ARRAY ), 'get_recipients_methods' => $this->getSignatureService()->getSignatureConfigurationService( )->getRecipientsMethods(), 'levels' => [] ]); ] ); } /** Loading src/Entity/Db/SignatureFlow.php +36 −2 Changes for src/Entity/Db/SignatureFlow.php: 36 added lines, 2 removed lines. Original line number Diff line number Diff line Loading @@ -5,6 +5,8 @@ namespace UnicaenSignature\Entity\Db; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\ORM\Mapping as ORM; use DateTime; use UnicaenSignature\Formatter\IObjectFormattable; use UnicaenSignature\Formatter\ObjectFormatter; use UnicaenSignature\Service\SignatureService; use UnicaenSignature\Utils\SignatureConstants; Loading @@ -13,7 +15,7 @@ use UnicaenSignature\Utils\SignatureConstants; * @ORM\Entity(repositoryClass="UnicaenSignature\Entity\Repository\SignatureFlowRepository") * @ORM\Table(name="unicaen_signature_signatureflow") */ class SignatureFlow class SignatureFlow implements IObjectFormattable { /** * @ORM\Id Loading @@ -37,13 +39,14 @@ class SignatureFlow /** * @var ArrayCollection * @ORM\OneToMany(targetEntity="SignatureFlowStep", mappedBy="signatureFlow", cascade={"persist","remove"}) * @ORM\OrderBy({"order" = "ASC"}) */ protected $steps; /** * @return int */ public function getId(): ?int public function getId(): int { return $this->id; } Loading Loading @@ -90,6 +93,14 @@ class SignatureFlow return $this->steps; } public function getStepsIndexed() :array { $out = []; foreach ($this->getSteps() as $step) { $out[$step->getId()] = $step; } return $out; } /** * @param $steps */ Loading @@ -98,4 +109,27 @@ class SignatureFlow $this->steps = $steps; return $this; } public function toJson(): array { return $this->toArray(); } public function toArray(): array { $objectFormatter = new ObjectFormatter(); return [ 'id' => $this->getId(), 'label' => $this->getLabel(), 'description' => $this->getDescription(), 'steps' => $objectFormatter->formatCollection($this->getSteps()->toArray(), ObjectFormatter::FORMAT_JSON) ]; } public function getOptionLabel(): string { return $this->getLabel(); } } No newline at end of file src/Entity/Db/SignatureFlowStep.php +60 −2 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
config/module.config.php +35 −2 Changes for config/module.config.php: 35 added lines, 2 removed lines. Original line number Diff line number Diff line Loading @@ -53,15 +53,48 @@ return [ 'unicaen-signature' => [ 'get_recipients_methods' => [ [ 'key' => 'persons_by_role', 'label' => 'Personnes par rôle', 'description' => 'Selectionne les personnes en fonction de leurs rôles', 'options' => [ [ 'key' => 'role_person_id', 'label' => "Rôle dans l'activité", 'type' => 'checkbox', 'values' => [ ['id' => 7, 'label' => 'Responsable scientifique'], ['id' => 9, 'label' => 'Chargé de projet'] ] ], [ 'key' => 'role_organisation_id', 'label' => "étendre aux structures", 'type' => 'checkbox', 'values' => [ ['id' => 3, 'label' => 'Laboratoire'], ['id' => 5, 'label' => 'Composante de gestion'] ] ] ], 'methods_on_create' => null ], [ 'key' => \UnicaenSignature\Utils\SignatureConstants::GET_RECIPIENTS_METHOD_FIXED, 'label' => 'Destinataires fixes', 'methods' => 'fixed' 'description' => 'Destinataires nommés explicitement', 'methods' => 'fixed', 'options' => [], 'methods_on_create' => null ], [ 'key' => \UnicaenSignature\Utils\SignatureConstants::GET_RECIPIENTS_METHOD_FREE, 'label' => 'Destinataires libres', 'methods' => 'free' 'description' => 'Destinataires nommés au déclenchement du processus', 'methods' => 'free', 'options' => [], 'methods_on_create' => null ] ], Loading
public/src/views/SignatureFlows.vue +301 −40 Changes for public/src/views/SignatureFlows.vue: 301 added lines, 40 removed lines. Original line number Diff line number Diff line <template> <section class="signatureflows"> <div class="alert alert-danger" v-if="error"> <div class="overlay error" v-if="error"> <div class="overlay-content"> {{ error }} <hr> <a href="#" @click="error = ''">Fermer</a> <a href="#" class="btn btn-default" @click="error = ''">Fermer</a> </div> </div> <div class="overlay" v-if="loading"> <div class="overlay-content"> <i class="icon-spinner animate-spin"></i> {{ loading }} </div> </div> <section class="row"> <div class="col-md-6"> <div class="col-md-8"> <article v-if="editSignatureFlow" class="signatureflows-edit"> <h2>Edition de la procédure</h2> <div> <label for="label"> Intitulé </label> <input type="text" placeholder="Intitulé" name="label" id="label" class="form-control" /> <input type="text" v-model="editSignatureFlow.label" placeholder="Intitulé" name="label" id="label" class="form-control"/> </div> <div> <label for="description"> Description </label> <input type="text" placeholder="Intitulé" name="description" id="description" class="form-control" /> <input type="text" v-model="editSignatureFlow.description" placeholder="Une description" name="description" id="description" class="form-control"/> </div> <section class="steps"> <h3>étapes</h3> <article v-if="editStep" class="step-edit"> <h3> Modification de l'étape <strong>{{ editStep.label }}</strong> </h3> <input type="text" v-model="editStep.label" class="form-control"/> <div> ORDER : {{ editStep.order }} </div> <label for="letterfile">Parapheur</label> <select v-model="editStep.letterfile" id="letterfile" class="form-control"> <option v-for="l in letterfiles" :value="l.name">{{ l.label }}</option> Loading @@ -37,37 +50,87 @@ <label for="level">Type de validation</label> <select v-model="editStep.level" v-if="editStep.letterfile" id="level" class="form-control"> <option v-for="l in getLevel(editStep.letterfile)" :value="l.key">{{ l.label }}</option> <option v-for="l in getLevels(editStep.letterfile)" :value="l.key">{{ l.label }}</option> </select> <label for="method">Méthode d'obtention des destinataires</label> <select v-model="editStep.method" id="method" class="form-control"> <select v-model="editStep.method" id="method" class="form-control" @change="handlerChangeMethod"> <option v-for="l in get_recipients_methods" :value="l.key">{{ l.label }}</option> </select> <section class="options" v-if="stepHasOptions(editStep)"> <h3>Paramètres de récupération des destinataires</h3> <section v-for="o in getStepOptions(editStep)"> <h4>{{ o.label }}</h4> <p>{{ o.description }}</p> <section v-if="o.type == 'checkbox'"> <label :for="o.key +'_'+ id" v-for="v,id in o.values" class="form-control"> <input v-model="editStep.options[o.key]" type="checkbox" :value="v.id" :id="o.key +'_'+ id" /> {{ v.label }} </label> </section> </section> </section> <nav> <button @click="handlerEditStepSave" class="btn btn-success">Enregistré</button> <button @click="handlerEditStepCancel" class="btn btn-danger">Annulé</button> <button @click="handlerEditStepSave" class="btn btn-success">Terminer</button> <button @click="handlerEditStepCancel" class="btn btn-danger">Annuler</button> </nav> </article> <article v-for="s in editSignatureFlow.steps" class="step" v-else> {{ s }} - <button class="btn btn-success btn-xs" @click="handlerEditStep(s)">Modifier</button> <button class="btn btn-danger btn-xs" @click="handlerDeleteStep(s)">Supprimer</button> <section v-else> <h3>étapes</h3> <article v-for="s in editSignatureFlow.steps" class="step"> <h4> <i class="icon-location"></i> {{ s.label }}</h4> <div> Niveau de validation : <strong>{{ getLevelsLabel(s) }}</strong><br> Parapheur : <strong>{{ getLetterfileLabel(s.letterfile) }}</strong><br> Destinataires : <strong>{{ getMethodLabel(s.method) }}</strong> </div> <nav class="buttons-bar"> <button class="btn btn-default btn-xs" @click="handlerEditStep(s)">Modifier</button> <button class="btn btn-default btn-xs" @click="handlerDeleteStep(s)">Supprimer</button> </nav> </article> <button @click="handlerNewStep" class="btn btn-success btn-xs">Nouvelle étape</button> <nav class="buttons-bar"> <button @click="handlerNewStep" class="btn btn-default"> <i class="icon-location"></i> Nouvelle étape </button> </nav> <hr> <nav> <button @click="handlerEditSignatureFlowSave" class="btn btn-success">Enregistrer</button> <button @click="handlerEditSignatureFlowCancel" class="btn btn-success">Annuler</button> <button @click="handlerEditSignatureFlowSave" class="btn btn-large btn-success">Enregistrer la procédure</button> <button @click="handlerEditSignatureFlowCancel" class="btn btn-danger">Annuler les modifications</button> </nav> </section> </section> </article> <section v-else> <article v-for="sf in signatureflows" class="signatureflow"> {{ sf }} - <button class="btn btn-xs btn-success" @click="handlerEditSignatureFlow(sf)">Modifier</button> <button class="btn btn-xs btn-danger" @click="handlerDeleteSignatureFlow(sf)">Supprimer</button> <h3>Procédure : <strong>{{ sf.label }}</strong> <small> (ID: {{ sf.id }})</small></h3> <p><small>{{ sf.description }}</small></p> <section class="steps" v-if="sf.steps.length"> <article v-for="s in sf.steps" class="step"> <h4>{{ s.label }}</h4> <small> Parapheur : <strong>{{ getLetterfileLabel(s.letterfile) }}</strong> - Niveau de validation : <strong>{{ getLevelsLabel(s) }}</strong> - Destinataires : <strong>{{ getMethodLabel(s.method) }}</strong> </small> </article> </section> <section class="alert alert-info" v-else> Aucune étape configurée </section> <nav class="buttons-bar"> <button class="btn btn-xs" @click="handlerEditSignatureFlow(sf)">Modifier la procédure</button> <button class="btn btn-xs" @click="handlerDeleteSignatureFlow(sf)">Supprimer la procédure</button> </nav> </article> <nav> <button class="btn btn-success" @click="handlerNewSignatureFlow"> Loading @@ -77,8 +140,9 @@ </section> <hr> </div> <div class="col-md-6"> <pre style="font-size: 12px">{{ $data }}</pre> <div class="col-md-4"> <pre style="font-size: 12px">{{ letterfiles }}</pre> <pre style="font-size: 12px">{{ signatureflows }}</pre> </div> </section> Loading @@ -91,39 +155,53 @@ export default { props: { entrypoint: {required: true, type: String} }, data() { return { signatureflows: [], letterfiles: [], get_recipients_methods: null, editSignatureFlow: null, editStep: null, editedStep: null, editSignatureFlow: null, editedSignatureFlow: null, error: '' } }, methods: { //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // PROCESSUS handlerEditSignatureFlow(sf) { this.editedSignatureFlow = sf; this.editSignatureFlow = JSON.parse(JSON.stringify(sf)); }, handlerDeleteSignatureFlow(sf) { let i = this.signatureflows.indexOf(sf); this.signatureflows.splice(i, 1); this.remoteDelete(sf); // let i = this.signatureflows.indexOf(sf); // this.signatureflows.splice(i, 1); }, handlerEditSignatureFlowCancel() { this.editedStep = null; this.editStep = null; this.editSignatureFlow = null; this.editedSignatureFlow = null; }, handlerEditSignatureFlowSave() { if (this.editedSignatureFlow) { let i = this.signatureflows.indexOf(this.editSignatureFlow); this.signatureflows[i] = JSON.parse(JSON.stringify(this.editSignatureFlow)); this.editedSignatureFlow = null; } else { this.signatureflows.push(JSON.parse(JSON.stringify(this.editSignatureFlow))); this.editSignatureFlow = null; } this.remoteSave(this.editSignatureFlow); this.editSignatureFlow = null; }, handlerNewSignatureFlow() { this.editSignatureFlow = { id: null, Loading @@ -131,16 +209,19 @@ export default { description: "", letterfile: "", level: "", steps: [ ] steps: [], options: null } }, //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // ETAPES handlerNewStep() { let order = this.editSignatureFlow.steps.length; let autoOrder = this.editSignatureFlow.steps.length; this.editSignatureFlow.steps.push({ id: null, label: "Nouvelle étape", order : order, order: autoOrder, letterfile: null, level: null, allValid: false, Loading @@ -160,14 +241,19 @@ export default { handlerEditStep(step) { this.editStep = JSON.parse(JSON.stringify(step)); this.editedStep = step; let options = this.getStepOptions(step); console.log("options", options); }, handlerDeleteStep(step) { let i = this.editSignatureFlow.steps.indexOf(step); this.editSignatureFlow.steps.splice(i, 1); }, // getLevel(letterfileKey){ //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Accès aux données getLevels(letterfileKey) { for (let i = 0; i < this.letterfiles.length; i++) { if (this.letterfiles[i].name == letterfileKey) { return this.letterfiles[i].levels; Loading @@ -175,14 +261,137 @@ export default { } return []; }, getLevelsLabel(step) { let levelKey = step.level; if( !levelKey ) { return 'Non configuré'; } else { let letterfile = step.letterfile; if( !letterfile ){ return 'Pas de parapheur'; } else { let levels = this.getLevels(step.letterfile); for (let i = 0; i < levels.length; i++) { if (levels[i].key == step.level) { return levels[i].label; } } return 'inconnue'; } } }, handlerChangeMethod(evt){ console.log("Changement de méthode", this.editStep.method); let methodConfig = this.getMethodOption(this.editStep.method); if( !this.editStep.options || Array.isArray(this.editStep.options) ){ this.editStep.options = {}; } methodConfig.forEach(opt => { if(!this.editStep.options.hasOwnProperty(opt.key)){ this.editStep.options[opt.key] = []; } }); console.log(methodConfig); }, getMethod( methodKey ){ for ( let i=0; i<this.get_recipients_methods.length; i++) { if( this.get_recipients_methods[i].key == methodKey ){ return this.get_recipients_methods[i]; } } return null; }, getMethodLabel( methodKey ){ let method = this.getMethod(methodKey); if( method ){ return method.label; } else { return "N.D"; } }, getStepOptions(step) { let method = this.getMethod(step.method); if( method ){ return method.options; } else { return null; } }, stepHasOptions(step) { let options = this.getStepOptions(step); return options != null; }, getLetterfile( letterFileKey) { for ( let i=0; i<this.letterfiles.length; i++) { if( this.letterfiles[i].name == letterFileKey ){ return this.letterfiles[i]; } } return null; }, getLetterfileLabel( letterFileKey) { let letterfile = this.getLetterfile(letterFileKey); if( letterfile ){ return letterfile.label; } else { return "N.D"; } }, fetch() { console.log(this.entrypoint); this.loading = "Chargement des processus"; axios.get(this.entrypoint).then(ok => { this.signatureflows = ok.data.signatureflows this.letterfiles = ok.data.letterfiles this.get_recipients_methods = ok.data.get_recipients_methods this.loading = ""; }, ko => { this.error = ""; }) }, remoteDelete(signatureflow) { this.loading = "Suppression"; let datas = new FormData(); datas.append('action', 'delete'); datas.append('json', JSON.stringify(signatureflow)); axios.post(this.entrypoint, datas).then(ok => { this.loading = ""; this.fetch(); }, ko => { this.loading = ""; try { this.error = ko.response.data.error; } catch (err) { this.error = "Une erreur inconnue est survenue côté serveur"; } }) }, remoteSave(signatureflow) { this.loading = "Enregistement"; let datas = new FormData(); datas.append('action', 'save'); datas.append('json', JSON.stringify(signatureflow)); axios.post(this.entrypoint, datas).then(ok => { this.loading = ""; this.fetch(); }, ko => { this.loading = ""; try { this.error = ko.response.data.error; } catch (err) { this.error = "Une erreur inconnue est survenue côté serveur"; } }) } }, Loading @@ -192,15 +401,67 @@ export default { } </script> <style type="text/css"> <style lang="scss"> .signatureflow { border: solid #dde2e5 thin; padding: .5em 1em; margin: 1em 0; } .step { .buttons-bar { padding-top: .5em; border-top: solid #dde2e5 thin; } .steps { margin: 1em 0; padding: 1em; border: solid #dde2e5 thin; } .step { padding: .5em 1em; border: solid #dde2e5 thin; border-left: solid #dde2e5 4px; margin: 1em 0; } .buttons-right { text-align: right; } .overlay { display: flex; position: fixed; top: 0; left: 0; bottom: 0; right: 0; transition: all .3s; background: rgba(255, 255, 255, .9); .overlay-content { font-size: 1.2em; flex: 0 50%; padding: 1em 2em; border: solid 1px #dae1e5; background: #ffffff; box-shadow: 0 0 3em rgba(0, 0, 0, .25); } } .overlay.error { display: flex; position: fixed; top: 0; left: 0; bottom: 0; right: 0; background: rgba(0, 10, 0, .9); .overlay-content { color: white; background: rgba(150, 10, 0, 1); } } </style> No newline at end of file
src/Controller/SignatureController.php +67 −6 Changes for src/Controller/SignatureController.php: 67 added lines, 6 removed lines. Original line number Diff line number Diff line Loading @@ -3,11 +3,14 @@ namespace UnicaenSignature\Controller; use Exception; use Laminas\Http\Request; use Laminas\Http\Response; use Laminas\Mvc\Controller\AbstractActionController; use Laminas\Mvc\Plugin\FlashMessenger\FlashMessenger; use Laminas\View\Model\JsonModel; use Laminas\View\Model\ViewModel; use UnicaenSignature\Entity\Db\Signature; use UnicaenSignature\Entity\Db\SignatureFlow; use UnicaenSignature\Form\SignatureForm; use UnicaenSignature\Service\SignatureServiceAwareTrait; use UnicaenSignature\Utils\SignatureConstants; Loading @@ -22,14 +25,72 @@ class SignatureController extends AbstractActionController return $this->getPluginManager()->get('flashmessenger'); } public function signatureflowsAction() :ViewModel { return new JsonModel([ public function signatureflowsAction(): ViewModel|\Laminas\Http\Response { if ($this->getRequest()->isPost()) { $this->getSignatureService()->getLoggerService()->debug("Traitement des données envoyées"); $posted = $this->getRequest()->getPost()->toArray(); $action = $posted['action']; switch ($action) { case 'save' : $datas = json_decode($posted['json'], true); try { $this->getSignatureService()->saveSignatureFlowFromJSON($datas); return new JsonModel(['message' => "ok"]); } catch (Exception $e) { $this->response->setCustomStatusCode(Response::STATUS_CODE_501); return new JsonModel(['error' => $e->getMessage()]); } break; case 'delete' : $datas = json_decode($posted['json'], true); try { $this->getSignatureService()->deleteSignatureFlowFromJSON($datas); return new JsonModel(['message' => "ok"]); } catch (Exception $e) { $this->response->setCustomStatusCode(Response::STATUS_CODE_501); return new JsonModel(['error' => $e->getMessage()]); } break; default: $this->response->setCustomStatusCode(Response::STATUS_CODE_400); return new JsonModel(['error' => "Mauvaise utilisation de l'API"]); } $this->getSignatureService()->getLoggerService()->debug(print_r($posted, true)); } // SignatureFlow normalize $signatureflows = $this->getSignatureService()->getSignatureFlows(SignatureConstants::FORMAT_ARRAY); foreach ($signatureflows as $i=>$sf) { foreach ($sf['steps'] as $j=>&$step) { $this->getSignatureService()->getLoggerService()->debug("ICI"); $options = $this->getSignatureService()->getSignatureConfigurationService()->getDefaultMethodOptionsByKey($step['method']); $this->getSignatureService()->getLoggerService()->debug(print_r($options,true)); foreach ($options as $key=>$value) { if( !array_key_exists($key,$step['options']) ){ $step['options'][$key] = $value; } } $signatureflows[$i]['steps'][$j]['options'] = $step['options']; } } return new JsonModel( [ 'version' => 1.0, 'signatureflows' => $this->getSignatureService()->getSignatureFlows(SignatureConstants::FORMAT_ARRAY), 'letterfiles' => $this->getSignatureService()->getLetterFiles(SignatureConstants::FORMAT_ARRAY), 'get_recipients_methods' => $this->getSignatureService()->getSignatureConfigurationService()->getRecipientsMethods(), 'signatureflows' => $signatureflows, 'letterfiles' => $this->getSignatureService()->getLetterFiles( SignatureConstants::FORMAT_ARRAY ), 'get_recipients_methods' => $this->getSignatureService()->getSignatureConfigurationService( )->getRecipientsMethods(), 'levels' => [] ]); ] ); } /** Loading
src/Entity/Db/SignatureFlow.php +36 −2 Changes for src/Entity/Db/SignatureFlow.php: 36 added lines, 2 removed lines. Original line number Diff line number Diff line Loading @@ -5,6 +5,8 @@ namespace UnicaenSignature\Entity\Db; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\ORM\Mapping as ORM; use DateTime; use UnicaenSignature\Formatter\IObjectFormattable; use UnicaenSignature\Formatter\ObjectFormatter; use UnicaenSignature\Service\SignatureService; use UnicaenSignature\Utils\SignatureConstants; Loading @@ -13,7 +15,7 @@ use UnicaenSignature\Utils\SignatureConstants; * @ORM\Entity(repositoryClass="UnicaenSignature\Entity\Repository\SignatureFlowRepository") * @ORM\Table(name="unicaen_signature_signatureflow") */ class SignatureFlow class SignatureFlow implements IObjectFormattable { /** * @ORM\Id Loading @@ -37,13 +39,14 @@ class SignatureFlow /** * @var ArrayCollection * @ORM\OneToMany(targetEntity="SignatureFlowStep", mappedBy="signatureFlow", cascade={"persist","remove"}) * @ORM\OrderBy({"order" = "ASC"}) */ protected $steps; /** * @return int */ public function getId(): ?int public function getId(): int { return $this->id; } Loading Loading @@ -90,6 +93,14 @@ class SignatureFlow return $this->steps; } public function getStepsIndexed() :array { $out = []; foreach ($this->getSteps() as $step) { $out[$step->getId()] = $step; } return $out; } /** * @param $steps */ Loading @@ -98,4 +109,27 @@ class SignatureFlow $this->steps = $steps; return $this; } public function toJson(): array { return $this->toArray(); } public function toArray(): array { $objectFormatter = new ObjectFormatter(); return [ 'id' => $this->getId(), 'label' => $this->getLabel(), 'description' => $this->getDescription(), 'steps' => $objectFormatter->formatCollection($this->getSteps()->toArray(), ObjectFormatter::FORMAT_JSON) ]; } public function getOptionLabel(): string { return $this->getLabel(); } } No newline at end of file
src/Entity/Db/SignatureFlowStep.php +60 −2 File changed.Preview size limit exceeded, changes collapsed. Show changes