@@ -97,7 +506,7 @@
type="button"
class="btn btn-ghost btn-sm"
:disabled="skeletonEditor.submitting"
- @click="closeSkeletonEditor"
+ @click="changeMachineView('details')"
>
Fermer
@@ -285,8 +694,8 @@
:key="`${requirement.id}-piece-${entryIndex}`"
class="bg-base-200/60 rounded-md p-3 space-y-3"
>
-
@@ -844,12 +886,14 @@ import IconLucidePrinter from '~icons/lucide/printer'
import IconLucidePlus from '~icons/lucide/plus'
import IconLucideX from '~icons/lucide/x'
import ModelStructureViewer from '~/components/ModelStructureViewer.vue'
+import SkeletonComponentNodeSelector from '~/components/SkeletonComponentNodeSelector.vue'
import { useComponentModels } from '~/composables/useComponentModels'
import { usePieceModels } from '~/composables/usePieceModels'
import {
defaultStructure,
extractStructureFromComponent,
formatStructurePreview,
+ cloneStructure,
} from '~/shared/modelUtils'
const route = useRoute()
@@ -874,7 +918,7 @@ const {
updatePiece: updatePieceApi
} = usePieces()
-const { upsertCustomFieldValue } = useCustomFields()
+const { upsertCustomFieldValue, updateCustomFieldValue: updateCustomFieldValueApi } = useCustomFields()
const {
uploadDocuments,
deleteDocument,
@@ -917,6 +961,7 @@ const machineConstructeurDisplay = computed(() => {
const machineDocumentFiles = ref([])
const machineDocumentsUploading = ref(false)
const machineDocumentsLoaded = ref(false)
+const machineCustomFields = ref([])
const previewDocument = ref(null)
const previewVisible = ref(false)
const printModalOpen = ref(false)
@@ -930,6 +975,10 @@ const printSelection = reactive({
pieces: {},
})
+const activeMachineView = ref('details')
+const isDetailsView = computed(() => activeMachineView.value === 'details')
+const isSkeletonView = computed(() => activeMachineView.value === 'skeleton')
+
const saveComponentAsModelModal = reactive({
open: false,
submitting: false,
@@ -963,6 +1012,220 @@ const machineHasSkeletonRequirements = computed(() =>
componentRequirements.value.length > 0 || pieceRequirements.value.length > 0
)
+const componentTypeLabelMap = computed(() => {
+ const map = new Map()
+ componentRequirements.value.forEach((requirement) => {
+ const type = requirement.typeComposant
+ if (type?.id) {
+ map.set(type.id, type.name || '')
+ }
+ })
+ return map
+})
+
+const pieceTypeLabelMap = computed(() => {
+ const map = new Map()
+ pieceRequirements.value.forEach((requirement) => {
+ const type = requirement.typePiece
+ if (type?.id) {
+ map.set(type.id, type.name || '')
+ }
+ })
+ return map
+})
+
+const getComponentRequirementById = (id) =>
+ componentRequirements.value.find((requirement) => requirement.id === id) || null
+
+const getPieceRequirementById = (id) =>
+ pieceRequirements.value.find((requirement) => requirement.id === id) || null
+
+const getComponentTypeLabel = (typeId) => {
+ if (!typeId) return ''
+ return componentTypeLabelMap.value.get(typeId) || ''
+}
+
+const getPieceTypeLabel = (typeId) => {
+ if (!typeId) return ''
+ return pieceTypeLabelMap.value.get(typeId) || ''
+}
+
+const normalizePieceNode = (source, context = {}) => {
+ const name = source?.name || context.name || source?.typePieceLabel || source?.typePiece?.name || ''
+ const typePieceId = source?.typePieceId
+ || source?.typePiece?.id
+ || context.typePieceId
+ || ''
+ const typePieceLabel = source?.typePieceLabel
+ || source?.typePiece?.name
+ || context.typePieceLabel
+ || ''
+
+ return {
+ name,
+ typePieceId,
+ typePieceLabel,
+ __pieceModelId: source?.__pieceModelId
+ ?? source?.pieceModelId
+ ?? source?.pieceModel?.id
+ ?? context.pieceModelId
+ ?? null,
+ customFields: Array.isArray(source?.customFields)
+ ? cloneStructure(source.customFields)
+ : [],
+ }
+}
+
+const normalizeComponentNode = (source, context = {}) => {
+ const typeComposantId = source?.typeComposantId
+ || source?.typeComposant?.id
+ || context.typeComposantId
+ || ''
+
+ const node = {
+ name: source?.name || context.name || '' ,
+ description: source?.description || context.description || '',
+ typeComposantId,
+ typeComposantLabel: source?.typeComposantLabel
+ || source?.typeComposant?.name
+ || context.typeComposantLabel
+ || getComponentTypeLabel(typeComposantId),
+ __componentModelId: source?.__componentModelId
+ ?? source?.componentModelId
+ ?? source?.composantModelId
+ ?? source?.composantModel?.id
+ ?? context.componentModelId
+ ?? null,
+ __requirementId: source?.__requirementId ?? context.requirementId ?? null,
+ customFields: Array.isArray(source?.customFields)
+ ? cloneStructure(source.customFields)
+ : [],
+ pieces: Array.isArray(source?.pieces)
+ ? source.pieces.map((piece: any) => normalizePieceNode(piece))
+ : [],
+ subComponents: Array.isArray(source?.subComponents || source?.sousComposants)
+ ? (source.subComponents || source.sousComposants).map((sub: any) => normalizeComponentNode(sub, {
+ name: sub?.name || '',
+ description: sub?.description || '',
+ typeComposantId: sub?.typeComposantId || sub?.typeComposant?.id || '',
+ typeComposantLabel: sub?.typeComposantLabel || sub?.typeComposant?.name || '',
+ componentModelId: sub?.__componentModelId
+ ?? sub?.componentModelId
+ ?? sub?.composantModelId
+ ?? sub?.composantModel?.id
+ ?? null,
+ }))
+ : [],
+ }
+
+ if (!node.name) {
+ node.name = node.typeComposantLabel || 'Composant'
+ }
+
+ return node
+}
+
+const createEmptyComponentDefinition = (requirement) => {
+ return normalizeComponentNode(
+ {
+ name: requirement?.typeComposant?.name || 'Composant',
+ typeComposantId: requirement?.typeComposantId || '',
+ },
+ {
+ requirementId: requirement?.id || null,
+ },
+ )
+}
+
+const createDefinitionFromModel = (model, requirement) => {
+ const structure = cloneStructure(model?.structure || defaultStructure())
+ if (!structure.name) {
+ structure.name = model?.name || requirement?.typeComposant?.name || 'Composant'
+ }
+ if (!structure.typeComposantId) {
+ structure.typeComposantId = model?.typeComposantId || requirement?.typeComposantId || ''
+ }
+ const definition = normalizeComponentNode(structure, {
+ requirementId: requirement?.id || null,
+ componentModelId: model?.id || null,
+ })
+ definition.__componentModelId = model?.id || null
+ return definition
+}
+
+const buildDefinitionFromComponent = (component, requirement) => {
+ const definition = normalizeComponentNode(component, {
+ requirementId: requirement?.id || null,
+ componentModelId: component?.composantModelId
+ || component?.composantModel?.id
+ || null,
+ typeComposantId: requirement?.typeComposantId
+ || component?.typeComposantId
+ || component?.typeComposant?.id
+ || '',
+ typeComposantLabel: requirement?.typeComposant?.name
+ || component?.typeComposant?.name
+ || '',
+ })
+ return definition
+}
+
+const applyDefinitionToNode = (target, definition) => {
+ target.name = definition.name
+ target.description = definition.description
+ target.typeComposantId = definition.typeComposantId
+ target.typeComposantLabel = definition.typeComposantLabel
+ target.__componentModelId = definition.__componentModelId ?? null
+ target.__requirementId = definition.__requirementId ?? null
+ target.customFields = Array.isArray(definition.customFields)
+ ? cloneStructure(definition.customFields)
+ : []
+ target.pieces = Array.isArray(definition.pieces)
+ ? definition.pieces.map((piece: any) => normalizePieceNode(piece))
+ : []
+ target.subComponents = Array.isArray(definition.subComponents)
+ ? definition.subComponents.map((sub: any) => normalizeComponentNode(sub))
+ : []
+}
+
+const handleNodeComponentModelChange = async (node, typeComposantId, modelId) => {
+ const requirement = node.__requirementId
+ ? getComponentRequirementById(node.__requirementId)
+ : null
+
+ const previousModelId = node.__componentModelId || null
+ if (previousModelId === modelId) {
+ return
+ }
+
+ if (typeComposantId) {
+ await loadComponentModels(typeComposantId)
+ }
+
+ const models = typeComposantId ? getComponentModelsForType(typeComposantId) : []
+ const selectedModel = models.find((model) => model.id === modelId)
+
+ if (selectedModel) {
+ const definition = createDefinitionFromModel(selectedModel, requirement)
+ if (!definition.name && node.name) {
+ definition.name = node.name
+ }
+ applyDefinitionToNode(node, definition)
+ node.__componentModelId = selectedModel.id
+ } else {
+ node.__componentModelId = null
+ node.pieces = []
+ node.subComponents = []
+ }
+}
+
+const handleNodePieceModelChange = async (pieceNode, typePieceId, modelId) => {
+ if (typePieceId) {
+ await loadPieceModels(typePieceId)
+ }
+ pieceNode.__pieceModelId = modelId || null
+}
+
const getComponentRequirementEntries = (requirementId) => {
return componentRequirementSelections[requirementId] || []
}
@@ -971,10 +1234,11 @@ const getPieceRequirementEntries = (requirementId) => {
return pieceRequirementSelections[requirementId] || []
}
-const createComponentSelectionEntry = () => ({
+const createComponentSelectionEntry = (requirement) => ({
mode: 'model',
componentModelId: '',
- name: '',
+ name: requirement?.typeComposant?.name || '',
+ definition: createEmptyComponentDefinition(requirement),
})
const createPieceSelectionEntry = () => ({
@@ -999,7 +1263,10 @@ const addComponentSelectionEntry = (requirement) => {
)
return
}
- componentRequirementSelections[requirement.id] = [...entries, createComponentSelectionEntry()]
+ componentRequirementSelections[requirement.id] = [
+ ...entries,
+ createComponentSelectionEntry(requirement),
+ ]
}
const removeComponentSelectionEntry = (requirementId, index) => {
@@ -1009,20 +1276,51 @@ const removeComponentSelectionEntry = (requirementId, index) => {
const setComponentSelectionMode = (requirementId, index, mode) => {
const entries = getComponentRequirementEntries(requirementId)
+ const requirement = getComponentRequirementById(requirementId)
componentRequirementSelections[requirementId] = entries.map((entry, i) => {
if (i !== index) return entry
if (mode === 'model') {
- return { ...entry, mode: 'model', componentModelId: entry.componentModelId || '', name: '' }
+ return {
+ ...entry,
+ mode: 'model',
+ componentModelId: entry.componentModelId || '',
+ definition: entry.definition || createEmptyComponentDefinition(requirement),
+ }
+ }
+ return {
+ ...entry,
+ mode: 'manual',
+ componentModelId: '',
+ definition: entry.definition || createEmptyComponentDefinition(requirement),
}
- return { ...entry, mode: 'manual', componentModelId: '', name: entry.name || '' }
})
}
const updateComponentSelectionEntry = (requirementId, index, patch) => {
const entries = getComponentRequirementEntries(requirementId)
- componentRequirementSelections[requirementId] = entries.map((entry, i) =>
- i === index ? { ...entry, ...patch } : entry
- )
+ const requirement = getComponentRequirementById(requirementId)
+ componentRequirementSelections[requirementId] = entries.map((entry, i) => {
+ if (i !== index) {
+ return entry
+ }
+
+ const updated = { ...entry, ...patch }
+
+ if (Object.prototype.hasOwnProperty.call(patch, 'componentModelId')) {
+ const newModelId = patch.componentModelId || ''
+ const typeId = requirement?.typeComposantId || ''
+ const models = typeId ? getComponentModelsForType(typeId) : []
+ const selectedModel = models.find((model) => model.id === newModelId)
+
+ if (selectedModel) {
+ updated.definition = createDefinitionFromModel(selectedModel, requirement)
+ } else {
+ updated.definition = createEmptyComponentDefinition(requirement)
+ }
+ }
+
+ return updated
+ })
}
const addPieceSelectionEntry = (requirement) => {
@@ -1144,6 +1442,9 @@ const openSkeletonEditor = async () => {
}
const closeSkeletonEditor = () => {
+ if (!skeletonEditor.open) {
+ return
+ }
if (skeletonEditor.submitting) {
return
}
@@ -1153,6 +1454,35 @@ const closeSkeletonEditor = () => {
resetSkeletonRequirementSelections()
}
+const changeMachineView = async (view) => {
+ if (view === activeMachineView.value) {
+ return
+ }
+
+ if (view === 'skeleton') {
+ if (!machineHasSkeletonRequirements.value) {
+ toast.showInfo('Aucun squelette configuré pour cette machine.')
+ return
+ }
+
+ activeMachineView.value = 'skeleton'
+
+ if (!skeletonEditor.open) {
+ try {
+ await openSkeletonEditor()
+ } catch (error) {
+ console.error('Impossible d\'ouvrir l\'éditeur de squelette:', error)
+ toast.showError('Impossible de charger les éléments du squelette.')
+ activeMachineView.value = 'details'
+ }
+ }
+ return
+ }
+
+ closeSkeletonEditor()
+ activeMachineView.value = 'details'
+}
+
const validateSkeletonSelections = (type) => {
const errors = []
const componentSelectionsPayload = []
@@ -1296,8 +1626,7 @@ const saveSkeletonConfiguration = async () => {
const result = await reconfigureMachineSkeleton(machine.value.id, payload)
if (result.success) {
await applySkeletonReconfigurationResult(result.data)
- skeletonEditor.open = false
- resetSkeletonRequirementSelections()
+ await changeMachineView('details')
} else if (result.error) {
toast.showError(result.error)
}
@@ -1353,9 +1682,12 @@ const closeSaveComponentModelModal = () => {
const isEditMode = ref(false)
const debug = ref(false) // Ajout de debug pour afficher les infos de debug
-const machineViewTitle = computed(() =>
- isEditMode.value ? 'Modification de la machine' : 'Détails de la machine'
-)
+const machineViewTitle = computed(() => {
+ if (isSkeletonView.value) {
+ return 'Squelette de la machine'
+ }
+ return isEditMode.value ? 'Modification de la machine' : 'Détails de la machine'
+})
const skeletonEditorTitle = computed(() =>
skeletonEditor.open
@@ -1755,70 +2087,273 @@ const formatSize = (size) => {
return `${formatted.toFixed(1)} ${units[index]}`
}
+const formatCustomFieldValue = (field) => {
+ if (!field) {
+ return 'Non défini'
+ }
+
+ const value = field.value ?? ''
+ if (!value && value !== 0) {
+ return 'Non défini'
+ }
+
+ if (field.type === 'boolean') {
+ const normalized = String(value).toLowerCase()
+ if (normalized === 'true') return 'Oui'
+ if (normalized === 'false') return 'Non'
+ }
+
+ return value
+}
+
+const shouldDisplayCustomField = (field) => {
+ if (!field) {
+ return false
+ }
+
+ if (field.readOnly) {
+ return true
+ }
+
+ if (field.type === 'boolean') {
+ return field.value !== undefined && field.value !== null
+ }
+
+ const value = field.value
+ if (value === null || value === undefined) {
+ return false
+ }
+
+ if (typeof value === 'string') {
+ return value.trim().length > 0
+ }
+
+ return true
+}
+
+const summarizeCustomFields = (fields = []) => {
+ const seen = new Set()
+ return fields
+ .filter(shouldDisplayCustomField)
+ .filter((field) => {
+ const key = field.customFieldId || field.id || field.name
+ if (!key) {
+ return true
+ }
+ if (seen.has(key)) {
+ return false
+ }
+ seen.add(key)
+ return true
+ })
+ .map((field, index) => ({
+ key: field.customFieldId || field.id || field.name || `custom-field-${index}`,
+ label: field.name || 'Champ',
+ value: formatCustomFieldValue(field),
+ }))
+}
+
+const getStructureCustomFields = (structure) => {
+ if (!structure || typeof structure !== 'object') {
+ return []
+ }
+ const customFields = structure.customFields
+ return Array.isArray(customFields) ? customFields : []
+}
+
// Transform custom field values to custom fields format
+const mergeCustomFieldValuesWithDefinitions = (valueEntries = [], ...definitionSources) => {
+ const normalizedValues = (Array.isArray(valueEntries) ? valueEntries : []).map((entry) => {
+ const id = entry?.customField?.id ?? entry?.customFieldId ?? null
+ const name = entry?.customField?.name ?? ''
+ const type = entry?.customField?.type ?? 'text'
+ const required = !!entry?.customField?.required
+ const options = Array.isArray(entry?.customField?.options) ? entry.customField.options : []
+
+ return {
+ customFieldValueId: entry?.id ?? null,
+ id,
+ customFieldId: id,
+ name,
+ type,
+ required,
+ options,
+ value: entry?.value ?? '',
+ readOnly: false,
+ }
+ })
+
+ const result = [...normalizedValues]
+ const keyFor = (item) => item?.id ?? `${item?.name ?? ''}::${item?.type ?? ''}`
+ const existingMap = new Map()
+ result.forEach((item) => {
+ const key = keyFor(item)
+ if (key) {
+ existingMap.set(key, item)
+ }
+ const fallbackKey = item?.name ? `${item.name}::${item.type ?? ''}` : null
+ if (fallbackKey) {
+ existingMap.set(fallbackKey, item)
+ }
+ })
+
+ const definitions = definitionSources
+ .flatMap((source) => (Array.isArray(source) ? source : []))
+ .filter(Boolean)
+
+ definitions.forEach((definition) => {
+ const normalizedDefinition = {
+ id: definition?.id ?? definition?.customFieldId ?? null,
+ name: definition?.name ?? '',
+ type: definition?.type ?? 'text',
+ required: !!definition?.required,
+ options: Array.isArray(definition?.options) ? definition.options : [],
+ customFieldId: definition?.id ?? definition?.customFieldId ?? null,
+ readOnly: !!definition?.readOnly,
+ }
+ const key = normalizedDefinition.id ?? `${normalizedDefinition.name}::${normalizedDefinition.type}`
+ if (!key) {
+ return
+ }
+ if (normalizedDefinition.id) {
+ const fallbackKey = `${normalizedDefinition.name}::${normalizedDefinition.type}`
+ if (existingMap.has(fallbackKey)) {
+ const existingFallback = existingMap.get(fallbackKey)
+ if (existingFallback) {
+ existingFallback.id = existingFallback.id || normalizedDefinition.id
+ existingFallback.customFieldId = normalizedDefinition.id
+ existingFallback.readOnly = existingFallback.readOnly && normalizedDefinition.readOnly
+ existingMap.delete(fallbackKey)
+ existingMap.set(normalizedDefinition.id, existingFallback)
+ existingMap.set(fallbackKey, existingFallback)
+ return
+ }
+ }
+ }
+ const existing = existingMap.get(key) || (normalizedDefinition.name
+ ? existingMap.get(`${normalizedDefinition.name}::${normalizedDefinition.type}`)
+ : null)
+ if (existing) {
+ existing.name = existing.name || normalizedDefinition.name
+ existing.type = existing.type || normalizedDefinition.type
+ existing.required = existing.required ?? normalizedDefinition.required
+ if (!existing.options?.length) {
+ existing.options = normalizedDefinition.options
+ }
+ existing.customFieldId = existing.customFieldId || normalizedDefinition.id
+ existing.readOnly = existing.readOnly && normalizedDefinition.readOnly
+ if (normalizedDefinition.id) {
+ existingMap.set(normalizedDefinition.id, existing)
+ }
+ if (normalizedDefinition.name) {
+ existingMap.set(`${normalizedDefinition.name}::${normalizedDefinition.type}`, existing)
+ }
+ return
+ }
+
+ const entry = {
+ customFieldValueId: null,
+ id: normalizedDefinition.id,
+ customFieldId: normalizedDefinition.id,
+ name: normalizedDefinition.name,
+ type: normalizedDefinition.type,
+ required: normalizedDefinition.required,
+ options: normalizedDefinition.options,
+ value: '',
+ readOnly: false,
+ }
+ result.push(entry)
+ existingMap.set(key, entry)
+ const fallbackKey = entry.name ? `${entry.name}::${entry.type}` : null
+ if (fallbackKey) {
+ existingMap.set(fallbackKey, entry)
+ }
+ })
+
+ return result
+}
+
const transformCustomFields = (pieces) => {
- return pieces.map(piece => {
- const customFields = piece.customFieldValues?.map(cfv => ({
- id: cfv.customField.id,
- name: cfv.customField.name,
- type: cfv.customField.type,
- required: cfv.customField.required,
- options: cfv.customField.options || [],
- value: cfv.value
- })) || []
-
+ return (pieces || []).map((piece) => {
+ const customFields = mergeCustomFieldValuesWithDefinitions(
+ piece.customFieldValues,
+ piece.customFields,
+ piece.typePiece?.customFields,
+ piece.pieceModel?.customFields,
+ getStructureCustomFields(piece.pieceModel?.structure),
+ piece.typeMachinePieceRequirement?.customFields,
+ )
+
return {
...piece,
customFields,
documents: piece.documents || [],
constructeur: piece.constructeur || null,
constructeurId: piece.constructeurId || piece.constructeur?.id || null,
+ typePieceId: piece.typePieceId
+ || piece.typeMachinePieceRequirement?.typePieceId
+ || piece.typePiece?.id
+ || null,
}
})
}
// Transform custom fields for components (now handles nested structure)
const transformComponentCustomFields = (componentsData) => {
- console.log('transformComponentCustomFields called with:', componentsData)
+ return (componentsData || []).map((component) => {
+ const customFields = mergeCustomFieldValuesWithDefinitions(
+ component.customFieldValues,
+ component.customFields,
+ component.typeComposant?.customFields,
+ component.composantModel?.customFields,
+ getStructureCustomFields(component.composantModel?.structure),
+ component.typeMachineComponentRequirement?.customFields,
+ )
- return componentsData.map(component => {
- console.log('Processing component:', component.name, 'with sousComposants:', component.sousComposants?.length || 0)
-
- // Transform custom fields for the current component
- const customFields = component.customFieldValues?.map(cfv => ({
- id: cfv.customField.id,
- name: cfv.customField.name,
- type: cfv.customField.type,
- required: cfv.customField.required,
- options: cfv.customField.options || [],
- value: cfv.value
- })) || [];
-
- // Transform pieces for the current component
const pieces = component.pieces
? transformCustomFields(component.pieces).map((piece) => ({
...piece,
parentComponentName: component.name,
}))
- : [];
-
- // Recursively transform sub-components (using 'sousComposants' from backend)
- const subComponents = component.sousComposants ? transformComponentCustomFields(component.sousComposants) : [];
-
- const result = {
+ : []
+
+ const subComponents = component.sousComposants
+ ? transformComponentCustomFields(component.sousComposants)
+ : []
+
+ return {
...component,
- customFields, // Use customFields for frontend display
+ customFields,
pieces,
- subComponents, // Use the transformed sousComposants as subComponents
+ subComponents,
documents: component.documents || [],
constructeur: component.constructeur || null,
constructeurId: component.constructeurId || component.constructeur?.id || null,
- };
-
- console.log('Transformed component:', result.name, 'with subComponents:', result.subComponents?.length || 0)
- return result;
- });
-};
+ typeComposantId: component.typeComposantId
+ || component.typeMachineComponentRequirement?.typeComposantId
+ || component.typeComposant?.id
+ || null,
+ }
+ })
+}
+
+const syncMachineCustomFields = () => {
+ if (!machine.value) {
+ machineCustomFields.value = []
+ return
+ }
+
+ const merged = mergeCustomFieldValuesWithDefinitions(
+ machine.value.customFieldValues,
+ machine.value.customFields,
+ machine.value.typeMachine?.customFields,
+ ).map((field) => ({
+ ...field,
+ readOnly: false,
+ }))
+
+ machineCustomFields.value = merged
+}
function mergePieceLists(existing = [], updates = []) {
if (!existing.length) {
@@ -1902,9 +2437,11 @@ const loadMachineData = async () => {
if (machineResult.success) {
machine.value = machineResult.data
machine.value.documents = machine.value.documents || []
+ machine.value.customFieldValues = machine.value.customFieldValues || []
machineDocumentsLoaded.value = !!(machine.value.documents?.length)
console.log('Machine trouvée et assignée:', machine.value)
+ syncMachineCustomFields()
await preloadModelsForTypeMachine(machine.value.typeMachine)
} else {
console.error('Machine non trouvée:', machineId)
@@ -2067,12 +2604,14 @@ const assignComponentModel = async ({ componentId, composantModelId, previousMod
const target = findComponentById(components.value, componentId)
if (target) {
Object.assign(target, transformed)
+ components.value = [...components.value]
}
} else {
const target = findComponentById(components.value, componentId)
if (target) {
target.composantModelId = previousModelId || null
target.composantModel = previousModel || null
+ components.value = [...components.value]
}
toast.showError(result.error || 'Impossible de mettre à jour le modèle du composant')
}
@@ -2082,6 +2621,7 @@ const assignComponentModel = async ({ componentId, composantModelId, previousMod
if (target) {
target.composantModelId = previousModelId || null
target.composantModel = previousModel || null
+ components.value = [...components.value]
}
toast.showError('Impossible de mettre à jour le modèle du composant')
}
@@ -2149,12 +2689,16 @@ const assignPieceModel = async ({ pieceId, pieceModelId, previousModelId, previo
const target = findPieceById(pieceId)
if (target) {
Object.assign(target, transformed)
+ pieces.value = [...pieces.value]
+ components.value = [...components.value]
}
} else {
const target = findPieceById(pieceId)
if (target) {
target.pieceModelId = previousModelId || null
target.pieceModel = previousModel || null
+ pieces.value = [...pieces.value]
+ components.value = [...components.value]
}
toast.showError(result.error || 'Impossible de mettre à jour le modèle de pièce')
}
@@ -2164,31 +2708,86 @@ const assignPieceModel = async ({ pieceId, pieceModelId, previousModelId, previo
if (target) {
target.pieceModelId = previousModelId || null
target.pieceModel = previousModel || null
+ pieces.value = [...pieces.value]
+ components.value = [...components.value]
}
toast.showError('Impossible de mettre à jour le modèle de pièce')
}
}
// Méthodes pour les champs personnalisés de la machine
-const setMachineCustomFieldValue = (fieldValueId, value) => {
- const fieldValue = machine.value?.customFieldValues?.find(fv => fv.id === fieldValueId)
- if (fieldValue) {
- fieldValue.value = value
+const setMachineCustomFieldValue = (field, value) => {
+ if (!field) {
+ return
+ }
+
+ field.value = value
+
+ if (field.customFieldValueId && machine.value?.customFieldValues) {
+ const stored = machine.value.customFieldValues.find((fv) => fv.id === field.customFieldValueId)
+ if (stored) {
+ stored.value = value
+ }
}
}
-const updateMachineCustomField = async (fieldValueId) => {
- const fieldValue = machine.value?.customFieldValues?.find(fv => fv.id === fieldValueId)
- if (fieldValue) {
- const { updateCustomFieldValue } = useCustomFields()
- const { showSuccess, showError } = useToast()
-
- const result = await updateCustomFieldValue(fieldValueId, { value: fieldValue.value })
- if (result.success) {
- showSuccess(`Champ "${fieldValue.customField.name}" de la machine mis à jour avec succès`)
- } else {
- showError(`Erreur lors de la mise à jour du champ "${fieldValue.customField.name}"`)
+const updateMachineCustomField = async (field) => {
+ if (!machine.value || !field) {
+ return
+ }
+
+ const { id: customFieldId, customFieldValueId } = field
+ const fieldLabel = field.name || 'Champ personnalisé'
+
+ try {
+ if (customFieldValueId) {
+ const result = await updateCustomFieldValueApi(customFieldValueId, { value: field.value ?? '' })
+ if (result.success) {
+ toast.showSuccess(`Champ "${fieldLabel}" de la machine mis à jour avec succès`)
+ syncMachineCustomFields()
+ } else {
+ toast.showError(`Erreur lors de la mise à jour du champ "${fieldLabel}"`)
+ }
+ return
}
+
+ if (!customFieldId) {
+ toast.showError('Impossible de mettre à jour ce champ personnalisé (identifiant manquant).')
+ return
+ }
+
+ const result = await upsertCustomFieldValue(customFieldId, 'machine', machine.value.id, field.value ?? '')
+ if (result.success) {
+ const createdValue = result.data
+ toast.showSuccess(`Champ "${fieldLabel}" de la machine mis à jour avec succès`)
+
+ if (createdValue?.id) {
+ if (!createdValue.customField) {
+ createdValue.customField = {
+ id: customFieldId,
+ name: field.name,
+ type: field.type,
+ required: field.required,
+ options: field.options,
+ }
+ }
+ field.customFieldValueId = createdValue.id
+ field.readOnly = false
+
+ const existingValues = Array.isArray(machine.value.customFieldValues)
+ ? machine.value.customFieldValues.filter((item) => item.id !== createdValue.id)
+ : []
+
+ machine.value.customFieldValues = [...existingValues, createdValue]
+ }
+
+ syncMachineCustomFields()
+ } else {
+ toast.showError(`Erreur lors de la mise à jour du champ "${fieldLabel}"`)
+ }
+ } catch (error) {
+ console.error('Erreur lors de la mise à jour du champ personnalisé de la machine:', error)
+ toast.showError(`Erreur lors de la mise à jour du champ "${fieldLabel}"`)
}
}
@@ -2231,6 +2830,30 @@ const toggleEditMode = () => {
}
}
+watch(
+ () => machine.value?.customFieldValues,
+ () => {
+ syncMachineCustomFields()
+ },
+ { deep: true }
+)
+
+watch(
+ () => machine.value?.customFields,
+ () => {
+ syncMachineCustomFields()
+ },
+ { deep: true }
+)
+
+watch(
+ () => machine.value?.typeMachine?.customFields,
+ () => {
+ syncMachineCustomFields()
+ },
+ { deep: true }
+)
+
watch(
() => [components.value.length, machinePieces.value.length],
() => {