ecccab90fd
- Statuts camions calculés automatiquement selon les shows assignés - Gestion manuelle limitée aux statuts "En panne" et "En maintenance" - Bouton pour supprimer un spectacle directement depuis la grille ou le panneau - Ajustement de la largeur dynamique des évènements et camions dans les créneaux - Nouveau style pour les badges de statut et indices visuels des actions - Indications sur les statuts automatiques dans le formulaire camion
368 lines
21 KiB
HTML
368 lines
21 KiB
HTML
<div class="background">
|
||
<div class="planning">
|
||
|
||
<!-- ── Grille hebdomadaire ─────────────────────────────── -->
|
||
<div class="left">
|
||
<div class="week-section">
|
||
|
||
<div class="week-toolbar">
|
||
<div class="week-actions">
|
||
<button [class]="isCamionFilterActive ? 'action-btn active' : 'action-btn'"
|
||
(click)="camionFilter()">
|
||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor">
|
||
<rect x="1" y="3" width="15" height="13" rx="2" ry="2" stroke-width="2"/>
|
||
<path d="M16 8h5l3 3v5h-4" stroke-width="2"/>
|
||
<circle cx="5.5" cy="18.5" r="2.5" stroke-width="2"/>
|
||
<circle cx="18.5" cy="18.5" r="2.5" stroke-width="2"/>
|
||
</svg>
|
||
Camion
|
||
</button>
|
||
<button [class]="isShowFilterActive ? 'action-btn active' : 'action-btn'"
|
||
(click)="showFilter()">
|
||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor">
|
||
<polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2" stroke-width="2"/>
|
||
</svg>
|
||
Show
|
||
</button>
|
||
</div>
|
||
<div class="week-nav">
|
||
<button class="nav-button-week" (click)="previousWeek()">
|
||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none">
|
||
<path d="M15 18L9 12L15 6" stroke="#666" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||
</svg>
|
||
</button>
|
||
<span class="week-label">Semaine {{ getWeekNumber() }}</span>
|
||
<button class="today-btn" (click)="goToToday()">Aujourd'hui</button>
|
||
<button class="nav-button-week" (click)="nextWeek()">
|
||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none">
|
||
<path d="M9 18L15 12L9 6" stroke="#666" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||
</svg>
|
||
</button>
|
||
</div>
|
||
<button class="new-show-btn" (click)="showModal()">
|
||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor">
|
||
<path d="M12 5v14M5 12h14" stroke-width="2.5" stroke-linecap="round"/>
|
||
</svg>
|
||
Nouveau spectacle
|
||
</button>
|
||
</div>
|
||
|
||
<div class="week-calendar" #weekCalendar>
|
||
<div class="week-grid">
|
||
<div class="time-column">
|
||
<div class="time-header"></div>
|
||
<div class="time-slot" *ngFor="let hour of getHours()">{{ hour }}</div>
|
||
</div>
|
||
<div class="day-column" *ngFor="let date of selectedDates">
|
||
<div class="day-header"
|
||
[class.today]="isToday(date)"
|
||
[class.selected-day]="isDaySelected(date)"
|
||
(click)="selectDay(date)">
|
||
<div class="day-name">{{ getDayName(date) }}</div>
|
||
<div class="day-date">{{ date.getDate() }}</div>
|
||
</div>
|
||
<div class="day-slots">
|
||
@if (isToday(date)) {
|
||
<div class="now-line" [style.top.px]="getNowTopPx()"></div>
|
||
}
|
||
<div class="hour-slot"
|
||
*ngFor="let hour of getHours()"
|
||
(click)="selectDay(date)">
|
||
@for (show of getShowsForSlot(date, hour); track show.id) {
|
||
<div class="show-event"
|
||
[style.top.px]="show.date ? getEventTopPx(show.date) : 0"
|
||
[style.left]="'calc(' + (show.colIndex / show.colCount * 100) + '% + 3px)'"
|
||
[style.right]="'calc(' + ((show.colCount - show.colIndex - 1) / show.colCount * 100) + '% + 3px)'">
|
||
<span class="show-event-name">{{ show.name }}</span>
|
||
<span class="show-event-time" *ngIf="show.date">{{ formatShowTime(show.date) }}</span>
|
||
</div>
|
||
}
|
||
@for (truck of getTrucksForSlot(date, hour); track truck.id) {
|
||
<div class="truck-event"
|
||
[style.top.px]="truck.showId ? 0 : 0"
|
||
[style.left]="'calc(' + (truck.colIndex / truck.colCount * 100) + '% + 3px)'"
|
||
[style.right]="'calc(' + ((truck.colCount - truck.colIndex - 1) / truck.colCount * 100) + '% + 3px)'">
|
||
<span class="truck-event-name">{{ truck.type || 'Camion' }}</span>
|
||
<span class="truck-event-statut">{{ getComputedTruckStatus(truck) }}</span>
|
||
</div>
|
||
}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ── Panneau droit ────────────────────────────────────── -->
|
||
<div class="right">
|
||
|
||
<div class="calendar-section">
|
||
<div class="calendar-title">CALENDRIER</div>
|
||
<div class="card">
|
||
<div class="calendar-header">
|
||
<button class="nav-button" (click)="previousMonth()">
|
||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none">
|
||
<path d="M15 18L9 12L15 6" stroke="#d4a574" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||
</svg>
|
||
</button>
|
||
<h2 class="month-title">{{ currentMonthYear }}</h2>
|
||
<button class="nav-button" (click)="nextMonth()">
|
||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none">
|
||
<path d="M9 18L15 12L9 6" stroke="#d4a574" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||
</svg>
|
||
</button>
|
||
</div>
|
||
<nz-calendar
|
||
[nzFullscreen]="false"
|
||
[ngModel]="currentDate"
|
||
(nzSelectChange)="onValueChange($event)"
|
||
(nzPanelChange)="onPanelChange($event)"
|
||
[nzDateFullCell]="dateCellTemplate"
|
||
></nz-calendar>
|
||
<ng-template #dateCellTemplate let-date>
|
||
<div class="ant-picker-cell-inner" [class.in-selection]="isDateSelected(date)">
|
||
{{ date.getDate() }}
|
||
</div>
|
||
</ng-template>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="details">
|
||
<div class="sidebar-header">
|
||
<h3 class="sidebar-title">
|
||
@if (selectedDay) {
|
||
{{ formatSelectedDay(selectedDay) }}
|
||
} @else {
|
||
Détails
|
||
}
|
||
</h3>
|
||
</div>
|
||
<div class="sidebar-content">
|
||
|
||
<div class="sidebar-block">
|
||
<h4>
|
||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor">
|
||
<polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2" stroke-width="2"/>
|
||
</svg>
|
||
Spectacles du jour
|
||
</h4>
|
||
@if (getDayShows().length === 0) {
|
||
<p class="no-items">Aucun spectacle ce jour</p>
|
||
} @else {
|
||
<div class="slot-info">
|
||
@for (show of getDayShows(); track show.id) {
|
||
<div class="show-card">
|
||
<div class="show-card-header">
|
||
<strong>{{ show.name }}</strong>
|
||
<div style="display:flex; align-items:center; gap:6px;">
|
||
<span class="show-time" *ngIf="show.date">{{ formatShowTime(show.date) }}</span>
|
||
<button class="show-delete-btn" (click)="deleteShow(show.id!)">×</button>
|
||
</div>
|
||
</div>
|
||
<p *ngIf="show.place">{{ show.place }}</p>
|
||
<p *ngIf="show.description">{{ show.description }}</p>
|
||
<div class="show-trucks-row">
|
||
@for (truck of getTrucksForShow(show.id!); track truck.id) {
|
||
<span class="truck-tag">
|
||
{{ truck.type }}
|
||
<span class="truck-tag-statut" [class]="'statut-' + getComputedTruckStatus(truck).toLowerCase().replace(' ', '-')">
|
||
{{ getComputedTruckStatus(truck) }}
|
||
</span>
|
||
<button class="truck-edit" (click)="openEditTruckModal(truck)">✎</button>
|
||
<button class="truck-remove" (click)="removeTruck(truck.id!)">×</button>
|
||
</span>
|
||
}
|
||
@if (getAvailableTrucks().length > 0) {
|
||
<select class="truck-select" (change)="onTruckAssign($event, show.id!)">
|
||
<option value="">+ Assigner</option>
|
||
@for (truck of getAvailableTrucks(); track truck.id) {
|
||
<option [value]="truck.id">{{ truck.type }}</option>
|
||
}
|
||
</select>
|
||
}
|
||
<button class="truck-create-btn" (click)="showTruckModal(show.id!)">+ Nouveau</button>
|
||
</div>
|
||
</div>
|
||
}
|
||
</div>
|
||
}
|
||
</div>
|
||
|
||
<div class="sidebar-block">
|
||
<h4>
|
||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor">
|
||
<rect x="1" y="3" width="15" height="13" rx="2" ry="2" stroke-width="2"/>
|
||
<path d="M16 8h5l3 3v5h-4" stroke-width="2"/>
|
||
<circle cx="5.5" cy="18.5" r="2.5" stroke-width="2"/>
|
||
<circle cx="18.5" cy="18.5" r="2.5" stroke-width="2"/>
|
||
</svg>
|
||
Camions du jour
|
||
</h4>
|
||
@if (getDayTrucks().length === 0) {
|
||
<p class="no-items">Aucun camion ce jour</p>
|
||
} @else {
|
||
<div class="slot-info">
|
||
@for (truck of getDayTrucks(); track truck.id) {
|
||
<div class="show-card truck-card">
|
||
<div class="show-card-header">
|
||
<strong>{{ truck.type || 'Camion' }}</strong>
|
||
<div style="display:flex; align-items:center; gap:6px;">
|
||
<span class="truck-statut" [class]="'statut-' + getComputedTruckStatus(truck).toLowerCase().replace(' ', '-')">
|
||
{{ getComputedTruckStatus(truck) }}
|
||
</span>
|
||
<button class="truck-edit-card" (click)="openEditTruckModal(truck)">✎</button>
|
||
</div>
|
||
</div>
|
||
<p *ngIf="truck.sizes">Taille : {{ truck.sizes }}</p>
|
||
<p *ngIf="truck.maxExplosiveCapacity">Capacité : {{ truck.maxExplosiveCapacity }} kg</p>
|
||
</div>
|
||
}
|
||
</div>
|
||
}
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<nz-modal
|
||
[nzVisible]="isVisible()"
|
||
(nzVisibleChange)="isVisible.set($event)"
|
||
[nzFooter]="null"
|
||
[nzWidth]="480"
|
||
nzClassName="create-show-modal"
|
||
(nzOnCancel)="handleCancel()">
|
||
<ng-container *nzModalContent>
|
||
<div class="create-form">
|
||
<div class="create-form-title">
|
||
<div class="create-form-icon">
|
||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor">
|
||
<polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2" stroke-width="1.5"/>
|
||
</svg>
|
||
</div>
|
||
<div>
|
||
<h3>Créer un spectacle</h3>
|
||
<p>Renseignez les informations du spectacle</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="form-field">
|
||
<label class="form-label">Nom du spectacle <span class="form-required">*</span></label>
|
||
<input class="form-input" placeholder="Ex: Feu d'artifice 14 juillet"
|
||
[(ngModel)]="newShow.name" name="name"/>
|
||
</div>
|
||
|
||
<div class="form-row-2">
|
||
<div class="form-field">
|
||
<label class="form-label">Lieu</label>
|
||
<input class="form-input" placeholder="Ex: Place de la mairie"
|
||
[(ngModel)]="newShow.place" name="place"/>
|
||
</div>
|
||
<div class="form-field">
|
||
<label class="form-label">Date et heure</label>
|
||
<div class="form-datepicker-wrap">
|
||
<nz-date-picker
|
||
nzShowTime
|
||
nzFormat="dd/MM/yyyy HH:mm"
|
||
[(ngModel)]="newShowDate"
|
||
nzPlaceHolder="Choisir une date..."
|
||
nzDropdownClassName="pyro-datepicker-dropdown"
|
||
name="date">
|
||
</nz-date-picker>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="form-field">
|
||
<label class="form-label">Description</label>
|
||
<textarea class="form-input form-textarea"
|
||
placeholder="Notes, consignes, détails techniques..."
|
||
[(ngModel)]="newShow.description"
|
||
name="description">
|
||
</textarea>
|
||
</div>
|
||
|
||
<div class="form-actions">
|
||
<button class="form-btn-cancel" (click)="handleCancel()">Annuler</button>
|
||
<button class="form-btn-submit" [disabled]="!newShow.name" (click)="handleOk()">
|
||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor">
|
||
<path d="M12 5v14M5 12h14" stroke-width="2.5" stroke-linecap="round"/>
|
||
</svg>
|
||
Créer le spectacle
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</ng-container>
|
||
</nz-modal>
|
||
|
||
<nz-modal
|
||
[nzVisible]="isTruckModalVisible()"
|
||
(nzVisibleChange)="isTruckModalVisible.set($event)"
|
||
[nzFooter]="null"
|
||
[nzWidth]="440"
|
||
(nzOnCancel)="handleTruckCancel()">
|
||
<ng-container *nzModalContent>
|
||
<div class="create-form">
|
||
<div class="create-form-title">
|
||
<div class="create-form-icon" style="background: linear-gradient(135deg, #605DC8, #4e4aaa)">
|
||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor">
|
||
<rect x="1" y="3" width="15" height="13" rx="2" ry="2" stroke-width="1.5"/>
|
||
<path d="M16 8h5l3 3v5h-4" stroke-width="1.5"/>
|
||
<circle cx="5.5" cy="18.5" r="2.5" stroke-width="1.5"/>
|
||
<circle cx="18.5" cy="18.5" r="2.5" stroke-width="1.5"/>
|
||
</svg>
|
||
</div>
|
||
<div>
|
||
<h3>{{ editTruckId ? 'Modifier le camion' : 'Nouveau camion' }}</h3>
|
||
<p>{{ editTruckId ? 'Modifiez les informations du camion' : 'Renseignez les informations du camion' }}</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="form-field">
|
||
<label class="form-label">Plaque d'immatriculation <span class="form-required">*</span></label>
|
||
<input class="form-input" placeholder="Ex: AB-123-CD"
|
||
[(ngModel)]="newTruck.type" name="truckType"/>
|
||
</div>
|
||
|
||
<div class="form-row-2">
|
||
<div class="form-field">
|
||
<label class="form-label">Dimensions</label>
|
||
<input class="form-input" placeholder="Ex: 12m x 2.5m"
|
||
[(ngModel)]="newTruck.sizes" name="truckSizes"/>
|
||
</div>
|
||
<div class="form-field">
|
||
<label class="form-label">Capacité max (kg)</label>
|
||
<input class="form-input" type="number" placeholder="Ex: 500"
|
||
[(ngModel)]="newTruck.maxExplosiveCapacity" name="truckCapacity"/>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Statut : uniquement En panne et En maintenance sont modifiables manuellement -->
|
||
<div class="form-field">
|
||
<label class="form-label">Statut manuel</label>
|
||
<select class="form-input" [(ngModel)]="newTruck.status" name="truckStatus">
|
||
<option value="">-- Automatique --</option>
|
||
<option value="En panne">En panne</option>
|
||
<option value="En maintenance">En maintenance</option>
|
||
</select>
|
||
<p class="form-hint">Les statuts Disponible, Indisponible et En déplacement sont calculés automatiquement selon le show assigné.</p>
|
||
</div>
|
||
|
||
<div class="form-actions">
|
||
<button class="form-btn-cancel" (click)="handleTruckCancel()">Annuler</button>
|
||
<button class="form-btn-submit" [disabled]="!newTruck.type" (click)="handleTruckOk()"
|
||
style="background: linear-gradient(135deg, #605DC8, #4e4aaa)">
|
||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor">
|
||
<path d="M12 5v14M5 12h14" stroke-width="2.5" stroke-linecap="round"/>
|
||
</svg>
|
||
{{ editTruckId ? 'Enregistrer' : 'Créer le camion' }}
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</ng-container>
|
||
</nz-modal>
|