Compare commits
69 commits
issue-24-f
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c5ef81f668 | ||
|
|
4fcc529864 | ||
|
|
bfbf4e9e01 | ||
|
|
500f127090 | ||
|
|
54848f4be6 | ||
|
|
23b40f4d63 | ||
|
|
250058c085 | ||
|
|
b52e4d2747 | ||
|
|
883060e2dd | ||
|
|
b8005a2a04 | ||
|
|
d8428b494e | ||
|
|
470a84ae86 | ||
|
|
8d281c2159 | ||
|
|
a8426f80c6 | ||
|
|
1c18491a86 | ||
|
|
fcf49ba582 | ||
|
|
c9178a139d | ||
|
|
09959e412b | ||
|
|
76824459f8 | ||
|
|
6ea7a4117f | ||
|
|
4ea9f35108 | ||
|
|
702ea23e02 | ||
|
|
a10ff94d4a | ||
|
|
6583a8f01e | ||
|
|
3c6762ae2d | ||
|
|
ee1e33e036 | ||
|
|
8c52e52079 | ||
|
|
2023eca826 | ||
|
|
48a50d07f8 | ||
|
|
81125b461e | ||
|
|
f813cc214a | ||
|
|
42da6618dc | ||
|
|
6013663d73 | ||
|
|
ba79189293 | ||
|
|
29ef828dbe | ||
|
|
ed8798ac66 | ||
|
|
76edd08394 | ||
|
|
a8d34cd23b | ||
|
|
eb51d562c1 | ||
|
|
fa19527c3e | ||
|
|
e6b8b7402a | ||
|
|
bc53526a08 | ||
|
|
86052f72b5 | ||
|
|
e1275ecf96 | ||
|
|
52b80aba00 | ||
|
|
13a1340a61 | ||
|
|
63548d0e3c | ||
|
|
8d351fbc6c | ||
|
|
b16c89eb88 | ||
|
|
6fa7f53714 | ||
|
|
579eff439f | ||
|
|
6c47de0cf0 | ||
|
|
3f7059e9fb | ||
|
|
4b522e7c21 | ||
|
|
66e0f1d523 | ||
|
|
456a5deeab | ||
|
|
e35081cfa7 | ||
|
|
c9ac965e74 | ||
|
|
2bb81e7bcd | ||
|
|
bfb62cf5ba | ||
|
|
df4db5fb5a | ||
|
|
655eedb52e | ||
|
|
aec90d91e8 | ||
|
|
a5c72b9cbe | ||
|
|
a473d4a49c | ||
|
|
dbf2d39f8a | ||
|
|
1f1ccf0807 | ||
|
|
194bf51032 | ||
|
|
90451c7a89 |
8 changed files with 923 additions and 1146 deletions
11
Dockerfile
11
Dockerfile
|
|
@ -1,5 +1,9 @@
|
|||
ARG PHP_8_5_TAG=latest
|
||||
|
||||
FROM composer:2.9.2 AS vendor
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
ARG GITLAB_USER
|
||||
ARG GITLAB_PASSWORD
|
||||
|
||||
|
|
@ -8,7 +12,7 @@ COPY database/ database/
|
|||
COPY composer.json composer.json
|
||||
COPY composer.lock composer.lock
|
||||
|
||||
RUN composer config gitlab-token.lab.s-web.fr ${GITLAB_USER} ${GITLAB_PASSWORD}
|
||||
RUN composer config gitlab-token.lab.s-web.fr "${GITLAB_USER}" "${GITLAB_PASSWORD}"
|
||||
RUN composer install \
|
||||
--ignore-platform-reqs \
|
||||
--no-interaction \
|
||||
|
|
@ -28,9 +32,10 @@ COPY resources/ /app/resources/
|
|||
WORKDIR /app
|
||||
RUN npm config set @ldc-web:registry https://lab.s-web.fr/api/v4/packages/npm/
|
||||
RUN npm config set -- '//lab.s-web.fr/api/v4/packages/npm/:_authToken' "${GITLAB_PASSWORD}"
|
||||
RUN npm ci && npm run prod
|
||||
RUN npm ci --no-audit --no-fund --loglevel=error && npm run prod
|
||||
|
||||
FROM registry.s-web.fr/ldc-web/projets/ldc-web-images-docker/uwil-production-8.4:170625-130159
|
||||
ARG PHP_8_5_TAG
|
||||
FROM registry.s-web.fr/ldc-web/projets/ldc-web-images-docker/uwil-production-8.5:${PHP_8_5_TAG}
|
||||
|
||||
ARG USER=www-data
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
],
|
||||
"license": "MIT",
|
||||
"require": {
|
||||
"php": "^8.4",
|
||||
"php": "^8.5",
|
||||
"24slides/laravel-saml2": "^2.4",
|
||||
"guzzlehttp/guzzle": "^7.5.0",
|
||||
"laravel/framework": "^12.0",
|
||||
|
|
@ -46,7 +46,9 @@
|
|||
"dealerdirect/phpcodesniffer-composer-installer": true,
|
||||
"php-http/discovery": true
|
||||
},
|
||||
"gitlab-domains": ["lab.s-web.fr"]
|
||||
"gitlab-domains": [
|
||||
"lab.s-web.fr"
|
||||
]
|
||||
},
|
||||
"extra": {
|
||||
"laravel": {
|
||||
|
|
|
|||
1575
composer.lock
generated
1575
composer.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -10,7 +10,8 @@ data:
|
|||
APP_DEBUG: "${APP_APP_DEBUG}"
|
||||
APP_URL: "https://${APP_DOMAIN}"
|
||||
LOG_CHANNEL: "k8s"
|
||||
DB_HOST: "${APP_DB_HOST}"
|
||||
DB_HOST: "${APP_GLOBAL_OVH_MYSQL_HOST}"
|
||||
DB_PORT: "${APP_GLOBAL_OVH_MYSQL_PORT}"
|
||||
DB_DATABASE: "${APP_DB_DATABASE}"
|
||||
DB_USERNAME: "${APP_DB_USERNAME}"
|
||||
DB_PASSWORD: "${APP_DB_PASSWORD}"
|
||||
|
|
@ -83,9 +84,9 @@ spec:
|
|||
imagePullSecrets:
|
||||
- name: docker-registry-credentials
|
||||
securityContext:
|
||||
runAsUser: 33
|
||||
runAsGroup: 33
|
||||
fsGroup: 33
|
||||
runAsUser: 82
|
||||
runAsGroup: 82
|
||||
fsGroup: 82
|
||||
fsGroupChangePolicy: "OnRootMismatch"
|
||||
volumes:
|
||||
- name: storage
|
||||
|
|
@ -171,8 +172,8 @@ spec:
|
|||
persistentVolumeClaim:
|
||||
claimName: ${CI_PROJECT_PATH_SLUG}-pvc-storage
|
||||
securityContext:
|
||||
runAsUser: 33
|
||||
runAsGroup: 33
|
||||
fsGroup: 33
|
||||
runAsUser: 82
|
||||
runAsGroup: 82
|
||||
fsGroup: 82
|
||||
fsGroupChangePolicy: "OnRootMismatch"
|
||||
restartPolicy: OnFailure
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<div class="pro--objectifs">
|
||||
<div class="objectifs--form">
|
||||
<h2 class="post-title">Objectif de prix</h2>
|
||||
<h2 class="post-title">Fixer un objectif de prix</h2>
|
||||
|
||||
<transition name="fade">
|
||||
<div class="alert alert-success" v-show="processing">
|
||||
|
|
@ -24,95 +24,50 @@
|
|||
</div>
|
||||
</transition>
|
||||
|
||||
<form @submit.prevent="saveData">
|
||||
<div class="objectifs--grid">
|
||||
<label for="produit" class="col-start">Produit * :</label>
|
||||
<select name="produit" id="produit" v-model="objectif.produit" @change="populate">
|
||||
<option value="--">Choisir un produit</option>
|
||||
<option v-for="produit in enums.produit" :key="produit.value" :value="produit.value">
|
||||
{{ produit.value }}
|
||||
</option>
|
||||
</select>
|
||||
<form>
|
||||
<div class="flex row">
|
||||
<select name="produit" id="produit" v-model="objectif.produit" @change="populate">
|
||||
<option value="--">Selectionner un produit*</option>
|
||||
<option v-for="produit in enums.produit" :key="produit.value" :value="produit.value">
|
||||
{{ produit.value }}
|
||||
</option>
|
||||
</select>
|
||||
|
||||
<label for="campagne">Campagne * :</label>
|
||||
<select name="campagne" id="campagne" v-model="objectif.campagne" @change="populate">
|
||||
<option value="--">Choisir une campagne</option>
|
||||
<option v-for="campagne in campagneEnums" :key="campagne.value" :value="campagne.value">
|
||||
{{ campagne.value }}
|
||||
</option>
|
||||
</select>
|
||||
<select name="qualite" v-model="objectif.qualite">
|
||||
<option value="--">Qualité*</option>
|
||||
<option v-for="qualite in qualiteEnums" :key="qualite.value" :value="qualite.value">
|
||||
{{ qualite.value }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<label for="qualite" class="col-start">Qualité * :</label>
|
||||
<select name="qualite" id="qualite" v-model="objectif.qualite">
|
||||
<option value="--">Choisir une qualité</option>
|
||||
<option v-for="qualite in qualiteEnums" :key="qualite.value" :value="qualite.value">
|
||||
{{ qualite.value }}
|
||||
</option>
|
||||
</select>
|
||||
<div class="flex row">
|
||||
<select name="campagne" v-model="objectif.campagne" @change="populate">
|
||||
<option value="--">Campagne*</option>
|
||||
<option v-for="campagne in campagneEnums" :key="campagne.value" :value="campagne.value">
|
||||
{{ campagne.value }}
|
||||
</option>
|
||||
</select>
|
||||
|
||||
<label for="quantite_liste" class="col-start">Quantité * :</label>
|
||||
<select id="quantite_liste" name="quantite_liste" v-model.number="objectif.quantite">
|
||||
<option :value="null">Multiple de 30 T</option>
|
||||
<option v-for="q in QUANTITES" :key="q" :value="q">{{ q }} T</option>
|
||||
</select>
|
||||
<select name="echeance" v-model="objectif.echeance">
|
||||
<option value="--">Échéance*</option>
|
||||
<option v-for="echeance in echeanceEnums" :key="echeance.value" :value="echeance.value">
|
||||
{{ echeance.value }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<span class="objectifs--ou">ou</span>
|
||||
<input type="number" name="quantite" class="objectifs--wide" v-model.number="objectif.quantite" min="0" placeholder="Saisie libre*">
|
||||
<div class="flex row">
|
||||
<input type="number" name="quantite" v-model.number="objectif.quantite" min="0" placeholder="Quantité*">
|
||||
<input type="number" name="prix" v-model.number="objectif.prix" min="0" step="0.01" placeholder="Prix (€)*">
|
||||
</div>
|
||||
|
||||
<label for="prix" class="col-start">Prix * :</label>
|
||||
<div class="objectifs--prix">
|
||||
<input type="number" id="prix" name="prix" class="objectifs--wide" v-model.number="objectif.prix" min="0" step="0.01" placeholder="Prix (€/TM)*">
|
||||
<span>€/TM</span>
|
||||
</div>
|
||||
|
||||
<label for="echeance">Échéance * :</label>
|
||||
<select name="echeance" id="echeance" v-model="objectif.echeance">
|
||||
<option value="--">Choisir une échéance</option>
|
||||
<option v-for="echeance in echeanceEnums" :key="echeance.value" :value="echeance.value">
|
||||
{{ echeance.value }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="objectifs--line">
|
||||
<div class="objectifs--field">
|
||||
<label for="volume_restant">Volume restant à commercialiser :</label>
|
||||
<input type="number" id="volume_restant" name="volume_restant"
|
||||
v-model.number="objectif.volume_restant" min="0" placeholder="Saisie libre">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="objectifs--line">
|
||||
<div class="objectifs--field grow">
|
||||
<label for="observations">Observations :</label>
|
||||
<input type="text" id="observations" name="observations"
|
||||
v-model="objectif.observations" placeholder="Saisie libre">
|
||||
</div>
|
||||
<button type="submit" class="first-btn" :disabled="processing">OK</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- RESUME -->
|
||||
<div class="objectifs--resume" v-if="myobjectives.length">
|
||||
<hr class="objectifs--divider">
|
||||
|
||||
<h3>Résumé :</h3>
|
||||
<ul>
|
||||
<li v-for="(item, i) in myobjectives" :key="item.id ?? i" class="objectif--ligne">
|
||||
<span class="objectif--texte"
|
||||
:class="{ editable: isEditable(item) }"
|
||||
:title="isEditable(item) ? 'Cliquer pour modifier' : ''"
|
||||
@click="editItem(item)">
|
||||
Campagne {{ item.campagne }} {{ item.quantite }}TM {{ item.produit }} {{ item.prix }}€
|
||||
</span>
|
||||
<span class="objectif--statut" :class="statusClass(item)">
|
||||
{{ statusLabel(item) }}
|
||||
</span>
|
||||
<button type="button" class="objectif--delete" @click="removeItem(i)" aria-label="Supprimer">X</button>
|
||||
</li>
|
||||
</ul>
|
||||
<p class="objectifs--hint">(Modifiable en cliquant sur la ligne)</p>
|
||||
<div class="validate">
|
||||
<button class="first-btn" @click.prevent="saveData" :disabled="processing">
|
||||
Enregistrer l'objectif
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -121,21 +76,11 @@
|
|||
import { ref } from "vue"
|
||||
import axios from "axios"
|
||||
|
||||
import {
|
||||
ObjectiveStatus,
|
||||
OBJECTIVE_STATUS_LABELS,
|
||||
OBJECTIVE_STATUS_CLASSES,
|
||||
} from "../../types/ObjectiveStatus"
|
||||
|
||||
const props = defineProps<{ json: string }>()
|
||||
|
||||
const QUANTITES = Array.from({ length: 20 }, (_, i) => (i + 1) * 30)
|
||||
|
||||
const initial = JSON.parse(props.json)
|
||||
|
||||
initial.dbobjectif.quantite = null
|
||||
initial.dbobjectif.volume_restant = null
|
||||
initial.dbobjectif.observations ??= ""
|
||||
|
||||
const objectif = ref<any>(structuredClone(initial.dbobjectif))
|
||||
const myobjectives = ref<any[]>(initial.dbmyObjectives)
|
||||
|
|
@ -149,6 +94,7 @@ const success = ref(false)
|
|||
const errors = ref<string[]>([])
|
||||
const response = ref("")
|
||||
|
||||
|
||||
function populate(event: Event) {
|
||||
const target = event.target as HTMLSelectElement
|
||||
|
||||
|
|
@ -161,47 +107,14 @@ function populate(event: Event) {
|
|||
campagneEnums.value = enums.value.campagne[target.value] || []
|
||||
break
|
||||
|
||||
case "campagne": {
|
||||
case "campagne":
|
||||
const selectProduit = objectif.value.produit
|
||||
echeanceEnums.value =
|
||||
enums.value.echeance?.[selectProduit]?.[target.value] || []
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function resetForm() {
|
||||
objectif.value = structuredClone(initial.dbobjectif)
|
||||
qualiteEnums.value = []
|
||||
campagneEnums.value = []
|
||||
echeanceEnums.value = []
|
||||
}
|
||||
|
||||
function isEditable(item: any): boolean {
|
||||
return statusId(item) === ObjectiveStatus.EnCours
|
||||
}
|
||||
|
||||
function editItem(item: any) {
|
||||
if (!isEditable(item)) return
|
||||
|
||||
objectif.value = JSON.parse(JSON.stringify(item))
|
||||
qualiteEnums.value = enums.value.qualite?.[item.produit] || []
|
||||
campagneEnums.value = enums.value.campagne?.[item.produit] || []
|
||||
echeanceEnums.value = enums.value.echeance?.[item.produit]?.[item.campagne] || []
|
||||
errors.value = []
|
||||
}
|
||||
|
||||
function statusId(item: any): ObjectiveStatus {
|
||||
return item.status?.id ?? item.status_id ?? ObjectiveStatus.EnCours
|
||||
}
|
||||
function statusLabel(item: any): string {
|
||||
return OBJECTIVE_STATUS_LABELS[statusId(item)] ?? "En cours"
|
||||
}
|
||||
function statusClass(item: any): string {
|
||||
return OBJECTIVE_STATUS_CLASSES[statusId(item)] ?? "en-cours"
|
||||
}
|
||||
|
||||
|
||||
function checkForm(): boolean {
|
||||
errors.value = []
|
||||
|
||||
|
|
@ -245,7 +158,6 @@ function removeItem(index: number) {
|
|||
|
||||
if (result === 0 || result === 2) {
|
||||
myobjectives.value.splice(index, 1)
|
||||
if (String(objectif.value.id) === String(item.id)) resetForm()
|
||||
response.value = "Suppression terminée !"
|
||||
} else {
|
||||
response.value = "Erreur : Suppression impossible"
|
||||
|
|
@ -265,8 +177,6 @@ function removeItem(index: number) {
|
|||
function saveData() {
|
||||
if (!checkForm()) return
|
||||
|
||||
const editingId = objectif.value.id ?? null
|
||||
|
||||
processing.value = true
|
||||
success.value = false
|
||||
errors.value = []
|
||||
|
|
@ -277,25 +187,17 @@ function saveData() {
|
|||
objectif: objectif.value,
|
||||
})
|
||||
.then((res) => {
|
||||
const savedId = editingId ?? res.data.id
|
||||
const index = myobjectives.value.findIndex(
|
||||
(o) => String(o.id) === String(savedId)
|
||||
)
|
||||
|
||||
if (index !== -1) {
|
||||
myobjectives.value[index] = res.data
|
||||
} else {
|
||||
myobjectives.value.unshift(res.data)
|
||||
}
|
||||
|
||||
resetForm()
|
||||
success.value = true
|
||||
response.value = "Sauvegarde terminée !"
|
||||
myobjectives.value.push(res.data)
|
||||
objectif.value = structuredClone(initial.dbobjectif)
|
||||
qualiteEnums.value = []
|
||||
campagneEnums.value = []
|
||||
echeanceEnums.value = []
|
||||
setTimeout(() => (success.value = false), 3000)
|
||||
})
|
||||
.catch((err) => {
|
||||
response.value = "Erreur lors de la sauvegarde :"
|
||||
errors.value = [err.response?.data?.message ?? "Erreur lors de la sauvegarde."]
|
||||
.catch(() => {
|
||||
errors.value.push("Erreur lors de la sauvegarde.")
|
||||
})
|
||||
.finally(() => {
|
||||
processing.value = false
|
||||
|
|
@ -312,232 +214,4 @@ function saveData() {
|
|||
.fade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.objectifs--required {
|
||||
margin-left: 1.5rem;
|
||||
font-size: .6em;
|
||||
font-weight: normal;
|
||||
color: #d00;
|
||||
}
|
||||
|
||||
.objectifs--required span {
|
||||
font-size: 1.5em;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.objectifs--grid {
|
||||
display: grid;
|
||||
grid-template-columns: max-content minmax(0, 1fr) max-content minmax(0, 1fr);
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.objectifs--grid > label {
|
||||
margin: 0;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.objectifs--grid .col-start {
|
||||
grid-column: 1;
|
||||
}
|
||||
|
||||
.objectifs--grid select,
|
||||
.objectifs--grid input {
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* Qualité sur toute la largeur */
|
||||
.objectifs--grid #qualite {
|
||||
grid-column: 2 / -1;
|
||||
}
|
||||
|
||||
.objectifs--grid .objectifs--ou {
|
||||
justify-self: end;
|
||||
}
|
||||
|
||||
.objectifs--prix {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: .5rem;
|
||||
}
|
||||
|
||||
.pro--objectifs .objectifs--form form .objectifs--grid input[type="number"].objectifs--wide {
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
max-width: none;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.objectifs--line {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem 2rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.objectifs--field {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: .5rem;
|
||||
}
|
||||
|
||||
.objectifs--field.grow {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.objectifs--field.grow input {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.objectifs--field label {
|
||||
margin: 0;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.objectifs--line .first-btn {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.objectifs--resume {
|
||||
margin-top: -25px;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.objectifs--divider {
|
||||
margin: 0 0 1rem;
|
||||
border: 0;
|
||||
border-top: 2px solid #000;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.objectifs--resume h3 {
|
||||
margin-top: 0;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.objectifs--resume ul {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.objectif--ligne {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
padding: .25rem 0;
|
||||
}
|
||||
|
||||
.objectif--texte {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.objectif--texte.editable {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.objectif--texte.editable:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.objectif--statut.en-cours {
|
||||
color: #1a9a3c;
|
||||
}
|
||||
|
||||
.objectif--statut.atteint {
|
||||
color: #d00;
|
||||
}
|
||||
|
||||
.objectif--statut.depassee {
|
||||
color: #888;
|
||||
}
|
||||
|
||||
.objectif--delete {
|
||||
border: 0;
|
||||
background: none;
|
||||
color: #d00;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
padding-inline: 5px;
|
||||
}
|
||||
|
||||
.objectifs--hint {
|
||||
margin-bottom: 0;
|
||||
font-style: italic;
|
||||
font-size: .9em;
|
||||
}
|
||||
|
||||
/* Tablette */
|
||||
@media (max-width: 768px) {
|
||||
.objectifs--grid {
|
||||
grid-template-columns: max-content minmax(0, 1fr);
|
||||
}
|
||||
|
||||
/* Tous les libellés reviennent en colonne 1 */
|
||||
.objectifs--grid > label {
|
||||
grid-column: 1;
|
||||
}
|
||||
|
||||
.objectifs--grid .objectifs--ou {
|
||||
justify-self: start;
|
||||
}
|
||||
|
||||
.objectifs--line {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.objectifs--line .first-btn {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Mobile*/
|
||||
@media (max-width: 480px) {
|
||||
.objectifs--grid {
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
gap: .5rem;
|
||||
}
|
||||
|
||||
.objectifs--grid > label,
|
||||
.objectifs--grid .col-start,
|
||||
.objectifs--grid #qualite {
|
||||
grid-column: 1;
|
||||
}
|
||||
|
||||
.objectifs--grid > label {
|
||||
margin-top: .5rem;
|
||||
}
|
||||
|
||||
.objectifs--field {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.objectifs--field label {
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.pro--objectifs .objectifs--form form #volume_restant {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.objectifs--line .first-btn {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.objectif--ligne {
|
||||
flex-wrap: wrap;
|
||||
gap: .25rem 1rem;
|
||||
}
|
||||
|
||||
.objectif--texte {
|
||||
flex: 1 1 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,22 +0,0 @@
|
|||
export enum ObjectiveStatus {
|
||||
EnCours = 1,
|
||||
Atteint = 2,
|
||||
EcheanceDepassee = 3,
|
||||
}
|
||||
|
||||
export interface ObjectiveStatusData {
|
||||
id: ObjectiveStatus
|
||||
label: string
|
||||
}
|
||||
|
||||
export const OBJECTIVE_STATUS_LABELS: Record<ObjectiveStatus, string> = {
|
||||
[ObjectiveStatus.EnCours]: "En cours",
|
||||
[ObjectiveStatus.Atteint]: "Atteint",
|
||||
[ObjectiveStatus.EcheanceDepassee]: "Échéance dépassée",
|
||||
}
|
||||
|
||||
export const OBJECTIVE_STATUS_CLASSES: Record<ObjectiveStatus, string> = {
|
||||
[ObjectiveStatus.EnCours]: "en-cours",
|
||||
[ObjectiveStatus.Atteint]: "atteint",
|
||||
[ObjectiveStatus.EcheanceDepassee]: "depassee",
|
||||
}
|
||||
|
|
@ -154,7 +154,7 @@
|
|||
@endsection
|
||||
|
||||
@push('scripts')
|
||||
<script nonce="{{ $nonce ?? '' }}">
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const select = document.querySelector('select[name=mps]');
|
||||
const blocs = document.querySelectorAll('.cotations--grid .mp--bloc');
|
||||
|
|
|
|||
|
|
@ -35,18 +35,26 @@ Route::prefix('bo')->name('bo.')->middleware('admin-secure')->group(function ()
|
|||
Route::get('/', [DashboardController::class, 'index'])->name('dashboard');
|
||||
// * Utilisateurs BO
|
||||
Route::resource('objectives', ObjectivesController::class)->except([
|
||||
'create', 'edit'
|
||||
'create',
|
||||
'edit'
|
||||
]);
|
||||
Route::resources([
|
||||
'users' => UsersController::class,
|
||||
'employees' => EmployeesController::class,
|
||||
'home-sliders' => HomeSlidersController::class,
|
||||
'articles' => ArticlesController::class,
|
||||
'cotations' => CotationsController::class,
|
||||
'public-pdfs' => PublicPdfsController::class,
|
||||
]);
|
||||
|
||||
// * ARTICLES
|
||||
Route::resource(
|
||||
'articles',
|
||||
ArticlesController::class,
|
||||
)->withoutMiddleware('htmlsanitize')
|
||||
->middleware('htmlsanitize:content');
|
||||
|
||||
Route::resource('customers', CustomerController::class)
|
||||
->only(['index', 'edit', 'update']);
|
||||
->only(['index', 'edit', 'update']);
|
||||
|
||||
// *ordres
|
||||
Route::get(
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue