Loading module/Oscar/src/Oscar/Controller/ProjectGrantController.php +38 −46 Original line number Diff line number Diff line Loading @@ -1848,19 +1848,12 @@ class ProjectGrantController extends AbstractOscarController implements UseNotif switch ($method) { case 'GET' : if ($this->isAjax() || $this->getRequest()->getQuery('f') === 'json2') { $datas = [ 'activity' => $this->getProjectGrantApiService()->getActivityJson( $entity->getId(), $this->url(), $this->getOscarUserContextService() ), ]; return $this->jsonOutput($datas); } elseif ($this->isAjax() || $this->getRequest()->getQuery('f') === 'json') { $format = $this->getRequest()->getQuery('f', null); if ($isAjax || $format === 'json' || $format === 'json2') { try { $perimeter = $this->getRequest()->getQuery('p', null); $perimeter = $format === 'json' ? $this->getRequest()->getQuery('p', null) : null; $datas = [ 'activity' => $this->getProjectGrantApiService()->getActivityJson( $entity->getId(), Loading Loading @@ -1910,7 +1903,6 @@ class ProjectGrantController extends AbstractOscarController implements UseNotif } default: return $this->jsonError("Action '$action' inconnue"); } break; default : Loading module/Oscar/src/Oscar/Service/ProjectGrantApiService.php +20 −0 Original line number Diff line number Diff line Loading @@ -572,6 +572,7 @@ class ProjectGrantApiService implements } $project = null; $projectActivities = []; if ($activity->getProject() !== null) { $project = [ 'id' => $activity->getProject()->getId(), Loading @@ -580,6 +581,24 @@ class ProjectGrantApiService implements 'description' => $activity->getProject()->getDescription(), 'url_show' => $urlPlugin->fromRoute('project/show', ['id' => $activity->getProject()->getId()]) ]; /** @var Activity $projectActivity */ foreach ($activity->getProject()->getActivities() as $projectActivity) { if ($projectActivity->getId() === $activity->getId()) { continue; } $projectActivities[] = [ 'id' => $projectActivity->getId(), 'label' => $projectActivity->getLabel(), 'status' => $projectActivity->getStatus(), 'status_label' => $projectActivity->getStatusLabel(), 'numOscar' => $projectActivity->getOscarNum(), 'codeEOTP' => $projectActivity->getCodeEOTP(), 'dateStart' => $this->formatDateTime($projectActivity->getDateStart()), 'dateEnd' => $this->formatDateTime($projectActivity->getDateEnd()), 'url_show' => $urlPlugin->fromRoute('contract/show', ['id' => $projectActivity->getId()]), ]; } } // Numérotation Loading Loading @@ -614,6 +633,7 @@ class ProjectGrantApiService implements $out['notefinanciere'] = $activity->getNoteFinanciere(); $out['acronym'] = $activity->getAcronym(); $out['project'] = $project; $out['project_activities'] = $projectActivities; $out['disciplines'] = $activity->getDisciplinesArray(); $out['numeros'] = $numeros; $out['motscles'] = $activity->getMotsclesArray(); Loading ui/src/views/Activity.vue +89 −3 Original line number Diff line number Diff line Loading @@ -295,6 +295,12 @@ data-bs-toggle="tab" data-bs-target="#nav-general" type="button" role="tab" aria-controls="nav-general" aria-selected="false"> <i class="icon-bank"></i> Général </button> <button class="nav-link" id="nav-project-tab" :class="{'active': uiActiveTab === 'project'}" @click="uiActiveTab = 'project'" data-bs-toggle="tab" data-bs-target="#nav-project" type="button" role="tab" aria-controls="nav-project" aria-selected="false"> <i class="icon-cubes"></i> Projet </button> <button class="nav-link" id="nav-dates-tab" :class="{'active': uiActiveTab === 'dates'}" @click="uiActiveTab = 'dates'" Loading Loading @@ -377,12 +383,76 @@ </div> </div> <div class="col-md-4"> <div class="col-md-8"> <h3>Description</h3> {{ core.description }} <div class="description-limited"> {{ core.description || '-' }} </div> </div> </div> </div> <div class="tab-pane fade" id="nav-project" :class="{'active show': uiActiveTab === 'project'}" role="tabpanel" aria-labelledby="nav-project-tab" tabindex="0"> <div class="row row-bordered" v-if="core.project"> <div class="col-md-12"> <div class="labeled-value labeled-value-horizontal"> <div class="label">Acronyme</div> <div class="value">{{ core.project.acronym || '-' }}</div> </div> <div class="labeled-value labeled-value-horizontal"> <div class="label">Intitulé</div> <div class="value"> <a :href="core.project.url_show"> <i class="icon-cubes"></i> {{ core.project.label }} </a> </div> </div> </div> <div class="col-md-12"> <h3>Autres activités du projet</h3> <div class="alert alert-info" v-if="projectActivitiesSorted.length === 0"> Aucune autre activité liée à ce projet. </div> <table class="table table-condensed" v-else> <thead> <tr> <th>{{ $filters.oscarText('Activité') }}</th> <th>{{ $filters.oscarText('status') }}</th> <th>{{ $filters.oscarText('numOscar') }}</th> <th>{{ $filters.oscarText('codeEOTP') }}</th> <th>{{ $filters.oscarText('dateStart') }}</th> <th>{{ $filters.oscarText('dateEnd') }}</th> </tr> </thead> <tbody> <tr v-for="activity in projectActivitiesSorted" :key="activity.id"> <td> <a :href="activity.url_show"> <i class="icon-cube"></i> <strong>{{ activity.label }}</strong> </a> <small class="text-muted"> (#{{ activity.id }})</small> </td> <td> <span class="status cartouche" :class="'status-' + activity.status" > {{ activity.status_label || '-' }} </span> </td> <td>{{ activity.numOscar || '-' }}</td> <td>{{ activity.codeEOTP || '-' }}</td> <td>{{ activity.dateStart ? $filters.date(activity.dateStart) : '-' }}</td> <td>{{ activity.dateEnd ? $filters.date(activity.dateEnd) : '-' }}</td> </tr> </tbody> </table> </div> </div> <div class="alert alert-info" v-else> Cette activité n'est liée à aucun projet. </div> </div> <div class="tab-pane fade" id="nav-financial" :class="{'active show': uiActiveTab === 'financial'}" role="tabpanel" aria-labelledby="nav-financial-tab" tabindex="0"> Loading Loading @@ -1248,6 +1318,17 @@ export default { } else { return label; } }, projectActivitiesSorted() { const activities = this.core?.project_activities || []; return [...activities].sort((a, b) => { const aTs = a?.dateStart ? new Date(a.dateStart).getTime() : Number.POSITIVE_INFINITY; const bTs = b?.dateStart ? new Date(b.dateStart).getTime() : Number.POSITIVE_INFINITY; if (aTs === bTs) { return (a?.label || '').localeCompare(b?.label || ''); } return aTs - bTs; }); } }, Loading Loading @@ -1505,5 +1586,10 @@ export default { </script> <style lang="scss" scoped> .description-limited { line-height: 1.4; max-height: 14em; overflow-y: auto; white-space: pre-wrap; } </style> Loading
module/Oscar/src/Oscar/Controller/ProjectGrantController.php +38 −46 Original line number Diff line number Diff line Loading @@ -1848,19 +1848,12 @@ class ProjectGrantController extends AbstractOscarController implements UseNotif switch ($method) { case 'GET' : if ($this->isAjax() || $this->getRequest()->getQuery('f') === 'json2') { $datas = [ 'activity' => $this->getProjectGrantApiService()->getActivityJson( $entity->getId(), $this->url(), $this->getOscarUserContextService() ), ]; return $this->jsonOutput($datas); } elseif ($this->isAjax() || $this->getRequest()->getQuery('f') === 'json') { $format = $this->getRequest()->getQuery('f', null); if ($isAjax || $format === 'json' || $format === 'json2') { try { $perimeter = $this->getRequest()->getQuery('p', null); $perimeter = $format === 'json' ? $this->getRequest()->getQuery('p', null) : null; $datas = [ 'activity' => $this->getProjectGrantApiService()->getActivityJson( $entity->getId(), Loading Loading @@ -1910,7 +1903,6 @@ class ProjectGrantController extends AbstractOscarController implements UseNotif } default: return $this->jsonError("Action '$action' inconnue"); } break; default : Loading
module/Oscar/src/Oscar/Service/ProjectGrantApiService.php +20 −0 Original line number Diff line number Diff line Loading @@ -572,6 +572,7 @@ class ProjectGrantApiService implements } $project = null; $projectActivities = []; if ($activity->getProject() !== null) { $project = [ 'id' => $activity->getProject()->getId(), Loading @@ -580,6 +581,24 @@ class ProjectGrantApiService implements 'description' => $activity->getProject()->getDescription(), 'url_show' => $urlPlugin->fromRoute('project/show', ['id' => $activity->getProject()->getId()]) ]; /** @var Activity $projectActivity */ foreach ($activity->getProject()->getActivities() as $projectActivity) { if ($projectActivity->getId() === $activity->getId()) { continue; } $projectActivities[] = [ 'id' => $projectActivity->getId(), 'label' => $projectActivity->getLabel(), 'status' => $projectActivity->getStatus(), 'status_label' => $projectActivity->getStatusLabel(), 'numOscar' => $projectActivity->getOscarNum(), 'codeEOTP' => $projectActivity->getCodeEOTP(), 'dateStart' => $this->formatDateTime($projectActivity->getDateStart()), 'dateEnd' => $this->formatDateTime($projectActivity->getDateEnd()), 'url_show' => $urlPlugin->fromRoute('contract/show', ['id' => $projectActivity->getId()]), ]; } } // Numérotation Loading Loading @@ -614,6 +633,7 @@ class ProjectGrantApiService implements $out['notefinanciere'] = $activity->getNoteFinanciere(); $out['acronym'] = $activity->getAcronym(); $out['project'] = $project; $out['project_activities'] = $projectActivities; $out['disciplines'] = $activity->getDisciplinesArray(); $out['numeros'] = $numeros; $out['motscles'] = $activity->getMotsclesArray(); Loading
ui/src/views/Activity.vue +89 −3 Original line number Diff line number Diff line Loading @@ -295,6 +295,12 @@ data-bs-toggle="tab" data-bs-target="#nav-general" type="button" role="tab" aria-controls="nav-general" aria-selected="false"> <i class="icon-bank"></i> Général </button> <button class="nav-link" id="nav-project-tab" :class="{'active': uiActiveTab === 'project'}" @click="uiActiveTab = 'project'" data-bs-toggle="tab" data-bs-target="#nav-project" type="button" role="tab" aria-controls="nav-project" aria-selected="false"> <i class="icon-cubes"></i> Projet </button> <button class="nav-link" id="nav-dates-tab" :class="{'active': uiActiveTab === 'dates'}" @click="uiActiveTab = 'dates'" Loading Loading @@ -377,12 +383,76 @@ </div> </div> <div class="col-md-4"> <div class="col-md-8"> <h3>Description</h3> {{ core.description }} <div class="description-limited"> {{ core.description || '-' }} </div> </div> </div> </div> <div class="tab-pane fade" id="nav-project" :class="{'active show': uiActiveTab === 'project'}" role="tabpanel" aria-labelledby="nav-project-tab" tabindex="0"> <div class="row row-bordered" v-if="core.project"> <div class="col-md-12"> <div class="labeled-value labeled-value-horizontal"> <div class="label">Acronyme</div> <div class="value">{{ core.project.acronym || '-' }}</div> </div> <div class="labeled-value labeled-value-horizontal"> <div class="label">Intitulé</div> <div class="value"> <a :href="core.project.url_show"> <i class="icon-cubes"></i> {{ core.project.label }} </a> </div> </div> </div> <div class="col-md-12"> <h3>Autres activités du projet</h3> <div class="alert alert-info" v-if="projectActivitiesSorted.length === 0"> Aucune autre activité liée à ce projet. </div> <table class="table table-condensed" v-else> <thead> <tr> <th>{{ $filters.oscarText('Activité') }}</th> <th>{{ $filters.oscarText('status') }}</th> <th>{{ $filters.oscarText('numOscar') }}</th> <th>{{ $filters.oscarText('codeEOTP') }}</th> <th>{{ $filters.oscarText('dateStart') }}</th> <th>{{ $filters.oscarText('dateEnd') }}</th> </tr> </thead> <tbody> <tr v-for="activity in projectActivitiesSorted" :key="activity.id"> <td> <a :href="activity.url_show"> <i class="icon-cube"></i> <strong>{{ activity.label }}</strong> </a> <small class="text-muted"> (#{{ activity.id }})</small> </td> <td> <span class="status cartouche" :class="'status-' + activity.status" > {{ activity.status_label || '-' }} </span> </td> <td>{{ activity.numOscar || '-' }}</td> <td>{{ activity.codeEOTP || '-' }}</td> <td>{{ activity.dateStart ? $filters.date(activity.dateStart) : '-' }}</td> <td>{{ activity.dateEnd ? $filters.date(activity.dateEnd) : '-' }}</td> </tr> </tbody> </table> </div> </div> <div class="alert alert-info" v-else> Cette activité n'est liée à aucun projet. </div> </div> <div class="tab-pane fade" id="nav-financial" :class="{'active show': uiActiveTab === 'financial'}" role="tabpanel" aria-labelledby="nav-financial-tab" tabindex="0"> Loading Loading @@ -1248,6 +1318,17 @@ export default { } else { return label; } }, projectActivitiesSorted() { const activities = this.core?.project_activities || []; return [...activities].sort((a, b) => { const aTs = a?.dateStart ? new Date(a.dateStart).getTime() : Number.POSITIVE_INFINITY; const bTs = b?.dateStart ? new Date(b.dateStart).getTime() : Number.POSITIVE_INFINITY; if (aTs === bTs) { return (a?.label || '').localeCompare(b?.label || ''); } return aTs - bTs; }); } }, Loading Loading @@ -1505,5 +1586,10 @@ export default { </script> <style lang="scss" scoped> .description-limited { line-height: 1.4; max-height: 14em; overflow-y: auto; white-space: pre-wrap; } </style>