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

@@ -295,30 +295,8 @@
: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="form-control">
<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>
</label>
@@ -343,32 +321,12 @@
>
Aucun modèle disponible pour ce type.
</p>
</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
/>
<p
v-else-if="!entry.pieceModelId && entry.legacyName"
class="text-[10px] text-warning mt-1"
>
Ancienne pièce : {{ entry.legacyName }} sélectionner un modèle.
</p>
</div>
</div>
@@ -1055,9 +1013,7 @@ const createComponentSelectionEntry = () => ({
})
const createPieceSelectionEntry = () => ({
mode: 'model',
pieceModelId: '',
name: '',
})
const resetSkeletonRequirementSelections = () => {
@@ -1121,24 +1077,20 @@ const removePieceSelectionEntry = (requirementId, index) => {
pieceRequirementSelections[requirementId] = entries.filter((_, i) => i !== index)
}
const setPieceSelectionMode = (requirementId, index, mode) => {
const updatePieceSelectionEntry = (requirementId, index, patch) => {
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: '' }
const updated = { ...entry, ...patch }
if (Object.prototype.hasOwnProperty.call(patch, 'pieceModelId')) {
if (patch.pieceModelId) {
delete updated.legacyName
}
}
return { ...entry, mode: 'manual', pieceModelId: '', name: entry.name || '' }
return updated
})
}
const updatePieceSelectionEntry = (requirementId, index, patch) => {
const entries = getPieceRequirementEntries(requirementId)
pieceRequirementSelections[requirementId] = entries.map((entry, i) =>
i === index ? { ...entry, ...patch } : entry
)
}
const collectPiecesForSkeleton = () => {
const aggregated = []
machinePieces.value.forEach((piece) => {
@@ -1195,9 +1147,12 @@ const initializeSkeletonRequirementSelections = async () => {
const entries = existingPieces.map((piece) => {
const modelId = piece.pieceModelId || piece.pieceModel?.id || null
if (modelId) {
return { mode: 'model', pieceModelId: modelId, name: '' }
return { pieceModelId: modelId }
}
return {
pieceModelId: '',
legacyName: piece.name || piece.reference || '',
}
return { mode: 'manual', pieceModelId: '', name: piece.name || '' }
})
const min = requirement.minCount ?? (requirement.required ? 1 : 0)
while (entries.length < min) {
@@ -1287,12 +1242,7 @@ const validateSkeletonSelections = (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
@@ -1309,26 +1259,11 @@ const validateSkeletonSelections = (type) => {
)
}
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,
})
})
}