Loading module/Oscar/src/Oscar/Controller/ActivityDateController.php +55 −3 Original line number Diff line number Diff line Loading @@ -515,24 +515,50 @@ class ActivityDateController extends AbstractOscarController implements UseServi return $view; } /** * Liste des jalons de la personnes. * * @return array|JsonModel * @throws OscarException */ public function mineAction(){ if( $this->isAjax() || $this->getRequest()->getQuery('f') === 'json' ){ $currentPerson = $this->getOscarUserContextService()->getCurrentPerson(); if( $currentPerson ){ $dateBounds = $this->getRequest()->getQuery("b", null); $page = $this->getRequest()->getQuery("p", 1); $size = $this->getRequest()->getQuery("s", 50); $orgs = $this->getRequest()->getQuery("o", null); $hideMine = $this->getRequest()->getQuery("m", null) === '0'; $filters = $this->getRequest()->getQuery("r", ''); $filterOrganizations = null; if( $orgs ){ $filterOrganizations = explode(',', $orgs); } $filtersBounds = []; if( $filters ){ $filtersBounds = explode(',', $filters); } $bounds = null; if( $dateBounds == '3months' ){ $todoOnly = false; if( in_array('3months', $filtersBounds )){ $first = (new \DateTime())->add(\DateInterval::createFromDateString('-2 month')); $last = (new \DateTime())->add(\DateInterval::createFromDateString('+2 month')); $last = (new \DateTime())->add(\DateInterval::createFromDateString('+1 month')); $bounds = [ 'from' => $first->format('Y-m-d'), 'to' => $last->format('Y-m-d') ]; } if( in_array('todo', $filtersBounds )){ $todoOnly = true; } // Récupération des IDS pour les activités "Directes" $idsActivityDirect = $this->getProjectGrantService()->getActivityRepository() Loading @@ -545,11 +571,16 @@ class ActivityDateController extends AbstractOscarController implements UseServi $organizationsNamed = []; $idsInOrganizations = []; foreach ($organizations as $organization){ $hiddenOrg = false; if( is_array($filterOrganizations) && in_array($organization->getId(), $filterOrganizations)) { $hiddenOrg = true; } $organizationsNamedItem = [ 'id' => $organization->getId(), 'code' => $organization->getCode(), 'shortname' => $organization->getShortName(), 'fullname' => $organization->getFullName(), 'hidden' => $hiddenOrg, 'activitiesIds' => [], ]; $milestonesIdsOrganizations = $this->getProjectGrantService()->getActivityRepository() Loading @@ -557,13 +588,25 @@ class ActivityDateController extends AbstractOscarController implements UseServi $organizationsNamedItem['activitiesIds'] = $milestonesIdsOrganizations; $organizationsNamed[] = $organizationsNamedItem; if( !$hiddenOrg ){ $idsInOrganizations = array_merge($idsInOrganizations, $milestonesIdsOrganizations); } } // Activités if( $hideMine ){ $idsActivities = $idsInOrganizations; } else { $idsActivities = array_merge($idsActivityDirect, $idsInOrganizations); } // Jalons $milestonesCount = $this->getProjectGrantService()->getActivityDateRepository() ->getMilestonesByIdsActivityCount($idsActivities, $bounds, $todoOnly); // Pagination $milestones = $this->getProjectGrantService()->getActivityDateRepository() ->getMilestonesByIdsActivity($idsActivities, $bounds); ->getMilestonesByIdsActivity($idsActivities, $bounds, $todoOnly, $size, $page); $types = $this->getProjectGrantService()->getActivityDateRepository() ->getMilestonesTypes(); Loading @@ -573,7 +616,16 @@ class ActivityDateController extends AbstractOscarController implements UseServi $formatter->setOscarUserContext($this->getOscarUserContextService()); $formatter->setUrlPlugin($this->url()); $out = $formatter->formatAllWithTypes($milestones, true); $out['pagination'] = [ 'page' => $page, 'size' => $size, 'totalPages' => ceil($milestonesCount / $size), ]; $out['filterBounds'] = $filtersBounds; $out['total'] = $milestonesCount; $out['organizationsDetails'] = $organizationsNamed; $out['organizationsSelected'] = []; $out['direct'] = $idsActivityDirect; $out['bounds'] = $bounds; return new JsonModel($out); Loading module/Oscar/src/Oscar/Entity/ActivityDateRepository.php +50 −11 Original line number Diff line number Diff line Loading @@ -173,32 +173,55 @@ class ActivityDateRepository extends EntityRepository } /** * Retourne la liste des jalons pour les activités données. * * @param array $idsActivities * @return ActivityDate[] * @param array|null $datesBounds * @return \Doctrine\ORM\QueryBuilder */ public function getMilestonesByIdsActivity(array $idsActivities, ?array $datesBounds = null) :array protected function getMilestonesByIdsActivityQuery(array $idsActivities, ?array $bounds = null, ?bool $todoOnly = false) { $query = $this->createQueryBuilder('m') ->select('m') ->innerJoin('m.activity', 'a') ->innerJoin('m.type', 't') ->where('a.id IN(:idsActivities)') ->orderBy('m.dateStart', 'desc') ->setParameter('idsActivities', $idsActivities); if( $datesBounds ){ if( $datesBounds['from'] ){ if( $todoOnly ){ $query->andWhere('t.finishable = TRUE'); $query->andWhere('m.finished = 0 OR m.finished IS NULL'); } if( $bounds ){ if( $bounds['from'] ){ $query->andWhere('m.dateStart >= :from') ->setParameter('from', $datesBounds['from']); ->setParameter('from', $bounds['from']); } if( $datesBounds['to'] ){ if( $bounds['to'] ){ $query->andWhere('m.dateStart <= :to') ->setParameter('to', $datesBounds['to']); ->setParameter('to', $bounds['to']); } } return $query; } /** * Retourne la liste des jalons pour les activités données. * * @param array $idsActivities * @return ActivityDate[] */ public function getMilestonesByIdsActivity( array $idsActivities, ?array $bounds = null, ?bool $todoOnly = false, ?int $size = 50, ?int $page = 1) :array { $query = $this->getMilestonesByIdsActivityQuery($idsActivities, $bounds, $todoOnly); $query->select('m') ->setMaxResults($size) ->setFirstResult($size*($page-1)) ->orderBy('m.dateStart', 'desc'); return $query->getQuery()->getResult(); } Loading @@ -206,4 +229,20 @@ class ActivityDateRepository extends EntityRepository { return $this->getEntityManager()->getRepository(DateType::class)->findAll(); } /** * Retourne le nombre de jalons total. * * @param array $idsActivities * @param array|null $bounds * @return bool|float|int|string|null * @throws \Doctrine\ORM\NoResultException * @throws \Doctrine\ORM\NonUniqueResultException */ public function getMilestonesByIdsActivityCount(array $idsActivities, ?array $bounds, bool $todoOnly = false) { $query = $this->getMilestonesByIdsActivityQuery($idsActivities, $bounds, $todoOnly); $query->select('COUNT(m.id) as total'); return $query->getQuery()->getSingleScalarResult(); } } ui/src/oscar-css.scss +19 −0 Original line number Diff line number Diff line Loading @@ -393,6 +393,15 @@ a.usage { .oscar-tag-icon { color: darken($brand-info, 15%); } &.--selected { background-color: darken($brand-info, 45%); } &.--selectable { cursor: pointer; &:hover { background-color: darken($brand-info, 50%); } } &.secondary { //text-shadow: 1px -1px 1px rgba(255,255,255,.3); background-color: lighten($brand-secondary1, 30%); Loading @@ -400,6 +409,16 @@ a.usage { .oscar-tag-icon { color: darken($brand-secondary1, 10%); } &.--selected { background-color: darken($brand-secondary1, 5%); color: lighten($brand-secondary1, 25%); } &.--selectable { &:hover { background-color: darken($brand-secondary1, 15%); color: lighten($brand-secondary1, 25%); } } } &.thridary { //text-shadow: 1px -1px 1px rgba(255,255,255,.3); Loading ui/src/views/MilestonesUI.vue +221 −44 Original line number Diff line number Diff line <template> <h1> <i class="icon-calendar"></i> {{ title }}</h1> <!-- <nav>--> <!-- {{ organizationsDetails }}--> <!-- </nav>--> <section class="milstones"> <article v-for="milestone in milestones" class="milestone card" {{ title }} <em> ({{ total + ' ' + $filters.oscarText('jalons') }})</em> <button class="btn btn-default" @click="fetch(2000)"> FETCH </button> </h1> <div class="row"> <section class="results col-md-8 milestones"> <div class="pagination btn-group"> <div v-for="i in pagination.totalPages" class="pagination-item btn btn-default" @click.prevent="handlerPage(i)" :class="{'btn-primary': pagination.page == i}"> {{ i }} </div> </div> <nav> Filtres : <div class="btn btn-lg" :class="filterBounds.includes('3months') ? 'btn-primary' : 'btn-default'" @click="handlerProche()"> <i class="icon-calendar"></i> Jalons proches </div> <div class="btn btn-lg" :class="filterBounds.includes('todo') ? 'btn-primary' : 'btn-default'" @click="handlerTodo()"> <i class="icon-valid"></i> Jalons à faire uniquement </div> </nav> <hr> <section class="by-year" v-for="(yearData, year) in groupedMilestones"> <div class="dateMarker"> {{ year }} </div> <section class="by-month" v-for="(monthData, month) in yearData.months"> <div class="dateMarker monthMarker"> {{ months[month] }} </div> <article v-for="milestone in monthData.milestones" class="milestone card" :class="{ 'has-problem': milestone.late, 'past': milestone.past, Loading @@ -18,13 +55,6 @@ 'progression-refused': milestone.finished == 400, }" > <div v-if="yearMarkerChange(milestone)" class="dateMarker"> {{ markerYear }} </div> <div v-if="monthMarkerChange(milestone)" class="dateMarker monthMarker"> {{ months[markerMonth] }} </div> <h2 class="card-title"> <strong> <span class="problem-info" v-if="milestone.late"> Loading Loading @@ -111,12 +141,60 @@ </div> </article> </section> </section> </section> <section class="results col-md-4"> <nav class="filters"> <section class="filters-select"> <h3>Nombre de résultats</h3> <select name="" id="" v-model="size"> <option value="50">50</option> <option value="25">25</option> <option value="10">10</option> </select> </section> <section> <h3>{{ $filters.oscarText('Mes activités') }}</h3> <div class="oscar-tag --selectable secondary" :class="{'--selected': filterMine}" @click.prevent="handlerFilterMine($event)"> > <i class="icon-eye-off" v-if="!filterMine"></i> <i class="icon-eye" v-else></i> {{ $filters.oscarText('Mes activités') }} ( {{ direct.length}} {{ $filters.oscarText('Activités') }} ) </div> </section> <section class="filters-select filters-organizations" v-if="organizationsDetails && organizationsDetails.length"> <h3>{{ $filters.oscarText('Mes structures') }}</h3> <article v-for="elem in organizationsDetails" class="oscar-tag --selectable secondary" :class="{'--selected': !elem.hidden}" @click.prevent="handlerFilterOrganization(elem, $event)"> <div class="select-label"> <i class="icon-eye-off" v-if="elem.hidden"></i> <i class="icon-eye" v-else></i> <code v-show="elem.code">{{ elem.code }}</code> <strong v-show="elem.shortname">{{ elem.shortname }}</strong> <em>{{ elem.fullname }}</em> <span class="total-rounded"> (<strong>{{ elem.activitiesIds.length }}</strong> {{ $filters.oscarText('Activités') }}) </span> </div> </article> </section> </nav> </section> </div> </template> <script> import AxiosOscar from "../utils/AxiosOscar.js"; let tempo = null; export default { props: { title: { Loading @@ -132,44 +210,92 @@ export default { types: [], milestones: [], progressions: [], pagination: {}, filterBounds: [], organizationsDetails: null, filterOrganizations: [], filterMine: true, // Nombre de résultat size: 50, direct: [], markerYear: "", total: 0, markerMonth: "", months:{ "01": "Janvier", "02": "Février", "03": "Mars", "04": "Avril", "05": "Mai", "06": "Juin", "07": "Juillet", "08": "Aout", "09": "Septembre", "10": "Octobre", "11": "Novembre", "12": "Décembre", months: [ "Janvier", "Février", "Mars", "Avril", "Mai", "Juin", "Juillet", "Aout", "Septembre", "Octobre", "Novembre", "Décembre"], } }, computed: { groupedMilestones(){ let grouped = {}; for( let i=0; i<this.milestones.length; i++) { let milestone = this.milestones[i]; let date = new Date(milestone.dateStart); let year = date.getFullYear(); let month = date.getMonth(); if( !grouped.hasOwnProperty(year) ){ grouped[year] = { months: {} }; } if( !grouped[year].months.hasOwnProperty(month) ){ grouped[year].months[month] = { milestones: [] } } grouped[year].months[month].milestones.push(milestone); } return grouped; } }, methods: { // {{ milestone.dateStart.substring(0, 4) }} yearMarkerChange(milestone) { let year = milestone.dateStart.substr(0, 4); if( year != this.markerYear ){ this.markerYear = year; return true; } return false; handlerProche(){ if(this.filterBounds.includes('3months')){ this.filterBounds.splice(this.filterBounds.indexOf('3months'),1); } else { this.filterBounds.push('3months') } this.fetch(1000); }, handlerTodo(){ if(this.filterBounds.includes('todo')){ this.filterBounds.splice(this.filterBounds.indexOf('todo'),1); } else { this.filterBounds.push('todo') } this.fetch(1000); }, monthMarkerChange(milestone) { let month = milestone.dateStart.substr(5, 2); if( month != this.markerMonth ){ this.markerMonth = month; return true; handlerPage(page){ this.pagination.page = page; this.fetch(0, page); }, handlerFilterOrganization( organization, event ){ if(event.ctrlKey){ this.organizationsDetails.forEach(org => { org.hidden = true; }); organization.hidden = false; } else { organization.hidden = !organization.hidden; } return false; this.fetch(2000); }, handlerFilterMine(event){ if(event.ctrlKey){ this.organizationsDetails.forEach(org => { org.hidden = true; }); this.filterMine = true; } else { this.filterMine = !this.filterMine; } this.fetch(2000); }, handlerProgression(milestone, action) { Loading Loading @@ -202,7 +328,7 @@ export default { if( this.organizationsDetails ){ Object.keys(this.organizationsDetails).forEach((org,key) => { let detail = this.organizationsDetails[key]; if( detail.activitiesIds && detail.activitiesIds.includes(activityMilestoneInfo.id) ){ if( detail && detail.activitiesIds && detail.activitiesIds.includes(activityMilestoneInfo.id) ){ info.orgs.push(detail); } }); Loading @@ -212,13 +338,58 @@ export default { info.activity = activityMilestoneInfo; return info; }, fetch(){ AxiosOscar.get(this.url).then((response) => { fetch(delay=1000, page=1){ if( this.pagination && this.pagination.page ){ this.pagination.page = page; console.log("page", this.pagination.page); } if( tempo ){ clearTimeout(tempo); } tempo = setTimeout(()=>{ this.performFetch(); clearTimeout(tempo); }, delay); }, performFetch(){ // Filtre organisations let orgs = null; let url = this.url +'?f=json'; if( this.organizationsDetails ){ orgs = []; for(let org in this.organizationsDetails){ let organizationInfos = this.organizationsDetails[org]; if( organizationInfos.hidden ){ orgs.push(organizationInfos.id); } } url += '&o=' +orgs.join(','); } if( this.filterMine === false ){ url += "&m=0" } if( this.pagination && this.pagination.page ){ url += "&p=" + this.pagination.page; } url += "&r=" + this.filterBounds.join(','); console.log(url); AxiosOscar.get(url).then((response) => { this.types = response.data.types; this.pagination = response.data.pagination; this.filterBounds = response.data.filterBounds; this.milestones = response.data.milestones; this.progressions = response.data.progressions; this.organizationsDetails = response.data.organizationsDetails; this.direct = response.data.direct; this.total = response.data.total; }) }, handlerActivityShow(milestone){ Loading @@ -238,10 +409,16 @@ export default { padding-top: 1.5em; padding-left: 100px; } .milestone { .milestones, .by-year, .by-month { position: relative; } .filters-organizations { article { margin: .5em; } } .dateMarker { border-radius: 8px 0 0 0; background: #484855; Loading Loading
module/Oscar/src/Oscar/Controller/ActivityDateController.php +55 −3 Original line number Diff line number Diff line Loading @@ -515,24 +515,50 @@ class ActivityDateController extends AbstractOscarController implements UseServi return $view; } /** * Liste des jalons de la personnes. * * @return array|JsonModel * @throws OscarException */ public function mineAction(){ if( $this->isAjax() || $this->getRequest()->getQuery('f') === 'json' ){ $currentPerson = $this->getOscarUserContextService()->getCurrentPerson(); if( $currentPerson ){ $dateBounds = $this->getRequest()->getQuery("b", null); $page = $this->getRequest()->getQuery("p", 1); $size = $this->getRequest()->getQuery("s", 50); $orgs = $this->getRequest()->getQuery("o", null); $hideMine = $this->getRequest()->getQuery("m", null) === '0'; $filters = $this->getRequest()->getQuery("r", ''); $filterOrganizations = null; if( $orgs ){ $filterOrganizations = explode(',', $orgs); } $filtersBounds = []; if( $filters ){ $filtersBounds = explode(',', $filters); } $bounds = null; if( $dateBounds == '3months' ){ $todoOnly = false; if( in_array('3months', $filtersBounds )){ $first = (new \DateTime())->add(\DateInterval::createFromDateString('-2 month')); $last = (new \DateTime())->add(\DateInterval::createFromDateString('+2 month')); $last = (new \DateTime())->add(\DateInterval::createFromDateString('+1 month')); $bounds = [ 'from' => $first->format('Y-m-d'), 'to' => $last->format('Y-m-d') ]; } if( in_array('todo', $filtersBounds )){ $todoOnly = true; } // Récupération des IDS pour les activités "Directes" $idsActivityDirect = $this->getProjectGrantService()->getActivityRepository() Loading @@ -545,11 +571,16 @@ class ActivityDateController extends AbstractOscarController implements UseServi $organizationsNamed = []; $idsInOrganizations = []; foreach ($organizations as $organization){ $hiddenOrg = false; if( is_array($filterOrganizations) && in_array($organization->getId(), $filterOrganizations)) { $hiddenOrg = true; } $organizationsNamedItem = [ 'id' => $organization->getId(), 'code' => $organization->getCode(), 'shortname' => $organization->getShortName(), 'fullname' => $organization->getFullName(), 'hidden' => $hiddenOrg, 'activitiesIds' => [], ]; $milestonesIdsOrganizations = $this->getProjectGrantService()->getActivityRepository() Loading @@ -557,13 +588,25 @@ class ActivityDateController extends AbstractOscarController implements UseServi $organizationsNamedItem['activitiesIds'] = $milestonesIdsOrganizations; $organizationsNamed[] = $organizationsNamedItem; if( !$hiddenOrg ){ $idsInOrganizations = array_merge($idsInOrganizations, $milestonesIdsOrganizations); } } // Activités if( $hideMine ){ $idsActivities = $idsInOrganizations; } else { $idsActivities = array_merge($idsActivityDirect, $idsInOrganizations); } // Jalons $milestonesCount = $this->getProjectGrantService()->getActivityDateRepository() ->getMilestonesByIdsActivityCount($idsActivities, $bounds, $todoOnly); // Pagination $milestones = $this->getProjectGrantService()->getActivityDateRepository() ->getMilestonesByIdsActivity($idsActivities, $bounds); ->getMilestonesByIdsActivity($idsActivities, $bounds, $todoOnly, $size, $page); $types = $this->getProjectGrantService()->getActivityDateRepository() ->getMilestonesTypes(); Loading @@ -573,7 +616,16 @@ class ActivityDateController extends AbstractOscarController implements UseServi $formatter->setOscarUserContext($this->getOscarUserContextService()); $formatter->setUrlPlugin($this->url()); $out = $formatter->formatAllWithTypes($milestones, true); $out['pagination'] = [ 'page' => $page, 'size' => $size, 'totalPages' => ceil($milestonesCount / $size), ]; $out['filterBounds'] = $filtersBounds; $out['total'] = $milestonesCount; $out['organizationsDetails'] = $organizationsNamed; $out['organizationsSelected'] = []; $out['direct'] = $idsActivityDirect; $out['bounds'] = $bounds; return new JsonModel($out); Loading
module/Oscar/src/Oscar/Entity/ActivityDateRepository.php +50 −11 Original line number Diff line number Diff line Loading @@ -173,32 +173,55 @@ class ActivityDateRepository extends EntityRepository } /** * Retourne la liste des jalons pour les activités données. * * @param array $idsActivities * @return ActivityDate[] * @param array|null $datesBounds * @return \Doctrine\ORM\QueryBuilder */ public function getMilestonesByIdsActivity(array $idsActivities, ?array $datesBounds = null) :array protected function getMilestonesByIdsActivityQuery(array $idsActivities, ?array $bounds = null, ?bool $todoOnly = false) { $query = $this->createQueryBuilder('m') ->select('m') ->innerJoin('m.activity', 'a') ->innerJoin('m.type', 't') ->where('a.id IN(:idsActivities)') ->orderBy('m.dateStart', 'desc') ->setParameter('idsActivities', $idsActivities); if( $datesBounds ){ if( $datesBounds['from'] ){ if( $todoOnly ){ $query->andWhere('t.finishable = TRUE'); $query->andWhere('m.finished = 0 OR m.finished IS NULL'); } if( $bounds ){ if( $bounds['from'] ){ $query->andWhere('m.dateStart >= :from') ->setParameter('from', $datesBounds['from']); ->setParameter('from', $bounds['from']); } if( $datesBounds['to'] ){ if( $bounds['to'] ){ $query->andWhere('m.dateStart <= :to') ->setParameter('to', $datesBounds['to']); ->setParameter('to', $bounds['to']); } } return $query; } /** * Retourne la liste des jalons pour les activités données. * * @param array $idsActivities * @return ActivityDate[] */ public function getMilestonesByIdsActivity( array $idsActivities, ?array $bounds = null, ?bool $todoOnly = false, ?int $size = 50, ?int $page = 1) :array { $query = $this->getMilestonesByIdsActivityQuery($idsActivities, $bounds, $todoOnly); $query->select('m') ->setMaxResults($size) ->setFirstResult($size*($page-1)) ->orderBy('m.dateStart', 'desc'); return $query->getQuery()->getResult(); } Loading @@ -206,4 +229,20 @@ class ActivityDateRepository extends EntityRepository { return $this->getEntityManager()->getRepository(DateType::class)->findAll(); } /** * Retourne le nombre de jalons total. * * @param array $idsActivities * @param array|null $bounds * @return bool|float|int|string|null * @throws \Doctrine\ORM\NoResultException * @throws \Doctrine\ORM\NonUniqueResultException */ public function getMilestonesByIdsActivityCount(array $idsActivities, ?array $bounds, bool $todoOnly = false) { $query = $this->getMilestonesByIdsActivityQuery($idsActivities, $bounds, $todoOnly); $query->select('COUNT(m.id) as total'); return $query->getQuery()->getSingleScalarResult(); } }
ui/src/oscar-css.scss +19 −0 Original line number Diff line number Diff line Loading @@ -393,6 +393,15 @@ a.usage { .oscar-tag-icon { color: darken($brand-info, 15%); } &.--selected { background-color: darken($brand-info, 45%); } &.--selectable { cursor: pointer; &:hover { background-color: darken($brand-info, 50%); } } &.secondary { //text-shadow: 1px -1px 1px rgba(255,255,255,.3); background-color: lighten($brand-secondary1, 30%); Loading @@ -400,6 +409,16 @@ a.usage { .oscar-tag-icon { color: darken($brand-secondary1, 10%); } &.--selected { background-color: darken($brand-secondary1, 5%); color: lighten($brand-secondary1, 25%); } &.--selectable { &:hover { background-color: darken($brand-secondary1, 15%); color: lighten($brand-secondary1, 25%); } } } &.thridary { //text-shadow: 1px -1px 1px rgba(255,255,255,.3); Loading
ui/src/views/MilestonesUI.vue +221 −44 Original line number Diff line number Diff line <template> <h1> <i class="icon-calendar"></i> {{ title }}</h1> <!-- <nav>--> <!-- {{ organizationsDetails }}--> <!-- </nav>--> <section class="milstones"> <article v-for="milestone in milestones" class="milestone card" {{ title }} <em> ({{ total + ' ' + $filters.oscarText('jalons') }})</em> <button class="btn btn-default" @click="fetch(2000)"> FETCH </button> </h1> <div class="row"> <section class="results col-md-8 milestones"> <div class="pagination btn-group"> <div v-for="i in pagination.totalPages" class="pagination-item btn btn-default" @click.prevent="handlerPage(i)" :class="{'btn-primary': pagination.page == i}"> {{ i }} </div> </div> <nav> Filtres : <div class="btn btn-lg" :class="filterBounds.includes('3months') ? 'btn-primary' : 'btn-default'" @click="handlerProche()"> <i class="icon-calendar"></i> Jalons proches </div> <div class="btn btn-lg" :class="filterBounds.includes('todo') ? 'btn-primary' : 'btn-default'" @click="handlerTodo()"> <i class="icon-valid"></i> Jalons à faire uniquement </div> </nav> <hr> <section class="by-year" v-for="(yearData, year) in groupedMilestones"> <div class="dateMarker"> {{ year }} </div> <section class="by-month" v-for="(monthData, month) in yearData.months"> <div class="dateMarker monthMarker"> {{ months[month] }} </div> <article v-for="milestone in monthData.milestones" class="milestone card" :class="{ 'has-problem': milestone.late, 'past': milestone.past, Loading @@ -18,13 +55,6 @@ 'progression-refused': milestone.finished == 400, }" > <div v-if="yearMarkerChange(milestone)" class="dateMarker"> {{ markerYear }} </div> <div v-if="monthMarkerChange(milestone)" class="dateMarker monthMarker"> {{ months[markerMonth] }} </div> <h2 class="card-title"> <strong> <span class="problem-info" v-if="milestone.late"> Loading Loading @@ -111,12 +141,60 @@ </div> </article> </section> </section> </section> <section class="results col-md-4"> <nav class="filters"> <section class="filters-select"> <h3>Nombre de résultats</h3> <select name="" id="" v-model="size"> <option value="50">50</option> <option value="25">25</option> <option value="10">10</option> </select> </section> <section> <h3>{{ $filters.oscarText('Mes activités') }}</h3> <div class="oscar-tag --selectable secondary" :class="{'--selected': filterMine}" @click.prevent="handlerFilterMine($event)"> > <i class="icon-eye-off" v-if="!filterMine"></i> <i class="icon-eye" v-else></i> {{ $filters.oscarText('Mes activités') }} ( {{ direct.length}} {{ $filters.oscarText('Activités') }} ) </div> </section> <section class="filters-select filters-organizations" v-if="organizationsDetails && organizationsDetails.length"> <h3>{{ $filters.oscarText('Mes structures') }}</h3> <article v-for="elem in organizationsDetails" class="oscar-tag --selectable secondary" :class="{'--selected': !elem.hidden}" @click.prevent="handlerFilterOrganization(elem, $event)"> <div class="select-label"> <i class="icon-eye-off" v-if="elem.hidden"></i> <i class="icon-eye" v-else></i> <code v-show="elem.code">{{ elem.code }}</code> <strong v-show="elem.shortname">{{ elem.shortname }}</strong> <em>{{ elem.fullname }}</em> <span class="total-rounded"> (<strong>{{ elem.activitiesIds.length }}</strong> {{ $filters.oscarText('Activités') }}) </span> </div> </article> </section> </nav> </section> </div> </template> <script> import AxiosOscar from "../utils/AxiosOscar.js"; let tempo = null; export default { props: { title: { Loading @@ -132,44 +210,92 @@ export default { types: [], milestones: [], progressions: [], pagination: {}, filterBounds: [], organizationsDetails: null, filterOrganizations: [], filterMine: true, // Nombre de résultat size: 50, direct: [], markerYear: "", total: 0, markerMonth: "", months:{ "01": "Janvier", "02": "Février", "03": "Mars", "04": "Avril", "05": "Mai", "06": "Juin", "07": "Juillet", "08": "Aout", "09": "Septembre", "10": "Octobre", "11": "Novembre", "12": "Décembre", months: [ "Janvier", "Février", "Mars", "Avril", "Mai", "Juin", "Juillet", "Aout", "Septembre", "Octobre", "Novembre", "Décembre"], } }, computed: { groupedMilestones(){ let grouped = {}; for( let i=0; i<this.milestones.length; i++) { let milestone = this.milestones[i]; let date = new Date(milestone.dateStart); let year = date.getFullYear(); let month = date.getMonth(); if( !grouped.hasOwnProperty(year) ){ grouped[year] = { months: {} }; } if( !grouped[year].months.hasOwnProperty(month) ){ grouped[year].months[month] = { milestones: [] } } grouped[year].months[month].milestones.push(milestone); } return grouped; } }, methods: { // {{ milestone.dateStart.substring(0, 4) }} yearMarkerChange(milestone) { let year = milestone.dateStart.substr(0, 4); if( year != this.markerYear ){ this.markerYear = year; return true; } return false; handlerProche(){ if(this.filterBounds.includes('3months')){ this.filterBounds.splice(this.filterBounds.indexOf('3months'),1); } else { this.filterBounds.push('3months') } this.fetch(1000); }, handlerTodo(){ if(this.filterBounds.includes('todo')){ this.filterBounds.splice(this.filterBounds.indexOf('todo'),1); } else { this.filterBounds.push('todo') } this.fetch(1000); }, monthMarkerChange(milestone) { let month = milestone.dateStart.substr(5, 2); if( month != this.markerMonth ){ this.markerMonth = month; return true; handlerPage(page){ this.pagination.page = page; this.fetch(0, page); }, handlerFilterOrganization( organization, event ){ if(event.ctrlKey){ this.organizationsDetails.forEach(org => { org.hidden = true; }); organization.hidden = false; } else { organization.hidden = !organization.hidden; } return false; this.fetch(2000); }, handlerFilterMine(event){ if(event.ctrlKey){ this.organizationsDetails.forEach(org => { org.hidden = true; }); this.filterMine = true; } else { this.filterMine = !this.filterMine; } this.fetch(2000); }, handlerProgression(milestone, action) { Loading Loading @@ -202,7 +328,7 @@ export default { if( this.organizationsDetails ){ Object.keys(this.organizationsDetails).forEach((org,key) => { let detail = this.organizationsDetails[key]; if( detail.activitiesIds && detail.activitiesIds.includes(activityMilestoneInfo.id) ){ if( detail && detail.activitiesIds && detail.activitiesIds.includes(activityMilestoneInfo.id) ){ info.orgs.push(detail); } }); Loading @@ -212,13 +338,58 @@ export default { info.activity = activityMilestoneInfo; return info; }, fetch(){ AxiosOscar.get(this.url).then((response) => { fetch(delay=1000, page=1){ if( this.pagination && this.pagination.page ){ this.pagination.page = page; console.log("page", this.pagination.page); } if( tempo ){ clearTimeout(tempo); } tempo = setTimeout(()=>{ this.performFetch(); clearTimeout(tempo); }, delay); }, performFetch(){ // Filtre organisations let orgs = null; let url = this.url +'?f=json'; if( this.organizationsDetails ){ orgs = []; for(let org in this.organizationsDetails){ let organizationInfos = this.organizationsDetails[org]; if( organizationInfos.hidden ){ orgs.push(organizationInfos.id); } } url += '&o=' +orgs.join(','); } if( this.filterMine === false ){ url += "&m=0" } if( this.pagination && this.pagination.page ){ url += "&p=" + this.pagination.page; } url += "&r=" + this.filterBounds.join(','); console.log(url); AxiosOscar.get(url).then((response) => { this.types = response.data.types; this.pagination = response.data.pagination; this.filterBounds = response.data.filterBounds; this.milestones = response.data.milestones; this.progressions = response.data.progressions; this.organizationsDetails = response.data.organizationsDetails; this.direct = response.data.direct; this.total = response.data.total; }) }, handlerActivityShow(milestone){ Loading @@ -238,10 +409,16 @@ export default { padding-top: 1.5em; padding-left: 100px; } .milestone { .milestones, .by-year, .by-month { position: relative; } .filters-organizations { article { margin: .5em; } } .dateMarker { border-radius: 8px 0 0 0; background: #484855; Loading