feat: implement rules engine and management panel for custom holiday optimization
This commit is contained in:
1 parent
c0549de4dd
commit
08ee84e5c9
20 files changed
+3951
-16847
No files matched your search
@@ -0,0 +1,376 @@
|
||||
<mat-expansion-panel class="rules-panel-container mat-elevation-z2">
|
||||
<mat-expansion-panel-header>
|
||||
<mat-panel-title>
|
||||
<mat-icon>rule</mat-icon>
|
||||
Règles Personnalisées
|
||||
</mat-panel-title>
|
||||
<mat-panel-description> Gérer les règles d'optimisation </mat-panel-description>
|
||||
</mat-expansion-panel-header>
|
||||
|
||||
<div class="priority-statement">
|
||||
<mat-icon color="primary">info</mat-icon>
|
||||
<span>L'ordre des règles définit leur priorité d'exécution (de haut en bas). Glissez-déposez pour réorganiser.</span>
|
||||
</div>
|
||||
|
||||
<div class="rules-list" cdkDropList (cdkDropListDropped)="drop($event)">
|
||||
@for (rule of rules; track rule.id; let i = $index) {
|
||||
<div class="rule-item" cdkDrag [cdkDragDisabled]="editingRuleId() === rule.id" [class.editing]="editingRuleId() === rule.id">
|
||||
@if (editingRuleId() !== rule.id) {
|
||||
<div class="rule-drag-grip">
|
||||
<mat-icon class="drag-handle-icon">drag_handle</mat-icon>
|
||||
</div>
|
||||
<div class="rule-display">
|
||||
<div class="rule-header">
|
||||
<mat-slide-toggle
|
||||
[checked]="rule.enabled"
|
||||
(change)="toggleRule(rule.id)"
|
||||
color="primary"
|
||||
>
|
||||
<span class="rule-name"><span class="rule-number">{{ i + 1 }}.</span> {{ rule.name }}</span>
|
||||
</mat-slide-toggle>
|
||||
<div class="rule-actions">
|
||||
<button mat-icon-button (click)="startEdit(rule, $event)">
|
||||
<mat-icon>edit</mat-icon>
|
||||
</button>
|
||||
<button
|
||||
mat-icon-button
|
||||
color="warn"
|
||||
(click)="deleteRule(rule.id, $event)"
|
||||
>
|
||||
<mat-icon>delete</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="rule-summary">
|
||||
@if (rule.type === RuleType.IF_THEN) {
|
||||
<span>
|
||||
Si un jour férié tombe un
|
||||
<strong>{{
|
||||
daysOfWeek[rule.dayOfWeek > 0 ? rule.dayOfWeek - 1 : 6]
|
||||
.label
|
||||
}}</strong
|
||||
>, placer <strong>{{ rule.placeDays }}</strong> jour(s)
|
||||
<strong>{{ getDayTypeLabel(rule.placeType) }}</strong>
|
||||
<strong>
|
||||
{{
|
||||
placementOptions.find((p) => p.value === rule.placement)
|
||||
?.label | lowercase
|
||||
}}</strong
|
||||
>
|
||||
et obtenir <strong>{{ rule.rewardDays }}</strong> jour(s)
|
||||
<strong>{{ getDayTypeLabel(rule.rewardType) }}</strong> en
|
||||
bonus.
|
||||
</span>
|
||||
} @else if (rule.type === RuleType.TIME_WINDOW) {
|
||||
<span>
|
||||
Placer <strong>{{ rule.placeDays }}</strong> jour(s)
|
||||
<strong>{{ getDayTypeLabel(rule.placeType) }}</strong> entre
|
||||
le <strong>{{ rule.startDate | date: 'dd/MM/yyyy' }}</strong> et
|
||||
le <strong>{{ rule.endDate | date: 'dd/MM/yyyy' }}</strong
|
||||
>.
|
||||
</span>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
} @else {
|
||||
<div class="rule-editor">
|
||||
<h4>Modifier la règle</h4>
|
||||
|
||||
<mat-form-field class="full-width">
|
||||
<mat-label>Nom de la règle</mat-label>
|
||||
<input matInput [(ngModel)]="$any(editBuffer).name" required />
|
||||
</mat-form-field>
|
||||
|
||||
@if ($any(editBuffer).type === RuleType.IF_THEN) {
|
||||
<div class="editor-row">
|
||||
<mat-form-field>
|
||||
<mat-label>Jour férié tombe un</mat-label>
|
||||
<mat-select [(ngModel)]="$any(editBuffer).dayOfWeek">
|
||||
@for (day of daysOfWeek; track day.value) {
|
||||
<mat-option [value]="day.value">{{
|
||||
day.label
|
||||
}}</mat-option>
|
||||
}
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div class="editor-row">
|
||||
<span class="action-text">Placer</span>
|
||||
<mat-form-field class="small-input">
|
||||
<mat-label>Jours</mat-label>
|
||||
<input
|
||||
matInput
|
||||
type="number"
|
||||
[(ngModel)]="$any(editBuffer).placeDays"
|
||||
min="1"
|
||||
/>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field>
|
||||
<mat-label>Type</mat-label>
|
||||
<mat-select [(ngModel)]="$any(editBuffer).placeType">
|
||||
@for (type of placeDayTypes; track type) {
|
||||
<mat-option [value]="type">{{
|
||||
getDayTypeLabel(type)
|
||||
}}</mat-option>
|
||||
}
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field>
|
||||
<mat-label>Position</mat-label>
|
||||
<mat-select [(ngModel)]="$any(editBuffer).placement">
|
||||
@for (opt of placementOptions; track opt.value) {
|
||||
<mat-option [value]="opt.value">{{
|
||||
opt.label
|
||||
}}</mat-option>
|
||||
}
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div class="editor-row">
|
||||
<span class="action-text">Obtenir en bonus</span>
|
||||
<mat-form-field class="small-input">
|
||||
<mat-label>Jours</mat-label>
|
||||
<input
|
||||
matInput
|
||||
type="number"
|
||||
[(ngModel)]="$any(editBuffer).rewardDays"
|
||||
min="0"
|
||||
/>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field>
|
||||
<mat-label>Type</mat-label>
|
||||
<mat-select [(ngModel)]="$any(editBuffer).rewardType">
|
||||
@for (type of rewardDayTypes; track type) {
|
||||
<mat-option [value]="type">{{
|
||||
getDayTypeLabel(type)
|
||||
}}</mat-option>
|
||||
}
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
} @else {
|
||||
<div class="editor-row">
|
||||
<mat-form-field>
|
||||
<mat-label>Date de début</mat-label>
|
||||
<input
|
||||
matInput
|
||||
[matDatepicker]="startPicker"
|
||||
[(ngModel)]="$any(editBuffer).startDate"
|
||||
/>
|
||||
<mat-datepicker-toggle
|
||||
matSuffix
|
||||
[for]="startPicker"
|
||||
></mat-datepicker-toggle>
|
||||
<mat-datepicker #startPicker></mat-datepicker>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field>
|
||||
<mat-label>Date de fin</mat-label>
|
||||
<input
|
||||
matInput
|
||||
[matDatepicker]="endPicker"
|
||||
[(ngModel)]="$any(editBuffer).endDate"
|
||||
/>
|
||||
<mat-datepicker-toggle
|
||||
matSuffix
|
||||
[for]="endPicker"
|
||||
></mat-datepicker-toggle>
|
||||
<mat-datepicker #endPicker></mat-datepicker>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div class="editor-row">
|
||||
<span class="action-text">Placer</span>
|
||||
<mat-form-field class="small-input">
|
||||
<mat-label>Jours</mat-label>
|
||||
<input
|
||||
matInput
|
||||
type="number"
|
||||
[(ngModel)]="$any(editBuffer).placeDays"
|
||||
min="1"
|
||||
/>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field>
|
||||
<mat-label>Type</mat-label>
|
||||
<mat-select [(ngModel)]="$any(editBuffer).placeType">
|
||||
@for (type of placeDayTypes; track type) {
|
||||
<mat-option [value]="type">{{
|
||||
getDayTypeLabel(type)
|
||||
}}</mat-option>
|
||||
}
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
}
|
||||
|
||||
<div class="editor-actions">
|
||||
<button mat-button (click)="cancelEdit()">Annuler</button>
|
||||
<button mat-flat-button color="primary" (click)="saveEdit()">
|
||||
Enregistrer
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
@if (isAddingNew()) {
|
||||
<div class="rule-item editing">
|
||||
<div class="rule-editor">
|
||||
<h4>Ajouter une règle</h4>
|
||||
|
||||
<mat-form-field class="full-width">
|
||||
<mat-label>Nom de la règle</mat-label>
|
||||
<input matInput [(ngModel)]="$any(editBuffer).name" required />
|
||||
</mat-form-field>
|
||||
|
||||
@if (newRuleType() === RuleType.IF_THEN) {
|
||||
<div class="editor-row">
|
||||
<mat-form-field>
|
||||
<mat-label>Jour férié tombe un</mat-label>
|
||||
<mat-select [(ngModel)]="$any(editBuffer).dayOfWeek">
|
||||
@for (day of daysOfWeek; track day.value) {
|
||||
<mat-option [value]="day.value">{{ day.label }}</mat-option>
|
||||
}
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div class="editor-row">
|
||||
<span class="action-text">Placer</span>
|
||||
<mat-form-field class="small-input">
|
||||
<mat-label>Jours</mat-label>
|
||||
<input
|
||||
matInput
|
||||
type="number"
|
||||
[(ngModel)]="$any(editBuffer).placeDays"
|
||||
min="1"
|
||||
/>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field>
|
||||
<mat-label>Type</mat-label>
|
||||
<mat-select [(ngModel)]="$any(editBuffer).placeType">
|
||||
@for (type of placeDayTypes; track type) {
|
||||
<mat-option [value]="type">{{
|
||||
getDayTypeLabel(type)
|
||||
}}</mat-option>
|
||||
}
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field>
|
||||
<mat-label>Position</mat-label>
|
||||
<mat-select [(ngModel)]="$any(editBuffer).placement">
|
||||
@for (opt of placementOptions; track opt.value) {
|
||||
<mat-option [value]="opt.value">{{ opt.label }}</mat-option>
|
||||
}
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div class="editor-row">
|
||||
<span class="action-text">Obtenir en bonus</span>
|
||||
<mat-form-field class="small-input">
|
||||
<mat-label>Jours</mat-label>
|
||||
<input
|
||||
matInput
|
||||
type="number"
|
||||
[(ngModel)]="$any(editBuffer).rewardDays"
|
||||
min="0"
|
||||
/>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field>
|
||||
<mat-label>Type</mat-label>
|
||||
<mat-select [(ngModel)]="$any(editBuffer).rewardType">
|
||||
@for (type of rewardDayTypes; track type) {
|
||||
<mat-option [value]="type">{{
|
||||
getDayTypeLabel(type)
|
||||
}}</mat-option>
|
||||
}
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
} @else {
|
||||
<div class="editor-row">
|
||||
<mat-form-field>
|
||||
<mat-label>Date de début</mat-label>
|
||||
<input
|
||||
matInput
|
||||
[matDatepicker]="startPicker"
|
||||
[(ngModel)]="$any(editBuffer).startDate"
|
||||
/>
|
||||
<mat-datepicker-toggle
|
||||
matSuffix
|
||||
[for]="startPicker"
|
||||
></mat-datepicker-toggle>
|
||||
<mat-datepicker #startPicker></mat-datepicker>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field>
|
||||
<mat-label>Date de fin</mat-label>
|
||||
<input
|
||||
matInput
|
||||
[matDatepicker]="endPicker"
|
||||
[(ngModel)]="$any(editBuffer).endDate"
|
||||
/>
|
||||
<mat-datepicker-toggle
|
||||
matSuffix
|
||||
[for]="endPicker"
|
||||
></mat-datepicker-toggle>
|
||||
<mat-datepicker #endPicker></mat-datepicker>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div class="editor-row">
|
||||
<span class="action-text">Placer</span>
|
||||
<mat-form-field class="small-input">
|
||||
<mat-label>Jours</mat-label>
|
||||
<input
|
||||
matInput
|
||||
type="number"
|
||||
[(ngModel)]="$any(editBuffer).placeDays"
|
||||
min="1"
|
||||
/>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field>
|
||||
<mat-label>Type</mat-label>
|
||||
<mat-select [(ngModel)]="$any(editBuffer).placeType">
|
||||
@for (type of placeDayTypes; track type) {
|
||||
<mat-option [value]="type">{{
|
||||
getDayTypeLabel(type)
|
||||
}}</mat-option>
|
||||
}
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
}
|
||||
|
||||
<div class="editor-actions">
|
||||
<button mat-button (click)="cancelEdit()">Annuler</button>
|
||||
<button mat-flat-button color="primary" (click)="saveEdit()">
|
||||
Ajouter
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
<div class="add-buttons" [class.hidden]="isAddingNew() || editingRuleId()">
|
||||
<button mat-stroked-button (click)="startAddNew(RuleType.IF_THEN)">
|
||||
<mat-icon>add</mat-icon> Nouvelle Règle "Si ... Alors"
|
||||
</button>
|
||||
<button mat-stroked-button (click)="startAddNew(RuleType.TIME_WINDOW)">
|
||||
<mat-icon>add</mat-icon> Nouvelle Période Imposée
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</mat-expansion-panel>
|
||||
Reference in new issue
Block a user