diff --git a/app/components/ComposantSelect.vue b/app/components/ComposantSelect.vue
new file mode 100644
index 0000000..f63f449
--- /dev/null
+++ b/app/components/ComposantSelect.vue
@@ -0,0 +1,116 @@
+
+
+
+
+
+ {{ formatDescription(option) }}
+
+
+
+
+ {{ helperText }}
+
+
+
+
+
diff --git a/app/components/PieceSelect.vue b/app/components/PieceSelect.vue
new file mode 100644
index 0000000..9f08cbf
--- /dev/null
+++ b/app/components/PieceSelect.vue
@@ -0,0 +1,116 @@
+
+
+
+
+
+ {{ formatDescription(option) }}
+
+
+
+
+ {{ helperText }}
+
+
+
+
+
diff --git a/app/composables/useComponentEdit.ts b/app/composables/useComponentEdit.ts
index 38408d1..674e0ec 100644
--- a/app/composables/useComponentEdit.ts
+++ b/app/composables/useComponentEdit.ts
@@ -270,6 +270,94 @@ export function useComponentEdit(componentId: string) {
}
})
+ // --- Slot selection entries (for selectors) ---
+
+ const pieceSlotEntries = computed(() => {
+ const structure = component.value?.structure
+ if (!structure?.pieces) return []
+ return (structure.pieces as any[]).map((slot: any, i: number) => ({
+ slotId: slot.slotId,
+ typePieceId: slot.typePieceId,
+ selectedPieceId: slot.selectedPieceId ?? null,
+ quantity: slot.quantity ?? 1,
+ position: slot.position ?? i,
+ label: pieceTypeLabelMap.value[slot.typePieceId] || `Pièce #${i + 1}`,
+ }))
+ })
+
+ const productSlotEntries = computed(() => {
+ const structure = component.value?.structure
+ if (!structure?.products) return []
+ return (structure.products as any[]).map((slot: any, i: number) => ({
+ slotId: slot.slotId,
+ typeProductId: slot.typeProductId,
+ selectedProductId: slot.selectedProductId ?? null,
+ familyCode: slot.familyCode,
+ position: slot.position ?? i,
+ label: productTypeLabelMap.value[slot.typeProductId] || `Produit #${i + 1}`,
+ }))
+ })
+
+ const subcomponentSlotEntries = computed(() => {
+ const structure = component.value?.structure
+ if (!structure?.subcomponents) return []
+ return (structure.subcomponents as any[]).map((slot: any, i: number) => ({
+ slotId: slot.slotId,
+ typeComposantId: slot.typeComposantId,
+ selectedComponentId: slot.selectedComponentId ?? null,
+ alias: slot.alias,
+ familyCode: slot.familyCode,
+ position: slot.position ?? i,
+ label: slot.alias || `Sous-composant #${i + 1}`,
+ }))
+ })
+
+ const savePieceSlotSelection = async (slotId: string, selectedPieceId: string | null) => {
+ try {
+ await patch(`/composant-piece-slots/${slotId}`, { selectedPieceId })
+ // Update local structure
+ const structure = component.value?.structure
+ if (structure?.pieces) {
+ const slot = (structure.pieces as any[]).find((s: any) => s.slotId === slotId)
+ if (slot) slot.selectedPieceId = selectedPieceId
+ }
+ toast.showSuccess('Pièce mise à jour')
+ }
+ catch (error: any) {
+ toast.showError(error?.message || 'Erreur lors de la mise à jour')
+ }
+ }
+
+ const saveProductSlotSelection = async (slotId: string, selectedProductId: string | null) => {
+ try {
+ await patch(`/composant-product-slots/${slotId}`, { selectedProductId })
+ const structure = component.value?.structure
+ if (structure?.products) {
+ const slot = (structure.products as any[]).find((s: any) => s.slotId === slotId)
+ if (slot) slot.selectedProductId = selectedProductId
+ }
+ toast.showSuccess('Produit mis à jour')
+ }
+ catch (error: any) {
+ toast.showError(error?.message || 'Erreur lors de la mise à jour')
+ }
+ }
+
+ const saveSubcomponentSlotSelection = async (slotId: string, selectedComposantId: string | null) => {
+ try {
+ await patch(`/composant-subcomponent-slots/${slotId}`, { selectedComposantId })
+ const structure = component.value?.structure
+ if (structure?.subcomponents) {
+ const slot = (structure.subcomponents as any[]).find((s: any) => s.slotId === slotId)
+ if (slot) slot.selectedComponentId = selectedComposantId
+ }
+ toast.showSuccess('Sous-composant mis à jour')
+ }
+ catch (error: any) {
+ toast.showError(error?.message || 'Erreur lors de la mise à jour')
+ }
+ }
+
const saveSlotQuantity = async (entry: SelectionEntry) => {
const slotId = entry.slotId
const quantity = typeof entry._definition?.quantity === 'number'
@@ -423,14 +511,12 @@ export function useComponentEdit(componentId: string) {
])
loading.value = false
- // Defer bulk catalog loads — only needed when component has structure selections
- if (component.value?.structure) {
- Promise.allSettled([
- loadPieces({ itemsPerPage: 200 }),
- loadProducts({ itemsPerPage: 200 }),
- loadComposants({ itemsPerPage: 200 }),
- ]).catch(() => {})
- }
+ // Load catalogs for slot selectors
+ Promise.allSettled([
+ loadPieces({ itemsPerPage: 200 }),
+ loadProducts({ itemsPerPage: 200 }),
+ loadComposants({ itemsPerPage: 200 }),
+ ]).catch(() => {})
})
return {
@@ -456,6 +542,9 @@ export function useComponentEdit(componentId: string) {
selectedType,
selectedTypeStructure,
structureSelections,
+ pieceSlotEntries,
+ productSlotEntries,
+ subcomponentSlotEntries,
// History
history,
@@ -470,6 +559,9 @@ export function useComponentEdit(componentId: string) {
refreshDocuments,
submitEdition,
saveSlotQuantity,
+ savePieceSlotSelection,
+ saveProductSlotSelection,
+ saveSubcomponentSlotSelection,
resolvePieceLabel,
resolveProductLabel,
resolveSubcomponentLabel,
diff --git a/app/pages/component/[id]/edit.vue b/app/pages/component/[id]/edit.vue
index fff3470..f0c340e 100644
--- a/app/pages/component/[id]/edit.vue
+++ b/app/pages/component/[id]/edit.vue
@@ -152,57 +152,76 @@
/>
- Sélections actuelles
+ Sélections du squelette
- Voici les pièces, produits et sous-composants réellement choisis pour ce composant.
+ Choisissez les pièces, produits et sous-composants pour chaque emplacement requis par la catégorie.
-
-
-
Pièces choisies
-
+
-
-
Produits choisis
-
-
- {{ entry.resolvedName }}
- — {{ entry.requirementLabel }}
-
-
+
-
-
Sous-composants choisis
-
-
- {{ entry.resolvedName }}
- — {{ entry.requirementLabel }}
-
-
+
+
Sous-composants
+
+
+
+ {{ slot.label }}
+
+ saveSubcomponentSlotSelection(slot.slotId, value)"
+ />
+
@@ -312,6 +331,9 @@ const {
selectedType,
selectedTypeStructure,
structureSelections,
+ pieceSlotEntries,
+ productSlotEntries,
+ subcomponentSlotEntries,
history,
historyLoading,
historyError,
@@ -321,6 +343,9 @@ const {
handleFilesAdded,
submitEdition,
saveSlotQuantity,
+ savePieceSlotSelection,
+ saveProductSlotSelection,
+ saveSubcomponentSlotSelection,
resolvePieceLabel,
resolveProductLabel,
resolveSubcomponentLabel,