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;
adresseIp: string;
adresseMac: string;
assigned: boolean;
agentConnecteId: string;
derniereConnexionAgent: string;
derniereDeconnexionAgent: string;

View File

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

View File

@@ -370,7 +370,7 @@
</div>
<div modal-actions class="flex justify-end gap-2">
<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
</button>
</div>

View File

@@ -458,25 +458,45 @@ export class AgentsPage {
confirmAssignTpe() {
const agent = this.assigningAgent();
const tpeId = this.selectedTpeId();
if (!agent || tpeId.length === 0) {
alert('Veuillez sélectionner un TPE');
const tpeId = this.selectedTpeId().map(id=> id);
if (!agent) {
toast.error('Veuillez sélectionner un TPE');
return;
}
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);
}
this.api.assigner(tpeId, agent.id).subscribe({
next:()=>{
this.assignTpeModalOpen.set(false);
this.assigningAgent.set(undefined);
this.selectedTpeId.set([]);
toast.success("Termiaux affectés avec succès!");
const params = {
page: this.page(),
size: this.size(),
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
// this.tpeSvc.assigner(tpeId, agent.id).subscribe({

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -60,6 +60,20 @@ export class CourseForm implements OnInit, AfterViewInit, OnDestroy {
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;
submitted = false;

View File

@@ -21,19 +21,18 @@
[disabled]="!canSave()">
Enregistrer
</button>
<button
<!-- <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"
(click)="validate.emit()"
[disabled]="!canValidate()">
Valider
</button>
</button> -->
<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"
(click)="confirm.emit()"
[disabled]="!canConfirm()"
>
[disabled]="!canConfirm()">
Confirmer
</button>
</div>

View File

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

View File

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