From 2e4d61c3ea114c5c44ca67ef8e48e98497a55142 Mon Sep 17 00:00:00 2001 From: matthieu Date: Thu, 15 Jan 2026 13:43:18 +0100 Subject: [PATCH] fix(modeles): normaliser structure et champs perso --- app/pages/component/[id]/edit.vue | 16 +++++++- app/services/modelTypes.ts | 67 +++++++++++++++++++++++++++---- 2 files changed, 74 insertions(+), 9 deletions(-) diff --git a/app/pages/component/[id]/edit.vue b/app/pages/component/[id]/edit.vue index bc7d32f..f6743ac 100644 --- a/app/pages/component/[id]/edit.vue +++ b/app/pages/component/[id]/edit.vue @@ -403,6 +403,7 @@ import { useComposants } from '~/composables/useComposants' import { useCustomFields } from '~/composables/useCustomFields' import { useApi } from '~/composables/useApi' import { useToast } from '~/composables/useToast' +import { extractRelationId } from '~/shared/apiRelations' import { useDocuments } from '~/composables/useDocuments' import { useConstructeurs } from '~/composables/useConstructeurs' import { formatStructurePreview, normalizeStructureForEditor } from '~/shared/modelUtils' @@ -435,7 +436,7 @@ const { get } = useApi() const { componentTypes, loadComponentTypes } = useComponentTypes() const { updateComposant } = useComposants() const { ensureConstructeurs } = useConstructeurs() -const { upsertCustomFieldValue, updateCustomFieldValue } = useCustomFields() +const { upsertCustomFieldValue, updateCustomFieldValue, getCustomFieldValuesByEntity } = useCustomFields() const toast = useToast() const { loadDocumentsByComponent, uploadDocuments, deleteDocument } = useDocuments() @@ -636,6 +637,11 @@ const fetchComponent = async () => { if (result.success) { component.value = result.data componentDocuments.value = Array.isArray(result.data?.documents) ? result.data.documents : [] + + const customValues = await getCustomFieldValuesByEntity('composant', result.data.id) + if (customValues.success && Array.isArray(customValues.data)) { + component.value.customFieldValues = customValues.data + } } else { component.value = null componentDocuments.value = [] @@ -651,7 +657,13 @@ watch( return } - selectedTypeId.value = currentComponent.typeComposantId || '' + const resolvedTypeId = currentComponent.typeComposantId + || extractRelationId(currentComponent.typeComposant) + || '' + if (resolvedTypeId && !currentComponent.typeComposantId) { + currentComponent.typeComposantId = resolvedTypeId + } + selectedTypeId.value = resolvedTypeId editionForm.name = currentComponent.name || '' editionForm.reference = currentComponent.reference || '' diff --git a/app/services/modelTypes.ts b/app/services/modelTypes.ts index ec875eb..c2467bc 100644 --- a/app/services/modelTypes.ts +++ b/app/services/modelTypes.ts @@ -47,6 +47,9 @@ export interface ModelType extends BaseModelTypePayload { updatedAt: string; category: ModelCategory; structure: ModelTypeStructure; + componentSkeleton?: ComponentModelStructure | null; + pieceSkeleton?: PieceModelStructure | null; + productSkeleton?: ProductModelStructure | null; } export interface ModelTypeListParams { @@ -80,6 +83,46 @@ function createOptions(options: FetchOptions = {}) { }; } +const normalizeModelType = (item: any): ModelType => { + if (!item || typeof item !== 'object') { + return item as ModelType; + } + if (!item.structure) { + if (item.category === 'COMPONENT' && item.componentSkeleton) { + item.structure = item.componentSkeleton; + } else if (item.category === 'PIECE' && item.pieceSkeleton) { + item.structure = item.pieceSkeleton; + } else if (item.category === 'PRODUCT' && item.productSkeleton) { + item.structure = item.productSkeleton; + } + } + return item as ModelType; +}; + +const mapStructureToSkeleton = >(payload: T): T => { + if (!payload || typeof payload !== 'object') { + return payload; + } + if (!('structure' in payload)) { + return payload; + } + const structure = (payload as any).structure; + if (!structure) { + return payload; + } + const category = (payload as any).category; + const next = { ...payload } as Record; + if (category === 'COMPONENT') { + next.componentSkeleton = structure; + } else if (category === 'PIECE') { + next.pieceSkeleton = structure; + } else if (category === 'PRODUCT') { + next.productSkeleton = structure; + } + delete next.structure; + return next as T; +}; + export async function listModelTypes(params: ModelTypeListParams = {}, opts: { signal?: AbortSignal } = {}) { const requestFetch = useRequestFetch(); const query: Record = {}; @@ -136,9 +179,9 @@ export async function listModelTypes(params: ModelTypeListParams = {}, opts: { s : Array.isArray(payload?.items) ? payload.items.length : rawItems.length; - const items = params.category && typeof effectiveLimit === 'number' + const items = (params.category && typeof effectiveLimit === 'number' ? filteredItems.slice(effectiveOffset, effectiveOffset + effectiveLimit) - : filteredItems; + : filteredItems).map(normalizeModelType); return { items, @@ -150,20 +193,30 @@ export async function listModelTypes(params: ModelTypeListParams = {}, opts: { s export function createModelType(payload: ModelTypePayload, opts: { signal?: AbortSignal } = {}) { const requestFetch = useRequestFetch(); + const mappedPayload = mapStructureToSkeleton(payload); return requestFetch(ENDPOINT, createOptions({ method: 'POST', - body: payload, + headers: { + 'Content-Type': 'application/ld+json', + Accept: 'application/ld+json', + }, + body: mappedPayload, signal: opts.signal, - })); + })).then(normalizeModelType); } export function updateModelType(id: string, payload: Partial, opts: { signal?: AbortSignal } = {}) { const requestFetch = useRequestFetch(); + const mappedPayload = mapStructureToSkeleton(payload); return requestFetch(`${ENDPOINT}/${id}`, createOptions({ method: 'PATCH', - body: payload, + headers: { + 'Content-Type': 'application/merge-patch+json', + Accept: 'application/ld+json', + }, + body: mappedPayload, signal: opts.signal, - })); + })).then(normalizeModelType); } export function deleteModelType(id: string, opts: { signal?: AbortSignal } = {}) { @@ -179,5 +232,5 @@ export function getModelType(id: string, opts: { signal?: AbortSignal } = {}) { return requestFetch(`${ENDPOINT}/${id}`, createOptions({ method: 'GET', signal: opts.signal, - })); + })).then(normalizeModelType); }