feat(reference-auto) : display referenceAuto in piece views + formula config in ModelTypeForm

- Piece interface: add referenceAuto field
- piece/[id].vue: read-only display with auto badge
- pieces/[id]/edit.vue: disabled input when referenceAuto is set
- pieces-catalog.vue: new column "Réf. auto"
- PieceItem.vue: badge + detail line for referenceAuto
- ModelTypeForm.vue: formula + required fields config for PIECE category
- modelTypes.ts: add referenceFormula/requiredFieldsForReference to types

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Matthieu
2026-03-26 20:33:33 +01:00
parent a7415964a7
commit a339e722a6
7 changed files with 112 additions and 2 deletions

View File

@@ -42,6 +42,7 @@
Rattachée à {{ piece.parentComponentName }}
</span>
<span v-if="pieceData.reference" class="badge badge-outline badge-sm">{{ pieceData.reference }}</span>
<span v-if="pieceData.referenceAuto" class="badge badge-secondary badge-sm" title="Référence auto">{{ pieceData.referenceAuto }}</span>
<template v-if="pieceConstructeursDisplay.length">
<span
v-for="constructeur in pieceConstructeursDisplay"
@@ -106,6 +107,10 @@
pieceData.reference || "Non définie"
}}</span>
</div>
<div v-if="pieceData.referenceAuto">
<span class="font-medium">Référence auto:</span>
<span class="ml-2">{{ pieceData.referenceAuto }}</span>
</div>
<div>
<span class="font-medium">Fournisseur:</span>
<div v-if="!isEditMode" class="ml-2">
@@ -301,6 +306,7 @@ const emit = defineEmits(['update', 'edit', 'custom-field-update', 'delete'])
const pieceData = reactive({
name: props.piece.name || '',
reference: props.piece.reference || '',
referenceAuto: props.piece.referenceAuto || null,
prix: props.piece.prix || '',
productId: props.piece.product?.id || props.piece.productId || null,
quantity: props.piece.quantity ?? 1,

View File

@@ -108,6 +108,57 @@
</template>
</section>
<section v-if="form.category === 'PIECE'" class="space-y-4">
<header>
<h3 class="text-lg font-semibold text-base-content">Génération de référence automatique</h3>
<p class="mt-1 text-sm text-base-content/70">
Définissez une formule pour générer automatiquement une référence technique à partir des champs personnalisés.
Utilisez <code class="bg-base-200 px-1 rounded">{'{'}nom_du_champ{'}'}</code> comme placeholder.
</p>
</header>
<div class="rounded-lg border border-base-300 p-4 space-y-4">
<div>
<label class="label" for="reference-formula">
<span class="label-text">Formule</span>
</label>
<input
id="reference-formula"
v-model.trim="form.referenceFormula"
type="text"
class="input input-bordered w-full font-mono"
placeholder="Ex: {serie}{diametre}{type}"
:disabled="isReadonly"
/>
<p class="mt-1 text-xs text-base-content/60">
Laissez vide si ce type n'utilise pas de référence automatique.
</p>
</div>
<div>
<label class="label" for="required-fields">
<span class="label-text">Champs requis</span>
</label>
<input
id="required-fields"
v-model.trim="requiredFieldsInput"
type="text"
class="input input-bordered w-full"
placeholder="Ex: serie, diametre, type"
:disabled="isReadonly"
/>
<p class="mt-1 text-xs text-base-content/60">
Noms des champs séparés par des virgules. Si un champ requis est vide, la référence ne sera pas générée.
</p>
</div>
<div v-if="form.referenceFormula" class="rounded bg-base-200 px-3 py-2 text-sm">
<span class="text-base-content/70">Aperçu :</span>
<span class="ml-1 font-mono font-semibold">{{ formulaPreview }}</span>
</div>
</div>
</section>
<footer class="flex flex-col gap-3 border-t border-base-300 pt-4 sm:flex-row sm:justify-end">
<button type="button" class="btn btn-ghost" :disabled="saving" @click="emit('cancel')">
Annuler
@@ -177,12 +228,21 @@ const componentSubcomponentMaxDepth = computed(() =>
)
const isReadonly = computed(() => props.readonly === true)
const form = reactive<ModelTypePayload>({
const form = reactive<ModelTypePayload & { referenceFormula?: string | null; requiredFieldsForReference?: string[] | null }>({
name: '',
code: '',
category: props.initialCategory,
notes: '',
structure: undefined,
referenceFormula: null,
requiredFieldsForReference: null,
})
const requiredFieldsInput = ref('')
const formulaPreview = computed(() => {
if (!form.referenceFormula) return ''
return form.referenceFormula.replace(/\{(\w+)\}/g, '___')
})
const errors = reactive<{ name?: string }>({})
@@ -248,6 +308,11 @@ const resetForm = () => {
errors.name = undefined
const incomingAny = incoming as Record<string, unknown>
form.referenceFormula = typeof incomingAny.referenceFormula === 'string' ? incomingAny.referenceFormula : null
form.requiredFieldsForReference = Array.isArray(incomingAny.requiredFieldsForReference) ? incomingAny.requiredFieldsForReference : null
requiredFieldsInput.value = form.requiredFieldsForReference?.join(', ') ?? ''
resetStructures(incoming.structure, form.category)
}
@@ -295,11 +360,16 @@ const handleSubmit = () => {
}
if (form.category === 'PIECE') {
const parsedRequiredFields = requiredFieldsInput.value
? requiredFieldsInput.value.split(',').map(s => s.trim()).filter(Boolean)
: null
emit('submit', {
...common,
category: 'PIECE',
structure: normalizePieceStructureForSave(clonePieceStructure(pieceStructure.value)),
})
referenceFormula: form.referenceFormula || null,
requiredFieldsForReference: parsedRequiredFields?.length ? parsedRequiredFields : null,
} as ModelTypePayload)
return
}