feat: Add model feature for piece and component

This commit is contained in:
Matthieu
2025-09-23 15:06:19 +02:00
parent c1e170b088
commit 83b3e33b1e
15 changed files with 2018 additions and 851 deletions

View File

@@ -293,29 +293,7 @@
:key="`${requirement.id}-piece-${entryIndex}`"
class="bg-base-200/60 rounded-md p-3 space-y-3"
>
<div class="flex flex-wrap items-center gap-2 text-xs">
<label class="inline-flex items-center gap-1">
<input
type="radio"
class="radio radio-xs"
:checked="entry.mode === 'model'"
@change="setPieceSelectionMode(requirement.id, entryIndex, 'model')"
/>
Modèle existant
</label>
<label class="inline-flex items-center gap-1">
<input
type="radio"
class="radio radio-xs"
:checked="entry.mode === 'manual'"
@change="setPieceSelectionMode(requirement.id, entryIndex, 'manual')"
:disabled="!requirement.allowNewModels"
/>
Définir manuellement
</label>
</div>
<div v-if="entry.mode === 'model'" class="grid grid-cols-1 md:grid-cols-2 gap-3">
<div class="grid grid-cols-1 md:grid-cols-2 gap-3">
<div class="form-control">
<label class="label">
<span class="label-text text-xs">Modèle de pièce</span>
@@ -344,32 +322,6 @@
</div>
</div>
<div v-else class="grid grid-cols-1 md:grid-cols-2 gap-3">
<div class="form-control">
<label class="label">
<span class="label-text text-xs">Nom de la pièce</span>
</label>
<input
type="text"
class="input input-bordered input-sm"
:value="entry.name"
placeholder="Nom de la pièce"
@input="updatePieceSelectionEntry(requirement.id, entryIndex, { name: $event.target.value })"
/>
</div>
<div class="form-control">
<label class="label">
<span class="label-text text-xs">Référence (optionnel)</span>
</label>
<input
type="text"
class="input input-bordered input-sm"
placeholder="(Non géré pour l'instant)"
disabled
/>
</div>
</div>
<div class="flex justify-end">
<button
type="button"
@@ -482,7 +434,6 @@
</p>
<p v-if="entry.subtitle" class="text-xs text-gray-500">{{ entry.subtitle }}</p>
</div>
<span v-if="entry.mode === 'manual'" class="badge badge-ghost badge-xs">manuel</span>
</li>
</ul>
</div>
@@ -903,23 +854,12 @@ const machinePreview = computed(() => {
const entriesSource = getPieceRequirementEntries(requirement.id)
const entriesList = entriesSource ? [...entriesSource] : []
const normalizedEntries = entriesList.map((entry, index) => {
if (entry.mode === 'model') {
const model = resolvePieceModel(requirement, entry.pieceModelId)
return {
key: `${requirement.id}-${index}`,
mode: 'model',
status: model ? 'complete' : 'pending',
title: model ? model.name : 'Sélectionner un modèle',
subtitle: model?.description || null,
}
}
const manualName = (entry.name || '').trim()
const model = resolvePieceModel(requirement, entry.pieceModelId)
return {
key: `${requirement.id}-${index}`,
mode: 'manual',
status: manualName ? 'complete' : 'pending',
title: manualName || 'Nom à renseigner',
subtitle: manualName ? null : null,
status: model ? 'complete' : 'pending',
title: model ? model.name : 'Sélectionner un modèle',
subtitle: model?.description || null,
}
})
@@ -936,10 +876,6 @@ const machinePreview = computed(() => {
issues.push({ message: `Maximum ${max} dépassé`, kind: 'error', anchor: `piece-group-${requirement.id}` })
}
if (!requirement.allowNewModels && normalizedEntries.some((entry) => entry.mode === 'manual' && entry.status === 'complete')) {
issues.push({ message: "Ce groupe n'autorise que les modèles existants.", kind: 'error', anchor: `piece-group-${requirement.id}` })
}
if (normalizedEntries.some((entry) => entry.status !== 'complete')) {
issues.push({ message: 'Compléter les sélections restantes.', kind: 'warning', anchor: `piece-group-${requirement.id}` })
}
@@ -1056,9 +992,7 @@ const createComponentSelectionEntry = () => ({
})
const createPieceSelectionEntry = () => ({
mode: 'model',
pieceModelId: '',
name: '',
})
const addComponentSelectionEntry = (requirement) => {
@@ -1109,17 +1043,6 @@ const removePieceSelectionEntry = (requirementId, index) => {
pieceRequirementSelections[requirementId] = entries.filter((_, i) => i !== index)
}
const setPieceSelectionMode = (requirementId, index, mode) => {
const entries = getPieceRequirementEntries(requirementId)
pieceRequirementSelections[requirementId] = entries.map((entry, i) => {
if (i !== index) return entry
if (mode === 'model') {
return { ...entry, mode: 'model', pieceModelId: entry.pieceModelId || '', name: '' }
}
return { ...entry, mode: 'manual', pieceModelId: '', name: entry.name || '' }
})
}
const updatePieceSelectionEntry = (requirementId, index, patch) => {
const entries = getPieceRequirementEntries(requirementId)
pieceRequirementSelections[requirementId] = entries.map((entry, i) =>
@@ -1175,12 +1098,7 @@ const validateRequirementSelections = (type) => {
for (const requirement of type.pieceRequirements || []) {
const entries = getPieceRequirementEntries(requirement.id)
const usableEntries = entries.filter((entry) => {
if (entry.mode === 'model') {
return !!entry.pieceModelId
}
return !!entry.name && entry.name.trim().length > 0
})
const usableEntries = entries.filter((entry) => !!entry.pieceModelId)
const min = requirement.minCount ?? (requirement.required ? 1 : 0)
const max = requirement.maxCount ?? null
@@ -1193,24 +1111,11 @@ const validateRequirementSelections = (type) => {
errors.push(`Le groupe "${requirement.label || requirement.typePiece?.name || 'Pièces'}" ne peut dépasser ${max} élément(s).`)
}
if (!requirement.allowNewModels && usableEntries.some((entry) => entry.mode === 'manual')) {
errors.push(`Le groupe "${requirement.label || requirement.typePiece?.name || 'Pièces'}" n'autorise que les modèles existants.`)
}
usableEntries.forEach((entry) => {
if (entry.mode === 'model') {
pieceSelectionsPayload.push({
requirementId: requirement.id,
pieceModelId: entry.pieceModelId,
})
} else {
pieceSelectionsPayload.push({
requirementId: requirement.id,
definition: {
name: entry.name.trim(),
},
})
}
pieceSelectionsPayload.push({
requirementId: requirement.id,
pieceModelId: entry.pieceModelId,
})
})
}
@@ -1322,10 +1227,9 @@ const submitCreatePieceModel = async () => {
if (result.success) {
await loadPieceModels(createPieceModelModal.requirement.typePieceId)
const entries = getPieceRequirementEntries(createPieceModelModal.requirement.id)
const targetIndex = entries.findIndex((entry) => entry.mode === 'model' && !entry.pieceModelId)
const targetIndex = entries.findIndex((entry) => !entry.pieceModelId)
if (targetIndex !== -1) {
updatePieceSelectionEntry(createPieceModelModal.requirement.id, targetIndex, {
mode: 'model',
pieceModelId: result.data.id,
})
} else {
@@ -1334,7 +1238,6 @@ const submitCreatePieceModel = async () => {
createPieceModelModal.requirement.id,
getPieceRequirementEntries(createPieceModelModal.requirement.id).length - 1,
{
mode: 'model',
pieceModelId: result.data.id,
},
)