tasks done

This commit is contained in:
OnlyPapy98
2026-01-08 17:13:46 +01:00
parent d7bcbce50d
commit 665c15b3d7
13 changed files with 127 additions and 58 deletions

View File

@@ -16,6 +16,7 @@ export interface TpeDevice {
versionOs: string; versionOs: string;
adresseIp: string; adresseIp: string;
adresseMac: string; adresseMac: string;
assigned: boolean;
agentConnecteId: string; agentConnecteId: string;
derniereConnexionAgent: string; derniereConnexionAgent: string;
derniereDeconnexionAgent: string; derniereDeconnexionAgent: string;

View File

@@ -229,9 +229,14 @@ export class AgentService {
assigner(tpeId: string, agentId:string):Observable<Agent | undefined>{ assigner(tpeIds: string[], agentId:string):Observable<Agent | undefined>{
return this.http.post<Agent>(`${this.apiUrl}/${agentId}/terminaux/${tpeId}`, const payload = {
{Headers: this.getNgrokHeaders()}).pipe(map(res=> res), terminalIds: [
...tpeIds
]
}
return this.http.put<Agent>(`${this.apiUrl}/${agentId}/terminaux`,
payload, {headers: this.getNgrokHeaders()}).pipe(map(res=> res),
catchError((err)=>{ catchError((err)=>{
console.error(err); console.error(err);
return of(undefined); return of(undefined);

View File

@@ -370,7 +370,7 @@
</div> </div>
<div modal-actions class="flex justify-end gap-2"> <div modal-actions class="flex justify-end gap-2">
<z-button zType="destructive" (click)="closeAssignTpeModal()">Annuler</z-button> <z-button zType="destructive" (click)="closeAssignTpeModal()">Annuler</z-button>
<button z-button [disabled]="selectedTpeId().length === 0 || tpesLoading()" (click)="confirmAssignTpe()"> <button z-button [disabled]="tpesLoading()" (click)="confirmAssignTpe()">
Assigner Assigner
</button> </button>
</div> </div>

View File

@@ -458,25 +458,45 @@ export class AgentsPage {
confirmAssignTpe() { confirmAssignTpe() {
const agent = this.assigningAgent(); const agent = this.assigningAgent();
const tpeId = this.selectedTpeId(); const tpeId = this.selectedTpeId().map(id=> id);
if (!agent || tpeId.length === 0) { if (!agent) {
alert('Veuillez sélectionner un TPE'); toast.error('Veuillez sélectionner un TPE');
return; return;
} }
forkJoin(this.selectedTpeId().map(id=> this.api.assigner(id, agent.id))).subscribe( this.api.assigner(tpeId, agent.id).subscribe({
{ next:()=>{
next:()=>{ this.assignTpeModalOpen.set(false);
this.assignTpeModalOpen.set(false); this.assigningAgent.set(undefined);
this.assigningAgent.set(undefined); this.selectedTpeId.set([]);
this.selectedTpeId.set([]); toast.success("Termiaux affectés avec succès!");
toast.success(`Tpe affecté à l'agent avec succès1`) const params = {
}, page: this.page(),
error: (err)=>{ size: this.size(),
console.error(err); search: this.search(),
} sortKey: this.sort().key,
sortDir: this.sort().dir as SortDir,
};
this.fetch(params);
},
error:()=>{
console.error("Une érreur s'est produite")
} }
) })
// forkJoin(this.selectedTpeId().map(id=> this.api.assigner(id, agent.id))).subscribe(
// {
// next:()=>{
// this.assignTpeModalOpen.set(false);
// this.assigningAgent.set(undefined);
// this.selectedTpeId.set([]);
// toast.success(`Tpe affecté à l'agent avec succès1`)
// },
// error: (err)=>{
// console.error(err);
// }
// }
// )
// // Assign TPE to agent // // Assign TPE to agent
// this.tpeSvc.assigner(tpeId, agent.id).subscribe({ // this.tpeSvc.assigner(tpeId, agent.id).subscribe({

View File

@@ -497,8 +497,8 @@ export class Course {
onResultatConfirm() { onResultatConfirm() {
const c = this.selectedCourseForResultat(); const c = this.selectedCourseForResultat();
if (!c) return; if (!c) return;
const resultat = this.resultatsMap().get(c.id); const resultat = this.resultatsMap().get(c.id);
if (!resultat) { if (!resultat) {
toast.error('Aucun résultat à confirmer'); toast.error('Aucun résultat à confirmer');
return; return;

View File

@@ -67,8 +67,6 @@ export class TpeSelect {
ngOnInit() { ngOnInit() {
// Initialiser les TPE sélectionnés si fournis // Initialiser les TPE sélectionnés si fournis
this.selectedIds.set(new Set(this.selected)); this.selectedIds.set(new Set(this.selected));
} }
private loadTpes(params:ListParams) { private loadTpes(params:ListParams) {
@@ -77,11 +75,11 @@ export class TpeSelect {
next: (res) => { next: (res) => {
// Filtrer : TPE non assignés ou déjà assignés à cet agent // Filtrer : TPE non assignés ou déjà assignés à cet agent
// console.log(res.content); // console.log(res.content);
// const available = res.content.filter( const available = res.content.filter(
// (t) => (t) =>
// !t.agentConnecteId || t.agentConnecteId === this.agent?.id !t.assigned || t.agentConnecteId === this.agent?.id
// ); );
this.tpes.set(res.content); this.tpes.set(available);
this.total.set(res.pageable.total); this.total.set(res.pageable.total);
this.loading.set(false); this.loading.set(false);
}, },
@@ -94,10 +92,10 @@ export class TpeSelect {
toggleTpe(tpe: TpeDevice) { toggleTpe(tpe: TpeDevice) {
const current = new Set(this.selectedIds()); const current = new Set(this.selectedIds());
if (current.has(tpe.id)) { if (current.has(String(tpe.id))) {
current.delete(tpe.id); current.delete(String(tpe.id));
} else { } else {
current.add(tpe.id); current.add(String(tpe.id));
} }
this.selectedIds.set(current); this.selectedIds.set(current);
this.selectionChange.emit(Array.from(current)); this.selectionChange.emit(Array.from(current));

View File

@@ -137,7 +137,7 @@
[total]="total()" [total]="total()"
[page]="page()" [page]="page()"
[perPage]="perPage()" [perPage]="perPage()"
(pageChange)="page.set($event)" (pageChange)="page.set($event - 1)"
(perPageChange)="perPage.set($event)" (perPageChange)="perPage.set($event)"
></app-paginator> ></app-paginator>
</div> </div>

View File

@@ -28,6 +28,7 @@ import { forkJoin, Subject } from 'rxjs';
import { debounceTime, distinctUntilChanged, switchMap } from 'rxjs/operators'; import { debounceTime, distinctUntilChanged, switchMap } from 'rxjs/operators';
import { toast } from 'ngx-sonner'; import { toast } from 'ngx-sonner';
import { PointsVenteService } from 'src/app/core/services/points-vente'; import { PointsVenteService } from 'src/app/core/services/points-vente';
import { PointVente } from 'src/app/core/interfaces/points-ventes';
@Component({ @Component({
standalone: true, standalone: true,
@@ -76,6 +77,8 @@ export class TpePage implements OnInit {
assignmentStats = signal({ total: 0, assignes: 0, disponibles: 0 }); assignmentStats = signal({ total: 0, assignes: 0, disponibles: 0 });
statsLoading = signal(false); statsLoading = signal(false);
pointDeVenteMap = signal<Map<string, PointVente>>(new Map());
// Live search // Live search
private searchSubject = new Subject<string>(); private searchSubject = new Subject<string>();
@@ -102,21 +105,10 @@ export class TpePage implements OnInit {
key: 'pointDeVenteId', key: 'pointDeVenteId',
label: 'Point de vente', label: 'Point de vente',
sortable: true, sortable: true,
cell:(p) => { cell: (t) => {
let pointVente = signal(''); const pdv = this.pointDeVenteMap().get(String(t.pointDeVenteId));
this.pointVenteService.getById(p.pointDeVenteId).subscribe({ if (!pdv) return 'Pas de point de vente';
next: (pdv)=>{ return `${pdv.ville}/${pdv.adresse}`;
if(!pdv || pdv === undefined){
pointVente.set("Aucun point")
return;
};
pointVente.set(`${pdv.ville}/${pdv.adresse}`)
},
error:(err)=>{
pointVente.set('Aucun point')
}
})
return pointVente();
}, },
}, },
{ key: 'versionLogicielle', label: 'Version', sortable: true }, { key: 'versionLogicielle', label: 'Version', sortable: true },
@@ -127,7 +119,7 @@ export class TpePage implements OnInit {
key: 'assigne', key: 'assigne',
label: 'Assigné à', label: 'Assigné à',
cell: (d) => { cell: (d) => {
if (!d.agentConnecteId) { if (!d.assigned) {
return '<span class="text-muted-foreground text-sm">Non assigné</span>'; return '<span class="text-muted-foreground text-sm">Non assigné</span>';
} }
// a rectifier apres avec les données des agents! // a rectifier apres avec les données des agents!
@@ -296,10 +288,32 @@ export class TpePage implements OnInit {
}); });
} else { } else {
// Normal list with pagination // Normal list with pagination
const map: Map<string, PointVente> = new Map();
this.api.list(params).subscribe({ this.api.list(params).subscribe({
next: (res) => { next: (res) => {
this.rows.set(res.content); this.rows.set(res.content);
this.total.set(res.pageable.total); this.total.set(res.pageable.total);
const requests = res.content
.filter((t) => t.pointDeVenteId)
.map((t) => this.pointVenteService.getById(t.pointDeVenteId!));
forkJoin(requests).subscribe({
next: (pdvs) => {
res.content.forEach((t) => {
if (!t.pointDeVenteId) return;
const pdv = pdvs.find((p) => p?.id === t.pointDeVenteId);
if (!pdv) return;
map.set(String(t.pointDeVenteId), pdv);
});
// ✅ SET ICI seulement
this.pointDeVenteMap.set(map);
this.loading.set(false);
},
error: () => this.loading.set(false),
});
this.pointDeVenteMap.set(map);
this.loading.set(false); this.loading.set(false);
}, },
error: () => { error: () => {

View File

@@ -25,6 +25,7 @@
> >
<z-select <z-select
id="hippodromeId" id="hippodromeId"
[zDisabled]="getCourseStatut()!==undefined && getCourseStatut() !=='BROUILLON'"
placeholder="Rechercher une réunion..." placeholder="Rechercher une réunion..."
formControlName="hippodromeId" formControlName="hippodromeId"
[zLabel]="selectedHippodromeLabel() || ''" [zLabel]="selectedHippodromeLabel() || ''"
@@ -43,6 +44,7 @@
> >
<z-form-control> <z-form-control>
<input <input
[readOnly]="getCourseStatut()!==undefined && getCourseStatut() !=='BROUILLON'"
z-input z-input
type="number" type="number"
min="1" min="1"
@@ -63,6 +65,7 @@
> >
<z-form-control> <z-form-control>
<input <input
[readOnly]="getCourseStatut()!==undefined && getCourseStatut() !=='BROUILLON'"
z-input z-input
type="date" type="date"
placeholder="Ex: 10/07/2025" placeholder="Ex: 10/07/2025"
@@ -82,6 +85,7 @@
> >
<z-form-control> <z-form-control>
<input <input
[readOnly]="getCourseStatut()!==undefined && getCourseStatut() !=='BROUILLON'"
z-input z-input
placeholder="Ex: Plat" placeholder="Ex: Plat"
formControlName="discipline" formControlName="discipline"
@@ -101,6 +105,7 @@
> >
<z-form-control> <z-form-control>
<input <input
[readOnly]="getCourseStatut()!==undefined && getCourseStatut() !=='BROUILLON'"
z-input z-input
type="text" type="text"
placeholder="Ex: Grand Prix du Sahel" placeholder="Ex: Grand Prix du Sahel"
@@ -145,6 +150,7 @@
</label> </label>
<div class="flex gap-3 items-center"> <div class="flex gap-3 items-center">
<input <input
[readOnly]="getCourseStatut()!==undefined && getCourseStatut() !=='BROUILLON'"
z-input z-input
type="time" type="time"
formControlName="heureDepartPrevue" formControlName="heureDepartPrevue"
@@ -184,6 +190,7 @@
@for (t of courseTypes; track t.value) { @for (t of courseTypes; track t.value) {
<label class="flex items-center gap-2 text-sm"> <label class="flex items-center gap-2 text-sm">
<input <input
[disabled]="getCourseStatut()!==undefined && getCourseStatut() !=='BROUILLON'"
type="checkbox" type="checkbox"
[value]="t.value" [value]="t.value"
(change)="onToggleType($event)" (change)="onToggleType($event)"
@@ -208,6 +215,7 @@
" "
> >
<input <input
[readOnly]="getCourseStatut()!==undefined && getCourseStatut() !=='BROUILLON'"
z-input z-input
type="number" type="number"
min="1" min="1"
@@ -223,6 +231,7 @@
> >
<z-form-control> <z-form-control>
<input <input
[readOnly]="getCourseStatut()!==undefined && getCourseStatut() !=='BROUILLON'"
z-input z-input
type="number" type="number"
min="1" min="1"
@@ -238,6 +247,7 @@
> >
<z-form-control> <z-form-control>
<input <input
[readOnly]="getCourseStatut()!==undefined && getCourseStatut() !=='BROUILLON'"
z-input z-input
placeholder="Ex: A" placeholder="Ex: A"
formControlName="categorie" formControlName="categorie"
@@ -267,7 +277,7 @@
>Statut</label >Statut</label
> >
<z-form-control> <z-form-control>
<z-select formControlName="statut" class="w-full"> <z-select [zDisabled]="updateDisabled()" formControlName="statut" class="w-full">
@for (s of courseStatus; track s.value) { @for (s of courseStatus; track s.value) {
<z-select-item [zValue]="s.value">{{ s.label }}</z-select-item> <z-select-item [zValue]="s.value">{{ s.label }}</z-select-item>
} }
@@ -281,6 +291,7 @@
> >
<z-form-control> <z-form-control>
<input <input
[readOnly]="getCourseStatut()!==undefined && getCourseStatut() !=='BROUILLON'"
z-input z-input
type="number" type="number"
min="1" min="1"
@@ -314,6 +325,7 @@
> >
<z-form-control> <z-form-control>
<input <input
readOnly
z-input z-input
formControlName="createdBy" formControlName="createdBy"
readonly readonly
@@ -328,6 +340,7 @@
> >
<z-form-control> <z-form-control>
<input <input
readOnly
z-input z-input
formControlName="validatedBy" formControlName="validatedBy"
readonly readonly

View File

@@ -60,6 +60,20 @@ export class CourseForm implements OnInit, AfterViewInit, OnDestroy {
return this._value; return this._value;
} }
getCourseStatut():string|undefined{
return this._value?.statut
}
updateDisabled():boolean{
const statut = this._value?.statut;
if(statut !== undefined){
if(statut === 'OUVERT' || statut === 'FERME'){
return true;
}
}
return false;
}
form: FormGroup; form: FormGroup;
submitted = false; submitted = false;

View File

@@ -21,19 +21,18 @@
[disabled]="!canSave()"> [disabled]="!canSave()">
Enregistrer Enregistrer
</button> </button>
<button <!-- <button
type="button" type="button"
class="flex-1 px-3 py-2 text-sm rounded border border-blue-300 bg-blue-50 text-blue-700 hover:bg-blue-100 disabled:opacity-50" class="flex-1 px-3 py-2 text-sm rounded border border-blue-300 bg-blue-50 text-blue-700 hover:bg-blue-100 disabled:opacity-50"
(click)="validate.emit()" (click)="validate.emit()"
[disabled]="!canValidate()"> [disabled]="!canValidate()">
Valider Valider
</button> </button> -->
<button <button
type="button" type="button"
class="flex-1 px-3 py-2 text-sm rounded border border-emerald-300 bg-emerald-50 text-emerald-700 hover:bg-emerald-100 disabled:opacity-50" class="flex-1 px-3 py-2 text-sm rounded border border-emerald-300 bg-emerald-50 text-emerald-700 hover:bg-emerald-100 disabled:opacity-50"
(click)="confirm.emit()" (click)="confirm.emit()"
[disabled]="!canConfirm()" [disabled]="!canConfirm()">
>
Confirmer Confirmer
</button> </button>
</div> </div>

View File

@@ -5,7 +5,7 @@ import { ZardFormModule } from '@shared/components/form/form.module';
import { ZardSelectComponent } from '@shared/components/select/select.component'; import { ZardSelectComponent } from '@shared/components/select/select.component';
import { ZardSelectItemComponent } from '@shared/components/select/select-item.component'; import { ZardSelectItemComponent } from '@shared/components/select/select-item.component';
import { Course, CourseType } from 'src/app/core/interfaces/course'; import { Course, CourseType } from 'src/app/core/interfaces/course';
import { Resultat } from 'src/app/core/interfaces/resultat'; import { Resultat, ResultatStatut } from 'src/app/core/interfaces/resultat';
type PlaceRow = { picks: FormArray<FormControl<number | null>> }; type PlaceRow = { picks: FormArray<FormControl<number | null>> };
type ResultatShape = { places: FormArray<FormGroup<PlaceRow>> }; type ResultatShape = { places: FormArray<FormGroup<PlaceRow>> };
@@ -65,12 +65,12 @@ export class ResultatForm {
return this.resultat ? 'PROVISOIRE' : 'EN_ATTENTE'; return this.resultat ? 'PROVISOIRE' : 'EN_ATTENTE';
}); });
canValidate(): boolean { // canValidate(): boolean {
return this.statut() === 'EN_ATTENTE'; // return this.statut() === 'PROVISOIRE';
} // }
canConfirm(): boolean { canConfirm(): boolean {
return this.statut() === 'PROVISOIRE'; return this.statut() === 'PROVISOIRE' || this.statut() === 'OFFICIEL';
} }
// Helper methods for template // Helper methods for template
@@ -228,6 +228,7 @@ export class ResultatForm {
}); });
ngOnInit() { ngOnInit() {
this.seed(); this.seed();
// Watch for changes to auto-populate places when ex-aequo is detected // Watch for changes to auto-populate places when ex-aequo is detected
this.setupAutoPopulate(); this.setupAutoPopulate();
@@ -549,6 +550,10 @@ export class ResultatForm {
} }
} }
if(this.statut()==='OFFICIEL'){
return false;
}
return true; return true;
} }

View File

@@ -1,5 +1,5 @@
export const environment = { export const environment = {
production: false, production: false,
apiBaseUrl: 'http://192.168.40.204:8080', apiBaseUrl: 'http://192.168.40.212:8080',
depouillementBaseUrl: 'http://192.168.1.235:8383' depouillementBaseUrl: 'http://192.168.1.235:8383'
}; };