瀏覽代碼

dev en cours

rajah 11 月之前
父節點
當前提交
4ece464fe5

+ 4 - 0
src/app/app.routes.ts

@@ -32,6 +32,8 @@ import { ProductionCreateComponent } from './composants/production-create/produc
 import { ProductionDetailsComponent } from './composants/production-details/production-details.component';
 import { ProductionUpdateComponent } from './composants/production-update/production-update.component';
 import { ProductionUploadComponent } from './composants/production-upload/production-upload.component';
+import { ShowListComponent } from './composants/show-list/show-list.component';
+import { ShowLinksComponent } from './composants/show-links/show-links.component';
 
 export const routes: Routes = [
   {path: '', redirectTo: 'home', pathMatch: 'full'},
@@ -60,6 +62,8 @@ export const routes: Routes = [
   {path: 'production-details/:numeroProduction', component: ProductionDetailsComponent, canActivate: [UserGuard], runGuardsAndResolvers: 'always' },
   {path: 'production-update/:numeroProduction', component: ProductionUpdateComponent, canActivate: [UserGuard], runGuardsAndResolvers: 'always' },
   {path: 'production-upload/:numeroProduction', component: ProductionUploadComponent, canActivate: [UserGuard], runGuardsAndResolvers: 'always' },
+  {path: 'show-list', component: ShowListComponent, canActivate: [AdminGuard], runGuardsAndResolvers: 'always' },
+  {path: 'show-links/:numeroCategorie', component: ShowLinksComponent, canActivate: [AdminGuard], runGuardsAndResolvers: 'always' },
 ];
 
 @NgModule({

+ 3 - 2
src/app/composants/categorie-details/categorie-details.component.ts

@@ -1,9 +1,10 @@
 import { Component, OnInit } from '@angular/core';
-import { MenuComponent } from '../menu/menu.component';
 import { ActivatedRoute, Router } from '@angular/router';
+import { FormsModule } from '@angular/forms';
+
+import { MenuComponent } from '../menu/menu.component';
 import { Categorie } from '../../interfaces/categorie';
 import { CategorieService } from '../../services/categorie.service';
-import { FormsModule } from '@angular/forms';
 
 @Component({ selector: 'app-categorie-details', imports: [FormsModule, MenuComponent], templateUrl: './categorie-details.component.html', styleUrl: './categorie-details.component.css' })
 

+ 2 - 1
src/app/composants/categorie-list/categorie-list.component.ts

@@ -1,6 +1,7 @@
 import { Component, OnInit } from '@angular/core';
-import { MenuComponent } from '../menu/menu.component';
 import { Router } from '@angular/router';
+
+import { MenuComponent } from '../menu/menu.component';
 import { Categorie } from '../../interfaces/categorie';
 import { CategorieService } from '../../services/categorie.service';
 

+ 4 - 3
src/app/composants/production-list/production-list.component.ts

@@ -1,11 +1,12 @@
 import { Component, OnInit } from '@angular/core';
 import { Router } from '@angular/router';
+import { FormsModule, NgForm } from '@angular/forms';
+import { saveAs } from 'file-saver';
+import { TooltipModule } from 'ngx-bootstrap/tooltip';
+
 import { MenuComponent } from '../menu/menu.component';
 import { ProductionShort, ProductionEnum, ProductionTypeList } from '../../interfaces/production';
 import { ProductionService } from '../../services/production.service';
-import { saveAs } from 'file-saver';
-import { TooltipModule } from 'ngx-bootstrap/tooltip';
-import { FormsModule, NgForm } from '@angular/forms';
 
 @Component({ selector: 'app-production-list', imports: [FormsModule, TooltipModule, MenuComponent], templateUrl: './production-list.component.html', styleUrl: './production-list.component.css' })
 

+ 3 - 0
src/app/composants/show-links/show-links.component.css

@@ -0,0 +1,3 @@
+#selectionLinked, #selectionUnlinked { width: 360px; min-height: 400px; overflow-x: auto; }
+
+.boutons { width: 90px; }

+ 41 - 0
src/app/composants/show-links/show-links.component.html

@@ -0,0 +1,41 @@
+<app-menu></app-menu>
+<div id="main">
+<div class="card shadow center">
+
+  <div class="card-header"><span i18n>Productions liées à la catégorie {{ categorie.libelle }}</span></div>
+	<div class="card-header shadow-sm">
+		<button (click)="goToListPresentations()" class="btn bg-gradient btn-primary btn-sm"><i class="fa-solid fa-xmark"></i>&nbsp;<span i18n>Retour</span></button>
+	</div>
+	<div class="card-body"><div class="row align-items-start">
+
+    <div class="col">
+      <select class="form-select-sm" multiple id="selectionLinked" (change)="changeEtatBoutonsLinked($event)">
+      @for (prod of linkedProductions; track prod.numeroProduction) {
+        <option [value]="prod.numeroProduction"> {{ prod.titre }}</option>
+      }
+      </select>
+    </div>
+
+    <div class="col mx-auto">
+      <br/><br/>
+      <button (click)="lierProduction()" #boutonLier class="btn bg-gradient btn-primary btn-sm boutons disabled"><i class="fa-solid fa-arrow-left"></i>&nbsp;<span i18n>Lier</span></button>
+      <hr/>
+      <button (click)="retirerProduction()" #boutonRetirer class="btn bg-gradient btn-primary btn-sm boutons disabled"><i class="fa-solid fa-arrow-right"></i>&nbsp;<span i18n>Retirer</span></button>
+      <br/><br/>
+      <button (click)="avancerProduction()" #boutonAvancer class="btn bg-gradient btn-primary btn-sm boutons disabled"><i class="fa-solid fa-arrow-up"></i>&nbsp;<span i18n>Avancer</span></button>
+      <br/><br/>
+      <button (click)="reculerProduction()" #boutonReculer class="btn bg-gradient btn-primary btn-sm boutons disabled"><i class="fa-solid fa-arrow-down"></i>&nbsp;<span i18n>Reculer</span></button>
+    </div>
+
+    <div class="col">
+      <select class="form-select-sm" multiple id="selectionUnlinked" (change)="changeEtatBoutonsUnlinked($event)">
+      @for (prod of unlinkedProductions; track prod.numeroProduction) {
+        <option [value]="prod.numeroProduction"> {{ prod.titre }}</option>
+      }
+      </select>
+    </div>
+
+  </div></div>
+
+</div>
+</div>

+ 82 - 0
src/app/composants/show-links/show-links.component.ts

@@ -0,0 +1,82 @@
+import { Component, OnInit, ViewChild, ElementRef, Renderer2 } from '@angular/core';
+import { Router, ActivatedRoute } from '@angular/router';
+import { FormsModule, NgForm } from '@angular/forms';
+
+import { MenuComponent } from '../menu/menu.component';
+import { Categorie } from '../../interfaces/categorie';
+import { CategorieService } from '../../services/categorie.service';
+import { ProductionItem, ProductionEnum } from '../../interfaces/production';
+import { PresentationService } from '../../services/presentation.service';
+
+@Component({ selector: 'app-show-links', imports: [FormsModule, MenuComponent], templateUrl: './show-links.component.html', styleUrl: './show-links.component.css' })
+
+export class ShowLinksComponent implements OnInit
+{
+
+  @ViewChild('boutonLier', {static: false}) boutonLier!: ElementRef;
+  @ViewChild('boutonRetirer', {static: false}) boutonRetirer!: ElementRef;
+  @ViewChild('boutonAvancer', {static: false}) boutonAvancer!: ElementRef;
+  @ViewChild('boutonReculer', {static: false}) boutonReculer!: ElementRef;
+
+  numeroCategorie: number = 0;
+  categorie: Categorie = new Categorie();
+
+  numeroProduction: number = 0;
+  linkedProductions: ProductionItem[] = [];
+  unlinkedProductions: ProductionItem[] = [];
+
+  constructor(
+    private categorieService: CategorieService,
+    private presentationService: PresentationService,
+    private route: ActivatedRoute,
+    private router: Router,
+    private menu: MenuComponent,
+    private renderer: Renderer2
+  ) { }
+
+  ngOnInit()
+  {
+    this.numeroCategorie = this.route.snapshot.params['numeroCategorie'];
+    this.categorie = new Categorie();
+    this.categorieService.getByIdCategorie(this.numeroCategorie).subscribe( data => { this.categorie = data; });
+
+    this.retreiveDatas();
+  }
+
+  private retreiveDatas()
+  {
+    this.presentationService.getLinkedProductions(this.numeroCategorie).subscribe(data => { this.linkedProductions = data; });
+    this.presentationService.getUnlinkedProductions().subscribe(data => { this.unlinkedProductions = data; });
+  }
+
+  goToListPresentations() { this.router.navigate(['/show-list'], { queryParams: { 'refresh': this.menu.getRandomInteger(1, 100000) } }); }
+
+  changeEtatBoutonsUnlinked(event: any)
+  {
+    this.numeroProduction = event.target.value;
+
+    var b: boolean = (this.numeroProduction != 0);
+
+    if (this.boutonLier) { if (b) { this.renderer.removeClass(this.boutonLier.nativeElement, 'disabled'); } else { this.renderer.addClass(this.boutonLier.nativeElement, 'disabled'); } }
+  }
+
+  changeEtatBoutonsLinked(event: any)
+  {
+    this.numeroProduction = -event.target.value;
+
+    var b: boolean = (this.numeroProduction != 0);
+
+    if (this.boutonRetirer) { if (b) { this.renderer.removeClass(this.boutonRetirer.nativeElement, 'disabled'); } else { this.renderer.addClass(this.boutonRetirer.nativeElement, 'disabled'); } }
+    if (this.boutonAvancer) { if (b) { this.renderer.removeClass(this.boutonAvancer.nativeElement, 'disabled'); } else { this.renderer.addClass(this.boutonAvancer.nativeElement, 'disabled'); } }
+    if (this.boutonReculer) { if (b) { this.renderer.removeClass(this.boutonReculer.nativeElement, 'disabled'); } else { this.renderer.addClass(this.boutonReculer.nativeElement, 'disabled'); } }
+  }
+
+  lierProduction() { if (this.numeroProduction > 0) { this.presentationService.lierProduction(this.numeroCategorie, this.numeroProduction).subscribe(() => { this.retreiveDatas(); }); } }
+
+  retirerProduction() { if (this.numeroProduction < 0) { this.presentationService.retirerProduction(this.numeroCategorie, this.numeroProduction).subscribe(() => { this.retreiveDatas(); }); } }
+
+  avancerProduction() { if (this.numeroProduction < 0) { this.presentationService.avancerProduction(this.numeroCategorie, this.numeroProduction).subscribe(() => { this.retreiveDatas(); }); } }
+
+  reculerProduction() { if (this.numeroProduction < 0) { this.presentationService.reculerProduction(this.numeroCategorie, this.numeroProduction).subscribe(() => { this.retreiveDatas(); }); } }
+
+}

+ 0 - 0
src/app/composants/show-list/show-list.component.css


+ 48 - 0
src/app/composants/show-list/show-list.component.html

@@ -0,0 +1,48 @@
+<app-menu></app-menu>
+<div id="main">
+<div class="card shadow">
+  <div class="card-header"><span i18n>Liste des présentations</span></div>
+	<div class="card-header shadow-sm">
+		<div class="row">
+			<div class="form-group col-sm-4 label-nobr">
+				<button type="button" (click)="goToRefreshListCategorie()" class="btn bg-gradient btn-primary btn-sm" style="margin-right: 5px;"><i class="fa-solid fa-rotate"></i>&nbsp;<span i18n>Actualiser</span></button>
+			</div>
+		</div>
+	</div>
+</div>
+
+@for (categorie of categories; track categorie.numeroCategorie) { @if (categorie.available) {
+<div class="card shadow overflow-x-auto" style="height:22rem;">
+  <div class="card-header">
+    {{ categorie.libelle }}&nbsp;&nbsp;&nbsp;&nbsp;
+    <button type="button" (click)="lierProductions(categorie.numeroCategorie)" class="btn bg-gradient btn-primary btn-sm" style="margin-right: 5px;" i18n-tootip tooltip="Rattacher des productions et les ordonner" placement="right" container="body"><i class="fa-solid fa-link"></i>&nbsp;<span i18n>Affilier</span></button>
+    @if (categorie.uploadable) { }
+    @if (categorie.pollable) { }
+    @if (categorie.computed) { }
+    @if (categorie.displayable) { }
+  </div>
+  <div class="card-body">
+@for (production of productions; track production.numeroProduction) { @if (categorie.numeroCategorie == production.numeroCategorie) {
+    <div class="card shadow" style="max-height:20rem;">
+      <img src="{{ production.vignette }}" class="img-fluid card-img-top pointeur-souris" (click)="formProduction(production.numeroProduction)">
+      <div class="card-header">
+        <span class="card-title">@if (production.type === types[0].key) { <i class="fa-solid fa-square-binary"></i> } @else if (production.type === types[1].key) { <i class="fa-solid fa-image"></i> } @else if (production.type === types[2].key) { <i class="fa-solid fa-music"></i> } @else if (production.type === types[3].key) { <i class="fa-solid fa-video"></i> } @else if (production.type === types[4].key) { <i class="fa-solid fa-comment"></i> } @else { <i class="fa-solid fa-question"></i> }
+          <a (click)="formProduction(production.numeroProduction)" class="text-primary pointeur-souris" style="margin-left:7px;">{{ production.titre }}</a></span><br/>
+          <small><span class="text-muted">par</span> {{ production.auteurs }} @if (production.groupes) { @if (production.groupes.length > 0) { &nbsp;/&nbsp;{{ production.groupes }} } }</small>
+      </div>
+      <div class="card-body">
+        <small><span class="text-muted">sur</span> {{ production.plateforme }}</small><br/>
+        <small>{{ production.commentaire }}</small><br/>
+        <small class="text-warning">{{ production.informationsPrivees }}</small>
+      </div>
+      <div class="card-footer d-flex justify-content-between">
+        <i class="fa-solid fa-download text-primary pointeur-souris" (click)="getFile(production.numeroProduction, production.nomArchive)" tooltip="{{ production.nomArchive }} (v{{ production.numeroVersion }})" placement="top" container="body"></i>
+        <i class="fa-solid fa-user-tie text-muted" style="margin-left:7px;" i18n-tootip tooltip="géré par {{ production.nomGestionnaire }}" placement="top" container="body"></i>
+      </div>
+    </div>
+} }
+  </div>
+</div>
+} }
+
+</div>

+ 44 - 0
src/app/composants/show-list/show-list.component.ts

@@ -0,0 +1,44 @@
+import { Component, OnInit } from '@angular/core';
+import { Router } from '@angular/router';
+import { FormsModule, NgForm } from '@angular/forms';
+import { TooltipModule } from 'ngx-bootstrap/tooltip';
+import { saveAs } from 'file-saver';
+
+import { MenuComponent } from '../menu/menu.component';
+import { Categorie } from '../../interfaces/categorie';
+import { CategorieService } from '../../services/categorie.service';
+
+import { ProductionShort, ProductionEnum, ProductionTypeList } from '../../interfaces/production';
+import { ProductionService } from '../../services/production.service';
+
+@Component({ selector: 'app-show-list', imports: [FormsModule, TooltipModule, MenuComponent], templateUrl: './show-list.component.html', styleUrl: './show-list.component.css' })
+
+export class ShowListComponent implements OnInit
+{
+
+  categories: Categorie[] = [];
+
+  types: ProductionEnum[] = ProductionTypeList;
+  productions: ProductionShort[] = [];
+
+  constructor(private categorieService: CategorieService, private productionService: ProductionService, private router: Router) { }
+
+  ngOnInit() { this.retreiveDatas(); }
+
+  private retreiveDatas()
+  {
+    this.categorieService.getListCategorie().subscribe(data => { this.categories = data; });
+    this.productionService.getListProduction('').subscribe(data => { this.productions = data; });
+  }
+
+  goToRefreshListCategorie(){ this.retreiveDatas(); }
+
+  formProduction(id: number) { this.router.navigate(['/production-details', id]); }
+
+  lierProductions(id: number) { this.router.navigate(['/show-links', id]); }
+
+  getFile(id: number, nom: string) { this.productionService.getProductionFile(id).subscribe(response => { this.saveFile(response.body, nom); }); }
+
+  saveFile(data: any, filename?: string) { const blob = new Blob([data], {type: 'application/zip'}); saveAs(blob, filename); }
+
+}

+ 12 - 0
src/app/interfaces/production.ts

@@ -46,6 +46,7 @@ export class ProductionShort
   nomArchive: string = "";
   vignette!: string | any;
   numeroVersion: number = 0;
+  numeroCategorie: number = 0;
 }
 
 export class ProductionFile
@@ -56,3 +57,14 @@ export class ProductionFile
   nomArchive: string = "";
   archive!: string | any;
 }
+
+export class ProductionItem
+{
+  numeroProduction: number = 0;
+  type: string = "AUTRE";
+  titre: string = "";
+  auteurs: string = "";
+  groupes: string = "";
+  plateforme: string = "";
+  numeroOrdre: number = 0;
+}

+ 60 - 0
src/app/services/presentation.service.ts

@@ -0,0 +1,60 @@
+import { Injectable } from '@angular/core';
+import { HttpClient, HttpParams } from '@angular/common/http'
+import { Observable } from 'rxjs';
+import { Environnement } from '../env';
+import { ProductionItem } from '../interfaces/production';
+
+@Injectable({ providedIn: 'root' })
+
+export class PresentationService
+{
+
+  private baseURL = Environnement.apiUrl + "presentation";
+
+  constructor(private httpClient: HttpClient) { }
+
+  getLinkedProductions(id: number): Observable<ProductionItem[]> { return this.httpClient.get<ProductionItem[]>(`${this.baseURL}/list-linked/${id}`); }
+
+  getUnlinkedProductions(): Observable<ProductionItem[]> { return this.httpClient.get<ProductionItem[]>(`${this.baseURL}/list-unlinked`); }
+
+  lierProduction(id_cat: number, id_prod: number): Observable<Object>
+  {
+    let params = new HttpParams();
+
+    params = params.append('id_cat', id_cat);
+    params = params.append('id_prod', id_prod);
+
+    return this.httpClient.put(`${this.baseURL}/add`, { params: params });
+  }
+
+  retirerProduction(id_cat: number, id_prod: number): Observable<Object>
+  {
+    let params = new HttpParams();
+
+    params = params.append('id_cat', id_cat);
+    params = params.append('id_prod', id_prod);
+
+    return this.httpClient.put(`${this.baseURL}/remove`, { params: params });
+  }
+
+  avancerProduction(id_cat: number, id_prod: number): Observable<Object>
+  {
+    let params = new HttpParams();
+
+    params = params.append('id_cat', id_cat);
+    params = params.append('id_prod', id_prod);
+
+    return this.httpClient.put(`${this.baseURL}/forward`, { params: params });
+  }
+
+  reculerProduction(id_cat: number, id_prod: number): Observable<Object>
+  {
+    let params = new HttpParams();
+
+    params = params.append('id_cat', id_cat);
+    params = params.append('id_prod', id_prod);
+
+    return this.httpClient.put(`${this.baseURL}/backward`, { params: params });
+  }
+
+}