From 4a3bceffa18fcbd7b79fd13e9c5477f115f9a9b6 Mon Sep 17 00:00:00 2001 From: Matthieu Date: Thu, 12 Mar 2026 17:22:20 +0100 Subject: [PATCH] =?UTF-8?q?feat(machine)=20:=20afficher=20quantit=C3=A9=20?= =?UTF-8?q?pi=C3=A8ces=20+=20pi=C3=A8ces=20incluses=20des=20composants?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - MachinePiecesCard : passer isEditMode au PieceItem + forward event update - useMachineHierarchy : mapper quantity depuis le backend + construire les pièces de structure du composant en lecture seule - useMachineDetailUpdates : PATCH MachinePieceLink.quantity + fix reference null - ComponentItem : séparer pièces liées / pièces incluses par défaut - useEntityDocuments : skip chargement documents pour pièces de structure Co-Authored-By: Claude Opus 4.6 --- app/components/ComponentItem.vue | 29 ++++++++++++++++-- app/components/machine/MachinePiecesCard.vue | 4 ++- app/composables/useEntityDocuments.ts | 2 +- app/composables/useMachineDetailData.ts | 3 +- app/composables/useMachineDetailUpdates.ts | 11 ++++++- app/composables/useMachineHierarchy.ts | 31 +++++++++++++++++++- 6 files changed, 72 insertions(+), 8 deletions(-) diff --git a/app/components/ComponentItem.vue b/app/components/ComponentItem.vue index 01da2fe..39ae3e3 100644 --- a/app/components/ComponentItem.vue +++ b/app/components/ComponentItem.vue @@ -215,14 +215,14 @@ /> - -
+ +

Pièces du composant

+ +
+

+ Pièces incluses par défaut +

+
+ +
+
+

@@ -341,6 +356,14 @@ const childComponents = computed(() => { return Array.isArray(list) ? list : [] }) +// --- Pieces split: real links vs structure definitions --- +const allPieces = computed(() => { + const list = props.component.pieces + return Array.isArray(list) ? list : [] +}) +const linkedPieces = computed(() => allPieces.value.filter((p) => !p._structurePiece)) +const structurePieces = computed(() => allPieces.value.filter((p) => p._structurePiece)) + // --- Constructeurs --- const { constructeurs } = useConstructeurs() diff --git a/app/components/machine/MachinePiecesCard.vue b/app/components/machine/MachinePiecesCard.vue index 2dbe97c..20d2c72 100644 --- a/app/components/machine/MachinePiecesCard.vue +++ b/app/components/machine/MachinePiecesCard.vue @@ -28,10 +28,11 @@

@@ -62,6 +63,7 @@ defineProps<{ defineEmits<{ 'toggle-collapse': [] + 'update-piece': [piece: any] 'edit-piece': [piece: any] 'add-piece': [] 'remove-piece': [linkId: string] diff --git a/app/composables/useEntityDocuments.ts b/app/composables/useEntityDocuments.ts index 00d8064..91d2883 100644 --- a/app/composables/useEntityDocuments.ts +++ b/app/composables/useEntityDocuments.ts @@ -56,7 +56,7 @@ export function useEntityDocuments(deps: EntityDocumentsDeps) { // CRUD operations const refreshDocuments = async () => { const e = entity() - if (!e?.id) return + if (!e?.id || e._structurePiece) return loadingDocuments.value = true try { const result: any = await loadDocumentsFn(e.id, { updateStore: false }) diff --git a/app/composables/useMachineDetailData.ts b/app/composables/useMachineDetailData.ts index 13e102a..c8511ce 100644 --- a/app/composables/useMachineDetailData.ts +++ b/app/composables/useMachineDetailData.ts @@ -42,7 +42,7 @@ export function useMachineDetailData(machineId: string) { const { componentTypes, loadComponentTypes } = useComponentTypes() const { pieceTypes, loadPieceTypes } = usePieceTypes() const { upsertCustomFieldValue } = useCustomFields() - const { get } = useApi() + const { get, patch: apiPatch } = useApi() const toast = useToast() const { constructeurs, loadConstructeurs } = useConstructeurs() const { sites, loadSites } = useSites() @@ -274,6 +274,7 @@ export function useMachineDetailData(machineId: string) { updateMachineApi, updateComposantApi: updateComposantApi, updatePieceApi, + apiPatch, toast, }) diff --git a/app/composables/useMachineDetailUpdates.ts b/app/composables/useMachineDetailUpdates.ts index 3e0d657..3b779f4 100644 --- a/app/composables/useMachineDetailUpdates.ts +++ b/app/composables/useMachineDetailUpdates.ts @@ -33,6 +33,7 @@ export interface UseMachineDetailUpdatesDeps { updateMachineApi: (id: string, data: any) => Promise updateComposantApi: (id: string, data: any) => Promise updatePieceApi: (id: string, data: any) => Promise + apiPatch: (endpoint: string, data?: unknown) => Promise toast: { showInfo: (msg: string) => void } } @@ -53,6 +54,7 @@ export function useMachineDetailUpdates(deps: UseMachineDetailUpdatesDeps) { updateMachineApi, updateComposantApi, updatePieceApi, + apiPatch, toast, } = deps @@ -147,7 +149,7 @@ export function useMachineDetailUpdates(deps: UseMachineDetailUpdatesDeps) { const result: any = await updatePieceApi(updatedPiece.id as string, { name: updatedPiece.name, - reference: updatedPiece.reference, + reference: updatedPiece.reference || null, constructeurIds: cIds, prix: Number.isNaN(prix) ? null : prix, productId, @@ -187,6 +189,13 @@ export function useMachineDetailUpdates(deps: UseMachineDetailUpdatesDeps) { const updatePieceInfo = async (updatedPiece: AnyRecord) => { try { await _buildAndUpdatePiece(updatedPiece) + + // Update link quantity if this is a direct machine piece + const linkId = updatedPiece.linkId || updatedPiece.machinePieceLinkId + const quantity = typeof updatedPiece.quantity === 'number' ? Math.max(1, updatedPiece.quantity) : null + if (linkId && quantity !== null) { + await apiPatch(`/machine_piece_links/${linkId}`, { quantity }) + } } catch (error) { console.error('Erreur lors de la mise à jour de la pièce:', error) } diff --git a/app/composables/useMachineHierarchy.ts b/app/composables/useMachineHierarchy.ts index 6598a84..df7b28e 100644 --- a/app/composables/useMachineHierarchy.ts +++ b/app/composables/useMachineHierarchy.ts @@ -181,6 +181,7 @@ export const buildMachineHierarchyFromLinks = ( parentLinkId: resolveIdentifier(link.parentLinkId, link.parentMachinePieceLinkId, appliedPiece.parentLinkId), parentPieceLinkId: resolveIdentifier(link.parentPieceLinkId, appliedPiece.parentPieceLinkId), parentPieceId: resolveIdentifier(appliedPiece.parentPieceId, link.parentPieceId), + quantity: typeof link.quantity === 'number' ? link.quantity : 1, definition: appliedPiece.definition || originalPiece?.definition || {}, customFields: appliedPiece.customFields || [], } @@ -214,10 +215,38 @@ export const buildMachineHierarchyFromLinks = ( const componentName = (compOverrides?.name || appliedComponent.name || (appliedComponent.definition as AnyRecord)?.alias || (appliedComponent.definition as AnyRecord)?.name || originalComponent?.name || 'Composant') as string - const pieces = Array.isArray(link.pieceLinks) + const linkedPieces = Array.isArray(link.pieceLinks) ? (link.pieceLinks as AnyRecord[]).map((pl) => createPieceNode(pl, componentName)).filter(Boolean) as AnyRecord[] : [] + // If no linked pieces exist, build read-only entries from the composant's structure + const structurePieceDefs = (!linkedPieces.length && appliedComponent.structure && typeof appliedComponent.structure === 'object') + ? (Array.isArray((appliedComponent.structure as AnyRecord).pieces) ? (appliedComponent.structure as AnyRecord).pieces as AnyRecord[] : []) + : [] + const structurePieces = structurePieceDefs.map((def, index) => { + const definition = (def.definition && typeof def.definition === 'object' ? def.definition : def) as AnyRecord + const resolved = (def.resolvedPiece && typeof def.resolvedPiece === 'object' ? def.resolvedPiece : null) as AnyRecord | null + const quantity = typeof definition.quantity === 'number' ? definition.quantity : (typeof def.quantity === 'number' ? def.quantity : 1) + return { + ...(resolved || {}), + id: resolved?.id || `structure-piece-${composantId}-${index}`, + pieceId: resolved?.id || null, + name: resolved?.name || definition.role || definition.name || def.role || def.name || `Pièce ${index + 1}`, + reference: resolved?.reference || definition.reference || def.reference || null, + prix: resolved?.prix ?? null, + constructeurs: resolved?.constructeurs || [], + documents: [], + quantity, + typePieceId: resolved?.typePieceId || definition.typePieceId || def.typePieceId || null, + typePiece: resolved?.typePiece || null, + parentComponentLinkId: machineComponentLinkId, + parentComponentName: componentName, + _structurePiece: true, + } + }) as AnyRecord[] + + const pieces = linkedPieces.length ? linkedPieces : structurePieces + const subComponents = Array.isArray(link.childLinks) ? (link.childLinks as AnyRecord[]).map(createComponentNode).filter(Boolean) as AnyRecord[] : []