Commit 3d55c0e2 authored by Stephane Bouvry's avatar Stephane Bouvry
Browse files

Merge + UI de test

parent ba76abbb
Loading
Loading
Loading
Loading
+42 −8
Changes for doc/connectors.md: 42 added lines, 8 removed lines.
Original line number Diff line number Diff line
@@ -174,16 +174,50 @@ Pour l'URL "liste", le service REST doit retourner un tableau composé d'objets
```JSON
[
  {
    "uid": "person1",
    "login": "etc..." 
  },
  {
    "uid": "person2",
   "login": "etc..." 
    "uid": "p1001",
    "login": "alberteinstein",
    "firstname": "Albert",
    "lastname": "Einstein",
    "displayname": "Albert Einstein",
    "mail": "albert.einstein@univ-berne.com",
    "civilite": "",
    "preferedlanguage": "",
    "status": "",
    "affectation": "",
    "structure": "",
    "inm": "",
    "phone": "",
    "birthday": "",
    "datefininscription": "",
    "datecreated": "",
    "dateupdated": "1905-07-04",
    "datecached": "2020-07-04",
    "address": null,
    "groups": [],
    "roles": {}
  },
  {
    "uid": "person3",
    "login": "etc..." 
    "uid": "p1002",
    "login": "maxplank",
    "firstname": "Max",
    "lastname": "Plank",
    "displayname": "Max Plank",
    "mail": "max.plank@univ-berlin.com",
    "civilite": "",
    "preferedlanguage": "",
    "status": "",
    "affectation": "",
    "structure": "",
    "inm": "",
    "phone": "",
    "birthday": "",
    "datefininscription": "",
    "datecreated": "",
    "dateupdated": "1905-07-04",
    "datecached": "2020-07-04",
    "address": null,
    "groups": [],
    "roles": {}
  }
]
```
+370 −18
Changes for front/src/ActivityTimesheetSynthesisMenu.vue: 370 added lines, 18 removed lines.
Original line number Diff line number Diff line
<template>
  <div>
    <div class="overlay" v-if="open">
    <button class="btn btn-primary" @click="handlerOpenSynthesis()" :class="{'disabled': loading}">
      <i class="icon-spinner animate-spin" v-if="loading"></i>
      <i class="icon-calendar" v-else></i>
      Synthèse des déclarations
    </button>

    <div class="overlay-content">
      <a href="#" class="overlay-closer" @click="handlerCloseSynthesis()">Close</a>
        OPTIONS ICI
      <div v-if="synthese" class="activity-timesheet-synthesis">
        <nav class="text-center">
          <button v-for="p, person_id in persons"
                  class="btn"
                  :class="filterPersons.indexOf(parseInt(person_id)) < 0 ? 'btn-primary' : 'btn-default'"
                  @click="handlerTooglePerson(person_id)">
            {{ p }}
          </button>
        </nav>

        <section v-for="y in sortedDatas.years" class="year" :class="{'open': y.open }">
          <h3 class="line" @click="handlerOpenYear(y)">
            <strong>
              <i class="icon-angle-right" v-show="!y.open"></i>
              <i class="icon-angle-down" v-show="y.open"></i>
              {{ y.label }}
            </strong>
            <em class="total" v-show="!y.open">{{ y.totalmain | hours }}</em>
          </h3>

          <section v-for="p in y.periods" class="month" v-show="y.open" :class="{'open': y.open }">
            <h4 class="line" @click="handlerOpenPeriod(p)">
              <strong>
                <i class="icon-angle-right" v-show="!p.open"></i>
                <i class="icon-angle-down" v-show="p.open"></i>
                {{ p.label }}
              </strong>
              <em class="total" v-show="!p.open">{{ p.totalmain | hours }}</em>
            </h4>

            <section v-for="pers in p.persons" class="person" v-show="p.open" :class="{'open': p.open }" @click="handlerOpenPerson(pers)">
              <h5 class="line">
                <strong>{{ pers.label }}</strong>
                <em class="total">{{ pers.totalmain | hours }}</em>
              </h5>
              <section class="details-person" v-if="pers.open">
                <article class="line">
                  <strong>
                    <i class="icon-cube"></i> {{ mainContext }}
                  </strong>
                  <em>
                    {{ pers.totalmain | hours }}
                  </em>
                </article>
                <section class="othersprojects" v-if="pers.othersprojects.total > 0">

                  <article v-for="projectDuration, projectName in pers.othersprojects.projects" class="line">
                    <strong>
                      <i class="icon-cube"></i> {{ projectName }}
                    </strong>
                    <em style="font-weight: 800">
                      {{ projectDuration | hours }}
                    </em>
                  </article>
                </section>
                <section class="othersprojects" v-if="pers.others.total > 0">
                  <article v-for="otherDuration, otherName in pers.others.context" class="line">
                    <strong>
                      {{ otherName | contextLabel }}
                    </strong>
                    <em>
                      {{ otherDuration | hours }}
                    </em>
                  </article>
                </section>
                <article class="line totalline">
                  <strong>
                    Total pour cette période :
                  </strong>
                  <em>
                    {{ pers.total | hours }}
                  </em>
                </article>
              </section>
            </section>

            <section class="person" v-show="p.open">
              <h5 class="line totalline">
                <strong>Total pour la période {{ p.label }}</strong>
                <em class="total">{{ p.totalmain | hours }}</em>
              </h5>
            </section>

          </section>

          <section class="person" v-show="y.open">
            <h5 class="line totalline">
              <strong>Total pour {{ y.label }}</strong>
              <em class="total">{{ y.totalmain | hours }}</em>
            </h5>
          </section>
        </section>
      </div>
    </div>
    <pre>{{ url }}</pre>
    <button class="btn btn-primary" @click="handlerOpenSynthesis()">
      <i class="icon-calendar"></i>
      Synthèse des déclarations
    </button>

    <div class="overlay" v-if="open">

    </div>

  </div>
</template>
<script>
@@ -28,15 +124,25 @@ node node_modules/.bin/gulp activityTimesheetSynthesisMenu

 */

// import AjaxOscar from "./remote/AjaxOscar";
// import OscarRemoteData from "./remote/OscarRemoteData";
let periodStr = function (year, month) {
  return year + '-' + (month < 10 ? '0' + month : month);
};

// test
export default {
let months = ["", "Janvier", "Février", "Mars", "Avril", "Mai", "Juin", "Juillet", "Aout", "Septembre", "Octobre", "Novembre", "Décembre"];

let periodFullStr = function (year, month) {
  return months[month] + ' ' + year;
};

  // components: {
  //   "ajax-oscar": AjaxOscar
  // },
let contextsLabels = {
  'research' : "Autres recherches",
      'conges' : "Congès",
      'training' : "Formation",
      'sickleave' : "Arrêt maladie",
      'other' : "Autre activité"
};

export default {

  props: {
    url: {require: true}
@@ -46,33 +152,279 @@ export default {
    return {
      configuration: null,
      open: false,
      synthese: null
      // Donnèes brutes
      synthese: null,
      structuredDatas: {},

      // Filtres
      filterPersons: [],

      // Donnèes calculées au fetch
      mainContext: null, // Projet référent
      mainContextId: null, // Projet référent
      contexts: null, // Autres contextes
      periods: null, // Liste des périodes
      persons: null, // Liste des déclarants
      years: null, // Années

      //
      openYear: [],
      openPeriod: [],
      openPerson: [],
    }
  },

  filters: {
    hours(str) {
      let t = parseFloat(str);
      let rnd = Math.round(t * 100);
      return (rnd / 100).toFixed(2);
    },
    contextLabel(contextKey){
      if( contextsLabels.hasOwnProperty(contextKey) ){
        return contextsLabels[contextKey];
      }
      return contextKey+"*";
    }
  },

  computed: {
    byDate() {
      let bydate = {};
    },

    sortedDatas() {

      // Structure racine
      let out = {
        "totaux": {
          "all": 0.0,
          "totalmain": 0.0,
          "othersprojects": {
            "projects": {},
            "total": 0.0
          },
          "others": {
            "context": {},
            "total": 0.0
          },
        },
        "years": {},
      };

      // Annèes
      this.years.forEach(year => {
        out.years[year] = {
          "key": year,
          "label": year,
          "totalmain": 0.0,
          "open": this.openYear.indexOf(year) >= 0,
          "periods": {}
        }
      });

      //
      this.periods.forEach(period => {
        let year = period.substring(0, 4);
        let month = period.substring(5, 7);
        out.years[year].periods[period] = {
          "key": period,
          "label": periodFullStr(year, parseInt(month)),
          "totalmain": 0.0,
          "persons": {},
          "open": this.openPeriod.indexOf(period) >= 0,
        }
      });

      this.synthese.synthesis.forEach(d => {

        let period = d.period;
        let year = parseInt(d.period.substring(0, 4));
        let month = parseInt(d.period.substring(5, 7));
        let person_id = d.person_id;
        let person = d.displayname;
        let context = d.context;
        let activity_id = d.activity_id;
        let type = d.type;
        let duration = parseFloat(d.duration);

        if (this.filterPersons.indexOf(person_id) >= 0) {
          return;
        }

        if (!out.years[year].periods[period].persons.hasOwnProperty(person_id)) {
          let indexOpen = year+"-"+period+"-"+person_id;
          out.years[year].periods[period].persons[person_id] = {
            "key": person_id,
            "label": person,
            "indexOpen": indexOpen,
            "open": this.openPerson.indexOf(indexOpen) >= 0,
            "totalmain": 0.0,
            "total": 0.0,
            "othersprojects": {
              "projects": {},
              "total": 0.0
            },
            "others": {
              "context": {},
              "total": 0.0
            },
          }
        }

        // --- Comptabilisé pour le projet principal
        if (activity_id == this.mainContextId) {
          out.totaux.totalmain += duration;
          out.years[year].totalmain += duration;
          out.years[year].periods[period].totalmain += duration;
          out.years[year].periods[period].persons[person_id].totalmain += duration;
        }
        // --- Comptabilisé pour les autres projets
        else if (type == "wp") {
          out.years[year].periods[period].persons[person_id].othersprojects.total += duration;
          //
          if (!out.years[year].periods[period].persons[person_id].othersprojects.projects.hasOwnProperty(context)) {
            out.years[year].periods[period].persons[person_id].othersprojects.projects[context] = 0.0;
          }
          out.years[year].periods[period].persons[person_id].othersprojects.projects[context] += duration;
          let project = context;
          if (!out.totaux.othersprojects.projects.hasOwnProperty(project)) {
            out.totaux.othersprojects.projects[project] = 0.0;
          }
          out.totaux.othersprojects.projects[project] += duration;
          out.totaux.othersprojects.total += duration;
        }
        // --- Autre (Congès, enseignement, etc...)
        else {
          out.years[year].periods[period].persons[person_id].others.total += duration;
          if (!out.years[year].periods[period].persons[person_id].others.context.hasOwnProperty(context)) {
            out.years[year].periods[period].persons[person_id].others.context[context] = 0.0;
          }
          out.years[year].periods[period].persons[person_id].others.context[context] += duration;
        }
        out.years[year].periods[period].persons[person_id].total += duration;
        out.totaux.all += duration;
      });

      return out;
    }
  },

  methods: {
    handlerTooglePerson(id) {
      let personId = parseInt(id);
      let indexId = this.filterPersons.indexOf(personId);
      if (indexId < 0) {
        this.filterPersons.push(personId);
      } else {
        this.filterPersons.splice(indexId, 1);
      }
    },

    handlerOpenPerson(person) {
      console.log(person);
      let indexId = this.openPerson.indexOf(person.indexOpen);
      if (indexId < 0) {
        this.openPerson.push(person.indexOpen);
      } else {
        this.openPerson.splice(indexId, 1);
      }
    },

    handlerOpenYear(year) {
      let i = this.openYear.indexOf(year.key);
      if (i < 0) {
        this.openYear.push(year.key);
      } else {
        this.openYear.splice(i, 1);
      }
    },

    handlerOpenPeriod(period) {
      console.log(period.key, this.openPeriod);
      let i = this.openPeriod.indexOf(period.key);
      if (i < 0) {
        this.openPeriod.push(period.key);
      } else {
        this.openPeriod.splice(i, 1);
      }
    },

    handlerOpenSynthesis() {
      this.open = true;
      this.loadSynthesis();
    },

    handlerCloseSynthesis() {
      this.open = false;
      console.log("CLOSE Synthesis");
      console.log("CLOSE Synthesis 'update'");
    },

    buildStructuredDatas() {
      // @deprecated
    },

    buildSynthese(datas) {
      // TODO Tester les dates de début/fin
      // ...
      this.mainContext = datas.acronym;
      this.mainContextId = datas.activity_id;

      // Constuction de la liste des périodes
      let fromYear = parseInt(datas.start.substring(0, 4));
      let toYear = parseInt(datas.end.substring(0, 4));
      let fromMonth = parseInt(datas.start.substring(5, 7));
      let toMonth = parseInt(datas.end.substring(5, 7));

      let periods = [];
      let years = [];
      let j = fromMonth;
      for (let i = fromYear; i <= toYear; i++) {
        years.push(i);
        for (; j <= 12 || (j <= toMonth && i == toYear); j++) {
          periods.push(periodStr(i, j));
        }
        j = 1;
      }

      let persons = {};
      let contexts = [];

      datas.synthesis.forEach(e => {
        if (!persons.hasOwnProperty(e.person_id)) {
          persons[e.person_id] = e.displayname;
        }
        if (contexts.indexOf(e.context) < 0 && e.activity_id != this.mainContextId) {
          contexts.push(e.context)
        }
      });

      this.periods = periods;
      this.contexts = contexts;
      this.persons = persons;
      this.years = years;

    },

    loadSynthesis() {
      this.loading = "Chargement de la synthèse...";
      this.$http.get(this.url).then(
          ok => {
            console.log(ok);
            this.synthese = ok.body;
            this.buildSynthese(ok.body);
          }, ko => {

          }
      )
      ).then(foo => {
        this.loading = false;
      })
    }
  },

  mounted() {
    console.log("ActivityTimesheetSynthesisMenu.vue")
    console.log("ActivityTimesheetSynthesisMenu.vue");
    this.loadSynthesis();
  }

}
+96 −0
Changes for public/css/_common.scss: 96 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -5588,3 +5588,99 @@ pre.alert-danger, pre.alert-info {
  font-weight: lighter;
  background: rgba(0,0,0,.05);
}



//////////////////////////////////////////////////////////
///
//////////////////////////////////////////////////////////
.activity-timesheet-synthesis {
  background: rgba(#fff, .5);

  h2, h3, h4, h5 {
    font-size: 1.5rem;
    margin: 0 1rem;
    padding: 0;
  }

  .line {
    border-top: solid thin $brand-primary;
    display: flex;
    strong { flex: 1; font-weight: 400 }
    em { flex: 0 10rem; text-align: right; font-weight: 400; font-style: normal  }
    &.totalline {
      strong { font-weight: 700 !important }
      em { font-weight: 700; }
    }
    &:hover {
      background: lighten($brand-primary, 50%);
    }
  }

  .year {
    border: solid thin grey;
    border-left: 4px solid grey;
    margin: 1em;
    h3 {
      cursor: pointer;
      line-height: 1.5rem;
      strong {
        font-size: 2rem;
      }
    }
    &:hover {
      border-color: $brand-primary;
    }
    &:not(.open){
      h3 em {
        font-weight: 700;
      }
    }
    &.open {
      h3 strong {
        font-weight: 700;
      }
      .month h4 strong {
        // font-weight: 700;
      }
    }
  }

  .month {
    margin-left: 1rem;
    margin-bottom: .25em;
    border: solid thin grey;
    border-left: 2px solid grey;
    border-right: none;
    padding: .1em;
    background: rgba(#fff, .7);
    h4 {
      cursor: pointer;
    }
    &:hover {
      border-color: $brand-primary;
      em {
        color: $brand-primary;
      }
    }
  }

  .person {
    margin-left: 2rem ;
    font-size: 1.5rem;
    border-top: thin $colorMedium solid;
    background: rgba(#fff, .7);

    .line {
      strong { font-weight: 300 };
    }
    &:hover {
      background: lighten($brand-primary, 60%);
    }
    &:nth-child(odd) {
      background: rgba($brand-primary,.1);
    }
  }


}
+86 −0
Changes for public/css/adaj.css: 86 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -11756,6 +11756,92 @@ pre.alert-danger, pre.alert-info {
  background: rgba(0, 0, 0, 0.05);
}

.activity-timesheet-synthesis {
  background: rgba(255, 255, 255, 0.5);
}
.activity-timesheet-synthesis h2, .activity-timesheet-synthesis h3, .activity-timesheet-synthesis h4, .activity-timesheet-synthesis h5 {
  font-size: 1.5rem;
  margin: 0 1rem;
  padding: 0;
}
.activity-timesheet-synthesis .line {
  border-top: solid thin #24587A;
  display: flex;
}
.activity-timesheet-synthesis .line strong {
  flex: 1;
  font-weight: 400;
}
.activity-timesheet-synthesis .line em {
  flex: 0 10rem;
  text-align: right;
  font-weight: 400;
  font-style: normal;
}
.activity-timesheet-synthesis .line.totalline strong {
  font-weight: 700 !important;
}
.activity-timesheet-synthesis .line.totalline em {
  font-weight: 700;
}
.activity-timesheet-synthesis .line:hover {
  background: #b4d4e9;
}
.activity-timesheet-synthesis .year {
  border: solid thin grey;
  border-left: 4px solid grey;
  margin: 1em;
}
.activity-timesheet-synthesis .year h3 {
  cursor: pointer;
  line-height: 1.5rem;
}
.activity-timesheet-synthesis .year h3 strong {
  font-size: 2rem;
}
.activity-timesheet-synthesis .year:hover {
  border-color: #24587A;
}
.activity-timesheet-synthesis .year:not(.open) h3 em {
  font-weight: 700;
}
.activity-timesheet-synthesis .year.open h3 strong {
  font-weight: 700;
}
.activity-timesheet-synthesis .month {
  margin-left: 1rem;
  margin-bottom: 0.25em;
  border: solid thin grey;
  border-left: 2px solid grey;
  border-right: none;
  padding: 0.1em;
  background: rgba(255, 255, 255, 0.7);
}
.activity-timesheet-synthesis .month h4 {
  cursor: pointer;
}
.activity-timesheet-synthesis .month:hover {
  border-color: #24587A;
}
.activity-timesheet-synthesis .month:hover em {
  color: #24587A;
}
.activity-timesheet-synthesis .person {
  margin-left: 2rem;
  font-size: 1.5rem;
  border-top: thin #64817A solid;
  background: rgba(255, 255, 255, 0.7);
}
.activity-timesheet-synthesis .person .line strong {
  font-weight: 300;
}
.activity-timesheet-synthesis .person:hover {
  background: #dbebf5;
}
.activity-timesheet-synthesis .person:nth-child(odd) {
  background: rgba(36, 88, 122, 0.1);
}

body {
  background: #f2f3eb;
}
+1 −1

File changed.

Preview size limit exceeded, changes collapsed.

Loading