fix(front) : ajustements du formulaire ticket de pesée (ERP-189/190)
- Poids/DSD en champs texte verrouillés sur les chiffres et désactivés. - Boutons de pesée : icône mdi:weight à gauche + gap-8. - Bloc « Poids à vide » réagencé en 3 lignes (contrepartie / Date-Poids-DSD-Immat / Tout format). - Omission des clés null dans les payloads (compact) : requis vides → message NotBlank métier au lieu d'une erreur de type. - Pesée obligatoire (RG-5.07) signalée inline sous Poids/DSD ; toutes les violations affichées d'un seul aller-retour. - Erreur d'immatriculation affichée uniquement sur le bloc « Poids à vide » (plus de doublon sur le bloc plein).
This commit is contained in:
@@ -3,15 +3,19 @@
|
||||
<!-- En-tête du bloc : titre + boutons de pesée (bascule / manuelle). -->
|
||||
<div class="flex items-center justify-between">
|
||||
<h2 class="text-[20px] font-semibold text-m-primary">{{ title }}</h2>
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="flex items-center gap-8">
|
||||
<MalioButton
|
||||
variant="secondary"
|
||||
icon-name="mdi:weight"
|
||||
icon-position="left"
|
||||
:label="t('logistique.weighingTickets.form.weighbridge.auto')"
|
||||
:disabled="disabled"
|
||||
@click="$emit('request-auto')"
|
||||
/>
|
||||
<MalioButton
|
||||
variant="primary"
|
||||
icon-name="mdi:weight"
|
||||
icon-position="left"
|
||||
:label="t('logistique.weighingTickets.form.weighbridge.manual')"
|
||||
:disabled="disabled"
|
||||
@click="$emit('request-manual')"
|
||||
@@ -19,64 +23,76 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-6 grid grid-cols-3 xl:grid-cols-4 gap-x-[44px] gap-y-4">
|
||||
<!-- Contrepartie : rendue par le parent (bloc vide uniquement) via le slot. -->
|
||||
<slot name="counterparty" />
|
||||
<div class="mt-6 flex flex-col gap-4">
|
||||
<!-- Ligne 1 : contrepartie (type en col 1 + champ conditionnel en col 2),
|
||||
rendue par le parent (bloc vide uniquement) via le slot. -->
|
||||
<div v-if="$slots.counterparty" class="grid grid-cols-3 xl:grid-cols-4 gap-x-[44px] gap-y-4">
|
||||
<slot name="counterparty" />
|
||||
</div>
|
||||
|
||||
<!-- Date de la pesée — jour par défaut (RG-5.07). MalioDate (composant
|
||||
projet pour le type date, exception tolérée @.claude/rules/frontend.md). -->
|
||||
<MalioDate
|
||||
:model-value="block.date"
|
||||
:label="t('logistique.weighingTickets.form.date')"
|
||||
:required="true"
|
||||
:editable="true"
|
||||
:disabled="disabled"
|
||||
:error="errors.date"
|
||||
@update:model-value="(v: string | null) => emitBlock('date', v)"
|
||||
/>
|
||||
<!-- Ligne 2 : Date, Poids, DSD, Immatriculation. -->
|
||||
<div class="grid grid-cols-3 xl:grid-cols-4 gap-x-[44px] gap-y-4">
|
||||
<!-- Date de la pesée — jour par défaut (RG-5.07). MalioDate (composant
|
||||
projet pour le type date, exception tolérée @.claude/rules/frontend.md). -->
|
||||
<MalioDate
|
||||
:model-value="block.date"
|
||||
:label="t('logistique.weighingTickets.form.date')"
|
||||
:required="true"
|
||||
:editable="true"
|
||||
:disabled="disabled"
|
||||
:error="errors.date"
|
||||
@update:model-value="(v: string | null) => emitBlock('date', v)"
|
||||
/>
|
||||
|
||||
<!-- Poids : readonly, rempli par la pesée (RG-5.07). Unité Kg dans le label. -->
|
||||
<MalioInputNumber
|
||||
:model-value="block.weight"
|
||||
:label="t('logistique.weighingTickets.form.weight')"
|
||||
:required="true"
|
||||
:readonly="true"
|
||||
:disabled="disabled"
|
||||
:error="errors.weight"
|
||||
/>
|
||||
<!-- Poids : champ texte verrouillé sur les chiffres, toujours désactivé
|
||||
(rempli par la pesée, jamais saisi à la main — RG-5.07). Unité Kg
|
||||
dans le label. -->
|
||||
<MalioInputText
|
||||
:model-value="weightDisplay"
|
||||
:mask="NUMERIC_MASK"
|
||||
:label="t('logistique.weighingTickets.form.weight')"
|
||||
:required="true"
|
||||
:disabled="true"
|
||||
:error="errors.weight"
|
||||
/>
|
||||
|
||||
<!-- DSD : readonly, rempli par la pesée (RG-5.04 / RG-5.07). -->
|
||||
<MalioInputNumber
|
||||
:model-value="block.dsd"
|
||||
:label="t('logistique.weighingTickets.form.dsd')"
|
||||
:required="true"
|
||||
:readonly="true"
|
||||
:disabled="disabled"
|
||||
:error="errors.dsd"
|
||||
/>
|
||||
<!-- DSD : champ texte verrouillé sur les chiffres, toujours désactivé
|
||||
(rempli par la pesée — RG-5.04 / RG-5.07). -->
|
||||
<MalioInputText
|
||||
:model-value="dsdDisplay"
|
||||
:mask="NUMERIC_MASK"
|
||||
:label="t('logistique.weighingTickets.form.dsd')"
|
||||
:required="true"
|
||||
:disabled="true"
|
||||
:error="errors.dsd"
|
||||
/>
|
||||
|
||||
<!-- Immatriculation : masque XX-000-XX (plaque FR SIV) sauf « Tout format ».
|
||||
PARTAGÉE entre les 2 blocs (RG-5.01) — v-model remonté au form parent.
|
||||
TODO migrer le masque plaque quand @malio/layer-ui couvrira le format. -->
|
||||
<MalioInputText
|
||||
:model-value="immatriculation"
|
||||
:mask="plateFreeFormat ? undefined : PLATE_MASK"
|
||||
:label="t('logistique.weighingTickets.form.immatriculation')"
|
||||
:required="true"
|
||||
:disabled="disabled"
|
||||
:error="errors.immatriculation"
|
||||
@update:model-value="(v: string | null) => $emit('update:immatriculation', v)"
|
||||
/>
|
||||
<!-- Immatriculation : masque XX-000-XX (plaque FR SIV) sauf « Tout format ».
|
||||
PARTAGÉE entre les 2 blocs (RG-5.01) — v-model remonté au form parent.
|
||||
TODO migrer le masque plaque quand @malio/layer-ui couvrira le format. -->
|
||||
<MalioInputText
|
||||
:model-value="immatriculation"
|
||||
:mask="plateFreeFormat ? undefined : PLATE_MASK"
|
||||
:label="t('logistique.weighingTickets.form.immatriculation')"
|
||||
:required="true"
|
||||
:disabled="disabled"
|
||||
:error="errors.immatriculation"
|
||||
@update:model-value="(v: string | null) => $emit('update:immatriculation', v)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- « Tout format » : désactive le masque plaque. Partagé entre blocs (RG-5.01). -->
|
||||
<MalioCheckbox
|
||||
:id="`${blockId}-plate-free-format`"
|
||||
:model-value="plateFreeFormat"
|
||||
:label="t('logistique.weighingTickets.form.plateFreeFormat')"
|
||||
group-class="self-center"
|
||||
:disabled="disabled"
|
||||
@update:model-value="(v: boolean) => $emit('update:plateFreeFormat', v)"
|
||||
/>
|
||||
<!-- Ligne 3 : « Tout format » (désactive le masque plaque). Partagé entre
|
||||
blocs (RG-5.01). Sur sa propre ligne. -->
|
||||
<div class="grid grid-cols-3 xl:grid-cols-4 gap-x-[44px] gap-y-4">
|
||||
<MalioCheckbox
|
||||
:id="`${blockId}-plate-free-format`"
|
||||
:model-value="plateFreeFormat"
|
||||
:label="t('logistique.weighingTickets.form.plateFreeFormat')"
|
||||
group-class="self-center"
|
||||
:disabled="disabled"
|
||||
@update:model-value="(v: boolean) => $emit('update:plateFreeFormat', v)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -99,6 +115,14 @@ const PLATE_MASK = {
|
||||
tokens: { A: { pattern: /[A-Za-z]/, transform: (c: string) => c.toUpperCase() } },
|
||||
}
|
||||
|
||||
// Masque « chiffres uniquement » (maska, longueur libre) pour Poids et DSD :
|
||||
// ces champs texte sont verrouillés sur des entiers, et de toute façon désactivés
|
||||
// (remplis par la pesée).
|
||||
const NUMERIC_MASK = {
|
||||
mask: 'D',
|
||||
tokens: { D: { pattern: /[0-9]/, multiple: true } },
|
||||
}
|
||||
|
||||
const props = defineProps<{
|
||||
/** Identifiant technique du bloc (pour les `id` de champs uniques). */
|
||||
blockId: string
|
||||
@@ -125,6 +149,11 @@ const { t } = useI18n()
|
||||
|
||||
const errors = computed(() => props.errors ?? {})
|
||||
|
||||
// Poids / DSD : champs texte → on présente l'entier sous forme de chaîne (vide
|
||||
// tant que la pesée n'a pas rempli la valeur).
|
||||
const weightDisplay = computed(() => (props.block.weight === null ? '' : String(props.block.weight)))
|
||||
const dsdDisplay = computed(() => (props.block.dsd === null ? '' : String(props.block.dsd)))
|
||||
|
||||
/** Remonte la mutation d'un champ du bloc au parent (état des pesées centralisé). */
|
||||
function emitBlock(field: keyof WeighingBlockState, value: unknown): void {
|
||||
emit('update:block', field, value)
|
||||
|
||||
Reference in New Issue
Block a user